Quellcode durchsuchen

feat(check): 新增保养任务执行人更新功能并优化任务列表显示

- 在CheckJobMapper中新增updateJobExecutor方法,支持显式更新任务执行人字段
- 在CheckJobMapper.xml中添加对应的SQL更新语句,允许将执行人字段置空
- 在CheckJobServiceImpl中添加任务列表默认时间过滤逻辑,只展示今天及之前的任务
- 在CheckStandardServiceImpl中新增resolveStandardCheckUserId方法,解析保养标准执行人
- 优化保养标准修改逻辑,支持班组与具体执行人之间的切换和任务移交
- 添加部门结构调整SQL脚本,去除顶层HITCH部门并将日立能源提升为顶层部门
dazhaxie vor 1 Woche
Ursprung
Commit
a60fb96336

+ 123 - 0
db/去掉顶层部门HITCH.sql

@@ -0,0 +1,123 @@
+-- =====================================================================================
+-- 去掉最外层部门 HITCH,将「日立能源」提升为顶层部门
+-- 涉及表:t_sys_dept / t_sys_dept_relation / t_sb_info / t_sys_dept_manager
+-- 使用说明:
+--   1. 先执行「一、预检查」,确认结果符合预期(HITCH 下只有日立能源一个子部门、无用户直挂 HITCH);
+--   2. 再按顺序执行「二、变量准备」「三、结构修改」「四、修改后验证」;
+--   3. 建议在业务低峰期执行,并先备份 t_sys_dept、t_sys_dept_relation、t_sb_info 三张表。
+-- =====================================================================================
+
+-- -------------------------------------------------------------------------------------
+-- 一、预检查(只读)
+-- -------------------------------------------------------------------------------------
+-- 1.1 确认 HITCH 与日立能源的 id / 编码 / 性质 / 层级
+SELECT dept_id, name, dept_code, nature, rank, parent_id, del_flag
+FROM t_sys_dept
+WHERE name IN ('HITCH', '日立能源');
+
+-- 1.2 HITCH 的子部门列表(预期:只有日立能源一条)
+SELECT dept_id, name, dept_code
+FROM t_sys_dept
+WHERE parent_id = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0)
+  AND del_flag = 0;
+
+-- 1.3 是否有用户直接挂在 HITCH 下(预期:0;若大于 0 需先在界面把用户调到其他部门)
+SELECT COUNT(*) AS user_cnt_on_hitch
+FROM t_sys_user_dept
+WHERE dept_id = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0);
+
+-- 1.4 是否有设备记录引用 HITCH(脚本第三步会统一改挂到日立能源,此处仅确认影响行数)
+SELECT COUNT(*) AS sb_ref_cnt
+FROM t_sb_info
+WHERE use_area = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0)
+   OR use_company = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0)
+   OR use_project = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0)
+   OR use_group = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0)
+   OR use_dept = (SELECT dept_id FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0);
+
+-- -------------------------------------------------------------------------------------
+-- 二、变量准备
+-- -------------------------------------------------------------------------------------
+SELECT dept_id INTO @hitch FROM t_sys_dept WHERE name = 'HITCH' AND del_flag = 0 LIMIT 1;
+SELECT dept_id INTO @rl FROM t_sys_dept WHERE name = '日立能源' AND del_flag = 0 AND parent_id = @hitch LIMIT 1;
+SELECT dept_code INTO @old_code FROM t_sys_dept WHERE dept_id = @rl;
+
+-- 校验:日立能源子树内所有部门编码都必须以旧编码为前缀(预期:0;大于 0 说明历史编码脏,先人工处理)
+SELECT COUNT(*) AS bad_prefix_cnt
+FROM t_sys_dept d
+JOIN t_sys_dept_relation r ON r.descendant = d.dept_id
+WHERE r.ancestor = @rl
+  AND d.dept_code NOT LIKE CONCAT(@old_code, '%');
+
+-- 模仿后端 SysDeptServiceImpl.getCode 的规则,计算日立能源升顶后的新顶层编码(顶层最大编码末三位 +1)
+SELECT dept_code INTO @max_root FROM t_sys_dept WHERE parent_id = '0' ORDER BY dept_code DESC LIMIT 1;
+SET @new_code = IF(@max_root IS NULL, '001',
+                CONCAT(LEFT(@max_root, CHAR_LENGTH(@max_root) - 3),
+                       LPAD(SUBSTRING(@max_root, -3) + 1, 3, '0')));
+SELECT @hitch AS hitch_id, @rl AS rili_id, @old_code AS old_code, @new_code AS new_code;
+
+-- -------------------------------------------------------------------------------------
+-- 三、结构修改(建议整体作为一个事务执行)
+-- -------------------------------------------------------------------------------------
+START TRANSACTION;
+
+-- 3.1 重写日立能源整棵子树(含自身)的 dept_code:旧前缀替换为新前缀
+--     (dept_code 被设备/用户等查询以 like '编码%' 的方式做子树过滤,前缀链必须保持一致)
+UPDATE t_sys_dept
+SET dept_code = CONCAT(@new_code, SUBSTRING(dept_code, CHAR_LENGTH(@old_code) + 1)),
+    update_time = NOW()
+WHERE dept_id IN (SELECT descendant FROM t_sys_dept_relation WHERE ancestor = @rl);
+
+-- 3.2 日立能源升为顶层
+UPDATE t_sys_dept
+SET parent_id = '0', parent_name = NULL, rank = 1, update_time = NOW()
+WHERE dept_id = @rl;
+
+-- 3.3 子树其余部门层级整体上移一级(rank 值减 1)
+UPDATE t_sys_dept d
+JOIN t_sys_dept_relation r ON r.descendant = d.dept_id AND r.ancestor = @rl AND r.descendant <> @rl
+SET d.rank = d.rank - 1;
+
+-- 3.4 闭包表摘除 HITCH(含 HITCH 自关联行及其到所有后代的行),子树内部关系保留
+DELETE FROM t_sys_dept_relation WHERE ancestor = @hitch;
+
+-- 3.5 原引用 HITCH 的设备记录改挂到日立能源
+UPDATE t_sb_info
+SET use_area = IF(use_area = @hitch, @rl, use_area),
+    use_company = IF(use_company = @hitch, @rl, use_company),
+    use_project = IF(use_project = @hitch, @rl, use_project),
+    use_group = IF(use_group = @hitch, @rl, use_group),
+    use_dept = IF(use_dept = @hitch, @rl, use_dept)
+WHERE @hitch IN (use_area, use_company, use_project, use_group, use_dept);
+
+-- 3.6 清理 HITCH 的部门负责人关系,并逻辑删除 HITCH
+DELETE FROM t_sys_dept_manager WHERE dept_id = @hitch;
+UPDATE t_sys_dept SET del_flag = 1, update_time = NOW() WHERE dept_id = @hitch;
+
+COMMIT;
+
+-- -------------------------------------------------------------------------------------
+-- 四、修改后验证(只读)
+-- -------------------------------------------------------------------------------------
+-- 4.1 顶层部门列表(HITCH 应消失,日立能源应在列)
+SELECT dept_id, name, dept_code, nature, rank FROM t_sys_dept WHERE parent_id = '0' AND del_flag = 0;
+
+-- 4.2 日立能源子树编码/层级应连续(编码以新前缀开头,rank 从 1 递增)
+SELECT d.dept_id, d.name, d.dept_code, d.rank, d.parent_id
+FROM t_sys_dept d
+JOIN t_sys_dept_relation r ON r.descendant = d.dept_id
+WHERE r.ancestor = @rl
+ORDER BY d.dept_code;
+
+-- 4.3 闭包表中不应再存在 HITCH 的任何关系行(预期:0)
+SELECT COUNT(*) AS hitch_relation_cnt FROM t_sys_dept_relation WHERE ancestor = @hitch OR descendant = @hitch;
+
+-- -------------------------------------------------------------------------------------
+-- 五、可选:部门性质继承(按需人工判断后执行)
+-- -------------------------------------------------------------------------------------
+-- 部门层级追溯(projectId/companyId、调拨范围等)是按 nature 向上找的。
+-- HITCH 被移除后,若它的 nature(如 JITUAN/FEN_GONG_SI)在链上再无其他部门承担,
+-- 相关追溯会查不到。如确认需要,可让日立能源继承 HITCH 的性质
+-- (前提:日立能源自身的 nature 不再需要保留,执行前先核对 1.1 的结果):
+-- UPDATE t_sys_dept SET nature = (SELECT t.nature FROM (SELECT nature FROM t_sys_dept WHERE dept_id = @hitch) t)
+-- WHERE dept_id = @rl;

