道路线索应急巡查系统服务后台
feiyu02
2025-09-30 84569abda51ecf6c5549dec4cadee8d043422379
2025.9.30
已修改17个文件
已删除1个文件
已添加5个文件
823 ■■■■■ 文件已修改
gridServer.rar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/config/CorsConfig.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/domain/ds1/entity/ClueInternal.java 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/domain/ds1/entity/ClueTask.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/domain/ds1/mapper/ClueInternalMapper.kt 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/domain/ds1/mapper/ClueTaskMapper.kt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/external/ClueHttpService.kt 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/service/ClueQuestionService.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/service/ClueTaskService.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/service/impl/ClueConclusionServiceImpl.kt 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/service/impl/ClueQuestionServiceImpl.kt 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/service/impl/ClueTaskServiceImpl.kt 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/vo/BaseResponse.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/vo/ClueTaskOptions.kt 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/vo/ClueTaskSummaryVo.kt 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/web/BaseResPack.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/web/ClueQuestionController.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/grid/web/ClueTaskController.kt 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generator/generatorConfig.xml 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ds1/ClueInternalMapper.xml 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ds1/ClueTaskMapper.xml 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/grid/external/ClueHttpServiceTest.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/grid/web/ClueTaskControllerTest.kt 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gridServer.rar
Binary files differ
src/main/kotlin/com/flightfeather/grid/config/CorsConfig.kt
@@ -6,7 +6,7 @@
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import org.springframework.web.filter.CorsFilter
@Configuration
//@Configuration
class CorsConfig {
    private fun buildConfig(): CorsConfiguration {
@@ -22,7 +22,7 @@
        }
    }
    @Bean
