ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -63,6 +63,12 @@ @Value("${spring.profiles.active}") private String active; /** * 管理员用户ID列表(配置项 isAdmin)。管理员不受「用户-部门关系表」限制,直接看本机构全部科室/病区。 */ @Value("${isAdmin:1}") private List<Long> isAdmin; // @Value("${wx_appid}") // private String wxAppid; // @@ -240,23 +246,43 @@ ajax.put("user", user); ajax.put("roles", roles); ajax.put("permissions", permissions); List<SysDept> sysDeptKSs = null; List<SysDept> sysDeptBQs = null; // 科室/病区下拉的数据源: // · 管理员(账号 admin,或命中配置 isAdmin 的用户ID):直接查 sys_dept 取本机构全部科室/病区, // 不再关联 sys_user_dept,也不按院区过滤——管理员天然拥有全部科室权限; // · 普通用户:仍然按「用户-部门关系表」只返回自己名下的科室/病区(保持原逻辑)。 SysUserDept sysUserDept = new SysUserDept(); sysUserDept.setUserId(user.getUserId()); sysUserDept.setDeptType("1"); sysUserDept.setOrgid(user.getOrgid()); sysUserDept.setCampusid(user.getCampusid()); sysDeptKSs = sysDeptService.selectLeafSysDeptListBySysUserDept(sysUserDept); if (!isAdminUser(user)) { sysUserDept.setUserId(user.getUserId()); sysUserDept.setCampusid(user.getCampusid()); } sysUserDept.setDeptType("1"); List<SysDept> sysDeptKSs = sysDeptService.selectLeafSysDeptListBySysUserDept(sysUserDept); ajax.put("belongDepts", sysDeptKSs); sysUserDept.setDeptType("2"); sysDeptBQs = sysDeptService.selectLeafSysDeptListBySysUserDept(sysUserDept); List<SysDept> sysDeptBQs = sysDeptService.selectLeafSysDeptListBySysUserDept(sysUserDept); ajax.put("belongWards", sysDeptBQs); return ajax; } /** * 是否管理员:账号名为 admin,或用户ID命中配置项 isAdmin。 * <p> * 管理员取科室/病区时不走 sys_user_dept(HIS 采集明确排除 admin,该表里管理员没有数据), * 否则会出现「登录成功但科室/病区下拉为空」。 */ private boolean isAdminUser(SysUser user) { if (user == null) { return false; } if ("admin".equalsIgnoreCase(user.getUserName())) { return true; } return user.getUserId() != null && isAdmin != null && isAdmin.contains(user.getUserId()); } /** * 获取路由信息 * * @return 路由信息 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -334,6 +334,10 @@ public List<SysDept> selectLeafSysDeptListBySysUserDept(SysUserDept sysUserDept){ List<SysDept> list = deptMapper.selectSysDeptListBySysUserDept(sysUserDept); // userId 为空 = 管理员取本机构全量科室/病区:要「全部」,不能再按叶子节点过滤掉父级部门 if (sysUserDept != null && sysUserDept.getUserId() == null) { return list == null ? new ArrayList<>() : list; } if(CollectionUtils.isNotEmpty(list)){ list = TreeUtils.getLeafDepts(list); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -146,7 +146,10 @@ deptIds.add(sysDept.getDeptId()); } SysUserDept sysUserDept = new SysUserDept(); sysUserDept.setUserId(sysUser.getUserId()); // 管理员:不按用户过滤(sys_user_dept 里没有 admin 的数据),直接取本机构全部科室/病区 if (!isAdminUser(sysUser)) { sysUserDept.setUserId(sysUser.getUserId()); } sysUserDept.setDeptType(sysUser.getSearchscope()); sysUserDept.setOrgid(sysUser.getOrgid()); List<SysUserDept> sysUserDeptKSs = null; @@ -201,7 +204,7 @@ if (sysUser.getUserType().equals("患者") && StringUtils.isNotEmpty(split[3]) && !split[3].equals("null") && !sysUser.getUserType().equals(split[3].trim())) throw new BaseException("当前用户类型与登录用户类型不一致"); boolean isAdmin = StringUtils.isNotEmpty(split[0]) && "admin".equals(split[0]); boolean isAdmin = isAdminUser(sysUser); IUserExtInfoService userExtInfoService = SpringUtils.getBean(IUserExtInfoService.class); Executor executor = SpringUtils.getBean("threadPoolTaskExecutor"); @@ -220,7 +223,7 @@ // 等待机构信息 Map<String, String> userOrgInfo = new HashMap<>(); try { userOrgInfo = orgInfoFuture.get(5, TimeUnit.SECONDS); userOrgInfo = orgInfoFuture.get(50, TimeUnit.SECONDS); } catch (Exception e) { log.warn("获取用户机构信息超时或异常", e); } @@ -258,8 +261,8 @@ CompletableFuture<List<SysDept>> ksFuture = CompletableFuture.supplyAsync(() -> selectLeafSysDeptForAdmin(deptKS), executor); CompletableFuture<List<SysDept>> bqFuture = CompletableFuture.supplyAsync(() -> selectLeafSysDeptForAdmin(deptBQ), executor); try { sysUserDeptKSs = distinctByDeptCode(DtoConversionUtils.sourceToTarget(ksFuture.get(5, TimeUnit.SECONDS), SysUserDept.class)); sysUserDeptBQs = distinctByDeptCode(DtoConversionUtils.sourceToTarget(bqFuture.get(5, TimeUnit.SECONDS), SysUserDept.class)); sysUserDeptKSs = distinctByDeptCode(DtoConversionUtils.sourceToTarget(ksFuture.get(50, TimeUnit.SECONDS), SysUserDept.class)); sysUserDeptBQs = distinctByDeptCode(DtoConversionUtils.sourceToTarget(bqFuture.get(50, TimeUnit.SECONDS), SysUserDept.class)); } catch (Exception e) { log.warn("获取admin科室/病区信息超时或异常", e); } @@ -358,6 +361,23 @@ log.warn("获取满意度分类失败,已降级为空结果(不影响登录)。orgid={}", orgid, e); return Collections.emptyMap(); } } /** * 是否管理员:账号名为 admin,或用户ID命中配置项 isAdmin。 * <p> * 管理员取科室/病区时不按 sys_user_dept 过滤——HIS 采集写该表时明确排除了 admin * (CollectHISMapper 的 yhyksxx/yhybfxx 都有 {@code ud.user_id != 'admin'}), * 走关联查询会得到空列表,表现为「登录成功但创建任务时选不到科室病区」。 */ private boolean isAdminUser(SysUser sysUser) { if (sysUser == null) { return false; } if ("admin".equalsIgnoreCase(sysUser.getUserName())) { return true; } return sysUser.getUserId() != null && isAdmin != null && isAdmin.contains(sysUser.getUserId()); } /** @@ -1022,8 +1042,11 @@ public List<SysUserDept> selectLeafSysDeptList(SysUserDept sysUserDept){ List<SysDept> list = sysDeptMapper.selectSysDeptListBySysUserDept(sysUserDept); if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(list)){ list = TreeUtils.getLeafDepts(list); // userId 为空 = 管理员取本机构全量:要「所有科室病区」,不能再按叶子节点过滤 if (sysUserDept == null || sysUserDept.getUserId() != null) { if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(list)){ list = TreeUtils.getLeafDepts(list); } } List<SysUserDept> list1 = DtoConversionUtils.sourceToTarget(list, SysUserDept.class); return list1; @@ -1031,11 +1054,9 @@ public List<SysDept> selectLeafSysDeptForAdmin(SysDept sysDept){ SysUserDept sysUserDept = DtoConversionUtils.sourceToTarget(sysDept, SysUserDept.class); List<SysDept> list = sysDeptMapper.selectSysDeptListBySysUserDept(sysUserDept); if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(list)){ list = TreeUtils.getLeafDepts(list); } return list; // 管理员分支:sysUserDept 不带 userId,mapper 会直接查 sys_dept(不关联 sys_user_dept), // 返回本机构全部科室/病区;这里不再做叶子过滤,否则「所有科室病区」会被砍掉父级部门。 return sysDeptMapper.selectSysDeptListBySysUserDept(sysUserDept); } /** ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -283,17 +283,36 @@ where dept_id = #{deptId} </delete> <!-- 查询科室/病区: · userId 有值(普通用户 / 用户编辑页:查某个用户名下的部门)→ 关联 sys_user_dept; · userId 为空(管理员:看本机构全部科室/病区)→ 只查 sys_dept,不关联关系表。 为什么要分支:HIS 采集写 sys_user_dept 时明确排除了 admin(CollectHISMapper 的 yhyksxx/yhybfxx 都有 ud.user_id != 'admin'),管理员在关系表里没有数据,走 inner join 会得到空列表,表现就是「登录成功但创建任务时选不到科室病区」。 另外不做院区过滤(管理员跨院区),院区隔离只对普通用户生效。 --> <select id="selectSysDeptListBySysUserDept" parameterType="com.ruoyi.common.core.domain.entity.SysUserDept" resultMap="SysDeptResult"> <include refid="selectDeptVo"/> inner join sys_user_dept ud on d.dept_code = ud.dept_code where 1=1 and d.del_flag = 0 and ud.del_flag = 0 <if test="orgid != null">and d.orgid = #{orgid} and ud.orgid = #{orgid}</if> <if test="campusid != null">and d.campusid = #{campusid}</if> <if test="userId != null">and ud.user_id = #{userId}</if> <if test="deptType != null and deptType != ''">and d.dept_type = #{deptType}</if> <choose> <when test="userId != null"> <include refid="selectDeptVo"/> inner join sys_user_dept ud on d.dept_code = ud.dept_code where 1=1 and d.del_flag = 0 and ud.del_flag = 0 <if test="orgid != null">and d.orgid = #{orgid} and ud.orgid = #{orgid}</if> <if test="campusid != null">and d.campusid = #{campusid}</if> <if test="deptType != null and deptType != ''">and d.dept_type = #{deptType}</if> and ud.user_id = #{userId} </when> <otherwise> <include refid="selectDeptVo"/> where d.del_flag = 0 <if test="orgid != null">and d.orgid = #{orgid}</if> <if test="deptType != null and deptType != ''">and d.dept_type = #{deptType}</if> </otherwise> </choose> </select> </mapper> ruoyi-task/src/main/resources/mapper/task/ServiceSubtaskMapper.xml
@@ -373,16 +373,34 @@ <sql id="filterLeaveDimAnd"> /* f-v3 */ <if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0"> AND leavehospitaldistrictcode IN AND ( leavehospitaldistrictcode IN <foreach collection="leavehospitaldistrictcodes" item="lvWardCodeItem" open="(" separator="," close=")"> #{lvWardCodeItem} </foreach> <!-- 延续护理任务(service_type='99')可以在患者还没出院时生成: 这类记录只有「在院维度」(hospitaldistrictcode / deptcode),出院维度是 NULL。 NULL 不匹配任何 IN,任务会「提示生成成功、列表里却查不到」, 所以出院维度为空时用同一套编码体系的在院维度兜底。 --> OR (service_type = '99' AND (leavehospitaldistrictcode IS NULL OR leavehospitaldistrictcode = '') AND hospitaldistrictcode IN <foreach collection="leavehospitaldistrictcodes" item="lvWardCodeItem" open="(" separator="," close=")"> #{lvWardCodeItem} </foreach>) ) </if> <if test="leaveldeptcodes != null and leaveldeptcodes.size() > 0"> AND leaveldeptcode IN AND ( leaveldeptcode IN <foreach collection="leaveldeptcodes" item="lvDeptCodeItem" open="(" separator="," close=")"> #{lvDeptCodeItem} </foreach> OR (service_type = '99' AND (leaveldeptcode IS NULL OR leaveldeptcode = '') AND deptcode IN <foreach collection="leaveldeptcodes" item="lvDeptCodeItem" open="(" separator="," close=")"> #{lvDeptCodeItem} </foreach>) ) </if> </sql> @@ -423,20 +441,38 @@ or (leaveldeptcodes != null and leaveldeptcodes.size() > 0)"> AND ( <if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0"> ( leavehospitaldistrictcode IN <foreach collection="leavehospitaldistrictcodes" item="lvWardCodeItem" open="(" separator="," close=")"> #{lvWardCodeItem} </foreach> <!-- 延续护理任务(service_type='99')可以在患者还没出院时生成: 这类记录只有「在院维度」(hospitaldistrictcode / deptcode),出院维度是 NULL。 NULL 不匹配任何 IN,任务会「提示生成成功、列表里却查不到」, 所以出院维度为空时用同一套编码体系的在院维度兜底。 --> OR (service_type = '99' AND (leavehospitaldistrictcode IS NULL OR leavehospitaldistrictcode = '') AND hospitaldistrictcode IN <foreach collection="leavehospitaldistrictcodes" item="lvWardCodeItem" open="(" separator="," close=")"> #{lvWardCodeItem} </foreach>) ) </if> <if test="(leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0) and (leaveldeptcodes != null and leaveldeptcodes.size() > 0)"> OR </if> <if test="leaveldeptcodes != null and leaveldeptcodes.size() > 0"> ( leaveldeptcode IN <foreach collection="leaveldeptcodes" item="lvDeptCodeItem" open="(" separator="," close=")"> #{lvDeptCodeItem} </foreach> OR (service_type = '99' AND (leaveldeptcode IS NULL OR leaveldeptcode = '') AND deptcode IN <foreach collection="leaveldeptcodes" item="lvDeptCodeItem" open="(" separator="," close=")"> #{lvDeptCodeItem} </foreach>) ) </if> ) </if>