+ 16 - 0
platform-dao/src/main/java/com/platform/dao/mapper/check/CheckJobMapper.java

@@ -83,4 +83,20 @@ public interface CheckJobMapper extends MyMapper<CheckJob> {
      * @return 未完成的班组保养任务列表
      */
     List<CheckJobVO> selectUnfinishedTeamJobs();
+
+    /**
+     * 显式更新指定标准下、指定状态任务的执行人字段(check_user_id / check_dept_id)。
+     * 与选择性更新不同,此方法会把传入为 null 的字段真正置空,
+     * 用于执行人方式在“班组”与“具体人”之间切换时彻底移交任务归属。
+     *
+     * @param standardId  保养标准ID
+     * @param status      任务状态(仅更新该状态的任务,通常为未执行)
+     * @param checkUserId 执行人用户ID,可为null(班组模式下置空)
+     * @param checkDeptId 班组部门ID,可为null(具体执行人模式下置空)
+     * @return 更新条数
+     */
+    int updateJobExecutor(@Param("standardId") String standardId,
+                          @Param("status") Integer status,
+                          @Param("checkUserId") String checkUserId,
+                          @Param("checkDeptId") String checkDeptId);
 }

+ 10 - 0
platform-dao/src/main/resources/mapper/check/CheckJobMapper.xml

