From 227fb9760a64b8f12c8a4a2c481da3ce88f35173 Mon Sep 17 00:00:00 2001 From: zhuibobo Date: Tue, 7 Jul 2026 11:09:42 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=81=E7=A7=BB=E4=B8=80=E6=9C=9F=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../014-初始化角色.sql | 11 ++++ .../service/IEfcodeVirtualUnitService.java | 12 ++++ .../impl/EfcodeVirtualUnitServiceImpl.java | 59 +++++++++++++++++++ .../EfcodeVirtualUnitController.java | 14 +++++ .../src/api/system/role/index.ts | 4 +- .../src/api/system/role/types.ts | 2 + .../views/system/role/index-dept-separate.vue | 2 +- .../src/views/system/role/index.vue | 29 ++++++++- 8 files changed, 128 insertions(+), 5 deletions(-) diff --git a/script/sql/zfjd-refactoring-v1/014-初始化角色.sql b/script/sql/zfjd-refactoring-v1/014-初始化角色.sql index a141018b..ae918a2c 100644 --- a/script/sql/zfjd-refactoring-v1/014-初始化角色.sql +++ b/script/sql/zfjd-refactoring-v1/014-初始化角色.sql @@ -1,3 +1,14 @@ +-- 清空一期没有无效的角色 +delete sys_role where role_id not in (177 +194 +206 +209 +211 +212 +213 +214 +215); + INSERT INTO sys_role (role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark, tenant_code, user_id, dept_id, sass_id, role_code, is_role_sys) VALUES (1000, '000000', '查看全部业务数据角色', 'ViewAllDataRole', 1, '1', 1, 1, '0', '0', null, 0, '2025-01-10 15:08:12', 0, '2025-01-10 15:10:18', 'roleKey不可修改', null, '1', null, null, null, '1'); INSERT INTO sys_role (role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark, tenant_code, user_id, dept_id, sass_id, role_code, is_role_sys) diff --git a/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java b/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java index 4e180438..b7a8e810 100644 --- a/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java +++ b/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java @@ -2,6 +2,7 @@ package com.zdxt.enforcementcode.service; import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; import com.zdxt.enforcementcode.domain.vo.UnitUserVo; +import com.zdxt.enforcementcode.domain.vo.VirtualUnitDeptTreeVo; import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo; import com.zdxt.enforcementcode.domain.bo.UnitUserBo; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -140,4 +141,15 @@ public interface IEfcodeVirtualUnitService { * @param userIds 用户ID数组 */ void deleteUsers(Long[] userIds); + + /** + * 构建角色数据权限使用的虚拟单位部门树 + *

+ * 树节点ID使用 vir_id 展示层级,节点携带 sysDeptId; + * checkedKeys 为角色已保存的 sys_dept_id 反查得到的 vir_id 列表。 + * + * @param roleId 角色ID + * @return 虚拟单位部门树选择数据 + */ + VirtualUnitDeptTreeVo buildRoleDeptTree(Long roleId); } diff --git a/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java b/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java index 6957ec8b..1781c39b 100644 --- a/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java +++ b/zdxt-modules/zdxt-enforcement-code-common/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java @@ -11,6 +11,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.TreeNodeConfig; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -18,6 +21,7 @@ import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo; import com.zdxt.enforcementcode.domain.bo.UnitUserBo; import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; import com.zdxt.enforcementcode.domain.vo.UnitUserVo; +import com.zdxt.enforcementcode.domain.vo.VirtualUnitDeptTreeVo; import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit; import com.zdxt.enforcementcode.mapper.EfcodeVirtualUnitMapper; import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService; @@ -25,6 +29,7 @@ import org.dromara.system.domain.SysDept; import org.dromara.system.domain.SysUser; import org.dromara.system.mapper.SysDeptMapper; import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysDeptService; import com.zdxt.enforcementcode.domain.vo.SrzDeptVo; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -46,6 +51,7 @@ public class EfcodeVirtualUnitServiceImpl implements IEfcodeVirtualUnitService { private final SysDeptMapper sysDeptMapper; private final SrzDeptMapper srzDeptMapper; private final SysUserMapper sysUserMapper; + private final ISysDeptService sysDeptService; /** * 查询虚拟单位树 @@ -376,4 +382,57 @@ public class EfcodeVirtualUnitServiceImpl implements IEfcodeVirtualUnitService { } sysUserMapper.deleteByIds(List.of(userIds)); } + + /** + * 构建角色数据权限使用的虚拟单位部门树 + *

+ * 树节点ID使用 vir_id 展示层级,节点携带 sysDeptId; + * checkedKeys 为角色已保存的 sys_dept_id 反查得到的 vir_id 列表。 + */ + @Override + public VirtualUnitDeptTreeVo buildRoleDeptTree(Long roleId) { + List allUnits = queryTreeList(); + + // 收集全部 virId,并构建 sysDeptId -> virId 映射(用于反查勾选项) + Set allVirIds = new HashSet<>(); + Map sysDeptIdToVirId = new HashMap<>(); + for (EfcodeVirtualUnitVo u : allUnits) { + allVirIds.add(u.getVirId()); + if (StringUtils.isNotBlank(u.getSysDeptId())) { + sysDeptIdToVirId.putIfAbsent(u.getSysDeptId(), u.getVirId()); + } + } + + // 计算根 parentId 集合:parentId 为空或不在所有 virId 中的节点视为根 + Set rootParentIds = new LinkedHashSet<>(); + for (EfcodeVirtualUnitVo u : allUnits) { + String pid = u.getVirParentId(); + if (StringUtils.isBlank(pid) || !allVirIds.contains(pid)) { + rootParentIds.add(StringUtils.isBlank(pid) ? "0" : pid); + } + } + + // 构建树:节点id=virId,label=virName,携带 sysDeptId + TreeNodeConfig config = new TreeNodeConfig().setNameKey("label"); + List> depts = new ArrayList<>(); + for (String rootPid : rootParentIds) { + depts.addAll(TreeUtil.build(allUnits, rootPid, config, (u, tree) -> { + tree.setId(u.getVirId()); + tree.setParentId(StringUtils.isBlank(u.getVirParentId()) ? "0" : u.getVirParentId()); + tree.setName(u.getVirName()); + tree.setWeight(u.getCustOrderNum() != null ? u.getCustOrderNum() : u.getOrderNum()); + tree.putExtra("sysDeptId", u.getSysDeptId()); + })); + } + + // checkedKeys:角色已保存的 sys_dept_id 反查为 vir_id + List deptSysIds = sysDeptService.selectDeptListByRoleId(roleId); + List checkedKeys = deptSysIds.stream() + .map(sysDeptIdToVirId::get) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + return new VirtualUnitDeptTreeVo(checkedKeys, depts); + } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java index d98bdba5..dd6621f4 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java @@ -19,6 +19,7 @@ import org.dromara.common.log.enums.BusinessType; import org.dromara.common.excel.utils.ExcelUtil; import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; import com.zdxt.enforcementcode.domain.vo.UnitUserVo; +import com.zdxt.enforcementcode.domain.vo.VirtualUnitDeptTreeVo; import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo; import com.zdxt.enforcementcode.domain.bo.UnitUserBo; import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService; @@ -66,6 +67,19 @@ public class EfcodeVirtualUnitController extends BaseController { return R.ok(efcodeVirtualUnitService.queryBusinessTreeList()); } + /** + * 获取角色数据权限使用的虚拟单位部门树 + *

+ * 树节点id使用 vir_id 展示层级,节点携带 sysDeptId; + * checkedKeys 为角色已保存的 sys_dept_id 反查得到的 vir_id 列表。 + * + * @param roleId 角色ID + */ + @GetMapping("/roleDeptTree/{roleId}") + public R roleDeptTree(@NotNull(message = "角色ID不能为空") @PathVariable Long roleId) { + return R.ok(efcodeVirtualUnitService.buildRoleDeptTree(roleId)); + } + /** * 根据虚拟单位分页查询关联人员列表 * diff --git a/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/index.ts b/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/index.ts index fb0fcabc..f65a9c21 100644 --- a/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/index.ts +++ b/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/index.ts @@ -146,10 +146,10 @@ export const authUserSelectAll = (data: any) => { params: data }); }; -// 根据角色ID查询部门树结构 +// 根据角色ID查询虚拟单位部门树结构(树节点id=vir_id,携带 sysDeptId;checkedKeys 为 vir_id) export const deptTreeSelect = (roleId: string | number): AxiosPromise => { return request({ - url: '/system/role/deptTree/' + roleId, + url: '/enforcementcode/virtualUnit/roleDeptTree/' + roleId, method: 'get' }); }; diff --git a/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/types.ts b/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/types.ts index ffb1de6b..a1e67dc8 100644 --- a/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/types.ts +++ b/zdxt-web-client/zdxt-admin-plus-ui/src/api/system/role/types.ts @@ -6,6 +6,8 @@ export interface DeptTreeOption { label: string; parentId: string; weight: number; + /** 虚拟单位对应的部门ID,用于绑定角色-部门关系时保存 */ + sysDeptId?: string; children?: DeptTreeOption[]; } diff --git a/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index-dept-separate.vue b/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index-dept-separate.vue index e628a96d..ec0ff1df 100644 --- a/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index-dept-separate.vue +++ b/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index-dept-separate.vue @@ -176,7 +176,7 @@ - + diff --git a/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index.vue b/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index.vue index 05487dd6..69f75e48 100644 --- a/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index.vue +++ b/zdxt-web-client/zdxt-admin-plus-ui/src/views/system/role/index.vue @@ -395,12 +395,33 @@ const getRoleMenuTreeselect = (roleId: string | number) => { return res.data; }); }; -/** 根据角色ID查询部门树结构 */ +/** 根据角色ID查询部门树结构(虚拟单位树:节点id=vir_id,携带 sysDeptId) */ const getRoleDeptTreeSelect = async (roleId: string | number) => { const res = await deptTreeSelect(roleId); deptOptions.value = res.data.depts; + // 构建 vir_id -> sys_dept_id 映射,供提交时绑定角色-部门关系使用 + buildVirIdToSysDeptIdMap(res.data.depts); return res.data; }; + +/** vir_id -> sys_dept_id 映射表 */ +const virIdToSysDeptId = new Map(); + +/** 遍历虚拟单位树构建 vir_id -> sys_dept_id 映射 */ +const buildVirIdToSysDeptIdMap = (nodes: DeptTreeOption[]) => { + virIdToSysDeptId.clear(); + const traverse = (list: DeptTreeOption[]) => { + for (const node of list) { + if (node.sysDeptId) { + virIdToSysDeptId.set(node.id, node.sysDeptId); + } + if (node.children?.length) { + traverse(node.children); + } + } + }; + traverse(nodes || []); +}; /** 树权限(展开/折叠)*/ const handleCheckedTreeExpand = (value: boolean, type: string) => { if (type == 'menu') { @@ -483,7 +504,11 @@ const handleDataScope = async (row: RoleVO) => { /** 提交按钮(数据权限) */ const submitDataScope = async () => { if (form.value.roleId) { - form.value.deptIds = getDeptAllCheckedKeys(); + // 勾选的树节点为 vir_id,绑定角色-部门关系时转换为 sys_dept_id 保存 + const checkedVirIds = getDeptAllCheckedKeys() as Array; + form.value.deptIds = (checkedVirIds || []) + .map((virId) => virIdToSysDeptId.get(String(virId))) + .filter((sysDeptId): sysDeptId is string => !!sysDeptId); await dataScope(form.value); proxy?.$modal.msgSuccess('修改成功'); openDataScope.value = false;