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
package cn.iocoder.yudao.module.mes.dal.mysql.pro.task;
 
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
 
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
 
/**
 * MES 生产任务 Mapper
 *
 * @author 超级管理员
 */
@Mapper
public interface MesProTaskMapper extends BaseMapperX<MesProTaskDO> {
 
    default PageResult<MesProTaskDO> selectPage(MesProTaskPageReqVO reqVO) {
        MPJLambdaWrapperX<MesProTaskDO> query = new MPJLambdaWrapperX<>();
        query.selectAll(MesProTaskDO.class);
        // 当需要按 checkFlag 过滤时,LEFT JOIN pro_route_process
        if (reqVO.getCheckFlag() != null) {
            query.leftJoin(MesProRouteProcessDO.class, on -> on
                    .eq(MesProRouteProcessDO::getRouteId, MesProTaskDO::getRouteId)
                    .eq(MesProRouteProcessDO::getProcessId, MesProTaskDO::getProcessId));
            query.eq(MesProRouteProcessDO::getCheckFlag, reqVO.getCheckFlag());
        }
        query.likeIfPresent(MesProTaskDO::getCode, reqVO.getCode())
                .likeIfPresent(MesProTaskDO::getName, reqVO.getName())
                .eqIfPresent(MesProTaskDO::getWorkOrderId, reqVO.getWorkOrderId())
                .eqIfPresent(MesProTaskDO::getRouteId, reqVO.getRouteId())
                .eqIfPresent(MesProTaskDO::getProcessId, reqVO.getProcessId())
                .eqIfPresent(MesProTaskDO::getWorkstationId, reqVO.getWorkstationId())
                .eqIfPresent(MesProTaskDO::getStatus, reqVO.getStatus())
                .inIfPresent(MesProTaskDO::getStatus, reqVO.getStatuses())
                .betweenIfPresent(MesProTaskDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(MesProTaskDO::getId);
        return selectPage(reqVO, query);
    }
 
    default PageResult<MesProTaskDO> selectPendingFeedbackPage(MesProTaskPageReqVO reqVO) {
        MPJLambdaWrapperX<MesProTaskDO> query = new MPJLambdaWrapperX<>();
        query.selectAll(MesProTaskDO.class);
        // 待报工台账:进行中的任务(排除已完成/已取消),且仍有待报工量
        query.in(MesProTaskDO::getStatus, MesProTaskStatusEnum.PREPARE.getStatus(),
                MesProTaskStatusEnum.PRODUCING.getStatus(), MesProTaskStatusEnum.PARTIAL_FINISHED.getStatus(),
                MesProTaskStatusEnum.PAUSED.getStatus());
        query.apply("(quantity - IFNULL(produced_quantity, 0)) > 0");
        query.likeIfPresent(MesProTaskDO::getCode, reqVO.getCode())
                .likeIfPresent(MesProTaskDO::getName, reqVO.getName())
                .eqIfPresent(MesProTaskDO::getWorkOrderId, reqVO.getWorkOrderId())
                .eqIfPresent(MesProTaskDO::getRouteId, reqVO.getRouteId())
                .eqIfPresent(MesProTaskDO::getProcessId, reqVO.getProcessId())
                .eqIfPresent(MesProTaskDO::getWorkstationId, reqVO.getWorkstationId())
                .betweenIfPresent(MesProTaskDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(MesProTaskDO::getId);
        return selectPage(reqVO, query);
    }
 
    /**
     * 按工作站统计待报工任务数,口径与 {@link #selectPendingFeedbackPage} 一致
     *
     * @return 每行包含 workstation_id、pending_count
     */
    default List<Map<String, Object>> selectPendingFeedbackCountByWorkstation() {
        return selectMaps(new QueryWrapper<MesProTaskDO>()
                .select("workstation_id", "COUNT(*) AS pending_count")
                .in("status", MesProTaskStatusEnum.PREPARE.getStatus(),
                        MesProTaskStatusEnum.PRODUCING.getStatus(), MesProTaskStatusEnum.PARTIAL_FINISHED.getStatus(),
                        MesProTaskStatusEnum.PAUSED.getStatus())
                .apply("(quantity - IFNULL(produced_quantity, 0)) > 0")
                .isNotNull("workstation_id")
                .groupBy("workstation_id"));
    }
 
    default List<MesProTaskDO> selectListByWorkOrderId(Long workOrderId) {
        return selectList(new LambdaQueryWrapperX<MesProTaskDO>()
                .eqIfPresent(MesProTaskDO::getWorkOrderId, workOrderId)
                .orderByDesc(MesProTaskDO::getId));
    }
 
    default MesProTaskDO selectByCode(String code) {
        return selectOne(MesProTaskDO::getCode, code);
    }
 
    default List<MesProTaskDO> selectListByWorkOrderIds(java.util.Collection<Long> workOrderIds) {
        return selectList(new LambdaQueryWrapperX<MesProTaskDO>()
                .in(MesProTaskDO::getWorkOrderId, workOrderIds)
                .orderByDesc(MesProTaskDO::getId));
    }
 
    /**
     * 班组报工工时统计:按班组聚合任务数与生产时长(duration 人日)
     *
     * @param startTime 生产开始时间下限
     * @param endTime   生产开始时间上限
     */
    default List<Map<String, Object>> selectWorkHourSummary(LocalDateTime startTime, LocalDateTime endTime) {
        return selectMaps(new QueryWrapper<MesProTaskDO>()
                .select("team_id", "team_name",
                        "COUNT(*) AS task_count",
                        "SUM(IFNULL(duration, 0)) AS total_duration")
                // 报工口径:排除草稿/已取消,仅统计实际进入生产的任务
                .notIn("status", MesProTaskStatusEnum.PREPARE.getStatus(), MesProTaskStatusEnum.CANCELED.getStatus())
                .ge(startTime != null, "start_time", startTime)
                .le(endTime != null, "start_time", endTime)
                .groupBy("team_id", "team_name"));
    }
 
    default void updateProducedQuantity(Long id,
                                        BigDecimal incrProducedQuantity,
                                        BigDecimal incrQualifyQuantity,
                                        BigDecimal incrUnqualifyQuantity) {
        update(null, new LambdaUpdateWrapper<MesProTaskDO>()
                .eq(MesProTaskDO::getId, id)
                .setSql("produced_quantity = IFNULL(produced_quantity, 0) + " + incrProducedQuantity)
                .setSql("qualify_quantity = IFNULL(qualify_quantity, 0) + " + incrQualifyQuantity)
                .setSql("unqualify_quantity = IFNULL(unqualify_quantity, 0) + " + incrUnqualifyQuantity)
                .setSql("status = CASE WHEN IFNULL(produced_quantity, 0) > 0 THEN "
                        + MesProTaskStatusEnum.PARTIAL_FINISHED.getStatus() + " ELSE "
                        + MesProTaskStatusEnum.PRODUCING.getStatus() + " END")
                .setSql("first_feedback_time = IFNULL(first_feedback_time, NOW())")
                .setSql("last_feedback_time = NOW()"));
    }
 
}