src/main/kotlin/cn/flightfeather/supervision/lightshare/service/impl/SearchServiceImpl.kt
@@ -1,8 +1,17 @@
package cn.flightfeather.supervision.lightshare.service.impl
import cn.flightfeather.supervision.business.report.DataSource
import cn.flightfeather.supervision.business.report.DbMapper
import cn.flightfeather.supervision.business.report.file.ReportOne
import cn.flightfeather.supervision.business.report.file.ReportThree
import cn.flightfeather.supervision.business.report.file.ReportTwo
import cn.flightfeather.supervision.business.report.template.*
import cn.flightfeather.supervision.common.utils.*
import cn.flightfeather.supervision.domain.ds1.entity.*
import cn.flightfeather.supervision.domain.ds1.mapper.*
import cn.flightfeather.supervision.domain.ds2.mapper.LedgerRecordMapper
import cn.flightfeather.supervision.domain.ds2.mapper.LedgerSubTypeMapper
import cn.flightfeather.supervision.domain.ds2.mapper.UserMapMapper
import cn.flightfeather.supervision.lightshare.service.SearchService
import cn.flightfeather.supervision.lightshare.vo.*
import com.github.pagehelper.PageHelper
@@ -12,6 +21,9 @@
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.OutputStream
import java.net.URLEncoder
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.util.*
import javax.servlet.http.HttpServletResponse
@@ -22,52 +34,126 @@
 */
@Service
class SearchServiceImpl(
    val userinfoMapper: UserinfoMapper,
    val subtaskMapper: SubtaskMapper,
    val scenseMapper: ScenseMapper,
    val problemlistMapper: ProblemlistMapper,
    val problemtypeMapper: ProblemtypeMapper,
    val townMapper: TownMapper,
    val mediafileMapper: MediafileMapper,
    val scoreMapper: ScoreMapper,
    val inspectionMapper: InspectionMapper,
    val taskMapper: TaskMapper
): SearchService {
        val userinfoMapper: UserinfoMapper,
        val subtaskMapper: SubtaskMapper,
        val scenseMapper: ScenseMapper,
        val sceneConstructionSiteMapper: SceneConstructionSiteMapper,
        val sceneMixingPlantMapper: SceneMixingPlantMapper,
        val sceneStorageYardMapper: SceneStorageYardMapper,
        val sceneWharfMapper: SceneWharfMapper,
        val problemlistMapper: ProblemlistMapper,
        val problemtypeMapper: ProblemtypeMapper,
        val townMapper: TownMapper,
        val mediafileMapper: MediafileMapper,
        val scoreMapper: ScoreMapper,
        val inspectionMapper: InspectionMapper,
        val taskMapper: TaskMapper,
        val monitorobjectversionMapper: MonitorobjectversionMapper,
        val evaluationruleMapper: EvaluationruleMapper,
        val evaluationsubruleMapper: EvaluationsubruleMapper2,
        val evaluationMapper: EvaluationMapper,
        val itemevaluationMapper: ItemevaluationMapper,
        val ledgerSubTypeMapper: LedgerSubTypeMapper,
        val ledgerRecordMapper: LedgerRecordMapper,
        val userMapMapper: UserMapMapper,
) : SearchService {
    private val dateUtil = DateUtil()
    override fun writeToFile(config: ExcelConfigVo) {
        val fileName = "e:/${DateUtil().DateToString(Date(), "yyyy-MM-ddhhmmss")}.xls"
        val out = FileOutputStream(fileName)
        val heads = getTableTitles()
        val contents = getTableContents(config)
        ExcelUtil.write2(out, heads, contents)
    override fun writeToFile(config: ExcelConfigVo, mode:Int) {
        val dbMapper = DbMapper(
            scenseMapper,
            problemlistMapper,
            problemtypeMapper,
            subtaskMapper,
            monitorobjectversionMapper,
            sceneConstructionSiteMapper,
            sceneMixingPlantMapper,
            sceneStorageYardMapper,
            sceneWharfMapper,
            taskMapper,
            evaluationruleMapper, evaluationsubruleMapper, evaluationMapper, itemevaluationMapper,
                ledgerSubTypeMapper, ledgerRecordMapper, userinfoMapper, userMapMapper, townMapper
        )
        val dataSource = DataSource(config, dbMapper)
        val t = when (mode) {
//            //问题与整改跟踪汇总表
//            0 -> ProDetailSummary(dataSource)
//            //分街镇问题整改分析汇总表
//            1 -> ProAnalysisSummary(dataSource)
//
//            //规范性评估详情表
//            2 -> ScoreDetailSummary(dataSource)
//            //分街镇规范性分析表
//            3 -> ScoreAnalysisSummary(dataSource)
//
//            //问题与整改分类统计表
//            4 -> ProTypeDetailSummary(dataSource)
//            //问题与整改分类排名
//            5 -> ProTypeRankSummary(dataSource)
//            //月度主要或典型问题分析表
//            6 -> ProTypeRankMainSummary(dataSource)
//            //工地施工阶段问题分类分析表
//            7 -> ProTypeStatusSummary(dataSource)
            8 -> ReportOne(dataSource)
            9 -> ReportTwo(dataSource)
            10 -> ReportThree(dataSource)
            else -> null
        }
//        t?.execute()
        t?.toFile("target/")
    }
    override fun getExcel(config: ExcelConfigVo, response: HttpServletResponse): HttpServletResponse {
    override fun getExcel(config: ExcelConfigVo, response: HttpServletResponse): Boolean {
        val dbMapper = DbMapper(
            scenseMapper,
            problemlistMapper,
            problemtypeMapper,
            subtaskMapper,
            monitorobjectversionMapper,
            sceneConstructionSiteMapper,
            sceneMixingPlantMapper,
            sceneStorageYardMapper,
            sceneWharfMapper,
            taskMapper,
            evaluationruleMapper, evaluationsubruleMapper, evaluationMapper, itemevaluationMapper,
            ledgerSubTypeMapper, ledgerRecordMapper, userinfoMapper, userMapMapper, townMapper
        )
        val dataSource = DataSource(config, dbMapper)
        val t = when (config.mode) {
            1 -> ReportOne(dataSource)
            2 -> ReportTwo(dataSource)
            3 -> ReportThree(dataSource)
        val fileName = "${DateUtil().DateToString(Date(), "yyyy-MM-dd hh:mm:ss")}.xls"
            else -> ReportOne(dataSource)
        }
        val fileName = t.getReportName()
        val fName = URLEncoder.encode(fileName, "UTF-8")
        response.apply {
            setHeader("Content-Disposition", "attachment;filename=$fileName")
            setHeader("fileName", fileName)
            setHeader("Content-Disposition", "attachment;filename=$fName")
            setHeader("fileName", fName)
            addHeader("Access-Control-Expose-Headers", "fileName")
            contentType = "application/vnd.ms-excel;charset=UTF-8"
            setHeader("Pragma", "no-cache")
            setHeader("Cache-Control", "no-cache")
            setDateHeader("Expires", 0)
        }
        val heads = getTableTitles()
        val contents = getTableContents(config)
        val p = Constant.DEFAULT_FILE_PATH + "/files/autoscore/"
        val file = File(p + fileName)
        if (config.forceUpdate || !file.exists()) {
            t.toFile(p)
        }
        response.outputStream.write(file.readBytes())
        val out = response.outputStream
        ExcelUtil.write2(out, heads, contents)
        return response
        return true
    }
    override fun getSubTaskDetail(config: ExcelConfigVo): SubTaskTableVo {
        val titles = getTableTitles2()
        val content = getTableContents2(config)
        val titles = getTableTitles(config.sceneType, config.districtCode)
        val content = getTableContents(config, titles.size)
        return SubTaskTableVo(titles, content)
    }
@@ -94,19 +180,19 @@
                }
            } else {
                createCriteria()
                        .andEqualTo("tguid", config.topTaskGuid)
                        .andGreaterThanOrEqualTo("planstarttime", config.startTime)
                        .andLessThanOrEqualTo("planendtime", config.endTime).apply {
                            config.provinceCode?.let {
                                andEqualTo("provincecode", it)
                            }
                            config.cityCode?.let {
                                andEqualTo("citycode", it)
                            }
                            config.districtCode?.let {
                                andEqualTo("districtcode", it)
                            }
                    .andEqualTo("tguid", config.topTaskGuid)
                    .andGreaterThanOrEqualTo("planstarttime", config.startTime)
                    .andLessThanOrEqualTo("planendtime", config.endTime).apply {
                        config.provinceCode?.let {
                            andEqualTo("provincecode", it)
                        }
                        config.cityCode?.let {
                            andEqualTo("citycode", it)
                        }
                        config.districtCode?.let {
                            andEqualTo("districtcode", it)
                        }
                    }
            }
            orderBy("planstarttime")
        }
@@ -153,7 +239,7 @@
        }
        //建立第一层目录,包含所有的任务
        val time = DateUtil().DateToString(Date(), "yyyy-MM-dd_HH-mm-ss")
        val time = dateUtil.DateToString(Date(), "yyyy-MM-dd_HH-mm-ss")
        var basePath = Constant.DEFAULT_FILE_PATH + File.separator + "images" + File.separator + "temp" + File.separator + time
        var file = File(basePath)
        var i = 1