@@ -1089,4 +1089,14 @@
         and checkjob.status != 3
         order by checkjob.check_dept_id asc, sbinfo.no asc
     </select>
+
+    <!-- 显式更新指定标准下某状态任务的执行人字段,允许将 check_user_id / check_dept_id 置空,
+         用于执行人方式在“班组”与“具体人”之间切换时彻底移交任务归属 -->
+    <update id="updateJobExecutor">
+        update t_check_job
+        set check_user_id = #{checkUserId},
+            check_dept_id = #{checkDeptId}
+        where standard_id = #{standardId}
+          and status = #{status}
+    </update>
 </mapper>

+ 10 - 0
platform-service/src/main/java/com/platform/service/check/impl/CheckJobServiceImpl.java

@@ -586,6 +586,16 @@ public class CheckJobServiceImpl extends BaseServiceImpl<CheckJobMapper, CheckJo
             model.setSearchEndTime(DateUtils.getLastDayOfThisMonth());
         }
 
+        // 默认进入保养任务列表时,只展示“今天及之前”的任务:
+        // 按周期(如1天)提前生成的未来任务(例如明天的任务)在其执行日期到达前不展示,等到当天再显示。
+        // 仅当未显式指定结束日期(结束日期/本周/本月等)、且不是查看已完成记录(status=3 或 record=1)时才生效,
+        // 避免影响已完成记录的查询(其按 actual_start_time 过滤,存在为空被误排除的风险)。
+        boolean queryFinishedRecord = CheckJobStatusEnum.FINISHED.getValue().equals(model.getStatus())
+                || (model.getRecord() != null && model.getRecord() == 1);
+        if (!queryFinishedRecord && model.getSearchEndTime() == null && model.getStartTimeEnd() == null) {
+            model.setSearchEndTime(DateUtils.getTodayEndTime());
+        }
+
         // 优化:统一处理用户权限逻辑,使用精确匹配避免安全漏洞
         model.setCheckUserId(userInfo.getUserId());
         String superUser = ConfigCache.getLabelByValue(SysConfigEnum.CHECK_JOB_SUPER_USER.name());

+ 44 - 16
platform-service/src/main/java/com/platform/service/check/impl/CheckStandardServiceImpl.java

