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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package com.ruoyi.process.service;
 
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.exception.ErrorException;
import com.ruoyi.inspect.mapper.InsOrderStateMapper;
import com.ruoyi.inspect.pojo.InsOrder;
import com.ruoyi.inspect.pojo.InsOrderState;
import com.ruoyi.inspect.service.InsOrderPlanService;
import com.ruoyi.inspect.vo.QualityMonitorRawContext;
import com.ruoyi.process.mapper.QualityMonitorDetailsEvaluateMapper;
import com.ruoyi.process.mapper.QualityMonitorDetailsMapper;
import com.ruoyi.process.mapper.QualityMonitorEvaluateResultMapper;
import com.ruoyi.process.mapper.QualityMonitorMapper;
import com.ruoyi.process.pojo.QualityMonitor;
import com.ruoyi.process.pojo.QualityMonitorDetails;
import com.ruoyi.process.pojo.QualityMonitorDetailsEvaluate;
import com.ruoyi.process.pojo.QualityMonitorEvaluateResult;
import com.ruoyi.system.mapper.UserMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
 
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
 
@Service
public class QualityMonitorInspectionEvaluationService {
    @Resource
    private QualityMonitorTaskService taskService;
    @Resource
    private QualityMonitorDetailsMapper detailsMapper;
    @Resource
    private QualityMonitorMapper monitorMapper;
    @Resource
    private QualityMonitorDetailsEvaluateMapper evaluateMapper;
    @Resource
    private QualityMonitorEvaluateResultMapper resultMapper;
    @Resource
    private InsOrderStateMapper stateMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private InsOrderPlanService insOrderPlanService;
 
    public QualityMonitorDetailsEvaluate get(Integer detailId) {
        QualityMonitorDetails detail = requireDetail(detailId);
        QualityMonitorDetailsEvaluate evaluation = evaluateMapper.selectOne(Wrappers.<QualityMonitorDetailsEvaluate>lambdaQuery()
                .eq(QualityMonitorDetailsEvaluate::getQualityMonitorDetailsId, detailId).last("limit 1"));
        InsOrder task = taskService.getTask(detailId);
        if (evaluation == null) {
            evaluation = new QualityMonitorDetailsEvaluate();
            evaluation.setQualityMonitorDetailsId(detailId);
            evaluation.setInspectorUserId(detail.getInspectorUserId());
            evaluation.setSampleName(detail.getSampleName());
            evaluation.setSampleSpec(detail.getSampleSpec());
        }
        List<QualityMonitorEvaluateResult> rows = evaluation.getDetailsEvaluateId() == null
                ? List.of() : resultMapper.selectList(Wrappers.<QualityMonitorEvaluateResult>lambdaQuery()
                                                      .eq(QualityMonitorEvaluateResult::getDetailsEvaluateId, evaluation.getDetailsEvaluateId())
                                                      .orderByAsc(QualityMonitorEvaluateResult::getSortNo, QualityMonitorEvaluateResult::getId));
        if (task != null && Integer.valueOf(5).equals(task.getInsState())) {
            List<Map<String, String>> rawRows = insOrderPlanService.getQualityMonitorRawResults(task.getId());
            fillRawContext(evaluation, insOrderPlanService.getQualityMonitorRawContext(task.getId()));
            if (!rows.isEmpty() && rows.size() != rawRows.size())
                throw new ErrorException("原始记录检测数据已变化,请重新核对评价记录");
            if (rows.isEmpty()) {
                rows = new java.util.ArrayList<>();
                for (int i = 0; i < rawRows.size(); i++) {
                    QualityMonitorEvaluateResult row = new QualityMonitorEvaluateResult();
                    row.setInspectorUserId(detail.getInspectorUserId());
                    row.setMeasuredValue(rawRows.get(i).get("result"));
                    row.setUnit(rawRows.get(i).get("unit"));
                    row.setSortNo(i);
                    rows.add(row);
                }
            }
            for (int i = 0; i < rows.size(); i++) rows.get(i).setItemName(rawRows.get(i).get("itemName"));
        }
        evaluation.setResultRows(rows);
        evaluation.setInspectionTaskState(task == null ? null : task.getInsState());
        if (Integer.valueOf(1).equals(evaluation.getIsFinish())) {
            evaluation.setEvaluationEditReason("评价已批准归档,只能查看");
        } else if (task == null) {
            evaluation.setEvaluationEditReason("质控检验任务尚未下发,暂不能填写评价");
        } else if (!Integer.valueOf(5).equals(task.getInsState())) {
            evaluation.setEvaluationEditReason("原始记录复核通过后,指定评价人才可以填写");
        } else if (detail.getEvaluatorUserId() == null) {
            evaluation.setEvaluationEditReason("计划项目尚未指定评价人");
        } else if (!Integer.valueOf(SecurityUtils.getUserId().intValue()).equals(detail.getEvaluatorUserId())) {
            var evaluator = userMapper.selectById(detail.getEvaluatorUserId());
            evaluation.setEvaluationEditReason("当前账号不是指定评价人("
                    + (evaluator == null ? "用户ID " + detail.getEvaluatorUserId() : evaluator.getName())
                    + "),只能查看");
        } else {
            evaluation.setEvaluationEditable(true);
        }
        return evaluation;
    }
 
