feiyu02
2025-12-20 5a003a42d2b34e8362910ac1d3e5a8866768e5fe
2025.12.20
巡查任务统计相关功能修改
已修改14个文件
618 ■■■■ 文件已修改
src/main/kotlin/cn/flightfeather/supervision/business/import/SceneImport.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/domain/ds1/repository/SceneRep.kt 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/ProblemlistService.kt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/SubtaskService.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/MonitorobjectversionServiceImpl.kt 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/ProblemlistServiceImpl.kt 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/SubtaskServiceImpl.kt 132 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/TaskServiceImpl.kt 84 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/vo/DayTaskProgressVo.kt 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/vo/MonitorObjectVersionVo.kt 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/vo/ScenseVo.kt 128 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/web/ProblemlistController.kt 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/lightshare/web/SubtaskController.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/cn/flightfeather/supervision/business/location/LocationRoadNearbyTest.kt 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/cn/flightfeather/supervision/business/import/SceneImport.kt
@@ -93,8 +93,12 @@
                        index = it.getCell(0)?.numericCellValue?.toInt()
                        remark = null
                    }
                    if (scense?.name.isNullOrBlank()) throw BizException(errorStr(it.rowNum + 1, 2, "场景名称不能空白"))
                    scense?.typeid = Constant.SceneType.getByName(scense?.type)?.value?.toByte()
                        ?: throw BizException(errorStr(it.rowNum + 1, 3, "场景类型不存在"))
                    if (scense?.location.isNullOrBlank()) throw BizException(errorStr(it.rowNum + 1, 4, "场景地址不能空白"))
                    scense?.longitude ?: throw BizException(errorStr(it.rowNum + 1, 5, "经度不能空白"))
                    scense?.latitude ?: throw BizException(errorStr(it.rowNum + 1, 6, "纬度不能空白"))
                    scense?.provincecode = regionRep.findProvince(scense?.provincename)?.provincecode
                        ?: throw BizException(errorStr(it.rowNum + 1, 7, "省份错误或系统未曾配置"))
                    scense?.citycode = regionRep.findCity(scense?.cityname)?.citycode
