Переглянути джерело

```
refactor(check): 优化年度保养计划表和权限控制逻辑

- 年度保养计划表以保养标准为行来源,即使未执行任务也显示一行
- 保养负责人取值与任务生成逻辑保持一致,支持使用人、维修人、指定人、班组长类型
- 完善班组任务权限控制,区分超级管理员、管理层和普通用户可见范围
- 管理层角色可查看本部门及所有下级班组的保养任务
- 移除导出文件中的期限日期列,该字段由系统自动推算无需展示
- 新增GLC管理层角色枚举定义
```

dazhaxie 1 день тому
батько
коміт
429b757f5f

+ 4 - 0
platform-dao/src/main/java/com/platform/dao/enums/SysRoleCodeEnum.java

@@ -139,6 +139,10 @@ public enum SysRoleCodeEnum {
      * 班长(班组负责人,接收本班组未完成保养任务的邮件提醒)
      */
     BAN_ZHANG,
+    /**
+     * 管理层(可查看本部门及所有下级班组的保养任务)
+     */
+    GLC,
     ;
 
 }

+ 2 - 1
platform-dao/src/main/java/com/platform/dao/vo/export/check/ExportCheckJobVO.java

@@ -77,8 +77,9 @@ public class ExportCheckJobVO implements Serializable {
 
     /**
      * 标准工时
+     * 截至日期由系统按执行周期自动推算,保养标准中无对应录入项,导出不再展示该列
      */
-    @Excel(name = "期限日期", orderNum = "12")
+    //@Excel(name = "期限日期", orderNum = "12")
     private LocalDate endTime;
     /**
      * 实际工时

+ 45 - 26
platform-dao/src/main/resources/mapper/check/CheckJobMapper.xml

@@ -1134,44 +1134,63 @@
           and status = #{status}
     </update>
 
-    <!-- 年度保养计划表:按设备类别/设备名称/保养负责人聚合,
-         当年每月只要有已完成(status=3)的保养任务则该月打勾√,排除按天(period_type=1)的保养 -->
+    <!-- 年度保养计划表:以“保养标准(t_check_standard)”为行来源,排除按天(period_type=1)的保养,
+         即使该标准尚未执行任何任务也会显示一行(月份不打勾);
+         当年某设备每月只要有已完成(status=3)的保养任务则该月打勾√ -->
     <select id="selectAnnualPlan" parameterType="com.platform.dao.dto.check.CheckJobDTO"
             resultType="com.platform.dao.vo.query.check.CheckJobAnnualPlanVO">
         select
             sbtype.name as category,
             sbinfo.name as sbName,
-            coalesce(u.real_name, dept.name) as owner,
+            <!-- 保养负责人与任务生成逻辑保持一致:
+                 1-使用人取设备保管人(save_user),2-维修人取设备第一维修人(repair_user),
+                 3-指定取标准上已绑定的人(保存时=维修人),4-班组取部门 -->
+            case standard.check_user_type
+                when 1 then su_save.real_name
+                when 2 then su_repair.real_name
+                when 3 then coalesce(su.real_name, su_repair.real_name)
+                when 4 then sdept.name
+                else coalesce(su.real_name, sdept.name)
+            end as owner,
             count(distinct sbinfo.id) as sbNum,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 1 then '√' else '' end) as month1,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 2 then '√' else '' end) as month2,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 3 then '√' else '' end) as month3,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 4 then '√' else '' end) as month4,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 5 then '√' else '' end) as month5,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 6 then '√' else '' end) as month6,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 7 then '√' else '' end) as month7,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 8 then '√' else '' end) as month8,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 9 then '√' else '' end) as month9,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 10 then '√' else '' end) as month10,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 11 then '√' else '' end) as month11,
-            max(case when month(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = 12 then '√' else '' end) as month12
-        from t_check_job checkjob
-        inner join t_sb_info sbinfo on sbinfo.id = checkjob.sb_id
-        inner join t_check_standard standard on standard.id = checkjob.standard_id
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 1 then '√' else '' end) as month1,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 2 then '√' else '' end) as month2,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 3 then '√' else '' end) as month3,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 4 then '√' else '' end) as month4,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 5 then '√' else '' end) as month5,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 6 then '√' else '' end) as month6,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 7 then '√' else '' end) as month7,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 8 then '√' else '' end) as month8,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 9 then '√' else '' end) as month9,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 10 then '√' else '' end) as month10,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 11 then '√' else '' end) as month11,
+            max(case when month(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = 12 then '√' else '' end) as month12
+        from t_check_standard standard
+        inner join t_sb_info sbinfo on sbinfo.id = standard.sb_id
         left join t_sb_type sbtype on sbtype.id = sbinfo.type_id
-        left join t_sys_user u on checkjob.check_user_id = u.user_id
-        left join t_sys_dept dept on checkjob.check_dept_id = dept.dept_id
-        <where>
-            checkjob.status = 3
-            and standard.period_type != 1
+        left join t_sys_user su on standard.check_user_id = su.user_id
+        left join t_sys_dept sdept on standard.check_dept_id = sdept.dept_id
+        left join t_sys_user su_save on sbinfo.save_user = su_save.user_id
+        left join t_sys_user su_repair on sbinfo.repair_user = su_repair.user_id
+        left join t_check_job job on job.standard_id = standard.id
+            and job.status = 3
             <if test="searchYear != null">
-                and year(coalesce(checkjob.actual_end_time, checkjob.actual_start_time, checkjob.end_time)) = #{searchYear}
+                and year(coalesce(job.actual_end_time, job.actual_start_time, job.end_time)) = #{searchYear}
             </if>
+        <where>
+            standard.period_type != 1
             <if test="type != null">
-                and checkjob.type = #{type}
+                and standard.type = #{type}
             </if>
         </where>
-        group by sbtype.name, sbinfo.name, coalesce(u.real_name, dept.name)
+        group by sbtype.name, sbinfo.name,
+            case standard.check_user_type
+                when 1 then su_save.real_name
+                when 2 then su_repair.real_name
+                when 3 then coalesce(su.real_name, su_repair.real_name)
+                when 4 then sdept.name
+                else coalesce(su.real_name, sdept.name)
+            end
         order by sbtype.name asc, sbinfo.name asc
     </select>
 </mapper>

+ 52 - 12
platform-service/src/main/java/com/platform/service/check/impl/CheckJobServiceImpl.java

@@ -597,14 +597,9 @@ public class CheckJobServiceImpl extends BaseServiceImpl<CheckJobMapper, CheckJo
         }
 
         // 优化:统一处理用户权限逻辑,使用精确匹配避免安全漏洞
+        // 班组任务可见性:超级管理员看全部;管理员看本部门及所有下级班组;普通用户看本班组及上级链
         model.setCheckUserId(userInfo.getUserId());
-        String superUser = ConfigCache.getLabelByValue(SysConfigEnum.CHECK_JOB_SUPER_USER.name());
-        if (superUser != null && Arrays.asList(superUser.split(",")).contains(userInfo.getUsername())) {
-            model.setCheckUserId(null);
-        } else {
-            // 班组任务可见性:获取用户所属部门及所有上级部门ID,用于匹配班组任务的checkDeptId
-            fillCheckDeptIds(model, userInfo);
-        }
+        fillCheckDeptIds(model, userInfo);
 
         // 修复分页重复:先分页获取任务ID,再根据ID查询完整数据
         // 为排序字段添加表别名前缀,避免 JOIN 查询时列名歧义
@@ -660,14 +655,22 @@ public class CheckJobServiceImpl extends BaseServiceImpl<CheckJobMapper, CheckJo
     }
 
     /**
-     * 填充班组任务可见性所需的部门链:用户所属部门 + 所有上级部门ID。
-     * 查询任务时,任务的 check_dept_id 命中该链中任意部门,用户即可看到该班组任务,
-     * 因此选择上级部门时,其所有下级部门的人员也能看到并执行任务。
+     * 填充班组任务可见性所需的部门链。
+     * 规则:
+     * 1. 超级管理员(superAdmin=1 或在 CHECK_JOB_SUPER_USER 白名单):查看全部保养任务,不做执行人与部门限制;
+     * 2. 管理层角色(SysRoleCodeEnum.GLC):可见范围 = 本部门 + 所有上级部门 + 所有下级部门(含附属班组);
+     * 3. 普通用户:可见范围 = 本部门 + 所有上级部门(向上追溯),即只能看到本班组及上级指派的任务。
      *
      * @param model    查询条件
      * @param userInfo 当前用户
      */
     private void fillCheckDeptIds(CheckJobDTO model, UserInfo userInfo) {
+        // 超级管理员:清空执行人与部门限制,查看全部保养任务
+        if (isCheckJobSuperUser(userInfo)) {
+            model.setCheckUserId(null);
+            model.setCheckDeptIds(null);
+            return;
+        }
         try {
             SysUserDeptVO userDept = com.platform.dao.util.UserUtil.getUserDeptAllowNull(userInfo);
             if (userDept == null) {
@@ -677,17 +680,28 @@ public class CheckJobServiceImpl extends BaseServiceImpl<CheckJobMapper, CheckJo
             List<String> deptIds = new ArrayList<>();
             deptIds.add(userDept.getDeptId());
             log.info("fillCheckDeptIds: 用户 {} 所属部门 {}", userInfo.getUserId(), userDept.getDeptId());
+            com.platform.dao.mapper.upms.SysDeptRelationMapper deptRelationMapper =
+                    com.platform.common.util.SpringContextHolder.getBean(com.platform.dao.mapper.upms.SysDeptRelationMapper.class);
             // 获取所有上级部门(班组→项目部→分公司→集团)
             com.platform.dao.dto.upms.SysDeptDTO deptQuery = new com.platform.dao.dto.upms.SysDeptDTO();
             deptQuery.setDescendant(userDept.getDeptId());
-            com.platform.dao.mapper.upms.SysDeptRelationMapper deptRelationMapper =
-                    com.platform.common.util.SpringContextHolder.getBean(com.platform.dao.mapper.upms.SysDeptRelationMapper.class);
             List<SysDeptVO> parentDepts = deptRelationMapper.allParentList(deptQuery);
             if (!CollectionUtils.isEmpty(parentDepts)) {
                 for (SysDeptVO dept : parentDepts) {
                     deptIds.add(dept.getDeptId());
                 }
             }
+            // 管理层角色:向下展开,纳入本部门及其所有下级部门(含附属班组)的保养任务
+            if (isAdminIdentity(userInfo)) {
+                com.platform.dao.dto.upms.SysDeptDTO childQuery = new com.platform.dao.dto.upms.SysDeptDTO();
+                childQuery.setAncestor(userDept.getDeptId());
+                List<SysDeptVO> childDepts = deptRelationMapper.allChildList(childQuery);
+                if (!CollectionUtils.isEmpty(childDepts)) {
+                    for (SysDeptVO dept : childDepts) {
+                        deptIds.add(dept.getDeptId());
+                    }
+                }
+            }
             log.info("fillCheckDeptIds: 用户 {} 部门链 {}", userInfo.getUserId(), deptIds);
             model.setCheckDeptIds(deptIds);
         } catch (Exception e) {
@@ -696,6 +710,32 @@ public class CheckJobServiceImpl extends BaseServiceImpl<CheckJobMapper, CheckJo
     }
 
     /**
+     * 是否保养任务的超级管理员:可查看全部保养任务,不受执行人与部门限制。
+     * 命中条件:用户 superAdmin 标记为 1,或用户名在 CHECK_JOB_SUPER_USER 配置白名单中。
+     */
+    private boolean isCheckJobSuperUser(UserInfo userInfo) {
+        if (userInfo == null) {
+            return false;
+        }
+        if (userInfo.getSuperAdmin() != null && userInfo.getSuperAdmin() == 1) {
+            return true;
+        }
+        String superUser = ConfigCache.getLabelByValue(SysConfigEnum.CHECK_JOB_SUPER_USER.name());
+        return superUser != null && Arrays.asList(superUser.split(",")).contains(userInfo.getUsername());
+    }
+
+    /**
+     * 是否管理层角色(SysRoleCodeEnum.GLC),管理层可查看本部门及所有下级班组的保养任务。
+     */
+    private boolean isAdminIdentity(UserInfo userInfo) {
+        if (userInfo == null) {
+            return false;
+        }
+        List<String> roleCodes = userInfo.getRoleCodes();
+        return !CollectionUtils.isEmpty(roleCodes) && roleCodes.contains(SysRoleCodeEnum.GLC.name());
+    }
+
+    /**
      * 获取当日移动端现场任务:当日的任务:主要是现场人员的任务
      * <p>
      * 如果有sbId,则说明是查询某一台设备的任务,需要查询设备的显示使用人员账号