@@ -163,7 +249,7 @@
            i++
        }
        if (file.exists()) {
            FileUtil().delAllFile(basePath)
            FileUtil.delAllFile(basePath)
        } else {
            file.mkdirs()
        }
@@ -180,7 +266,7 @@
                i++
            }
            if (sFile.exists()) {
                FileUtil().delAllFile(subTaskFilePath)
                FileUtil.delAllFile(subTaskFilePath)
            } else {
                sFile.mkdirs()
            }
@@ -196,7 +282,7 @@
                    i++
                }
                if (pFile.exists()) {
                    FileUtil().delAllFile(pPath)
                    FileUtil.delAllFile(pPath)
                } else {
                    pFile.mkdirs()
                }
@@ -209,7 +295,7 @@
                    val fromFile = File(picPath)
                    val picName = p.problemname + "_" + p.location + "($y).jpg"
                    val toFile = File(pPath + File.separator + picName)
                    FileUtil().copy(fromFile, toFile)
                    FileUtil.copy(fromFile, toFile)
                    y++
                }
            }
@@ -241,14 +327,10 @@
        return response
    }
    override fun downloadPic2(
        sceneType: Int,
        topTaskId: String,
        response: HttpServletResponse
    ): HttpServletResponse {
    override fun downloadPic2(sceneType: Int, topTaskId: String, response: HttpServletResponse): HttpServletResponse {
        //建立第一层目录,包含所有的任务
        val topTask = taskMapper.selectByPrimaryKey(topTaskId)
        val time = DateUtil().DateToString(Date(), "yyyy-MM-dd_HH-mm-ss")
        val time = dateUtil.DateToString(Date(), "yyyy-MM-dd_HH-mm-ss")
        val basePath = Constant.DEFAULT_FILE_PATH + File.separator + "images" + File.separator + "temp" + File.separator + topTask.name
        val file = File(basePath)
        if (!file.exists()) {
@@ -281,7 +363,7 @@
                    i++
                }
                if (sFile.exists()) {
                    FileUtil().delAllFile(subTaskFilePath)
                    FileUtil.delAllFile(subTaskFilePath)
                } else {
                    sFile.mkdirs()
                }
@@ -311,7 +393,7 @@
                            i++
                        }
                        if (pFile.exists()) {
                            FileUtil().delAllFile(pPath)
                            FileUtil.delAllFile(pPath)
                        } else {
                            pFile.mkdirs()
                        }
@@ -322,7 +404,7 @@
                            val fromFile = File(picPath)
                            val picName = f.description
                            val toFile = File(pPath + File.separator + picName)
                            FileUtil().copy(fromFile, toFile)
                            FileUtil.copy(fromFile, toFile)
                        }
                    }
                }