    @Transactional(rollbackFor = Exception.class)
    public QualityMonitorDetailsEvaluate submit(QualityMonitorDetailsEvaluate input) {
        if (input == null) throw new ErrorException("评价内容不能为空");
        QualityMonitorDetails detail = requireDetail(input.getQualityMonitorDetailsId());
        InsOrder task = taskService.getTask(detail.getQualityMonitorDetailsId());
        if (task == null || !QualityMonitorTaskService.SOURCE.equals(task.getTaskSource()))
            throw new ErrorException("质量监控检验任务不存在");
        if (!Integer.valueOf(5).equals(task.getInsState()))
            throw new ErrorException("原始记录复核通过后才能评价");
        if (!Integer.valueOf(SecurityUtils.getUserId().intValue()).equals(detail.getEvaluatorUserId()))
            throw new ErrorException("只有指定评价人可以填写评价");
        if (input.getSupervisorUserId() == null
                || input.getSupervisorUserId().equals(detail.getInspectorUserId())
                || input.getSupervisorUserId().equals(detail.getEvaluatorUserId())
                || userMapper.selectById(input.getSupervisorUserId()) == null)
            throw new ErrorException("请选择与检测员、评价人不同的监督员");
        Long pendingCount = stateMapper.selectCount(Wrappers.<InsOrderState>lambdaQuery()
                .eq(InsOrderState::getInsOrderId, task.getId()).ne(InsOrderState::getInsState, 5));
        if (pendingCount > 0) throw new ErrorException("原始记录复核通过后才能评价");
        List<Map<String, String>> rawRows = insOrderPlanService.getQualityMonitorRawResults(task.getId());
        QualityMonitorRawContext rawContext = insOrderPlanService.getQualityMonitorRawContext(task.getId());
        if (rawContext.getDetectionDates().isEmpty() || rawContext.getDevices().isEmpty())
            throw new ErrorException("原始记录缺少检测时间或所用设备,请先补齐并复核");
        if (!StringUtils.hasText(input.getEvaluationConclusion()) || input.getResultRows() == null
                || input.getResultRows().size() != rawRows.size())
            throw new ErrorException("请填写评价内容并核对全部原始记录检测数据");
        if (!Boolean.TRUE.equals(input.getMeasurementConfirmed()))
            throw new ErrorException("请先核对已复核原始记录的检测数据");
        QualityMonitorDetailsEvaluate existing = evaluateMapper.selectOne(Wrappers.<QualityMonitorDetailsEvaluate>lambdaQuery()
                .eq(QualityMonitorDetailsEvaluate::getQualityMonitorDetailsId, detail.getQualityMonitorDetailsId())
                .last("FOR UPDATE"));
        if (existing != null && Integer.valueOf(1).equals(existing.getIsFinish()))
            throw new ErrorException("已批准的评价不可修改");
        QualityMonitor plan = monitorMapper.selectById(detail.getQualityMonitorId());
        QualityMonitorDetailsEvaluate saved = existing == null ? new QualityMonitorDetailsEvaluate() : existing;
        saved.setQualityMonitorDetailsId(detail.getQualityMonitorDetailsId());
        saved.setInsOrderId(task.getId());
        saved.setInspectorUserId(detail.getInspectorUserId());
        saved.setImplementUserId(detail.getEvaluatorUserId());
        saved.setRatifyUserId(plan.getRatifyUserId());
        saved.setSupervisorUserId(input.getSupervisorUserId());
        saved.setSampleName(detail.getSampleName());
        saved.setSampleSpec(detail.getSampleSpec());
        // 时间和设备始终由已复核原始记录读取,评价请求中的同名字段不参与保存。
        saved.setImplementCondition(input.getEvaluationConclusion());
        saved.setImplementResult(input.getImplementResult());
        saved.setEvaluationConclusion(input.getEvaluationConclusion());
        saved.setCorrectiveAction(input.getCorrectiveAction());
        saved.setVerificationResult(input.getVerificationResult());
        saved.setCorrectiveResponsibleUserId(input.getCorrectiveResponsibleUserId());
        saved.setCorrectiveDueDate(input.getCorrectiveDueDate());
        saved.setVerificationResponsibleUserId(input.getVerificationResponsibleUserId());
        saved.setVerificationDate(input.getVerificationDate());
        saved.setReviewPurpose(detail.getMonitorPurpose());
        saved.setReviewUser(userMapper.selectById(detail.getEvaluatorUserId()).getName());
        saved.setReviewTime(LocalDateTime.now().toLocalDate().toString());
        if (!StringUtils.hasText(saved.getImplementResult())) {
            saved.setImplementResult(input.getEvaluationConclusion());
        }
        saved.setIsFinish(0);
        if (existing == null) evaluateMapper.insert(saved);
        else evaluateMapper.updateById(saved);
        resultMapper.delete(Wrappers.<QualityMonitorEvaluateResult>lambdaQuery()
                .eq(QualityMonitorEvaluateResult::getDetailsEvaluateId, saved.getDetailsEvaluateId()));
        int index = 0;
        for (QualityMonitorEvaluateResult row : input.getResultRows()) {
            Map<String, String> rawRow = rawRows.get(index);
            if (!Objects.equals(row.getMeasuredValue(), rawRow.get("result")))
                throw new ErrorException("检测数据与已复核原始记录不一致,请刷新后重新核对");
            if (!StringUtils.hasText(row.getReferenceValue())) throw new ErrorException("请填写盲样值");
            row.setId(null);
            row.setDetailsEvaluateId(saved.getDetailsEvaluateId());
            row.setInspectorUserId(detail.getInspectorUserId());
            row.setMeasuredValue(rawRow.get("result"));
            row.setUnit(rawRow.get("unit"));
            row.setSortNo(index++);
            resultMapper.insert(row);
        }
        return get(detail.getQualityMonitorDetailsId());
    }
 