@@ -374,6 +374,36 @@ public class CheckStandardServiceImpl extends BaseServiceImpl<CheckStandardMappe
         return String.format("%05d", no);
     }
 
+    /**
+     * 解析保养标准在“非班组”执行人方式下应绑定的具体执行人ID。
+     * 与任务生成(generate)保持一致:使用人取设备保管人,维修人/指定取设备第一维修人;
+     * 若标准已显式指定执行人(如“指定”方式),优先使用。
+     *
+     * @param model 保养标准DTO
+     * @return 执行人用户ID,可能为null(设备未绑定对应人员时)
+     */
+    private String resolveStandardCheckUserId(CheckStandardDTO model) {
+        if (StringUtils.isNotBlank(model.getCheckUserId())) {
+            return model.getCheckUserId();
+        }
+        if (StringUtils.isBlank(model.getSbId())) {
+            return null;
+        }
+        SbInfo sbInfo = sbInfoMapper.selectByPrimaryKey(model.getSbId());
+        if (sbInfo == null) {
+            return null;
+        }
+        Integer checkUserType = model.getCheckUserType();
+        if (CheckUserTypeEnum.USE_USER.getValue().equals(checkUserType)) {
+            return sbInfo.getSaveUser();
+        }
+        if (CheckUserTypeEnum.REPAIR_USER.getValue().equals(checkUserType)
+                || CheckUserTypeEnum.ZHIDING.getValue().equals(checkUserType)) {
+            return sbInfo.getRepairUser();
+        }
+        return null;
+    }
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void modModelByDTO(CheckStandardDTO model) {
@@ -439,25 +469,23 @@ public class CheckStandardServiceImpl extends BaseServiceImpl<CheckStandardMappe
             boolean deptIdChanged = !java.util.Objects.equals(model.getCheckDeptId(), originalStandard.getCheckDeptId());
             
             if (userTypeChanged || userIdChanged || deptIdChanged) {
-                Weekend<CheckJob> jobWeekend = new Weekend<>(CheckJob.class);
-                jobWeekend.weekendCriteria()
-                        .andEqualTo(CheckJob::getStandardId, model.getId())
-                        .andEqualTo(CheckJob::getStatus, CheckJobStatusEnum.NOT_EXECUTE.getValue());
-                
-                CheckJob updateJob = new CheckJob();
-                
+                String newCheckUserId;
+                String newCheckDeptId;
                 if (CheckUserTypeEnum.TEAM.getValue().equals(model.getCheckUserType())) {
-                    // 班组模式:更新 check_dept_id
-                    updateJob.setCheckDeptId(model.getCheckDeptId());
-                    log.info("保养标准 {} 切换到班组模式,更新 check_dept_id={}", model.getId(), model.getCheckDeptId());
+                    // 切换到班组:绑定班组ID,并清空原具体执行人,将任务彻底移交给班组
+                    newCheckDeptId = model.getCheckDeptId();
+                    newCheckUserId = null;
                 } else {
-                    // 非班组模式:更新 check_user_id
-                    updateJob.setCheckUserId(model.getCheckUserId());
-                    log.info("保养标准 {} 切换到非班组模式,更新 check_user_id={}", model.getId(), model.getCheckUserId());
+                    // 切换到具体执行人:解析执行人并清空班组ID,将任务彻底移交给个人
+                    newCheckDeptId = null;
+                    newCheckUserId = resolveStandardCheckUserId(model);
                 }
-                
-                int updated = checkJobMapper.updateByExampleSelective(updateJob, jobWeekend);
-                log.info("保养标准 {} 修改执行人信息,已更新 {} 条未执行任务", model.getId(), updated);
+
+                // 使用显式更新(可将对应字段置空),仅同步“未执行”任务;已接收(执行中)的任务不变更
+                int updated = checkJobMapper.updateJobExecutor(model.getId(),
+                        CheckJobStatusEnum.NOT_EXECUTE.getValue(), newCheckUserId, newCheckDeptId);
+                log.info("保养标准 {} 修改执行人信息,已更新 {} 条未执行任务,checkUserId={}, checkDeptId={}",
+                        model.getId(), updated, newCheckUserId, newCheckDeptId);
             }
         }