@@ -381,304 +463,6 @@
        return BaseResponse(true, head = DataHead(p.pageNum, p.pages), data = result)
    }
    private fun getTableTitles(): List<String> = listOf(
            "序号", "任务", "场景", "经度", "纬度",
            "类型",
            "开始时间", "结束时间",
            "状态", "组长",
            "组员", "问题类型","问题详情", "街镇", "审核"
    )
    /**
     * 相比于getTableContents() ,删减了部分列
     */
    private fun getTableTitles2(): List<String> = listOf(
//            "序号",
            "任务",
//            "场景", "经度", "纬度",
            "类型",
            "开始时间",
//            "结束时间",
            "状态", "组长",
            "组员", "问题类型","问题详情", "街镇", "审核"
    )
    private fun getTableContents(config: ExcelConfigVo): List<Array<Any>> {
        val townName = if (config.townCode == null) {
            null
        } else {
            val l = townMapper.selectByExample(Example(Town::class.java).apply {
                createCriteria().andEqualTo("towncode", config.townCode)
            })
            if (l.isNotEmpty()) {
                l[0].townname
            } else {
                null
            }
        }
        val subTaskExample = Example(Subtask::class.java).apply {
            if (config.subTaskIdList != null && config.subTaskIdList.isNotEmpty()) {
                createCriteria().apply {
                    config.subTaskIdList.forEach {
                        orEqualTo("stguid", it)
                    }
                }
            } else {
                createCriteria()
                        .andEqualTo("tguid", config.topTaskGuid)
                        .andGreaterThanOrEqualTo("planstarttime", config.startTime)
                        .andLessThanOrEqualTo("planendtime", config.endTime).apply {
                            config.provinceCode?.let {
                                andEqualTo("provincecode", it)
                            }
                            config.cityCode?.let {
                                andEqualTo("citycode", it)
                            }
                            config.districtCode?.let {
                                andEqualTo("districtcode", it)
                            }
//                            config.townCode?.let {
//                                andEqualTo("towncode", it)
//                            }
                        }
            }
            orderBy("planstarttime")
        }
        val contents = mutableListOf<Array<Any>>()
        val subTasks = mutableListOf<Subtask>()
        var i = 1
        subtaskMapper.selectByExample(subTaskExample).forEach {
            //查询该任务对应的场景
            val scene = scenseMapper.selectByPrimaryKey(it.scenseid)
            //根据场景条件筛选
            val need = if (config.sceneType != null) {
                scene.typeid == config.sceneType.toByte()
            } else {
                true
            }
            if (need) {
                //记录查询到子任务
                subTasks.add(it)
                val problemTypes = mutableListOf<String>()
                val problems = mutableListOf<String>()
                val districts = mutableListOf<String>()
                val checkStatus= mutableListOf<String>()
                //查询子任务对应的问题,并且根据条件进行筛选
                val problemlistExample = Example(Problemlist::class.java).apply {
                    createCriteria().andEqualTo("stguid", it.stguid).apply {
                        config.problemName?.let {p->
                            andEqualTo("problemname", p)
                        }
                        townName?.let {t->
                            andLike("location", "%$t%")
                        }
                    }
                }
                var y=1
                problemlistMapper.selectByExample(problemlistExample).forEach problemType@{p->
                    val result = problemtypeMapper.selectByPrimaryKey(p.ptguid)
                    if (config.problemTypeName != null) {
                        if (result.typename != config.problemTypeName) {
                            return@problemType
                        }
                    }
                    problemTypes.add(result.typename ?: "")
                    problems.add("$y、${p.problemname}")
                    districts.add(p.location ?: "")
                    val status = when (p.extension3) {
                        Constant.PROBLEM_UNCHECKED -> "未审核"
                        Constant.PROBLEM_CHECK_PASS-> "通过"
                        Constant.PROBLEM_CHECK_FAIL -> "未通过"
                        else->"未审核"
                    }
                    checkStatus.add(status)
                    y++
                }
                //当有问题作为筛选条件时,如果没有找到对应问题,则该次任务去除
                if ( (config.problemTypeName != null || config.problemName != null || townName != null)
                        && (problemTypes.isEmpty() && problems.isEmpty())) {
                    return@forEach
                }
                val rowContent = arrayOf<Any>(
                        "$i", it.name ?: "", it.scensename ?: "", scene.longitude.toString(), scene.latitude.toString(),
                        scene.type ?: "",
                        DateUtil().DateToString(it.executionstarttime, "yyyy-MM-dd HH:mm:ss") ?: "", DateUtil().DateToString(it.executionendtime, "yyyy-MM-dd hh:mm:ss") ?: "",
                        it.status ?: "", it.assessorrealname?.replace("#", "、") ?: "",
                        it.executorrealtimes?.replace("#", "、") ?: "", problemTypes.toTypedArray(), problems.toTypedArray(), districts.toTypedArray(), checkStatus.toTypedArray()
                )
                contents.add(rowContent)
                i++
            }
        }
        return contents
    }
    /**
     * 相比于getTableContents() ,删减了部分列
     */
    private fun getTableContents2(config: ExcelConfigVo): List<Array<Any>> {
        val townName = if (config.townCode == null) {
            null
        } else {
            val l = townMapper.selectByExample(Example(Town::class.java).apply {
                createCriteria().andEqualTo("towncode", config.townCode)
            })
            if (l.isNotEmpty()) {
                l[0].townname
            } else {
                null
            }
        }
        val subTaskExample = Example(Subtask::class.java).apply {
            if (config.subTaskIdList != null && config.subTaskIdList.isNotEmpty()) {
                createCriteria().apply {
                    config.subTaskIdList.forEach {
                        orEqualTo("stguid", it)
                    }
                }
            } else {
                createCriteria()
                        .andEqualTo("tguid", config.topTaskGuid)
                        .andGreaterThanOrEqualTo("planstarttime", config.startTime)
                        .andLessThanOrEqualTo("planendtime", config.endTime).apply {
                            config.provinceCode?.let {
                                andEqualTo("provincecode", it)
                            }
                            config.cityCode?.let {
                                andEqualTo("citycode", it)
                            }
                            config.districtCode?.let {
                                andEqualTo("districtcode", it)
                            }
//                            config.townCode?.let {
//                                andEqualTo("towncode", it)
//                            }
                        }
            }
            orderBy("planstarttime")
        }
        val contents = mutableListOf<Array<Any>>()
        val subTasks = mutableListOf<Subtask>()
        var i = 1
        subtaskMapper.selectByExample(subTaskExample).forEach {
            //查询该任务对应的场景
            val scene = scenseMapper.selectByPrimaryKey(it.scenseid)
            //根据场景条件筛选
            val need = if (config.sceneType != null) {
                scene.typeid == config.sceneType.toByte()
            } else {
                true
            }
            if (need) {
                //记录查询到子任务
                subTasks.add(it)
                val problemTypes = mutableListOf<String>()
                val problems = mutableListOf<String>()
                val districts = mutableListOf<String>()
                val checkStatus= mutableListOf<String>()
                //查询子任务对应的问题,并且根据条件进行筛选
                val problemlistExample = Example(Problemlist::class.java).apply {
                    createCriteria().andEqualTo("stguid", it.stguid).apply {
                        config.problemName?.let {p->
                            andEqualTo("problemname", p)
                        }
                        townName?.let {t->
                            andLike("location", "%$t%")
                        }
                    }
                }
                var y=1
                problemlistMapper.selectByExample(problemlistExample).forEach problemType@{p->
                    val result = problemtypeMapper.selectByPrimaryKey(p.ptguid)
                    if (config.problemTypeName != null) {
                        if (result?.typename != config.problemTypeName) {
                            return@problemType
                        }
                    }
                    problemTypes.add(result?.typename ?: "")
                    problems.add("$y、${p.problemname}")
                    districts.add(p.location ?: "")
                    val status = when (p.extension3) {
                        Constant.PROBLEM_UNCHECKED -> "未审核"
                        Constant.PROBLEM_CHECK_PASS-> "通过"
                        Constant.PROBLEM_CHECK_FAIL -> "未通过"
                        else->"未审核"
                    }
                    checkStatus.add(status)
                    y++
                }
                //当有问题作为筛选条件时,如果没有找到对应问题,则该次任务去除
                if ( (config.problemTypeName != null || config.problemName != null || townName != null)
                        && (problemTypes.isEmpty() && problems.isEmpty())) {
                    return@forEach
                }
//                val lineMaxSize =3
//
//                val leader = it.assessorrealname?.split("#")
//                val leaderStr = StringBuilder()
//                for (t in 0 until (leader?.size ?: 0)) {
//                    if (t > 0) {
//                        leaderStr.append("、")
//                    }
//                    if (t == lineMaxSize - 1) {
//                        leaderStr.append("\r\n")
//                    }
//                    leaderStr.append(leader?.get(t))
//                }
//
//                val member = it.executorrealtimes?.split("#")
//                val memberStr = StringBuilder()
//                for (t in 0 until (member?.size ?: 0)) {
//                    if (t > 0) {
//                        memberStr.append("、")
//                    }
//                    if (t == lineMaxSize - 1) {
//                        memberStr.append("\r\n")
//                    }
//                    memberStr.append(member?.get(t))
//                }
                val rowContent = arrayOf<Any>(
//                        "$i",
                        it.name ?: "",
//                        it.scensename ?: "", scene.longitude.toString(), scene.latitude.toString(),
                        scene.type ?: "",
                        DateUtil().DateToString(it.executionstarttime, "yyyy-MM-dd HH:mm:ss") ?: "",
//                        DateUtil().DateToString(it.executionendtime, "yyyy-MM-dd hh:mm:ss") ?: "",
                        it.status ?: "", it.assessorrealname?.replace("#", "、") ?: "",
                        it.executorrealtimes?.replace("#", "、") ?: "", problemTypes.toTypedArray(), problems.toTypedArray(), districts.toTypedArray(), checkStatus.toTypedArray()
                )
                contents.add(rowContent)
                i++
            }
        }
        return contents
    }
    override fun searchSubTaskByKeyword(userId: String, keyword: String, page: Int, perPage: Int): BaseResponse<List<SubtaskVo>> {
        val userInfo = userinfoMapper.selectByPrimaryKey(userId)
        if (userInfo.usertypeid?.toInt() == 3) return BaseResponse(false, "企业用户无查询权限")//企业用户无法查询
@@ -688,7 +472,8 @@
            createCriteria().andLike("name", "%${keyword}%")
                .apply {
                    when (userInfo.usertypeid?.toInt()) {
                        0 -> {} //管理员用户查询无其他限制
                        0 -> {
                        } //管理员用户查询无其他限制
                        1 -> andLike("executorguids", "%${userId}%")//对于一般的巡查人员,只能查询到自己参与的子任务
                        2 -> andEqualTo("districtcode", userInfo.dGuid)//此处对于政府用户,dGuid存储的是区县编号
                    }
@@ -700,6 +485,504 @@
            result.add(vo)
        }
        return BaseResponse(true, head = DataHead(pageInfo.pageNum, pageInfo.pages) ,data = result)
        return BaseResponse(true, head = DataHead(pageInfo.pageNum, pageInfo.pages), data = result)
    }
    private fun getTable(mode: Int, config: ExcelConfigVo): Pair<MutableList<Array<Any>>, MutableList<Array<Any>>> {
        //数据源
        val dataList = getTableDataSource(config)
        //生成表格
        val head = mutableListOf<MutableList<Any>>()
        val contents = mutableListOf<MutableList<Any>>()
        getSceneName(head, contents, dataList)
        when (mode) {
            // 问题分布
            1 -> {
                getProblemDistribution(head, contents, dataList, config)
            }
            2 -> {
                getInspectionInfo(head, contents, dataList, config)
            }
            3 -> {
            }
        }
        val h = mutableListOf<Array<Any>>()
        val c = mutableListOf<Array<Any>>()
        head.forEach { h.add(it.toTypedArray()) }
        contents.forEach { c.add(it.toTypedArray()) }
        c.sortBy {
            it[0] as Int
        }
        return Pair(h, c)
    }
    // 表头:场景名
    private fun getSceneName(head: MutableList<MutableList<Any>>, contents: MutableList<MutableList<Any>>, dataList: List<Subtask>) {
        head.add(mutableListOf(ExcelUtil.MyCell("表单编号"), ExcelUtil.MyCell("唯一序号"), ExcelUtil.MyCell("场景名称")))
        dataList.forEach {subtask ->
            val row = mutableListOf<Any>()
            //查询该任务对应的场景
            val scene = scenseMapper.selectByPrimaryKey(subtask.scenseid)
            row.apply {
                add(scene.index ?: -99)
                add(scene.extension2 ?: "")
                add(scene.name ?: "")
            }
            contents.add(row)
        }
    }
    // 表头:具体问题分布
    private fun getProblemDistribution(head: MutableList<MutableList<Any>>, contents: MutableList<MutableList<Any>>,
                                       dataList: List<Subtask>, config: ExcelConfigVo) {
        val h1 = mutableListOf<ExcelUtil.MyCell>()
        val h2 = mutableListOf<Any>()
        currentProblemType.clear()
        currentProblemHead.clear()
        // 问题分为两层,新增一行表头
        problemtypeMapper.selectByExample(Example(Problemtype::class.java).apply {
            createCriteria().andEqualTo("scensetypeid", config.sceneType)
                .andEqualTo("districtcode", config.districtCode)
            orderBy("extension1")
        }).forEach {
            if (!currentProblemHead.contains(it.typename)) {
                currentProblemHead.add(it.typename ?: "")
                h1.add(ExcelUtil.MyCell(it.typename ?: "", colSpan = 0))
            }
            currentProblemType[it.guid ?: ""] = it.description ?: ""
            if (currentProblemHead.contains(it.typename)) {
                h2.add(it.description ?: "")
                h1.last().colSpan++
                h2.add("是否整改")
                h1.last().colSpan++
            }
        }
        //问题分布
        for (i in dataList.indices) {
            val subtask = dataList[i]
            val pDis = mutableListOf<Any>()//具体问题分布及整改情况
            repeat(h2.size) { pDis.add("")}
            if (subtask.stguid != null) {
                problemlistMapper.selectByExample(Example(Problemlist::class.java).apply {
                    createCriteria().andEqualTo("stguid", subtask.stguid)
                }).forEach problemType@{ p ->
                    val des = currentProblemType[p.ptguid]
                    //具体问题分布
                    for (t in h2.indices) {
                        if (des == h2[t]) {
                            //具体问题这一列添加文本,表示问题存在
                            pDis[t] = 1
                            //问题列的下一列是该问题的整改情况
                            pDis[t + 1] = if (p.ischanged == true) 1 else 0
                            break
                        }
                    }
                }
            }
            contents[i].addAll(pDis)
        }
        //原有的第一行表头增加1行行跨度,同时新的第二行表头添加空位
        head[0].forEach {
            (it as ExcelUtil.MyCell).rowSpan++
//            h2.add(0, "")
        }
        //合并表头
        head[0].addAll(h1)
        head.add(h2)
    }
    // 表头:巡查情况及问题、整改统计
    private fun getInspectionInfo(head: MutableList<MutableList<Any>>, contents: MutableList<MutableList<Any>>, dataList: List<Subtask>, config: ExcelConfigVo) {
        val h1 = listOf("监管时间", "问题类型", "问题描述", "问题位置", "问题数", "整改情况", "整改问题", "整改数", "未整改问题", "未整改数", "审核情况")
        for (i in dataList.indices) {
            val subtask = dataList[i]
            val row = mutableListOf<Any>()
            if (subtask.stguid == null) {
                repeat(h1.size) { row.add("")}
            } else {
                row.apply {
                    // 表头:巡查情况及问题、整改统计
                    add(dateUtil.DateToString(subtask.planstarttime, DateUtil.DateStyle.MM_DD) ?: "")//监管时间
                    //查询子任务对应的问题,并且根据条件进行筛选
                    var y = 1
                    var pType = ""//问题类型
                    var pDes = ""//问题描述
                    var pLoc = ""//问题位置
                    var pNum = 0//问题数
                    var pChanged = ""//整改情况
                    var changedProblem = ""//整改问题
                    var cNum = 0//整改数
                    var unChangedProblem = ""//未整改问题
                    var unChangeNum = 0//未整改数
                    var checkStatus = ""//审核情况
                    problemlistMapper.selectByExample(Example(Problemlist::class.java).apply {
                        createCriteria().andEqualTo("stguid", subtask.stguid)
                    }).forEach problemType@{ p ->
                        val problemType = problemtypeMapper.selectByPrimaryKey(p.ptguid)
                        val typeName = if (problemType == null) {
                            val a = ""
                            a
                        } else {
                            problemType.typename
                        }
                        val lr = if (y > 1) "\n" else ""
                        //巡查情况及问题、整改统计
                        pType += "${lr}$y、${typeName}"
                        pDes += "${lr}$y、${p.problemname}"
                        pLoc += "${lr}$y、${p.location}"
                        pNum++
                        pChanged += "${lr}$y、${if (p.ischanged == true) "✓" else "×"}"
                        if (p.ischanged == true) {
                            if (changedProblem.isNotBlank()) {
                                changedProblem += "\n"
                            }
                            changedProblem += "$y、${p.problemname}"
                            cNum++
                        } else {
                            if (unChangedProblem.isNotBlank()) {
                                unChangedProblem += "\n"
                            }
                            unChangedProblem += "$y、${p.problemname}"
                            unChangeNum++
                        }
                        val status = when (p.extension3) {
                            Constant.PROBLEM_CHECK_PASS -> "问题审核通过"//
                            Constant.PROBLEM_CHECK_FAIL -> "问题审核未通过"//
                            Constant.PROBLEM_UNCHECKED -> "问题未审核"//
                            Constant.CHANGE_UNCHECKED -> "整改未审核"//
                            Constant.CHANGE_CHECK_PASS -> "整改审核通过"//
                            Constant.CHANGE_CHECK_FAIL -> "整改审核未通过"//
                            else -> "问题未审核"
                        }
                        checkStatus += "${lr}$y、${status}"
                        y++
                    }
                    addAll(listOf(pType, pDes, pLoc, pNum, pChanged, changedProblem, cNum, unChangedProblem, unChangeNum, checkStatus))
                }
            }
            contents[i].addAll(row)
        }
        head[0].addAll(h1)
    }
    private fun getTableTitles(sceneType: Int?, districtCode: String?): List<String> {
        if (sceneType == null || districtCode == null) return emptyList()
        val heads = mutableListOf<String>()
        heads.run {
            addAll(getSceneName())
            addAll(getLocation())
            addAll(getBaseInfo(sceneType))
            addAll(getContactInfo(sceneType))
            addAll(getRealTimeStatus(sceneType))
            addAll(getInspectionInfo(sceneType))
            addAll(getProblemDistribution(sceneType, districtCode))
        }
        return heads
    }
    // 表头:场景名
    private fun getSceneName() = listOf("表单编号", "唯一序号", "场景名称")
    // 表头:场景地理位置
    private fun getLocation(): List<String> = listOf(
        "街镇", "地址"
    )
    // 表头:场景专属基础信息
    private fun getBaseInfo(sceneType: Int): List<String> = when (sceneType.toString()) {
        Constant.ScenseType.TYPE1.value -> listOf("业主单位", "施工单位", "建筑面积(m²)", "施工起始时间", "施工结束时间", "施工阶段", "工程类型")
        Constant.ScenseType.TYPE2.value -> listOf("业主单位", "租赁单位", "占地面积(m²)", "营运状态", "类型")
        Constant.ScenseType.TYPE3.value -> listOf("业主单位", "文明场站", "绿色环保站厂", "占地面积(m²)", "营运状态")
        Constant.ScenseType.TYPE14.value -> listOf("业主单位", "租赁单位", "占地面积(m²)", "营运状态", "类型")
        else -> listOf()
    }
    // 表头:场景联系方式
    private fun getContactInfo(sceneType: Int): List<String> = when (sceneType) {
        else -> listOf("联系人", "联系方式")
    }
    // 表头:场景现场情况
    private fun getRealTimeStatus(sceneType: Int): List<String> = when (sceneType) {
        else -> listOf()
    }
    // 表头:巡查情况及问题、整改统计
    private fun getInspectionInfo(sceneType: Int): List<String> = when (sceneType) {
        else -> listOf("监管时间", "防治考核评分", "防治规范性", "扣分项","问题类型", "问题描述", "问题位置", "问题数", "整改情况", "整改数", "审核情况")
    }
    // 表头:具体问题分布
    private val currentProblemType = mutableMapOf<String, String>()
    private val currentProblemHead = mutableListOf<String>()
    private fun getProblemDistribution(sceneType: Int, districtCode: String): List<String> {
        val heads = mutableListOf<String>()
        currentProblemType.clear()
        currentProblemHead.clear()
        problemtypeMapper.selectByExample(Example(Problemtype::class.java).apply {
            createCriteria().andEqualTo("scensetypeid", sceneType)
                .andEqualTo("districtcode", districtCode)
            orderBy("typeid")
        }).forEach {
            if (!heads.contains(it.typename)) {
                heads.add(it.typename ?: "")
            }
            currentProblemType[it.guid ?: ""] = it.typename ?: ""
        }
        currentProblemHead.addAll(heads)
        return heads
    }
    /**
     * 获取表格数据源
     */
    private fun getTableDataSource(config: ExcelConfigVo): List<Subtask> {
        if (config.sceneType == null) return emptyList()
        val result = mutableListOf<Subtask>()
        //1. 查找特定的巡查任务或者所有的计划巡查任务
        var taskSceneIdList = listOf<String>()
        val subTaskList = if (config.subTaskIdList?.isNotEmpty() == true ||
            (config.startTime != null || config.endTime != null)
        ) {
            subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                createCriteria().apply {
                    if (config.subTaskIdList?.isNotEmpty() == true) {
                        andIn("stguid", config.subTaskIdList)
                    }
                    config.startTime?.let { andGreaterThanOrEqualTo("planstarttime", it) }
                    config.endTime?.let { andLessThanOrEqualTo("planendtime", it) }
                }
            })
        } else {
            taskSceneIdList = monitorobjectversionMapper.getSceneByType(config.topTaskGuid, config.sceneType)
            subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                createCriteria().andIn("scenseid", taskSceneIdList)
                    .andEqualTo("tguid", config.topTaskGuid)
            })
        }
        if (taskSceneIdList.isNotEmpty()) {
            taskSceneIdList.forEach {
                var subtask: Subtask? = null
                for (s in subTaskList) {
                    if (s.scenseid == it) {
                        subtask = s
                        break
                    }
                }
                if (subtask == null) subtask = Subtask().apply { scenseid = it }
                result.add(subtask)
            }
        } else {
            result.addAll(subTaskList)
        }
        return result
    }
    private fun getTableContents(config: ExcelConfigVo, colCounts: Int = 0): List<Array<Any>> {
        if (config.sceneType == null) return emptyList()
        //1. 查找特定的巡查任务或者所有的计划巡查任务
        var taskSceneIdList = listOf<String>()
        val subTaskList = if (config.subTaskIdList?.isNotEmpty() == true ||
            (config.startTime != null || config.endTime != null)
        ) {
            subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                createCriteria().apply {
                    if (config.subTaskIdList?.isNotEmpty() == true) {
                        andIn("stguid", config.subTaskIdList)
                    }
                    config.startTime?.let { andGreaterThanOrEqualTo("planstarttime", it) }
                    config.endTime?.let { andLessThanOrEqualTo("planendtime", it) }
                }
            })
        } else {
            taskSceneIdList = monitorobjectversionMapper.getSceneByType(config.topTaskGuid, config.sceneType)
            subtaskMapper.selectByExample(Example(Subtask::class.java).apply {
                createCriteria().andIn("scenseid", taskSceneIdList)
                    .andEqualTo("tguid", config.topTaskGuid)
            })
        }
        val contents = mutableListOf<Array<Any>>()
        val subTasks = mutableListOf<Subtask>()
        if (taskSceneIdList.isNotEmpty()) {
            taskSceneIdList.forEach {
                val rowContent = mutableListOf<Any>()
                var subtask: Subtask? = null
                for (s in subTaskList) {
                    if (s.scenseid == it) {
                        subtask = s
                        break
                    }
                }
                //该场景未巡查
                if (subtask == null) {
                    val scene = scenseMapper.selectByPrimaryKey(it)
                    rowContent.apply {
                        add(scene.index?.toString() ?: "")
                        add(scene.extension2 ?: "")
                        add(scene.name ?: "")
                    }
                    val left = colCounts - getSceneName().size
                    repeat(left) {
                        rowContent.add("")
                    }
                } else {
                    rowContent.addAll(tableContent(subtask))
                }
                contents.add(rowContent.toTypedArray())
            }
        } else {
            subTaskList.forEach {
                val c = tableContent(it)
                contents.add(c)
            }
        }
        return contents
    }
    private fun tableContent(subtask: Subtask): Array<Any> {
        val row = mutableListOf<Any>()
        //查询该任务对应的场景
        val scene = scenseMapper.selectByPrimaryKey(subtask.scenseid)
        row.apply {
            // 表头:场景名
            add(scene.index?.toString() ?: "")
            add(scene.extension2 ?: "")
            add(scene.name ?: "")
            // 表头:场景地理位置
            add(scene.townname ?: "")
            add(scene.location ?: "")
            // 表头:场景专属基础信息
            addAll(when (scene.typeid.toString()) {
                Constant.ScenseType.TYPE1.value -> {
//                    listOf("业主单位", "施工单位", "建筑面积(m²)", "施工起始时间", "施工结束时间", "施工阶段", "工程类型")
                    var r = listOf("-", "-", "-", "-", "-", "-", "-")
                    sceneConstructionSiteMapper.selectByPrimaryKey(scene.guid)?.let {
                        r = listOf(it.csEmployerUnit?:"", it.csConstructionUnit?:"", it.csFloorSpace?:"",
                            it.csStartTime?:"", it.csEndTime?:"", it.csStatus?:"", it.csProjectType?:"")
                    }
                    r
                }
                Constant.ScenseType.TYPE2.value -> {
//                    listOf("业主单位", "租赁单位", "占地面积(m²)", "营运状态", "类型")
                    var r = listOf("-", "-", "-", "-", "-")
                    sceneWharfMapper.selectByPrimaryKey(scene.guid)?.let {
                        r = listOf(it.getwEmployerUnit()?:"", it.getwRentUnit()?:"", it.getwFloorSpace()?:"", it.getwStatus()?:"",
                            it.getwProjectType()?:"")
                    }
                    r
                }
                Constant.ScenseType.TYPE3.value -> {
//                    listOf("业主单位", "文明场站", "绿色环保站厂", "占地面积(m²)", "营运状态")
                    var r = listOf("-", "-", "-", "-", "-")
                    sceneMixingPlantMapper.selectByPrimaryKey(scene.guid)?.let {
                        r = listOf(
                            it.mpEmployerUnit?:"", if (it.mpCivillyPlant == true) "是" else "否", if (it.mpGreenPlant == true) "是" else "否",
                            it.mpFloorSpace?:"", it.mpStatus?:""
                        )
                    }
                    r
                }
                Constant.ScenseType.TYPE14.value -> {
//                    listOf("业主单位", "租赁单位", "占地面积(m²)", "营运状态", "类型")
                    var r = listOf("-", "-", "-", "-", "-")
                    sceneStorageYardMapper.selectByPrimaryKey(scene.guid)?.let {
                        r = listOf(it.syEmployerUnit?:"", it.syRentUnit?:"", it.syFloorSpace?:"", it.syStatus?:"", it.syProjectType?:"")
                    }
                    r
                }
                else -> listOf()
            })
            // 表头:场景联系方式
            add(scene.contacts ?: "")
            add(scene.contactst ?: "")
            // 表头:场景现场情况
            // TODO: 2022/7/10 暂无
            // 表头:巡查情况及问题、整改统计 和 表头:具体问题分布
            listOf("监管时间", "防治考核评分", "防治规范性", "扣分项","问题类型", "问题描述", "问题位置", "问题数", "整改情况", "整改数", "审核情况")
            add(dateUtil.DateToString(subtask.planstarttime, DateUtil.DateStyle.MM_DD) ?: "")
            add("")
            add("")
            add("")
            //查询子任务对应的问题,并且根据条件进行筛选
            var y = 1
            var pType = ""//问题类型
            var pDes = ""//问题描述
            var pLoc = ""//问题位置
            var pNum = 0//问题数
            var pChanged = ""//整改情况
            var cNum = 0//整改数
            var checkStatus = ""//审核情况
            var pDis = mutableListOf<String>()//具体问题分布
            repeat(currentProblemHead.size) { pDis.add("")}
            problemlistMapper.selectByExample(Example(Problemlist::class.java).apply {
                createCriteria().andEqualTo("stguid", subtask.stguid)
            }).forEach problemType@{ p ->
                val typeName = currentProblemType[p.ptguid]
                val lr = if (y > 1) "\n" else ""
                //巡查情况及问题、整改统计
                pType += "${lr}$y、${typeName}"
                pDes += "${lr}$y、${p.problemname}"
                pLoc += "${lr}$y、${p.location}"
                pNum++
                pChanged += "${lr}$y、${if (p.ischanged == true) "✓" else "×"}"
                if (p.ischanged == true) cNum++
                val status = when (p.extension3) {
                    Constant.PROBLEM_CHECK_PASS -> "问题审核通过"//
                    Constant.PROBLEM_CHECK_FAIL -> "问题审核未通过"//
                    Constant.PROBLEM_UNCHECKED -> "问题未审核"//
                    Constant.CHANGE_UNCHECKED -> "整改未审核"//
                    Constant.CHANGE_CHECK_PASS -> "整改审核通过"//
                    Constant.CHANGE_CHECK_FAIL -> "整改审核未通过"//
                    else -> "问题未审核"
                }
                checkStatus += "${lr}$y、${status}"
                y++
                //具体问题分布
                for (t in currentProblemHead.indices) {
                    if (typeName == currentProblemHead[t]) {
                        pDis[t] = if (p.ischanged == true) "1" else "0"
                        break
                    }
                }
            }
            addAll(listOf(pType, pDes, pLoc, pNum, pChanged, cNum, checkStatus))
            addAll(pDis)
        }
        return row.toTypedArray()
    }
}