道路线索应急巡查系统服务后台
feiyu02
2025-09-30 84569abda51ecf6c5549dec4cadee8d043422379
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package com.flightfeather.grid.service.impl
 
import com.flightfeather.grid.config.exception.BizException
import com.flightfeather.grid.domain.ds1.entity.ClueQuestion
import com.flightfeather.grid.domain.ds1.mapper.ClueQuestionMapper
import com.flightfeather.grid.external.ClueHttpService
import com.flightfeather.grid.service.ClueQuestionService
import com.flightfeather.grid.utils.FileUtil
import com.github.pagehelper.PageHelper
import com.google.gson.Gson
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import tk.mybatis.mapper.entity.Example
import java.io.IOException
import java.util.*
 
@Service
class ClueQuestionServiceImpl(val clueQuestionMapper: ClueQuestionMapper, val clueHttpService: ClueHttpService) :
    ClueQuestionService {
 
    @Value("\${imgPath}")
    lateinit var imgPath: String
 
    override fun uploadQuestionAndImage(question: String, files: Array<MultipartFile>?): Boolean {
        val questionVo = Gson().fromJson(question, ClueQuestion::class.java)
        if (questionVo.cqInternal == null) questionVo.cqInternal = false
        newQuestionUid(questionVo)
        val picPath = saveImageFile(questionVo, files)
        questionVo.cqFilePath = picPath
        questionVo.cqUploaded = false
        questionVo.cqCreateTime = Date()
        val res = clueQuestionMapper.insertSelective(questionVo)
        return res == 1
    }
 
    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("问题已上传,无法修改")
        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)
        return res == 1
    }
 
    override fun deleteQuestion(questionId: String): Boolean {
        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
    }
 
    override fun newQuestionUid(question: ClueQuestion) {
        // 问题已存在或uid已经生成,直接返回
        if (question.cqId != null || question.cqUid != null) return
        // 否则根据上一个问题编号顺延生成新编号
        PageHelper.startPage<ClueQuestion>(1, 1)
        val clueQuestions = clueQuestionMapper.selectByExample(Example(ClueQuestion::class.java).apply {
            createCriteria().andEqualTo("cId", question.cId).apply {
                if (question.cqInternal == true) {
                    andEqualTo("cqInternal", true)
                } else {
                    and(
                        createCriteria().orIsNull("cqInternal")
                            .orEqualTo("cqInternal", false)
                    )
                }
            }
            orderBy("cqId").desc()
        })
        if (clueQuestions.isNotEmpty()) {
            val clueQuestion = clueQuestions[0]
            clueQuestion?.cqUid?.split("-")?.let {
                question.cqUid = "${it[0]}-${it[1].toInt() + 1}"
            }
        } else {
            question.cqUid = "${question.cId}-1"
        }
    }
 
    override fun saveImageFile(question: ClueQuestion, files: Array<MultipartFile>?): String {
        if (question.cId == null || question.cqUid == null) throw BizException("问题编号未生成,无法保存对应图片")
        //对每张图片生成相应的路径并保存
        var picPath = ""
        files?.forEach { file ->
            val suffix = file.originalFilename?.split(".")?.last()
            val fileName = UUID.randomUUID().toString() + "." + suffix
            val basePath = imgPath
 
            // 对于内部线索问题,图片路径要做出区分
            val path = if (question.cqInternal) {
                "internal-clue/${question.cId}/${question.cqUid}/"
            } else {
                "clue/${question.cId}/${question.cqUid}/"
            }
            picPath += if (picPath.isEmpty()) {
                "$path$fileName"
            } else {
                ";$path$fileName"
            }
            try {
                //调用文件保存方法
                FileUtil.uploadFile(file.bytes, basePath + path, fileName)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return picPath
    }
 
    @Transactional
    override fun deleteImageFile(question: ClueQuestion, deleteImg: String) {
        try {
            deleteImg.split(";").forEach {
                val path = imgPath + it
                if (FileUtil.deleteFile(path)) {
                    question.cqFilePath = question.cqFilePath.replace(it, "")
                    question.cqFilePath = question.cqFilePath.replace(";;", ";")
                }
            }
        } catch (e: IOException) {
            throw BizException("图片删除失败,服务器IO操作错误")
        }
        question.cqFilePath = question.cqFilePath.removePrefix(";")
        question.cqFilePath = question.cqFilePath.removeSuffix(";")
    }
 
    override fun getClueQuestion(clueId: String, internal: Boolean?): List<ClueQuestion?> {
        val res = clueQuestionMapper.selectByExample(Example(ClueQuestion::class.java).apply {
            createCriteria().andEqualTo("cId", clueId)
                .apply {
                    if (internal == true) {
                        andEqualTo("cqInternal", true)
                    } else {
                        and(
                            createCriteria().orIsNull("cqInternal")
                                .orEqualTo("cqInternal", false)
                        )
                    }
                }
            orderBy("cqUid")
        })
        return res
    }
 
    override fun pushQuestion(questionIdList: List<String>?): Boolean {
        clueQuestionMapper.selectByExample(Example(ClueQuestion::class.java).apply {
            createCriteria().andEqualTo("cqUploaded", false).apply {
                questionIdList?.let {
                    andIn("cqId", it)
                    // 排除掉内部线索问题
                    and(
                        createCriteria().orIsNull("cqInternal")
                            .orEqualTo("cqInternal", false)
                    )
                }
            }
        }).forEach { it?.let { clueHttpService.uploadQuestion(it) } }
        return true
    }
 
    private fun deleteImageDirectory(question: ClueQuestion) {
        // 对于内部线索问题,图片路径要做出区分
        val p = if (question.cqInternal) {
            "internal-clue/${question.cId}/${question.cqUid}/"
        } else {
            "clue/${question.cId}/${question.cqUid}/"
        }
        val path = imgPath + p
        FileUtil.deleteDirectory(path)
    }
}