src/main/kotlin/cn/flightfeather/supervision/domain/ds1/repository/SceneRep.kt
@@ -91,6 +91,35 @@
        return isUpdate to r
    }
    fun findSubSceneList(scenes: List<Scense>): List<BaseScene?> {
        val result = mutableListOf<BaseScene>()
        scenes.groupBy { it.typeid }.forEach {
            when (it.key.toString()) {
                Constant.SceneType.TYPE1.value -> {
                    sceneConstructionSiteMapper.selectByExample(Example(SceneConstructionSite::class.java).apply {
                        createCriteria().andIn("sGuid", it.value.map { v-> v.guid })
                    }).let { s-> result.addAll(s) }
                }
                Constant.SceneType.TYPE2.value -> {
                    sceneWharfMapper.selectByExample(Example(SceneWharf::class.java).apply {
                        createCriteria().andIn("sGuid", it.value.map { v-> v.guid })
                    }).let { s-> result.addAll(s) }
                }
                Constant.SceneType.TYPE3.value -> {
                    sceneMixingPlantMapper.selectByExample(Example(SceneMixingPlant::class.java).apply {
                        createCriteria().andIn("sGuid", it.value.map { v-> v.guid })
                    }).let { s-> result.addAll(s) }
                }
                Constant.SceneType.TYPE14.value -> {
                    sceneStorageYardMapper.selectByExample(Example(SceneStorageYard::class.java).apply {
                        createCriteria().andIn("sGuid", it.value.map { v-> v.guid })
                    }).let { s-> result.addAll(s) }
                }
            }
        }
        return result
    }
    fun findScene(userId: String?): Scense? {
        val user = userinfoMapper.selectByPrimaryKey(userId) ?: throw BizException("用户id不存在")
        return scenseMapper.selectByPrimaryKey(user.dGuid)
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/ProblemlistService.kt
@@ -37,6 +37,8 @@
    fun getProblemByScene(sceneId: String, date: String):List<ProblemListVo>
    fun getBySceneMonth(sceneId: String, year: Int?, month: Int?):List<ProblemListVo>
    fun findMonthProblemById(taskId:String, sceneId:Int?):List<MonthProblemVo>
    fun check(pId: String, action: Byte, remark: String, userId: String, userName: String): String
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/SubtaskService.kt
@@ -47,7 +47,7 @@
    fun searchSubTask3(token: String,updateTime: String?, sceneType: Int? = null, districtCode: String? = "310116", startTime: String? = "", endTime: String? = "", page: Int? = 1, perPage: Int? = 30): BaseResponse<BaseSearchResultVo>
    fun findByDate(date: String, userId: String): List<SubtaskVo>
    fun findByDate(date: String? = null, userId: String? = null, sceneId: String? = null): List<SubtaskVo>
    fun getByTopTaskAndDate(topTaskId: String, startTime: String?, endTime: String?, sceneTypeId: Int? = null): List<Subtask>
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/MonitorobjectversionServiceImpl.kt
@@ -1,10 +1,10 @@
package cn.flightfeather.supervision.lightshare.service.impl
import cn.flightfeather.supervision.common.utils.UUIDGenerator
import cn.flightfeather.supervision.domain.ds1.entity.Monitorobjectversion
import cn.flightfeather.supervision.domain.ds1.entity.Scense
import cn.flightfeather.supervision.domain.ds1.entity.*
import cn.flightfeather.supervision.domain.ds1.mapper.MonitorobjectversionMapper
import cn.flightfeather.supervision.domain.ds1.mapper.TaskMapper
import cn.flightfeather.supervision.domain.ds1.repository.SceneRep
import cn.flightfeather.supervision.lightshare.service.MonitorobjectversionService
import cn.flightfeather.supervision.lightshare.service.ScenseService
import cn.flightfeather.supervision.lightshare.vo.MonitorObjectVersionVo
@@ -14,8 +14,10 @@
import org.springframework.transaction.annotation.Transactional
@Service
class MonitorobjectversionServiceImpl(val monitorobjectversionMapper: MonitorobjectversionMapper) :
    MonitorobjectversionService {
class MonitorobjectversionServiceImpl(
    private val monitorobjectversionMapper: MonitorobjectversionMapper,
    private val sceneRep: SceneRep,
) : MonitorobjectversionService {
    @Autowired
    lateinit var taskMapper: TaskMapper
@@ -63,6 +65,7 @@
            districtcode = task.districtcode
        }
        val sceneList = scenseService.search(s)
        val subSceneList = sceneRep.findSubSceneList(sceneList)
        val monitorobjectversion = Monitorobjectversion()
        monitorobjectversion.tid = id
@@ -72,14 +75,21 @@
        monitorobjectversionlist.forEach {
            val vo = MonitorObjectVersionVo()
            BeanUtils.copyProperties(it, vo)
            sceneList.forEach f@ {scene ->
                if (vo.sguid == scene.guid) {
                    vo.sceneTypeId = scene.typeid?.toInt() ?: 0
                    vo.sceneType = scene.type
                    vo.scene = scene
                    return@f
                }
            sceneList.find {s-> s.guid == vo.sguid }?.let { s->
                vo.sceneTypeId = s.typeid?.toInt() ?: 0
                vo.sceneType = s.type
                vo.scene = s
            }
            subSceneList.find { s ->
                val sGuid = when(s){
                    is SceneConstructionSite-> s.getsGuid()
                    is SceneWharf -> s.getsGuid()
                    is SceneMixingPlant -> s.getsGuid()
                    is SceneStorageYard-> s.getsGuid()
                    else -> null
                }
                sGuid == vo.sguid
            }?.let { s-> vo.subScene = s }
            resultList.add(vo)
        }
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/ProblemlistServiceImpl.kt
@@ -13,6 +13,7 @@
import cn.flightfeather.supervision.domain.ds1.repository.TaskRep
import cn.flightfeather.supervision.lightshare.service.MediafileService
import cn.flightfeather.supervision.lightshare.service.ProblemlistService
import cn.flightfeather.supervision.lightshare.service.SubtaskService
import cn.flightfeather.supervision.lightshare.service.TaskService
import cn.flightfeather.supervision.lightshare.vo.*
import com.fasterxml.jackson.core.type.TypeReference
@@ -105,6 +106,36 @@
        return problemListVolistTemp1
    }
    override fun getBySceneMonth(sceneId: String, year: Int?, month: Int?): List<ProblemListVo> {
        var _year = year
        var _month = month
        if (year == null) {
            PageHelper.startPage<Problemlist>(1, 1)
            val lastProblem = problemlistMapper.selectByExample(Example(Problemlist::class.java).apply {
                createCriteria().andEqualTo("sguid", sceneId)
                orderBy("time").desc()
            }).takeIf { it.isNotEmpty() }?.get(0)
            if (lastProblem == null) {
                return emptyList()
            } else {
                val lt = LocalDateTime.ofInstant(lastProblem.time?.toInstant(), ZoneId.systemDefault())
                _year = lt.year
                _month = lt.monthValue
            }
        }
        val sT = LocalDateTime.of(_year!!, _month!!, 1, 0, 0, 0, 0)
        val eT = sT.plusMonths(1).minusSeconds(1)
        return problemlistMapper.selectByExample(Example(Problemlist::class.java).apply {
            createCriteria().andBetween("time", sT,eT)
                .andEqualTo("sguid", sceneId)
            orderBy("time").desc()
        }).map {
            val problemVo = ProblemListVo();
            BeanUtils.copyProperties(it, problemVo)
            problemVo
        }
    }
    //获取某顶层任务下,某个场景下的问题整改情况
    override fun getStatisticalResultById(topTaskId: String, sceneTypeId: String): List<StatisticsVo> {
        val map = problemlistMapper.getStatisticalResultById(topTaskId, sceneTypeId)
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/SubtaskServiceImpl.kt
@@ -33,20 +33,28 @@
    @Autowired
    lateinit var taskService: TaskService
    @Autowired
    lateinit var taskMapper: TaskMapper
    @Autowired
    lateinit var evaluationMapper: EvaluationMapper
    @Autowired
    lateinit var problemlistMapper: ProblemlistMapper
    @Autowired
    lateinit var mediafileMapper: MediafileMapper
    @Autowired
    lateinit var scenseMapper: ScenseMapper
    @Autowired
    lateinit var inspectionMapper: InspectionMapper
    @Autowired
    lateinit var monitorobjectversionMapper: MonitorobjectversionMapper
    @Autowired
    lateinit var problemtypeMapper: ProblemtypeMapper
@@ -65,11 +73,11 @@
            criteria.andEqualTo("towncode", areaVo.towncode)
        criteria.andBetween("planstarttime", areaVo.starttime, areaVo.endtime)
        if (!Objects.equals(userGuid, Constant.UserType.ALL_USER.des))
            criteria.andLike("executorguids","%"+userGuid+"%")
            criteria.andLike("executorguids", "%" + userGuid + "%")
        var completecount = 0
        var subtasklist = subtaskMapper.selectByExample(example)
        subtasklist.forEach {
            if (Objects.equals(it.status, Constant.TaskProgress.RUNINGSTATUS3.text)){
            if (Objects.equals(it.status, Constant.TaskProgress.RUNINGSTATUS3.text)) {
                completecount++
            }
        }
@@ -102,24 +110,26 @@
        criteria.andEqualTo("tsguid", dayTaskId)
        if (userType == "1") {
            example.and(
                    example.createCriteria().orLike("executorguids", "%$userId%")
                            .orLike("stAssessorguid", "%$userId%")
                example.createCriteria().orLike("executorguids", "%$userId%")
                    .orLike("stAssessorguid", "%$userId%")
            )
        }
        example.orderBy("name")
        val result = subtaskMapper.selectByExample(example).apply{
        val result = subtaskMapper.selectByExample(example).apply {
            forEach breaking@{
                //已审核提示
                it.remark= Constant.PROBLEM_CHECK_PASS
                it.remark = Constant.PROBLEM_CHECK_PASS
                problemlistMapper.selectByExample(Example(Problemlist::class.java).apply {
                    createCriteria().andEqualTo("stguid", it.stguid)
                    and(createCriteria().orIsNull("remark")
                            .orNotEqualTo("remark", Constant.PROBLEM_DELETED))
                }).forEach {problem ->
                    and(
                        createCriteria().orIsNull("remark")
                            .orNotEqualTo("remark", Constant.PROBLEM_DELETED)
                    )
                }).forEach { problem ->
                    //子任务中有问题未审核时,设置未审核提示
                    if (problem.extension3 == Constant.PROBLEM_UNCHECKED) {
                        it.remark= Constant.PROBLEM_UNCHECKED
                        it.remark = Constant.PROBLEM_UNCHECKED
                        return@breaking
                    }
                }
@@ -168,13 +178,13 @@
        } else {
            guid
        }
        val userTypeId = if (userType == "主管部门"){
        val userTypeId = if (userType == "主管部门") {
            "2"
        }else if (userType == "飞羽用户") {
        } else if (userType == "飞羽用户") {
            "1"
        } else if(userType == "管理员"){
        } else if (userType == "管理员") {
            "0"
        }else if (userType == "场景") {
        } else if (userType == "场景") {
            "3"
        } else {
            userType
@@ -197,16 +207,19 @@
                two = dateString
                three = DateUtil.addMonth(dateString, 1)
            }
            "Left" -> {
                one = DateUtil.addMonth(dateString, 1)
                two = DateUtil.addMonth(dateString, 2)
                three = DateUtil.addMonth(dateString, 3)
            }
            "Right" -> {
                one = DateUtil.addMonth(dateString, -1)
                two = DateUtil.addMonth(dateString, -2)
                three = DateUtil.addMonth(dateString, -3)
            }
            else -> {
                //参数不正确就返回
                return taskPackList
@@ -251,16 +264,19 @@
                two = dateString
                three = DateUtil.addMonth(dateString, 1)
            }
            "Left" -> {
                one = DateUtil.addMonth(dateString, 1)
                two = DateUtil.addMonth(dateString, 2)
                three = DateUtil.addMonth(dateString, 3)
            }
            "Right" -> {
                one = DateUtil.addMonth(dateString, -1)
                two = DateUtil.addMonth(dateString, -2)
                three = DateUtil.addMonth(dateString, -3)
            }
            else -> {
                //参数不正确就返回
                return taskPackList
@@ -422,21 +438,22 @@
            subtask.tsguid = daytaskVo.tguid
            //*(修改)*日任务正在执行,子任务结束,遍历所有其余子任务,都是结束时才将日任务修改为结束****
            if (subtask.status == Constant.TaskProgress.RUNINGSTATUS3.text
                && daytaskVo.runingstatus == Constant.TaskProgress.RUNINGSTATUS2.text){
                && daytaskVo.runingstatus == Constant.TaskProgress.RUNINGSTATUS2.text
            ) {
                val subtaskVolist = findByDayTaskID(daytaskVo.tguid!!)
                var bool = false
                subtaskVolist.forEach {
                    if (it.status != Constant.TaskProgress.RUNINGSTATUS3.text){
                    if (it.status != Constant.TaskProgress.RUNINGSTATUS3.text) {
                        bool = true
                    }
                }
                if (!bool){
                if (!bool) {
                    daytaskVo.runingstatus = Constant.TaskProgress.RUNINGSTATUS3.text
                }
            }
            //两者状态相同时不做修改,其余情况日任务都为正在执行
            else if (subtask.status != daytaskVo.runingstatus){
            else if (subtask.status != daytaskVo.runingstatus) {
                daytaskVo.runingstatus = Constant.TaskProgress.RUNINGSTATUS2.text
            }
            val daytask = Task()
@@ -465,7 +482,7 @@
    }
    @Transactional
    override fun delete(id: String): Int{
    override fun delete(id: String): Int {
        val subtask = subtaskMapper.selectByPrimaryKey(id)
        val dayTaskId = subtask.tsguid
        subtaskMapper.deleteByPrimaryKey(id)
@@ -500,7 +517,15 @@
    }
    override fun searchSubTask(token: String, sceneType: Int?, districtCode: String?, startTime: String?, endTime: String?, page: Int?, perPage: Int?): BaseSearchResultVo {
    override fun searchSubTask(
        token: String,
        sceneType: Int?,
        districtCode: String?,
        startTime: String?,
        endTime: String?,
        page: Int?,
        perPage: Int?,
    ): BaseSearchResultVo {
        if (token != "jingan") {
            return BaseSearchResultVo().apply {
                head = DataHead().apply {
@@ -543,7 +568,7 @@
//        val  p = PageHelper.startPage<Subtask>(page ?: 1, perPage ?: 30)
        subtaskMapper.getSubtask2(null, null, _districtCode, _sceneType.toByte(), _startTime, _endTime).forEach {
            if (!subtaskMap.containsKey(it.subTaskId)) {
                val vo =SubtaskSearchResultVo()
                val vo = SubtaskSearchResultVo()
                BeanUtils.copyProperties(it, vo)
                subtaskMap[it.subTaskId] = vo
            }
@@ -553,7 +578,7 @@
                problemMap[it.problemId] = problemDetail
                subtaskMap[it.subTaskId]?.problemList?.add(problemDetail)
            }
            val url = it.mExtension1 + it.mGuid+ ".jpg"
            val url = it.mExtension1 + it.mGuid + ".jpg"
            if (it.isChanged == true) {
                problemMap[it.problemId]?.rectificationPics?.add(url)
            } else {
@@ -647,8 +672,10 @@
                        .andNotEqualTo("extension3", Constant.CHANGE_CHECK_FAIL)
                        .andIsNotNull("extension3")
                    time?.let {
                        and(createCriteria().orGreaterThan("time", it)
                            .orGreaterThan("changedtime", it))
                        and(
                            createCriteria().orGreaterThan("time", it)
                                .orGreaterThan("changedtime", it)
                        )
                    }
                }).forEach { p ->
                    val problem = ProblemDetail().apply {
@@ -743,7 +770,16 @@
        return BaseResponse(true, "请求成功", data = result)
    }
    override fun searchSubTask3(token: String, updateTime: String?, sceneType: Int?, districtCode: String?, startTime: String?, endTime: String?, page: Int?, perPage: Int?): BaseResponse<BaseSearchResultVo> {
    override fun searchSubTask3(
        token: String,
        updateTime: String?,
        sceneType: Int?,
        districtCode: String?,
        startTime: String?,
        endTime: String?,
        page: Int?,
        perPage: Int?,
    ): BaseResponse<BaseSearchResultVo> {
        if (token != "jinshan") {
            return BaseResponse(false, "请求token错误")
        }
@@ -798,8 +834,10 @@
                        .andNotEqualTo("extension3", Constant.CHANGE_CHECK_FAIL)
                        .andIsNotNull("extension3")
                    time?.let {
                        and(createCriteria().orGreaterThan("time", it)
                            .orGreaterThan("changedtime", it))
                        and(
                            createCriteria().orGreaterThan("time", it)
                                .orGreaterThan("changedtime", it)
                        )
                    }
                }).forEach { p ->
                    val problem = ProblemDetail().apply {
@@ -868,7 +906,7 @@
//            val p = PageHelper.startPage<Subtask>(page ?: 1, perPage ?: 30)
            subtaskMapper.getSubtask2(time, time2, _districtCode, _sceneType?.toByte(), null, null).forEach {
                if (!subtaskMap.containsKey(it.subTaskId)) {
                    val vo =SubtaskSearchResultVo()
                    val vo = SubtaskSearchResultVo()
                    BeanUtils.copyProperties(it, vo)
                    subtaskMap[it.subTaskId] = vo
                }
@@ -878,7 +916,7 @@
                    problemMap[it.problemId] = problemDetail
                    subtaskMap[it.subTaskId]?.problemList?.add(problemDetail)
                }
                val url = it.mExtension1 + it.mGuid+ ".jpg"
                val url = it.mExtension1 + it.mGuid + ".jpg"
                if (it.isChanged == true) {
                    problemMap[it.problemId]?.rectificationPics?.add(url)
                } else {
@@ -899,15 +937,37 @@
        return BaseResponse(true, "请求成功", data = result)
    }
    override fun findByDate(date: String, userId: String): List<SubtaskVo> {
        val time = DateUtil.StringToDate(date)
    override fun findByDate(date: String?, userId: String?, sceneId: String?): List<SubtaskVo> {
        val time = if (date == null) null else DateUtil.StringToDate(date)
        val resultList = mutableListOf<SubtaskVo>()
        subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
            createCriteria().andLessThanOrEqualTo("planstarttime", time)
        val subtasks = if (time != null) {
            // 获取某一天的巡查任务
            subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                createCriteria().andLessThanOrEqualTo("planstarttime", time)
                    .andGreaterThanOrEqualTo("planendtime", time)
        }).forEach {
                    .apply { sceneId?.let { andEqualTo("scenseid", it) } }
            })
        } else {
            // 获取最近一个月内的(某个场景的)所有巡查任务
            PageHelper.startPage<Subtask>(1, 1)
            val lastOne = subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                createCriteria().apply {
                    sceneId?.let { andEqualTo("scenseid", it) }
                }
                orderBy("planstarttime").desc()
            }).takeIf { it.isNotEmpty() }?.get(0)
            if (lastOne == null) {
                emptyList()
            } else {
                subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                    createCriteria().andEqualTo("tguid", lastOne.tguid)
                        .andEqualTo("scenseid", lastOne.scenseid)
                })
            }
        }
        subtasks.forEach {
            val vo = SubtaskVo()
            BeanUtils.copyProperties(it, vo)
            resultList.add(vo)
@@ -920,7 +980,7 @@
        topTaskId: String,
        startTime: String?,
        endTime: String?,
        sceneTypeId: Int?
        sceneTypeId: Int?,
    ): List<Subtask> {
        return subtaskMapper.selectByTopTask2(topTaskId, sceneTypeId)
@@ -933,7 +993,7 @@
    override fun getTaskProgressByArea(areaVo: AreaVo): List<TaskProgressVo> {
//        areaVo.scensetypeid ?: throw BizException("缺少场景类型参数")
        val res = mutableListOf<TaskProgressVo>()
        taskRep.findTasks(areaVo).forEach {t->
        taskRep.findTasks(areaVo).forEach { t ->
            if (t?.tguid == null) return@forEach
            val pro = TaskProgressVo().apply {
                tguid = t.tguid
src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/TaskServiceImpl.kt
@@ -339,14 +339,6 @@
            val filterSubTasks = subTasks.filter {s->
                s?.tsguid == t?.tguid
            }
            // 子任务总数
            val total = filterSubTasks.size
            // 子任务完成数
            val complete = filterSubTasks.count {fs->
                fs?.status == Constant.TaskProgress.RUNINGSTATUS3.text
            }
            // 获取当日所有的问题
            val subTaskIds = filterSubTasks.map { fs-> fs?.stguid }
            val problemList = if (subTaskIds.isNotEmpty()) {
@@ -356,8 +348,69 @@
            } else{
                emptyList()
            }
            /** 总巡查量统计 **/
            // 子任务总数
            val total = filterSubTasks.size
            // 子任务完成数
            val complete = filterSubTasks.count {fs->
                fs?.status == Constant.TaskProgress.RUNINGSTATUS3.text
            }
            /** 总问题整改率统计 **/
            // 总问题数和总整改数
            val totalProblemNum = problemList.size
            val changedProblemNum = problemList.filter { it.ischanged == true }.size
            /** 每个人的巡查量问题整改率 **/
            val userProgressMap = mutableMapOf<String, ProgressPerUserPerDay>()
            filterSubTasks.forEach fst@ { fst->
                fst ?: return@fst
                // fixme 2025.11.30 由于监管APP的bug,导致用户可以不选择执行人员直接创建任务,所以暂时将没有执行人员的任务定义为匿名用户
                if (fst.executorguids.isNullOrBlank()) {
                    fst.executorguids = "niming"
                    fst.executorusernames = "niming"
                    fst.executorrealtimes = "匿名用户"
                }
                val ids = fst.executorguids?.split("#") ?: return@fst
                val names = fst.executorrealtimes?.split("#") ?: return@fst
                // 筛选每个子任务下的问题
                val proList = problemList.filter { p-> p?.stguid == fst.stguid }
                for (i in ids.indices) {
                    val key = ids[i]
                    if (!userProgressMap.containsKey(key)) {
                        userProgressMap[key] = ProgressPerUserPerDay().apply {
                            this.userId = key
                            this.userName = names[i]
                        }
                    }
                    userProgressMap[key]?.apply {
                        // 单人巡查量累计
                        // 当多个人一起执行同一任务时,平分巡查量
                        this.totalTaskNum += 1.0 / ids.size
                        if (fst.status== Constant.TaskProgress.RUNINGSTATUS3.text)
                            this.completeTaskNum += 1.0 / ids.size
                        // 单人整改率累计(评分)
                        this.totalProblemNum += proList.size.toDouble() / ids.size
                        this.changedProblemNum += proList.filter { it.ischanged == true }.size.toDouble() / ids.size
                        this.changedProblemNumOnTime += proList.filter {
                            // 整改耗时(天)
                            val day = ((it.changedtime?.time ?: 0L) - (it?.time?.time ?: 0L)).div(1000 * 60 * 60 * 24)
                            it.ischanged == true &&  day <= 1
                        }.size.toDouble() / ids.size
                        // 此处先累计巡查时长,最后再根据任务数量平均
                        this.avgInspectionTime +=
                            ((fst.executionendtime?.time ?: 0L) - (fst.executionstarttime?.time ?: 0L)).div(1000).div(ids.size)
                    }
                }
            }
            // 统一计算平均巡查时长(秒)
            userProgressMap.forEach { (t, u) ->
                u.avgInspectionTime = (u.avgInspectionTime / u.completeTaskNum).toLong()
                u.formatParam()
            }
            /** 任务整改完成情况和审核情况统计 **/
            var changed = 0
            //审核是否完成
            var check = true
@@ -376,9 +429,18 @@
                }
            }
            resultList.add(DayTaskProgressVo(
                t?.tguid, t?.starttime, taskId, complete, changed, total, check
            ))
            resultList.add(DayTaskProgressVo().apply {
                this.guid =t?.tguid
                this.date =t?.starttime
                this.tsGuid = taskId
                this.totalTaskNum = total
                this.completeTaskNum = complete
                this.changedTaskNum = changed
                this.check = check
                this.totalProblemNum = totalProblemNum
                this.changedProblemNum = changedProblemNum
                this.progressPerUser = userProgressMap.entries.map { it.value }
            })
        }
        return resultList
src/main/kotlin/cn/flightfeather/supervision/lightshare/vo/DayTaskProgressVo.kt
@@ -1,25 +1,80 @@
package cn.flightfeather.supervision.lightshare.vo
import org.apache.poi.hpsf.Decimal
import java.math.BigDecimal
import java.text.DecimalFormat
import java.util.*
import kotlin.math.round
/**
 * @author riku
 * Date: 2019/7/30
 * 日任务进度类
 */
data class DayTaskProgressVo(
        //日任务id
        val guid: String? = null,
        //日任务时间
        val date: Date? = null,
        //所属顶层任务id
        val tsGuid: String? = null,
        //完成子任务数
        val completeTaskNum: Int = 0,
        //已整改子任务数
        val changedTaskNum: Int = 0,
        //总子任务数
        val totalTaskNum: Int = 0,
        //是否有未审核的问题
        val check: Boolean = false
)
class DayTaskProgressVo {
    //日任务id
    var guid: String? = null
    //日任务时间
    var date: Date? = null
    //所属顶层任务id
    var tsGuid: String? = null
    //总子任务数
    var totalTaskNum: Int = 0
    //完成子任务数
    var completeTaskNum: Int = 0
    //已整改子任务数
    var changedTaskNum: Int = 0
    //当存在至少一个问题没有审核时,当日审核状态为未审核
    var check: Boolean = false
    // 总问题数
    var totalProblemNum: Int = 0
    // 总整改问题数
    var changedProblemNum: Int = 0
    // 每个用户的单日任务进度
    var progressPerUser: List<ProgressPerUserPerDay>? = null
}
class ProgressPerUserPerDay{
    //用户id
    var userId: String? = null
    //用户名
    var userName: String? = null
    //总子任务数
    var totalTaskNum: Double = .0
    //完成子任务数
    var completeTaskNum: Double = .0
    // 总问题数
    var totalProblemNum: Double = .0
    //已整改问题数
    var changedProblemNum: Double = .0
    //已整改问题数(在当天内整改)
    var changedProblemNumOnTime: Double = .0
    //平均巡查时长(秒)
    var avgInspectionTime: Long = 0
    /**
     * 格式化Double参数,保留两位小数,四舍五入
     */
    fun formatParam() {
        totalTaskNum = numberFormat(totalTaskNum)
        completeTaskNum = numberFormat(completeTaskNum)
        totalProblemNum = numberFormat(totalProblemNum)
        changedProblemNum = numberFormat(changedProblemNum)
        changedProblemNumOnTime = numberFormat(changedProblemNumOnTime)
    }
    private fun numberFormat(value:Double): Double {
        return BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP).toDouble()
    }
}
src/main/kotlin/cn/flightfeather/supervision/lightshare/vo/MonitorObjectVersionVo.kt
@@ -1,6 +1,9 @@
package cn.flightfeather.supervision.lightshare.vo
import cn.flightfeather.supervision.domain.ds1.entity.BaseScene
import cn.flightfeather.supervision.domain.ds1.entity.Monitorobjectversion
import cn.flightfeather.supervision.domain.ds1.entity.SceneDevice
import io.swagger.annotations.ApiModelProperty
class MonitorObjectVersionVo : Monitorobjectversion() {
@@ -15,4 +18,8 @@
    var sceneType: String? = null
    var scene: ScenseVo? = null
    //场景特有信息
    @ApiModelProperty(value = "场景特有信息", name = "根据不同的场景类型,属性各不相同")
    var subScene: BaseScene? = null
}
src/main/kotlin/cn/flightfeather/supervision/lightshare/vo/ScenseVo.kt
@@ -6,70 +6,70 @@
import java.util.*
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ScenseVo {
    var guid: String? = null
    var name: String? = null
    /**
     * 从值域表里取值
     */
    var typeid: Byte? = null
    /**
     * 从值域表里取值
     */
    var type: String? = null
    /**
     * 从值域表里取值
     */
    var scensesubtypeid: Byte? = null
    /**
     * 从值域表里取值
     */
    var scensesubtype: String? = null
    var location: String? = null
    var longitude: BigDecimal? = null
    var latitude: BigDecimal? = null
    var provincecode: String? = null
    var provincename: String? = null
    var citycode: String? = null
    var cityname: String? = null
    var districtcode: String? = null
    var districtname: String? = null
    var towncode: String? = null
    var townname: String? = null
    var contactst: String? = null
    var contactswx: String? = null
    var contacts: String? = null
    var createdate: Date? = null
    var updatedate: Date? = null
    var extension1: String? = null
    var extension2: String? = null
    var index: Int? = null
    var remark: String? = null
public class ScenseVo : Scense() {
//    var guid: String? = null
//
//    var name: String? = null
//
//    /**
//     * 从值域表里取值
//     */
//    var typeid: Byte? = null
//
//    /**
//     * 从值域表里取值
//     */
//    var type: String? = null
//
//    /**
//     * 从值域表里取值
//     */
//    var scensesubtypeid: Byte? = null
//
//    /**
//     * 从值域表里取值
//     */
//    var scensesubtype: String? = null
//
//    var location: String? = null
//
//    var longitude: BigDecimal? = null
//
//    var latitude: BigDecimal? = null
//
//    var provincecode: String? = null
//
//    var provincename: String? = null
//
//    var citycode: String? = null
//
//    var cityname: String? = null
//
//    var districtcode: String? = null
//
//    var districtname: String? = null
//
//    var towncode: String? = null
//
//    var townname: String? = null
//
//    var contactst: String? = null
//
//    var contactswx: String? = null
//
//    var contacts: String? = null
//
//    var createdate: Date? = null
//
//    var updatedate: Date? = null
//
//    var extension1: String? = null
//
//    var extension2: String? = null
//
//    var index: Int? = null
//
//    var remark: String? = null
    var monitorNum: Int = 0
src/main/kotlin/cn/flightfeather/supervision/lightshare/web/ProblemlistController.kt
@@ -92,6 +92,13 @@
        @RequestParam date: String,
    ): List<ProblemListVo> = problemlistService.getProblemByScene(sceneId, date)
    @GetMapping("/getBySceneMonth")
    fun getBySceneMonth(
        @RequestParam(value = "sceneId", required = true) sceneId: String,
        @RequestParam(required = false) year: Int?,
        @RequestParam(required = false) month: Int?,
    ) = problemlistService.getBySceneMonth(sceneId, year, month)
    @IgnoreResponseAdvice
    @GetMapping("/month_anlysis")
    fun getMonthProblemsById(
src/main/kotlin/cn/flightfeather/supervision/lightshare/web/SubtaskController.kt
@@ -10,6 +10,7 @@
import cn.flightfeather.supervision.lightshare.vo.TaskVo
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.web.bind.annotation.*
import java.time.LocalDateTime
@@ -91,11 +92,13 @@
    ) = subtaskService.findByDayTaskID(dayTaskId, userId, userType)
    @IgnoreResponseAdvice
    @ApiOperation("根据时间和场景id获取巡查任务")
    @GetMapping("/byDate")
    fun findByDate(
        @RequestParam("date") date: String,
        @RequestParam("userId") userId: String,
    ) = subtaskService.findByDate(date, userId)
        @ApiParam(value = "时间,如果不传,则默认获取最新一期") @RequestParam("date", required = false) date: String?,
        @RequestParam("userId", required = false) userId: String?,
        @ApiParam(value = "场景id") @RequestParam(required = false) sceneId: String?,
    ) = subtaskService.findByDate(date, userId, sceneId)
    @IgnoreResponseAdvice
    @GetMapping("/getSubTask")
src/test/kotlin/cn/flightfeather/supervision/business/location/LocationRoadNearbyTest.kt
@@ -48,7 +48,7 @@
//            LocationRoadNearby.BasePlace("市控点-徐家汇", Pair(121.44187, 31.19793), Pair(121.44187, 31.19793)),
//            LocationRoadNearby.BasePlace("市控点-华泾", Pair(121.461985, 31.124359), Pair(121.461985, 31.124359)),
//            LocationRoadNearby.BasePlace("静安监测站国控点", Pair(121.429439, 31.223632), Pair(121.429439, 31.223632)),
//            LocationRoadNearby.BasePlace("金山大道2000号", Pair(121.3404, 30.744262), Pair(121.3404, 30.744262)),
            LocationRoadNearby.BasePlace("金山大道2000号", Pair(121.3404, 30.744262), Pair(121.3404, 30.744262)),
//            LocationRoadNearby.BasePlace("仙霞站", Pair(121.394775, 31.203982), Pair(121.394775, 31.203982)),
//            LocationRoadNearby.BasePlace("程桥站", Pair(121.362928, 31.192925), Pair(121.362928, 31.192925)),
@@ -77,40 +77,40 @@
//            LocationRoadNearby.BasePlace("九丰路", Pair(121.254114, 30.903438), Pair(121.254715, 30.893363)),
//            小微站
            LocationRoadNearby.BasePlace("永和二村", Pair(121.43165,31.29083), Pair(121.43165,31.29083)),
            LocationRoadNearby.BasePlace("芷江中路529号", Pair(121.468446,31.258494), Pair(121.468446,31.258494)),
            LocationRoadNearby.BasePlace("康宁路18号", Pair(121.43447,31.306374), Pair(121.43447,31.306374)),
            LocationRoadNearby.BasePlace("协信星光广场", Pair(121.457125,31.297407), Pair(121.457125,31.297407)),
            LocationRoadNearby.BasePlace("共康前进公寓", Pair(121.441018,31.319358), Pair(121.441018,31.319358)),
            LocationRoadNearby.BasePlace("静安监测站", Pair(121.429872,31.224094), Pair(121.429872,31.224094)),
            LocationRoadNearby.BasePlace("共和新路场中路", Pair(121.449074,31.306086), Pair(121.449074,31.306086)),
            LocationRoadNearby.BasePlace("岭南路场中路", Pair(121.455317,31.304615), Pair(121.455317,31.304615)),
            LocationRoadNearby.BasePlace("高平路江场西路", Pair(121.427832,31.296076), Pair(121.427832,31.296076)),
            LocationRoadNearby.BasePlace("广中西路共和新路", Pair(121.451879,31.278988), Pair(121.451879,31.278988)),
            LocationRoadNearby.BasePlace("闸北公园", Pair(121.46179,31.271121), Pair(121.46179,31.271121)),
            LocationRoadNearby.BasePlace("柳营路共和新路", Pair(121.459427,31.265294), Pair(121.459427,31.265294)),
            LocationRoadNearby.BasePlace("中山北路共和新路", Pair(121.46149,31.260937), Pair(121.46149,31.260937)),
            LocationRoadNearby.BasePlace("东宝兴路中兴路2024年7月24日移位至宝通路539号", Pair(121.475521,31.261383), Pair(121.475521,31.261383)),
            LocationRoadNearby.BasePlace("大悦城", Pair(121.472183,31.243488), Pair(121.472183,31.243488)),
            LocationRoadNearby.BasePlace("陕西北路海防路", Pair(121.446472,31.238458), Pair(121.446472,31.238458)),
            LocationRoadNearby.BasePlace("常德路新闸路", Pair(121.447048,31.229643), Pair(121.447048,31.229643)),
            LocationRoadNearby.BasePlace("延安中路富民路", Pair(121.449711,31.221563), Pair(121.449711,31.221563)),
            LocationRoadNearby.BasePlace("延安西路镇宁路", Pair(121.439025,31.218146), Pair(121.439025,31.218146)),
            LocationRoadNearby.BasePlace("广中西路万荣路", Pair(121.442032,31.278071), Pair(121.442032,31.278071)),
            LocationRoadNearby.BasePlace("广中西路运城路2024年9月3日移位至中兴社区280-06地块", Pair(121.473931,31.254645), Pair(121.473931,31.254645)),
            LocationRoadNearby.BasePlace("嘉利明珠城", Pair(121.434364,31.304047), Pair(121.434364,31.304047)),
            LocationRoadNearby.BasePlace("汾西路阳泉路", Pair(121.464122,31.31351), Pair(121.464122,31.31351)),
            LocationRoadNearby.BasePlace("河南北路天潼路", Pair(121.482241,31.243679), Pair(121.482241,31.243679)),
            LocationRoadNearby.BasePlace("汶水路万荣路", Pair(121.441558,31.291293), Pair(121.441558,31.291293)),
            LocationRoadNearby.BasePlace("石门一路348号", Pair(121.462105,31.229639), Pair(121.462105,31.229639)),
            LocationRoadNearby.BasePlace("运城路宜川路", Pair(121.439137,31.271005), Pair(121.439137,31.271005)),
//            LocationRoadNearby.BasePlace("永和二村", Pair(121.43165,31.29083), Pair(121.43165,31.29083)),
//            LocationRoadNearby.BasePlace("芷江中路529号", Pair(121.468446,31.258494), Pair(121.468446,31.258494)),
//            LocationRoadNearby.BasePlace("康宁路18号", Pair(121.43447,31.306374), Pair(121.43447,31.306374)),
//            LocationRoadNearby.BasePlace("协信星光广场", Pair(121.457125,31.297407), Pair(121.457125,31.297407)),
//            LocationRoadNearby.BasePlace("共康前进公寓", Pair(121.441018,31.319358), Pair(121.441018,31.319358)),
//            LocationRoadNearby.BasePlace("静安监测站", Pair(121.429872,31.224094), Pair(121.429872,31.224094)),
//            LocationRoadNearby.BasePlace("共和新路场中路", Pair(121.449074,31.306086), Pair(121.449074,31.306086)),
//            LocationRoadNearby.BasePlace("岭南路场中路", Pair(121.455317,31.304615), Pair(121.455317,31.304615)),
//            LocationRoadNearby.BasePlace("高平路江场西路", Pair(121.427832,31.296076), Pair(121.427832,31.296076)),
//            LocationRoadNearby.BasePlace("广中西路共和新路", Pair(121.451879,31.278988), Pair(121.451879,31.278988)),
//            LocationRoadNearby.BasePlace("闸北公园", Pair(121.46179,31.271121), Pair(121.46179,31.271121)),
//            LocationRoadNearby.BasePlace("柳营路共和新路", Pair(121.459427,31.265294), Pair(121.459427,31.265294)),
//            LocationRoadNearby.BasePlace("中山北路共和新路", Pair(121.46149,31.260937), Pair(121.46149,31.260937)),
//            LocationRoadNearby.BasePlace("东宝兴路中兴路2024年7月24日移位至宝通路539号", Pair(121.475521,31.261383), Pair(121.475521,31.261383)),
//            LocationRoadNearby.BasePlace("大悦城", Pair(121.472183,31.243488), Pair(121.472183,31.243488)),
//            LocationRoadNearby.BasePlace("陕西北路海防路", Pair(121.446472,31.238458), Pair(121.446472,31.238458)),
//            LocationRoadNearby.BasePlace("常德路新闸路", Pair(121.447048,31.229643), Pair(121.447048,31.229643)),
//            LocationRoadNearby.BasePlace("延安中路富民路", Pair(121.449711,31.221563), Pair(121.449711,31.221563)),
//            LocationRoadNearby.BasePlace("延安西路镇宁路", Pair(121.439025,31.218146), Pair(121.439025,31.218146)),
//            LocationRoadNearby.BasePlace("广中西路万荣路", Pair(121.442032,31.278071), Pair(121.442032,31.278071)),
//            LocationRoadNearby.BasePlace("广中西路运城路2024年9月3日移位至中兴社区280-06地块", Pair(121.473931,31.254645), Pair(121.473931,31.254645)),
//            LocationRoadNearby.BasePlace("嘉利明珠城", Pair(121.434364,31.304047), Pair(121.434364,31.304047)),
//            LocationRoadNearby.BasePlace("汾西路阳泉路", Pair(121.464122,31.31351), Pair(121.464122,31.31351)),
//            LocationRoadNearby.BasePlace("河南北路天潼路", Pair(121.482241,31.243679), Pair(121.482241,31.243679)),
//            LocationRoadNearby.BasePlace("汶水路万荣路", Pair(121.441558,31.291293), Pair(121.441558,31.291293)),
//            LocationRoadNearby.BasePlace("石门一路348号", Pair(121.462105,31.229639), Pair(121.462105,31.229639)),
//            LocationRoadNearby.BasePlace("运城路宜川路", Pair(121.439137,31.271005), Pair(121.439137,31.271005)),
        )
        listOf(
            500.0,
            1000.0,
//            500.0,
//            1000.0,
//            2000.0,
//            3000.0,
//            5000.0
            3000.0,
            5000.0
        ).forEach {
            locationRoadNearby.searchList(bList, it)
        }