//    @Bean
    fun corsFilter(): CorsFilter {
        val source = UrlBasedCorsConfigurationSource().apply {
            registerCorsConfiguration("/**", buildConfig())
src/main/kotlin/com/flightfeather/grid/domain/ds1/entity/ClueInternal.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,381 @@
package com.flightfeather.grid.domain.ds1.entity;
import java.util.Date;
import javax.persistence.*;
@Table(name = "g_t_clue_internal")
public class ClueInternal {
    @Id
    @Column(name = "C_Id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer cId;
    /**
     * çº¿ç´¢åç§°
     */
    @Column(name = "C_Clue_Name")
    private String cClueName;
    /**
     * çº¿ç´¢ç»“论
     */
    @Column(name = "C_Conclusion")
    private String cConclusion;
    /**
     * æŠ¥è­¦æ—¶é—´
     */
    @Column(name = "C_Alarm_Time")
    private Date cAlarmTime;
    /**
     * æŠ¥è­¦ç«™ç‚¹åç§°
     */
    @Column(name = "C_Site_Name")
    private String cSiteName;
    /**
     * æŠ¥è­¦å› å­ï¼ˆå•因子)
     */
    @Column(name = "C_Factor")
    private String cFactor;
    /**
     * ä¸‹å‘æ—¶é—´
     */
    @Column(name = "C_Release_Time")
    private Date cReleaseTime;
    @Column(name = "C_Air_Checked_Options")
    private String cAirCheckedOptions;
    @Column(name = "C_Pollution_Checked_Options")
    private String cPollutionCheckedOptions;
    @Column(name = "C_Create_Time")
    private Date cCreateTime;
    @Column(name = "C_Center")
    private String cCenter;
    @Column(name = "C_Zoom")
    private String cZoom;
    @Column(name = "C_Longitude")
    private Double cLongitude;
    @Column(name = "C_Latitude")
    private Double cLatitude;
    @Column(name = "C_Site_Type")
    private String cSiteType;
    /**
     * çº¿ç´¢ä¸ŠæŠ¥æ—¶é—´
     */
    @Column(name = "C_Report_Time")
    private Date cReportTime;
    @Column(name = "C_Upload_Time")
    private Date cUploadTime;
    @Column(name = "C_Uploaded")
    private Boolean cUploaded;
    @Column(name = "C_Address")
    private String cAddress;
    /**
     * @return C_Id
     */
    public Integer getCId() {
        return cId;
    }
    /**
     * @param cId
     */
    public void setCId(Integer cId) {
        this.cId = cId;
    }
    /**
     * èŽ·å–çº¿ç´¢åç§°
     *
     * @return C_Clue_Name - çº¿ç´¢åç§°
     */
    public String getCClueName() {
        return cClueName;
    }
    /**
     * è®¾ç½®çº¿ç´¢åç§°
     *
     * @param cClueName çº¿ç´¢åç§°
     */
    public void setCClueName(String cClueName) {
        this.cClueName = cClueName == null ? null : cClueName.trim();
    }
    /**
     * èŽ·å–çº¿ç´¢ç»“è®º
     *
     * @return C_Conclusion - çº¿ç´¢ç»“论
     */
    public String getCConclusion() {
        return cConclusion;
    }
    /**
     * è®¾ç½®çº¿ç´¢ç»“论
     *
     * @param cConclusion çº¿ç´¢ç»“论
     */
    public void setCConclusion(String cConclusion) {
        this.cConclusion = cConclusion == null ? null : cConclusion.trim();
    }
    /**
     * èŽ·å–æŠ¥è­¦æ—¶é—´
     *
     * @return C_Alarm_Time - æŠ¥è­¦æ—¶é—´
     */
    public Date getCAlarmTime() {
        return cAlarmTime;
    }
    /**
     * è®¾ç½®æŠ¥è­¦æ—¶é—´
     *
     * @param cAlarmTime æŠ¥è­¦æ—¶é—´
     */
    public void setCAlarmTime(Date cAlarmTime) {
        this.cAlarmTime = cAlarmTime;
    }
    /**
     * èŽ·å–æŠ¥è­¦ç«™ç‚¹åç§°
     *
     * @return C_Site_Name - æŠ¥è­¦ç«™ç‚¹åç§°
     */
    public String getCSiteName() {
        return cSiteName;
    }
    /**
     * è®¾ç½®æŠ¥è­¦ç«™ç‚¹åç§°
     *
     * @param cSiteName æŠ¥è­¦ç«™ç‚¹åç§°
     */
    public void setCSiteName(String cSiteName) {
        this.cSiteName = cSiteName == null ? null : cSiteName.trim();
    }
    /**
     * èŽ·å–æŠ¥è­¦å› å­ï¼ˆå•å› å­ï¼‰
     *
     * @return C_Factor - æŠ¥è­¦å› å­ï¼ˆå•因子)
     */
    public String getCFactor() {
        return cFactor;
    }
    /**
     * è®¾ç½®æŠ¥è­¦å› å­ï¼ˆå•因子)
     *
     * @param cFactor æŠ¥è­¦å› å­ï¼ˆå•因子)
     */
    public void setCFactor(String cFactor) {
        this.cFactor = cFactor == null ? null : cFactor.trim();
    }
    /**
     * èŽ·å–ä¸‹å‘æ—¶é—´
     *
     * @return C_Release_Time - ä¸‹å‘æ—¶é—´
     */
    public Date getCReleaseTime() {
        return cReleaseTime;
    }
    /**
     * è®¾ç½®ä¸‹å‘æ—¶é—´
     *
     * @param cReleaseTime ä¸‹å‘æ—¶é—´
     */
    public void setCReleaseTime(Date cReleaseTime) {
        this.cReleaseTime = cReleaseTime;
    }
    /**
     * @return C_Air_Checked_Options
     */
    public String getCAirCheckedOptions() {
        return cAirCheckedOptions;
    }
    /**
     * @param cAirCheckedOptions
     */
    public void setCAirCheckedOptions(String cAirCheckedOptions) {
        this.cAirCheckedOptions = cAirCheckedOptions == null ? null : cAirCheckedOptions.trim();
    }
    /**
     * @return C_Pollution_Checked_Options
     */
    public String getCPollutionCheckedOptions() {
        return cPollutionCheckedOptions;
    }
    /**
     * @param cPollutionCheckedOptions
     */
    public void setCPollutionCheckedOptions(String cPollutionCheckedOptions) {
        this.cPollutionCheckedOptions = cPollutionCheckedOptions == null ? null : cPollutionCheckedOptions.trim();
    }
    /**
     * @return C_Create_Time
     */
    public Date getCCreateTime() {
        return cCreateTime;
    }
    /**
     * @param cCreateTime
     */
    public void setCCreateTime(Date cCreateTime) {
        this.cCreateTime = cCreateTime;
    }
    /**
     * @return C_Center
     */
    public String getCCenter() {
        return cCenter;
    }
    /**
     * @param cCenter
     */
    public void setCCenter(String cCenter) {
        this.cCenter = cCenter == null ? null : cCenter.trim();
    }
    /**
     * @return C_Zoom
     */
    public String getCZoom() {
        return cZoom;
    }
    /**
     * @param cZoom
     */
    public void setCZoom(String cZoom) {
        this.cZoom = cZoom == null ? null : cZoom.trim();
    }
    /**
     * @return C_Longitude
     */
    public Double getCLongitude() {
        return cLongitude;
    }
    /**
     * @param cLongitude
     */
    public void setCLongitude(Double cLongitude) {
        this.cLongitude = cLongitude;
    }
    /**
     * @return C_Latitude
     */
    public Double getCLatitude() {
        return cLatitude;
    }
    /**
     * @param cLatitude
     */
    public void setCLatitude(Double cLatitude) {
        this.cLatitude = cLatitude;
    }
    /**
     * @return C_Site_Type
     */
    public String getCSiteType() {
        return cSiteType;
    }
    /**
     * @param cSiteType
     */
    public void setCSiteType(String cSiteType) {
        this.cSiteType = cSiteType == null ? null : cSiteType.trim();
    }
    /**
     * èŽ·å–çº¿ç´¢ä¸ŠæŠ¥æ—¶é—´
     *
     * @return C_Report_Time - çº¿ç´¢ä¸ŠæŠ¥æ—¶é—´
     */
    public Date getCReportTime() {
        return cReportTime;
    }
    /**
     * è®¾ç½®çº¿ç´¢ä¸ŠæŠ¥æ—¶é—´
     *
     * @param cReportTime çº¿ç´¢ä¸ŠæŠ¥æ—¶é—´
     */
    public void setCReportTime(Date cReportTime) {
        this.cReportTime = cReportTime;
    }
    /**
     * @return C_Upload_Time
     */
    public Date getCUploadTime() {
        return cUploadTime;
    }
    /**
     * @param cUploadTime
     */
    public void setCUploadTime(Date cUploadTime) {
        this.cUploadTime = cUploadTime;
    }
    /**
     * @return C_Uploaded
     */
    public Boolean getCUploaded() {
        return cUploaded;
    }
    /**
     * @param cUploaded
     */
    public void setCUploaded(Boolean cUploaded) {
        this.cUploaded = cUploaded;
    }
    /**
     * @return C_Address
     */
    public String getCAddress() {
        return cAddress;
    }
    /**
     * @param cAddress
     */
    public void setCAddress(String cAddress) {
        this.cAddress = cAddress == null ? null : cAddress.trim();
    }
}
src/main/kotlin/com/flightfeather/grid/domain/ds1/entity/ClueTask.java
@@ -74,6 +74,8 @@
    @Column(name = "internal_task")
    private Boolean internalTask;
    private Boolean finished;
    /**
     * @return guid
     */
@@ -345,4 +347,18 @@
    public void setInternalTask(Boolean internalTask) {
        this.internalTask = internalTask;
    }
    /**
     * @return finished
     */
    public Boolean getFinished() {
        return finished;
    }
    /**
     * @param finished
     */
    public void setFinished(Boolean finished) {
        this.finished = finished;
    }
}
src/main/kotlin/com/flightfeather/grid/domain/ds1/mapper/ClueInternalMapper.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.flightfeather.grid.domain.ds1.mapper
import com.flightfeather.grid.domain.ds1.entity.ClueInternal
import com.flightfeather.grid.domain.util.MyMapper
import com.flightfeather.grid.vo.ClueVo
import org.apache.ibatis.annotations.Mapper
@Mapper
interface ClueInternalMapper : MyMapper<ClueInternal?> {
    fun getClue(sTime: String?, eTime: String?): List<ClueInternal?>
    fun getClueById(clueId: Int?): ClueInternal?
}
src/main/kotlin/com/flightfeather/grid/domain/ds1/mapper/ClueTaskMapper.kt
@@ -2,7 +2,13 @@
import com.flightfeather.grid.domain.ds1.entity.ClueTask
import com.flightfeather.grid.domain.util.MyMapper
import com.flightfeather.grid.vo.ClueTaskOptions
import com.flightfeather.grid.vo.ClueTaskSummaryVo
import org.apache.ibatis.annotations.Mapper
@Mapper
interface ClueTaskMapper : MyMapper<ClueTask?>
interface ClueTaskMapper : MyMapper<ClueTask?> {
    // æŸ¥è¯¢ä»»åŠ¡æ•°é‡ã€å®Œæˆæ•°æ®ã€å†…éƒ¨ä»»åŠ¡æ•°é‡
    fun selectSummaryCount(options: ClueTaskOptions): ClueTaskSummaryVo
}
src/main/kotlin/com/flightfeather/grid/external/ClueHttpService.kt
@@ -34,7 +34,10 @@
        private const val TAG = "ClueHttpService"
        private const val TOKEN = "e6dc8bb9e1ff0ce973fb92b4af2e4c3f"
    }
    private val httpMethod: HttpMethod = HttpMethod("101.230.224.80", 8082)
    // åŽŸå§‹IP地址
//    private val httpMethod: HttpMethod = HttpMethod("101.230.224.80", 8082)
    // 2025.9.22 æ ¹æ®é™å®‰åŒºç¬¬ä¸‰æ–¹æŽ¥å£æ–‡æ¡£ï¼Œä¿®æ”¹IP地址
    private val httpMethod: HttpMethod = HttpMethod("fmepi.jingan.gov.cn", 8088, true)
    @Value("\${imgPath}")
    lateinit var imgPath: String
@@ -85,7 +88,8 @@
        val time = updateTime.replace(" ", "%20")
//        val time = updateTime
        try {
            val res = httpMethod.get("/feedback/queryYxfListNew", listOf(Pair("updateTime", time)), headTimeStamp())
            val res = httpMethod.get("/govProxy/feedback/queryYxfListNew", listOf(Pair("updateTime", time)),
                headTimeStamp())
            val data = resCheck(res).asJsonArray
            return GsonUtils.parserJsonToArrayBeans(data.toString(), ClueDto::class.java)
        } catch (e: Exception) {
@@ -95,7 +99,7 @@
    fun getClueFile(clueId: String): HttpMethod.MyResponse {
        try {
            return httpMethod.get("/feedback/getPDFNew", listOf(Pair("id", clueId)), headTimeStamp())
            return httpMethod.get("/govProxy/feedback/getPDFNew", listOf(Pair("id", clueId)), headTimeStamp())
        } catch (e: Exception) {
            throw BizException(e.message, e.cause)
        }
@@ -109,7 +113,7 @@
        val vo = ClueConclusionDto(clueConclusion)
        val dataJson = Gson().toJson(vo)
        try {
            val res = httpMethod.post("/feedback/thirdReportNew", dataJson, headTimeStamp())
            val res = httpMethod.post("/govProxy/feedback/thirdReportNew", dataJson, headTimeStamp())
            resCheck(res)
            clueConclusion.ccUploaded = true
            clueConclusion.ccUploadTime = Date()
@@ -145,7 +149,7 @@
        val entity = builder.build()
        try {
            val res = httpMethod.post("/feedback/questionReportNew", entity, headTimeStamp())
            val res = httpMethod.post("/govProxy/feedback/questionReportNew", entity, headTimeStamp())
            resCheck(res)
            clueQuestion.cqUploaded = true
            clueQuestion.cqUploadTime = Date()
src/main/kotlin/com/flightfeather/grid/service/ClueQuestionService.kt
@@ -18,7 +18,7 @@
     * @param deleteImg åˆ é™¤çš„图片路径数组
     * @param files å›¾ç‰‡
     */
    fun updateQuestionAndImage(question: String, deleteImg: String, files: Array<MultipartFile>): Boolean
    fun updateQuestionAndImage(question: String, deleteImg: String?, files: Array<MultipartFile>?): Boolean
    /**
     * åˆ é™¤çº¿ç´¢é—®é¢˜åŠå›¾ç‰‡
src/main/kotlin/com/flightfeather/grid/service/ClueTaskService.kt
@@ -2,6 +2,9 @@
import com.flightfeather.grid.domain.ds1.entity.ClueTask
import com.flightfeather.grid.vo.ClueInternalTaskVo
import com.flightfeather.grid.vo.ClueTaskOptions
import com.flightfeather.grid.vo.ClueTaskSummaryVo
import com.flightfeather.grid.vo.DataHead
/**
 * çº¿ç´¢ä»»åŠ¡ç›¸å…³æœåŠ¡
@@ -18,6 +21,12 @@
    fun getClueTask(clueTask: ClueTask): List<ClueTask?>
    fun searchClueTask(options: ClueTaskOptions, page: Int?, perPage: Int?): Pair<DataHead, List<ClueTask?>>
    fun deleteClueTask(clueTask: ClueTask): Int
    fun getClueTaskSummary(options: ClueTaskOptions): ClueTaskSummaryVo
    fun finishClueTask(clueTaskId: String): Int
}
src/main/kotlin/com/flightfeather/grid/service/impl/ClueConclusionServiceImpl.kt
@@ -24,8 +24,15 @@
        clueConclusion.ccUploaded = false
        clueConclusion.ccCreateTime = Date()
        if (clueConclusion.ccInternal == null) clueConclusion.ccInternal = false
        val conclusion: ClueConclusion?
        try {
            val conclusion = clueConclusionMapper.selectOne(ClueConclusion().apply { cId = clueConclusion.cId })
            conclusion = clueConclusionMapper.selectOne(ClueConclusion().apply {
                cId = clueConclusion.cId
                ccInternal = clueConclusion.ccInternal
            })
        } catch (e: Exception) {
            throw BizException("每条线索最多能有一条结论,该线索结论存在多条,请检查系统逻辑")
        }
            // æ›´æ–°
            return if (conclusion != null) {
                if (conclusion.ccUploaded) throw BizException("线索结论已推送,无法修改")
@@ -38,9 +45,7 @@
                val res = clueConclusionMapper.insert(clueConclusion)
                res == 1
            }
        } catch (e: Exception) {
            throw BizException("每条线索最多能有一条结论,该线索结论存在多条,请检查系统逻辑")
        }
    }
    override fun getClueConclusion(clueId: String, internal: Boolean?): ClueConclusion? {
src/main/kotlin/com/flightfeather/grid/service/impl/ClueQuestionServiceImpl.kt
@@ -35,16 +35,18 @@
        return res == 1
    }
    override fun updateQuestionAndImage(question: String, deleteImg: String, files: Array<MultipartFile>): Boolean {
    override fun updateQuestionAndImage(question: String, deleteImg: String?, files: Array<MultipartFile>?): Boolean {
        val questionVo = Gson().fromJson(question, ClueQuestion::class.java)
        val oldOne = clueQuestionMapper.selectByPrimaryKey(questionVo.cqId) ?: throw BizException("问题不存在")
        if (oldOne.cqUploaded) throw BizException("问题已上传,无法修改")
        deleteImageFile(questionVo, deleteImg)
        if (deleteImg != null) deleteImageFile(questionVo, deleteImg)
        if (files != null) {
        val picPath = saveImageFile(questionVo, files)
        if (questionVo.cqFilePath.isEmpty()) {
            questionVo.cqFilePath = picPath
        } else {
            questionVo.cqFilePath += ";${picPath}"
            }
        }
        questionVo.cqCreateTime = Date()
        val res = clueQuestionMapper.updateByPrimaryKeySelective(questionVo)
@@ -55,6 +57,20 @@
        val oldOne = clueQuestionMapper.selectByPrimaryKey(questionId) ?: throw BizException("问题不存在")
        if (oldOne.cqUploaded) throw BizException("问题已上传,无法删除")
        deleteImageDirectory(oldOne)
        PageHelper.startPage<ClueQuestion>(1, 1)
        clueQuestionMapper.selectByExample(Example(ClueQuestion::class.java).apply {
            createCriteria().andEqualTo("cId", oldOne.cId)
            orderBy("cqUid").desc()
        })?.takeIf { it.isNotEmpty() }?.let {
            val q = it[0]
            if (q?.cqUid != oldOne.cqUid) {
                q?.cqUid = oldOne.cqUid
                clueQuestionMapper.updateByPrimaryKeySelective(q)
            }
        }
//        clueQuestionMapper.select
        val res = clueQuestionMapper.deleteByPrimaryKey(questionId)
        return res == 1
    }
@@ -147,7 +163,7 @@
                        )
                    }
                }
            orderBy("cqId")
            orderBy("cqUid")
        })
        return res
    }
src/main/kotlin/com/flightfeather/grid/service/impl/ClueTaskServiceImpl.kt
@@ -1,13 +1,20 @@
package com.flightfeather.grid.service.impl
import com.flightfeather.grid.config.exception.BizException
import com.flightfeather.grid.constant.ConstantHttp
import com.flightfeather.grid.domain.ds1.entity.ClueTask
import com.flightfeather.grid.domain.ds1.mapper.ClueInternalMapper
import com.flightfeather.grid.domain.ds1.mapper.ClueTaskMapper
import com.flightfeather.grid.service.ClueTaskService
import com.flightfeather.grid.vo.ClueInternalTaskVo
import com.flightfeather.grid.vo.ClueTaskOptions
import com.flightfeather.grid.vo.ClueTaskSummaryVo
import com.flightfeather.grid.vo.DataHead
import com.flightfeather.grid.web.responsePack
import com.github.pagehelper.PageHelper
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import tk.mybatis.mapper.entity.Example
import java.util.*
/**
@@ -39,6 +46,7 @@
        clueInternalTaskVo.clueTask?.createTime = Date()
        clueInternalTaskVo.clueTask?.updateTime = Date()
        clueInternalTaskVo.clueTask?.internalTask = true
        clueInternalTaskVo.clueTask?.finished = false
        return clueTaskMapper.insert(clueInternalTaskVo.clueTask)
    }
@@ -49,6 +57,7 @@
        clueTask.createTime = Date()
        clueTask.updateTime = Date()
        clueTask.internalTask = false
        clueTask.finished = false
        return clueTaskMapper.insert(clueTask)
    }
@@ -63,8 +72,45 @@
        return clueTaskMapper.select(clueTask)
    }
    override fun searchClueTask(options: ClueTaskOptions, page: Int?, perPage: Int?): Pair<DataHead, List<ClueTask?>> {
        val p = PageHelper.startPage<ClueTask>(
            page ?: ConstantHttp.DEFAULT_PAGE_NUM,
            perPage ?: ConstantHttp.DEFAULT_PAGE_SIZE
        )
        clueTaskMapper.selectByExample(Example(ClueTask::class.java).apply {
            createCriteria().apply {
                andEqualTo("internalTask", options.internal)
                andGreaterThanOrEqualTo("taskTime", options.startTime)
                andLessThanOrEqualTo("taskTime", options.endTime)
                andEqualTo("provinceCode", options.provinceCode)
                andEqualTo("provinceName", options.provinceName)
                andEqualTo("cityCode", options.cityCode)
                andEqualTo("cityName", options.cityName)
                andEqualTo("districtCode", options.districtCode)
                andEqualTo("districtName", options.districtName)
                andEqualTo("townCode", options.townCode)
                andEqualTo("townName", options.townName)
                andEqualTo("finished", options.finished)
            }
            orderBy(options.sortBy ?: "taskTime").apply { if (options.sort == "desc") desc() else asc() }
        })
        return responsePack(p)
    }
    override fun deleteClueTask(clueTask: ClueTask): Int {
        clueTask.guid ?: throw BizException("删除线索任务失败,缺少任务主键guid")
        return clueTaskMapper.delete(clueTask)
    }
    override fun getClueTaskSummary(options: ClueTaskOptions): ClueTaskSummaryVo {
        return clueTaskMapper.selectSummaryCount(options)
    }
    override fun finishClueTask(clueTaskId: String): Int {
        return clueTaskMapper.updateByPrimaryKeySelective(ClueTask().apply {
            guid = clueTaskId
            finished = true
        })
    }
}
src/main/kotlin/com/flightfeather/grid/vo/BaseResponse.kt
@@ -1,5 +1,6 @@
package com.flightfeather.grid.vo
import com.google.gson.Gson
import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty
@@ -19,6 +20,10 @@
            message = if (success) "请求成功" else "请求失败"
        }
    }
    override fun toString(): String {
        return Gson().toJson(this)
    }
}
data class DataHead(
src/main/kotlin/com/flightfeather/grid/vo/ClueTaskOptions.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package com.flightfeather.grid.vo
import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonInclude
import java.time.LocalDateTime
/**
 * åŒºåŸŸæŸ¥è¯¢æ¡ä»¶
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
open class ClueTaskOptions{
    // æ˜¯å¦æ˜¯å†…部任务
    var internal: Boolean? = 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
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    var startTime: LocalDateTime? = null
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    var endTime: LocalDateTime? = null
    // ä»»åŠ¡æ˜¯å¦å®Œæˆ
    var finished: Boolean? = null
    // æŽ’序方式,asc: å‡åºæŽ’列,desc:降序排列
    var sort: String = "desc"
    // æŽ’序字段,默认由接口自行定义
    var sortBy: String? = null
}
src/main/kotlin/com/flightfeather/grid/vo/ClueTaskSummaryVo.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.flightfeather.grid.vo
/**
 * çº¿ç´¢ä»»åŠ¡å®Œæˆæƒ…å†µç»Ÿè®¡
 * @date 2025/4/27
 * @author feiyu02
 */
data class ClueTaskSummaryVo(
    // ä»»åŠ¡æ€»è®¡
    val totalCount: Int = 0,
    // å†…部任务总计
    val internalTaskCount: Int = 0,
    // å¤–部任务总计
    val externalTaskCount: Int = 0,
    // å®Œæˆä»»åŠ¡æ€»è®¡
    val finishedCount: Int = 0,
    // æœªå®Œæˆä»»åŠ¡æ€»è®¡
    val unfinishedCount: Int = 0,
    // å†…部完成任务总计
    val internalFinishedCount: Int = 0,
    // å†…部未完成任务总计
    val internalUnFinishedCount: Int = 0,
    // å¤–部完成任务总计
    val externalFinishedCount: Int = 0,
    // å¤–部未完成任务总计
    val externalUnFinishedCount: Int = 0,
)
src/main/kotlin/com/flightfeather/grid/web/BaseResPack.kt
@@ -3,6 +3,7 @@
import com.flightfeather.grid.config.exception.BizException
import com.flightfeather.grid.vo.BaseResponse
import com.flightfeather.grid.vo.DataHead
import com.github.pagehelper.Page
/**
@@ -25,3 +26,10 @@
        BaseResponse(false, message = e.message ?: "")
    }
}
/**
 * åŒ…装带有分页的返回结果
 */
fun <T> responsePack(p: Page<T>): Pair<DataHead, List<T?>> {
    return DataHead(p.pageNum, p.pages, p.total) to p.result
}
src/main/kotlin/com/flightfeather/grid/web/ClueQuestionController.kt
@@ -23,8 +23,8 @@
    @PostMapping("/update")
    fun updateQuestion(
        @ApiParam("线索问题json") @RequestParam("question") question: String,
        @ApiParam("删除的图片路径数组") @RequestParam("deleteImg") deleteImg: String,
        @ApiParam("新增的线索图片") @RequestPart("images") files: Array<MultipartFile>,
        @ApiParam("删除的图片路径数组") @RequestParam("deleteImg", required = false) deleteImg: String?,
        @ApiParam("新增的线索图片") @RequestPart("images", required = false) files: Array<MultipartFile>?,
    ) = resPack { clueQuestionService.updateQuestionAndImage(question, deleteImg, files) }
    @ApiOperation("删除线索问题及图片")
src/main/kotlin/com/flightfeather/grid/web/ClueTaskController.kt
@@ -3,6 +3,7 @@
import com.flightfeather.grid.domain.ds1.entity.ClueTask
import com.flightfeather.grid.service.ClueTaskService
import com.flightfeather.grid.vo.ClueInternalTaskVo
import com.flightfeather.grid.vo.ClueTaskOptions
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
@@ -37,9 +38,29 @@
        @ApiParam("线索任务") @RequestBody clueTask: ClueTask,
    ) = resPack { clueTaskService.getClueTask(clueTask) }
    @ApiOperation("查询线索任务")
    @PostMapping("/search")
    fun searchClueTask(
        @RequestParam("page", required = false) page: Int?,
        @RequestParam("per_page", required = false) perPage: Int?,
        @ApiParam("线索任务查询条件") @RequestBody clueTaskOptions: ClueTaskOptions,
    ) = resPack { clueTaskService.searchClueTask(clueTaskOptions, page, perPage) }
    @ApiOperation("删除线索任务")
    @DeleteMapping("/delete")
    fun deleteClueTask(
        @ApiParam("线索任务") @RequestBody clueTask: ClueTask,
    ) = resPack { clueTaskService.deleteClueTask(clueTask) }
    @ApiOperation("查询线索任务完成情况统计")
    @PostMapping("/summary")
    fun getClueTaskSummary(
        @ApiParam("线索任务查询条件") @RequestBody clueTaskOptions: ClueTaskOptions,
    ) = resPack { clueTaskService.getClueTaskSummary(clueTaskOptions) }
    @ApiOperation("完成线索任务")
    @PostMapping("/finish")
    fun finishClueTask(
        @ApiParam("线索任务id") @RequestParam clueTaskId: String,
    ) = resPack { clueTaskService.finishClueTask(clueTaskId) }
}
src/main/resources/generator/generatorConfig.xml
@@ -56,17 +56,17 @@
<!--        <table tableName="g_t_clue" domainObjectName="Clue" enableCountByExample="false"-->
<!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
<!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
        <table tableName="g_t_clue_conclusion" domainObjectName="ClueConclusion" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false"/>
        <table tableName="g_t_clue_question" domainObjectName="ClueQuestion" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false"/>
<!--            <table tableName="g_t_clue_task" domainObjectName="ClueTask" enableCountByExample="false"-->
<!--        <table tableName="g_t_clue_conclusion" domainObjectName="ClueConclusion" enableCountByExample="false"-->
<!--                   enableUpdateByExample="false" enableDeleteByExample="false"-->
<!--                   enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="g_t_clue_internal" domainObjectName="ClueInternal" enableCountByExample="true"-->
<!--               enableUpdateByExample="true" enableDeleteByExample="true"-->
<!--               enableSelectByExample="true" selectByExampleQueryId="true"/>-->
<!--        <table tableName="g_t_clue_question" domainObjectName="ClueQuestion" enableCountByExample="false"-->
<!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
<!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
            <table tableName="g_t_clue_task" domainObjectName="ClueTask" enableCountByExample="false"
                   enableUpdateByExample="false" enableDeleteByExample="false"
                   enableSelectByExample="false" selectByExampleQueryId="false"/>
<!--        <table tableName="g_t_clue_internal" domainObjectName="ClueInternal" enableCountByExample="false"-->
<!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
<!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
    </context>
</generatorConfiguration>
src/main/resources/mapper/ds1/ClueInternalMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.flightfeather.grid.domain.ds1.mapper.ClueInternalMapper">
  <resultMap id="BaseResultMap" type="com.flightfeather.grid.domain.ds1.entity.ClueInternal">
    <!--
      WARNING - @mbg.generated
    -->
    <id column="C_Id" jdbcType="INTEGER" property="cId" />
    <result column="C_Clue_Name" jdbcType="VARCHAR" property="cClueName" />
    <result column="C_Conclusion" jdbcType="VARCHAR" property="cConclusion" />
    <result column="C_Alarm_Time" jdbcType="TIMESTAMP" property="cAlarmTime" />
    <result column="C_Site_Name" jdbcType="VARCHAR" property="cSiteName" />
    <result column="C_Factor" jdbcType="VARCHAR" property="cFactor" />
    <result column="C_Release_Time" jdbcType="TIMESTAMP" property="cReleaseTime" />
    <result column="C_Air_Checked_Options" jdbcType="VARCHAR" property="cAirCheckedOptions" />
    <result column="C_Pollution_Checked_Options" jdbcType="VARCHAR" property="cPollutionCheckedOptions" />
    <result column="C_Create_Time" jdbcType="TIMESTAMP" property="cCreateTime" />
    <result column="C_Center" jdbcType="VARCHAR" property="cCenter" />
    <result column="C_Zoom" jdbcType="VARCHAR" property="cZoom" />
    <result column="C_Longitude" jdbcType="DOUBLE" property="cLongitude" />
    <result column="C_Latitude" jdbcType="DOUBLE" property="cLatitude" />
    <result column="C_Site_Type" jdbcType="VARCHAR" property="cSiteType" />
    <result column="C_Report_Time" jdbcType="TIMESTAMP" property="cReportTime" />
    <result column="C_Upload_Time" jdbcType="TIMESTAMP" property="cUploadTime" />
    <result column="C_Uploaded" jdbcType="BIT" property="cUploaded" />
    <result column="C_Address" jdbcType="VARCHAR" property="cAddress" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--
      WARNING - @mbg.generated
    -->
    C_Id, C_Clue_Name, C_Conclusion, C_Alarm_Time, C_Site_Name, C_Factor, C_Release_Time,
    C_Air_Checked_Options, C_Pollution_Checked_Options, C_Create_Time, C_Center, C_Zoom,
    C_Longitude, C_Latitude, C_Site_Type, C_Report_Time, C_Upload_Time, C_Uploaded, C_Address
  </sql>
  <resultMap extends="BaseResultMap" id="ClueVoMap" type="com.flightfeather.grid.vo.ClueInternalVo">
    <!--    &amp;lt;result column="questionCount" jdbcType="INTEGER" property="questionCount" /&amp;gt;-->
    <!--    &amp;lt;result column="conclusionCount" jdbcType="INTEGER" property="conclusionCount" /&amp;gt;-->
  </resultMap>
  <sql id="selectClueVo">
    SELECT
    a.*,
    COUNT(DISTINCT b.CC_Id) AS conclusionCount,
    COUNT(DISTINCT c.CQ_Id) AS questionCount,
    COUNT(DISTINCT d.guid) AS taskCount
    FROM
    g_t_clue_internal AS a
    LEFT JOIN g_t_clue_conclusion AS b ON a.C_Id = b.C_Id and b.CC_Internal = true
    LEFT JOIN g_t_clue_question AS c ON a.C_Id = c.C_Id and c.CQ_Internal = true
    LEFT JOIN g_t_clue_task AS d ON a.C_Id = d.clue_id and d.internal_task = true
  </sql>
  <sql id="groupClueId">
    GROUP BY
    a.C_Id
    ORDER BY
    a.C_Id DESC
  </sql>
  <select id="getClue" resultMap="ClueVoMap">
    <include refid="selectClueVo" />
    <where>
      <if test="sTime != null">
        AND a.C_Release_Time &gt;= #{sTime}
      </if>
      <if test="eTime != null">
        AND a.C_Release_Time &lt;= #{eTime}
      </if>
    </where>
    <include refid="groupClueId" />
  </select>
  <select id="getClueById" resultMap="ClueVoMap">
    <include refid="selectClueVo" />
    <where>
      a.C_Id = #{clueId}
    </where>
    <include refid="groupClueId" />
  </select>
</mapper>
src/main/resources/mapper/ds1/ClueTaskMapper.xml
@@ -23,6 +23,7 @@
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
    <result column="executor_ids" jdbcType="VARCHAR" property="executorIds" />
    <result column="internal_task" jdbcType="BIT" property="internalTask" />
    <result column="finished" jdbcType="BIT" property="finished" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--
@@ -30,6 +31,70 @@
    -->
    guid, clue_id, task_time, province_code, province_name, city_code, city_name, district_code, 
    district_name, town_code, town_name, response_level, travel_mode, has_uav, create_time, 
    update_time, executor_ids, internal_task
    update_time, executor_ids, internal_task, finished
  </sql>
<!--  é€šç”¨SQL语句-->
  <sql id="Where_Area">
    <if test="provinceCode != null">
      AND ${tableAlias}.province_code = #{provinceCode}
    </if>
    <if test="provinceName != null">
      AND ${tableAlias}.province_name = #{provinceName}
    </if>
    <if test="cityCode != null">
      AND ${tableAlias}.city_code = #{cityCode}
    </if>
    <if test="cityName != null">
      AND ${tableAlias}.city_name = #{cityName}
    </if>
    <if test="districtCode != null">
      AND ${tableAlias}.district_code = #{districtCode}
    </if>
    <if test="districtName != null">
      AND ${tableAlias}.district_name = #{districtName}
    </if>
    <if test="townCode != null">
      AND ${tableAlias}.town_code = #{townCode}
    </if>
    <if test="townName != null">
      AND ${tableAlias}.town_name = #{townName}
    </if>
  </sql>
  <sql id="Where_Task_Time">
    <if test="startTime != null">
      AND ${tableAlias}.task_time &gt;= #{startTime}
    </if>
    <if test="endTime != null">
      AND ${tableAlias}.task_time &lt;= #{endTime}
    </if>
  </sql>
<!--  è¿”回结果模板-->
  <resultMap extends="BaseResultMap" id="SummaryMap" type="com.flightfeather.grid.vo.ClueTaskSummaryVo">
  </resultMap>
<!--  æŸ¥è¯¢è¯­å¥-->
  <select id="selectSummaryCount" resultMap="SummaryMap">
    select
    count(*) as totalCount,
    sum(if(internal_task = true, 1, 0)) as internalTaskCount,
    sum(if(internal_task = false, 1, 0)) as externalTaskCount,
    sum(if(finished = true, 1, 0)) as finishedCount,
    sum(if(finished = false, 1, 0)) as unfinishedCount,
    sum(if(finished = true and internal_task = true, 1, 0)) as internalFinishedCount,
    sum(if(finished = false and internal_task = true, 1, 0)) as internalUnFinishedCount,
    sum(if(finished = true and internal_task = false, 1, 0)) as externalFinishedCount,
    sum(if(finished = false and internal_task = false, 1, 0)) as externalUnFinishedCount
    from g_t_clue_task as a
    <where>
      <include refid="Where_Area">
        <property name="tableAlias" value="a"/>
      </include>
      <include refid="Where_Task_Time">
        <property name="tableAlias" value="a"/>
      </include>
    </where>
  </select>
</mapper>
src/test/kotlin/com/flightfeather/grid/external/ClueHttpServiceTest.kt
@@ -23,7 +23,7 @@
    @Test
    fun getClue() {
        val res = clueHttpService.getClue("2024-08-04 00:00:00")
        val res = clueHttpService.getClue("2025-08-01 00:00:00")
        res.forEach {
            println(it.clueName)
        }
src/test/kotlin/com/flightfeather/grid/web/ClueTaskControllerTest.kt
@@ -1,6 +1,7 @@
package com.flightfeather.grid.web
import com.flightfeather.grid.domain.ds1.entity.ClueTask
import com.flightfeather.grid.vo.ClueTaskOptions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.*
@@ -10,6 +11,7 @@
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.context.junit4.SpringRunner
import java.time.LocalDateTime
@RunWith(SpringRunner::class)
@ExtendWith(SpringExtension::class)
@@ -20,13 +22,23 @@
    lateinit var clueTaskController: ClueTaskController
    @Test
    fun createClueTask() {
        clueTaskController.createClueTask(ClueTask().apply {
    fun searchClueTask() {
        val res = clueTaskController.searchClueTask(1, 30, ClueTaskOptions().apply {
            provinceCode = "31"
            provinceName = "上海市"
            cityCode = "3100"
            cityName = "上海市"
            startTime = LocalDateTime.of(2025, 4, 22, 14, 35, 0)
            endTime = LocalDateTime.of(2025, 4, 24, 15, 10, 0)
            internal
            finished
        })
        println(res.toString())
    }
    @Test
    fun getClueTask() {
    fun getClueTaskSummary() {
        val res = clueTaskController.getClueTaskSummary(ClueTaskOptions())
        println(res.toString())
    }
}