    @Transactional(rollbackFor = Exception.class)
    public void approve(Integer detailId, boolean approved, String opinion) {
        QualityMonitorDetails detail = requireDetail(detailId);
        QualityMonitor plan = monitorMapper.selectById(detail.getQualityMonitorId());
        int current = SecurityUtils.getUserId().intValue();
        if (plan == null || !Integer.valueOf(current).equals(plan.getRatifyUserId())
                || Integer.valueOf(current).equals(detail.getInspectorUserId()))
            throw new ErrorException("只有指定批准人可以审批评价");
        QualityMonitorDetailsEvaluate evaluation = evaluateMapper.selectOne(Wrappers.<QualityMonitorDetailsEvaluate>lambdaQuery()
                .eq(QualityMonitorDetailsEvaluate::getQualityMonitorDetailsId, detailId).last("FOR UPDATE"));
        if (evaluation == null || Integer.valueOf(1).equals(evaluation.getIsFinish()))
            throw new ErrorException("评价不存在或已批准");
        if (approved && StringUtils.hasText(evaluation.getCorrectiveAction())
                && (!StringUtils.hasText(evaluation.getVerificationResult())
                || evaluation.getCorrectiveResponsibleUserId() == null
                || evaluation.getCorrectiveDueDate() == null
                || evaluation.getVerificationResponsibleUserId() == null
                || evaluation.getVerificationDate() == null))
            throw new ErrorException("请补齐纠正措施责任人、完成日期和验证信息后再批准");
        evaluation.setRatifyOpinion(opinion);
        evaluation.setRatifyTime(LocalDateTime.now());
        evaluation.setIsFinish(approved ? 1 : 0);
        evaluateMapper.updateById(evaluation);
    }
 
    private QualityMonitorDetails requireDetail(Integer detailId) {
        QualityMonitorDetails detail = detailId == null ? null : detailsMapper.selectById(detailId);
        if (detail == null || !"INSPECTION".equals(detail.getItemKind()))
            throw new ErrorException("质量监控检测明细不存在");
        return detail;
    }
 
    private void fillRawContext(QualityMonitorDetailsEvaluate evaluation, QualityMonitorRawContext context) {
        evaluation.setRawInspectionDates(context.getDetectionDates().stream()
                .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).collect(Collectors.toList()));
        List<String> names = new ArrayList<>();
        List<String> specs = new ArrayList<>();
        List<String> codes = new ArrayList<>();
        for (Map<String, String> device : context.getDevices()) {
            names.add(deviceText(device, "device_name", "deviceName"));
            specs.add(deviceText(device, "specification_model", "specificationModel"));
            String managementNumber = deviceText(device, "management_number", "managementNumber");
            codes.add("-".equals(managementNumber)
                    ? deviceText(device, "factory_no", "factoryNo") : managementNumber);
        }
        evaluation.setRawEquipmentDescription(String.join("\n", names));
        evaluation.setRawEquipmentSpec(String.join("\n", specs));
        evaluation.setRawEquipmentCode(String.join("\n", codes));
    }
 
    private String deviceText(Map<String, String> device, String snakeCase, String camelCase) {
        String value = device.get(snakeCase);
        if (!StringUtils.hasText(value)) value = device.get(camelCase);
        return StringUtils.hasText(value) ? value : "-";
    }
}