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
package cn.iocoder.yudao.module.mes.service.pro.feedback;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper;
import cn.iocoder.yudao.module.mes.service.pro.feedback.dto.MesFeedbackParamSnapshot;
import cn.iocoder.yudao.module.mes.service.pro.feedback.dto.MesTaskParamSnapshot;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
/** 统一参数校验;调用方须在事务中持有任务锁直到报工保存完成。 */
@Service
public class MesFeedbackParamService {
    @Resource private MesProTaskMapper taskMapper;
 
    public MesProTaskDO lockTask(Long taskId) {
        MesProTaskDO task = taskMapper.selectOne(new LambdaQueryWrapperX<MesProTaskDO>()
                .eq(MesProTaskDO::getId, taskId).last("FOR UPDATE"));
        if (task == null) throw exception(PRO_TASK_NOT_EXISTS);
        return task;
    }
 
    /** 草稿允许暂不填写;传值时仍校验属于该任务的模板。 */
    public String buildDraft(MesProTaskDO task, List<MesFeedbackParamSnapshot.Value> values) {
        if (task.getParamCollectMode() == null || task.getParamCollectMode() == 0 || CollUtil.isEmpty(values)) return null;
        return buildSnapshot(task, values, false);
    }
 
    /** 提交前锁定任务;任务共用模式首次提交固化数据,后续报工复制同一快照。 */
    public String complete(MesProTaskDO lockedTask, String draftSnapshot) {
        int mode = lockedTask.getParamCollectMode() == null ? 0 : lockedTask.getParamCollectMode();
        if (mode == 0) return null;
        if (mode != 1 && mode != 2) throw exception(PRO_FEEDBACK_PARAM_INVALID, "采集方式不正确");
        if (mode == 2 && StrUtil.isNotBlank(lockedTask.getParamSharedSnapshot())) return lockedTask.getParamSharedSnapshot();
        MesFeedbackParamSnapshot draft = StrUtil.isBlank(draftSnapshot) ? null : JsonUtils.parseObject(draftSnapshot, MesFeedbackParamSnapshot.class);
        String result = buildSnapshot(lockedTask, draft == null ? null : draft.getValues(), true);
        if (mode == 2) {
            MesProTaskDO update = new MesProTaskDO().setId(lockedTask.getId()).setParamSharedSnapshot(result);
            if (taskMapper.updateById(update) != 1) throw exception(PRO_TASK_NOT_EXISTS);
        }
        return result;
    }
 
    private String buildSnapshot(MesProTaskDO task, List<MesFeedbackParamSnapshot.Value> values, boolean requireAll) {
        MesTaskParamSnapshot template = JsonUtils.parseObject(task.getParamTemplateSnapshot(), MesTaskParamSnapshot.class);
        if (template == null || CollUtil.isEmpty(template.getDetails())) throw exception(PRO_FEEDBACK_PARAM_INVALID, "任务缺少参数模板快照");
        Map<Long, MesTaskParamSnapshot.Detail> expected = new LinkedHashMap<>();
        for (var detail : template.getDetails()) expected.put(detail.getId(), detail);
        Map<Long, String> submitted = new LinkedHashMap<>();
        if (values != null) for (var value : values) {
            if (value == null || value.getDetailId() == null || !expected.containsKey(value.getDetailId()))
                throw exception(PRO_FEEDBACK_PARAM_INVALID, "参数不属于当前任务的模板");
            if (submitted.containsKey(value.getDetailId())) throw exception(PRO_FEEDBACK_PARAM_INVALID, "参数明细重复");
            String text = value.getValue();
            if (text != null && text.length() > 100) throw exception(PRO_FEEDBACK_PARAM_INVALID, "参数值不能超过 100 字符");
            submitted.put(value.getDetailId(), text);
        }
        List<MesFeedbackParamSnapshot.Value> normalized = new ArrayList<>();
        for (var detail : template.getDetails()) {
            String value = submitted.get(detail.getId());
            if (requireAll && Boolean.TRUE.equals(detail.getRequired()) && StrUtil.isBlank(value))
                throw exception(PRO_FEEDBACK_PARAM_INVALID, "请填写必填参数:" + detail.getParamName());
            if (StrUtil.isNotBlank(value)) {
                try {
                    if (Objects.equals(detail.getParamType(), 1) || Objects.equals(detail.getParamType(), 2)) new java.math.BigDecimal(value.trim());
                    if (Objects.equals(detail.getParamType(), 4)) java.time.LocalTime.parse(value.trim());
                    if (Objects.equals(detail.getParamType(), 5)) java.time.LocalDate.parse(value.trim());
                } catch (RuntimeException ex) { throw exception(PRO_FEEDBACK_PARAM_INVALID, "参数格式不正确:" + detail.getParamName()); }
            }
            MesFeedbackParamSnapshot.Value item = new MesFeedbackParamSnapshot.Value();
            item.setDetailId(detail.getId()); item.setValue(value); normalized.add(item);
        }
        MesFeedbackParamSnapshot result = new MesFeedbackParamSnapshot();
        result.setTemplate(template); result.setValues(normalized);
        return JsonUtils.toJsonString(result);
    }
}