feiyu02
2024-08-15 196bb14112448857a885e32dc4149e308e00b01a
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
package cn.flightfeather.supervision.common.autoledger
 
import cn.flightfeather.supervision.common.pdf.PdfUtil
import cn.flightfeather.supervision.domain.entity.LedgerSubType
import cn.flightfeather.supervision.domain.entity.PracticalOperation
import cn.flightfeather.supervision.domain.entity.Userinfo
import cn.flightfeather.supervision.domain.repository.LedgerRep
import cn.flightfeather.supervision.domain.repository.PracticalOperationRep
import cn.flightfeather.supervision.infrastructure.utils.DateUtil
import cn.flightfeather.supervision.lightshare.service.LedgerService
import cn.flightfeather.supervision.lightshare.vo.LedgerVo
import org.springframework.stereotype.Component
import org.thymeleaf.context.Context
import org.thymeleaf.spring5.SpringTemplateEngine
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.*
 
/**
 * 台账自动生成
 */
@Component
class AutoLedger(
    private val springTemplateEngine: SpringTemplateEngine,
    private val ledgerRep: LedgerRep,
    private val practicalOperationRep: PracticalOperationRep,
    private val ledgerService: LedgerService,
) {
 
    /**
     * 根据实操事务的配置,生成对应的台账记录
     * 当月的台账记录应该由上个月的实操记录作为内容进行生成
     * @param userInfo 生成台账对应的用户信息
     * @param operations 实操事务
     * @param year 生成的台账所在年份
     * @param month 生成的台账所在月份
     */
    fun create(userInfo: Userinfo?, operations: List<PracticalOperation?>, year: Int, month: Int) {
        if (userInfo == null || operations.isEmpty()) {
            return
        }
        // 台账的时间范围
        val thisMonth = LocalDateTime.of(year, month, 1, 0, 0)
        val sT = thisMonth.minusMonths(1)
        val eT = thisMonth.minusSeconds(1)
 
        val ledger = ledgerRep.selectLedger(operations[0]?.poLedgerTypeId)
 
        val map = hashMapOf<String, Any>()
        map["info"] = getBaseInfo(ledger, userInfo, operations)
        val records = getRecords(userInfo, operations, sT, eT)
        // 当用户没有操作记录时,不生成对应台账
        if (records.isEmpty()) return
        map["table"] = records
 
        val context = Context()
        context.setVariables(map)
        val content = springTemplateEngine.process("ledger-3206", context)
        val pdf = PdfUtil.htmlToPdf(content)
        val pics = PdfUtil.pdfToPic(pdf)
        val files = pics.map { Pair(it, "jpg") }
 
        // 生成的台账时间为传入的时间
        val ledgerVo = LedgerVo.fromLedgerSubtype(ledger).apply {
            updateDate = Date.from(thisMonth.atZone(ZoneId.systemDefault()).toInstant())
        }
        ledgerService.uploadLedger(userInfo.guid!!, ledgerVo, files)
    }
 
    /**
     *
     */
    private fun getBaseInfo(ledger: LedgerSubType?, userInfo: Userinfo, operations: List<PracticalOperation?>):
            UserBaseInfo {
        val title = operations[0]?.poLedgerTypeName ?: ""
        val stateRange = operations[0]?.poStateRange?.split(";")
        val stateNames = getStateNames(stateRange)
        val now = LocalDate.now().format(DateTimeFormatter.ofPattern("YYYY年MM月"))
        return UserBaseInfo(title, userInfo.realname ?: "", now, stateNames)
    }
 
    /**
     * 获取状态标题
     */
    private fun getStateNames(stateRange: List<String>?): List<String> {
        stateRange ?: return emptyList()
        val res = mutableListOf<String>()
        res.addAll(stateRange.subList(1, stateRange.size))
        res.add(stateRange[0])
        return res
    }
 
    /**
     *
     */
    private fun getRecords(
        userInfo: Userinfo,
        operations: List<PracticalOperation?>,
        sT: LocalDateTime,
        eT: LocalDateTime,
    ): List<Record> {
        val userId = userInfo.guid
        val records = mutableListOf<Record>()
        operations.forEach {
            val deviceName = it?.poSubTypeName + it?.poDeviceCode
            val stateRange = it?.poStateRangeId?.split(";") ?: return@forEach
            // 状态最少有两种,否则应该是配置错误
            if (stateRange.size < 2) return@forEach
            val opRecords = practicalOperationRep.getRecords(userId, listOf(it.poId), sT, eT, true)
 
            // 判断事务的状态规则是否为依次变换型
            if (it.poStateRule == 0) {
                // 该规则下的台账记录会将一组完整的状态变换记为一条记录,
                // 通常首个状态含义为关闭,所以一般从第二个状态开始
                opRecords.forEach { r ->
                    val time = LocalDateTime.ofInstant(r?.prTime?.toInstant(), ZoneId.systemDefault())
                    val date = time.format(DateTimeFormatter.ofPattern("MM月dd日"))
                    val stateTimes = MutableList<String?>(stateRange.size) { "" }
                    // 当状态不是关闭时,表示这一组状态还未完成,因此添加到上一条记录中
                    // 如果没有上一条记录,或者状态为除了关闭的第一个状态,则新增记录
                    val record = if (records.isEmpty() || r?.prStateId == stateRange[1]) {
                        val r = Record(deviceName, date, stateTimes)
                        records.add(r)
                        r
                    } else {
                        val last = records.last()
                        // 判断当前记录和上一条记录是否在同一天
                        if (last.date == date) {
                            last
                        } else {
                            val r1 = Record(deviceName, date, stateTimes)
                            records.add(r1)
                            r1
                        }
                    }
                    var index = stateRange.indexOf(r?.prStateId)
                    if (index != -1) {
                        index -= 1
                        if (index == -1) index = stateRange.lastIndex
                        record.stateTimes[index] = DateUtil.DateToString(r?.prTime, DateUtil.DateStyle.HH_MM_SS)
                    }
                }
            } else if (it.poStateRule == 1) {
                // TODO: 2024/3/8
            }
        }
        return records
    }
 
    /**
     * 用户基本信息
     */
    inner class UserBaseInfo(
        val title: String?,
        val userName: String?,
        val timeStamp: String?,
        val stateNames: List<String>,
    )
 
    /**
     * 台账记录
     */
    inner class Record(
        val deviceName: String?,
        val date: String?,
        val stateTimes: MutableList<String?>,
    )
 
}