package com.emergencyrepair.system.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.emergencyrepair.business.entity.BaseEquipment; import com.emergencyrepair.business.entity.EngineeringMajor; import com.emergencyrepair.business.entity.TeamMajor; import com.emergencyrepair.business.entity.ProductNode; import com.emergencyrepair.business.mapper.BaseEquipmentMapper; import com.emergencyrepair.business.mapper.EngineeringMajorMapper; import com.emergencyrepair.business.mapper.ProductNodeMapper; import com.emergencyrepair.business.mapper.TeamMajorMapper; import com.emergencyrepair.common.BusinessException; import com.emergencyrepair.system.entity.SysMenu; import com.emergencyrepair.system.entity.SysErrorLog; import com.emergencyrepair.system.entity.SysLoginLog; import com.emergencyrepair.system.entity.SysOperationLog; import com.emergencyrepair.system.entity.SysRole; import com.emergencyrepair.system.entity.SysRoleMenu; import com.emergencyrepair.system.entity.SysRoleUser; import com.emergencyrepair.system.entity.SysTenantMenu; import com.emergencyrepair.system.mapper.SysMenuMapper; import com.emergencyrepair.system.mapper.SysErrorLogMapper; import com.emergencyrepair.system.mapper.SysLoginLogMapper; import com.emergencyrepair.system.mapper.SysOperationLogMapper; import com.emergencyrepair.system.mapper.SysRoleMapper; import com.emergencyrepair.system.mapper.SysRoleMenuMapper; import com.emergencyrepair.system.mapper.SysRoleUserMapper; import com.emergencyrepair.system.mapper.SysTenantMenuMapper; import lombok.RequiredArgsConstructor; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.time.LocalDateTime; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class SystemService { private final SysMenuMapper menuMapper; private final SysRoleMapper roleMapper; private final SysRoleMenuMapper roleMenuMapper; private final SysTenantMenuMapper tenantMenuMapper; private final SysRoleUserMapper roleUserMapper; private final SysLoginLogMapper loginLogMapper; private final SysOperationLogMapper operationLogMapper; private final SysErrorLogMapper errorLogMapper; private final ButtonPermissionCatalog buttonPermissionCatalog; private final JdbcTemplate jdbcTemplate; private final EngineeringMajorMapper engineeringMajorMapper; private final TeamMajorMapper teamMajorMapper; private final ProductNodeMapper productNodeMapper; private final BaseEquipmentMapper baseEquipmentMapper; public List menuTree() { // Buttons are permission points, not navigable nodes. List navigable = listMenus().stream() .filter(menu -> menu.getMenuType() == null || menu.getMenuType() != 2) .collect(Collectors.toList()); return buildTree(navigable); } public List menuTreeWithButtons() { return buildTree(listMenus()); } private List buildTree(List menus) { Map map = menus.stream().collect(Collectors.toMap(SysMenu::getId, item -> item)); List roots = new ArrayList<>(); for (SysMenu menu : menus) { if (menu.getPid() == null || menu.getPid() == 0L || !map.containsKey(menu.getPid())) { roots.add(menu); } else { map.get(menu.getPid()).getChildren().add(menu); } } sortTree(roots); return roots; } public List listMenus() { return menuMapper.selectList(Wrappers.lambdaQuery().orderByAsc(SysMenu::getSortNo)); } @Transactional public SysMenu saveMenu(SysMenu menu) { if (!StringUtils.hasText(menu.getName())) { throw new BusinessException("菜单名称不能为空"); } if (menu.getMenuType() == null) { menu.setMenuType(menu.getId() == null ? 1 : menu.getMenuType()); } boolean isRoot = menu.getPid() == null || menu.getPid() == 0L; if (menu.getMenuType() == 2) { if (isRoot) { throw new BusinessException("按钮类型只能建在菜单类型下级"); } SysMenu parent = menuMapper.selectById(menu.getPid()); if (parent == null || parent.getMenuType() == null || parent.getMenuType() != 1) { throw new BusinessException("按钮类型只能建在菜单类型下级"); } if (!StringUtils.hasText(menu.getPermissions())) { throw new BusinessException("按钮权限标识不能为空"); } menu.setUrl(null); menu.setIcon(null); } else if (!isRoot) { SysMenu parent = menuMapper.selectById(menu.getPid()); if (parent != null && parent.getMenuType() != null && parent.getMenuType() == 2) { throw new BusinessException("按钮类型下级不能再建菜单"); } } LocalDateTime now = LocalDateTime.now(); menu.setUpdateTime(now); if (menu.getId() == null) { menu.setCreateTime(now); if (menu.getVisible() == null) { menu.setVisible(1); } if (menu.getMenuType() == null) { menu.setMenuType(1); } menuMapper.insert(menu); } else { menuMapper.updateById(menu); } return menuMapper.selectById(menu.getId()); } @Transactional public void deleteMenu(Long id) { long children = menuMapper.selectCount(Wrappers.lambdaQuery().eq(SysMenu::getPid, id)); if (children > 0) { throw new BusinessException("请先删除下级菜单"); } menuMapper.deleteById(id); roleMenuMapper.delete(Wrappers.lambdaQuery().eq(SysRoleMenu::getMenuId, id)); tenantMenuMapper.delete(Wrappers.lambdaQuery().eq(SysTenantMenu::getMenuId, id)); } public List listRoles() { return roleMapper.selectList(Wrappers.lambdaQuery().orderByAsc(SysRole::getSortNo)); } @Transactional public SysRole saveRole(SysRole role) { if (!StringUtils.hasText(role.getName()) || !StringUtils.hasText(role.getCode())) { throw new BusinessException("角色名称和编码不能为空"); } LocalDateTime now = LocalDateTime.now(); role.setUpdateTime(now); if (role.getId() == null) { role.setCreateTime(now); roleMapper.insert(role); } else { roleMapper.updateById(role); } return roleMapper.selectById(role.getId()); } @Transactional public void deleteRole(Long id) { roleMapper.deleteById(id); roleMenuMapper.delete(Wrappers.lambdaQuery().eq(SysRoleMenu::getRoleId, id)); roleUserMapper.delete(Wrappers.lambdaQuery().eq(SysRoleUser::getRoleId, id)); } /** * Contractor units are maintained as department records with DEPT_TYPE='cj'. */ public List> listContractors() { return jdbcTemplate.query( "SELECT DEPT_ID, DEPT_NAME, ORDER_NUM, LEADER, PHONE, STATUS, DEPT_CODE FROM CSICZB_ZB.SYS_DEPT " + "WHERE DEPT_TYPE = 'cj' AND (DEL_FLAG = '0' OR DEL_FLAG IS NULL) ORDER BY ORDER_NUM, DEPT_ID", (rs, rowNum) -> { Map row = new LinkedHashMap<>(); row.put("id", String.valueOf(rs.getLong("DEPT_ID"))); row.put("name", rs.getString("DEPT_NAME")); row.put("shortName", null); row.put("nature", "承修单位"); row.put("sortNo", rs.getObject("ORDER_NUM")); row.put("contact", rs.getString("LEADER")); row.put("phone", rs.getString("PHONE")); row.put("status", rs.getString("STATUS")); row.put("deptCode", rs.getString("DEPT_CODE")); row.put("dishonest", 0); return row; }); } public List listEngineeringMajors() { return engineeringMajorMapper.selectList(Wrappers.lambdaQuery() .orderByAsc(EngineeringMajor::getId)); } @Transactional public EngineeringMajor saveEngineeringMajor(EngineeringMajor major) { if (major == null || !StringUtils.hasText(major.getName())) { throw new BusinessException("工程专业名称不能为空"); } String name = major.getName().trim(); LambdaQueryWrapper duplicate = Wrappers.lambdaQuery() .eq(EngineeringMajor::getName, name); if (major.getId() != null) { duplicate.ne(EngineeringMajor::getId, major.getId()); } if (engineeringMajorMapper.selectCount(duplicate) > 0) { throw new BusinessException("工程专业名称已存在:" + name); } LocalDateTime now = LocalDateTime.now(); major.setName(name); major.setUpdateTime(now); if (major.getId() == null) { major.setCreateTime(now); engineeringMajorMapper.insert(major); } else { engineeringMajorMapper.updateById(major); } return engineeringMajorMapper.selectById(major.getId()); } @Transactional public void deleteEngineeringMajor(Long id) { engineeringMajorMapper.deleteById(id); } public List listTeamMajors() { return teamMajorMapper.selectList(Wrappers.lambdaQuery() .orderByAsc(TeamMajor::getId)); } @Transactional public TeamMajor saveTeamMajor(TeamMajor major) { if (major == null || !StringUtils.hasText(major.getName())) { throw new BusinessException("rk_T队专业名称不能为空"); } String name = major.getName().trim(); String category = StringUtils.hasText(major.getCategory()) ? major.getCategory().trim().toUpperCase() : ""; if (!"A".equals(category) && !"B".equals(category)) { throw new BusinessException("rk_T队专业分类只能是A或B"); } LambdaQueryWrapper duplicate = Wrappers.lambdaQuery() .eq(TeamMajor::getName, name); if (major.getId() != null) { duplicate.ne(TeamMajor::getId, major.getId()); } if (teamMajorMapper.selectCount(duplicate) > 0) { throw new BusinessException("rk_T队专业名称已存在:" + name); } LocalDateTime now = LocalDateTime.now(); major.setName(name); major.setCategory(category); major.setUpdateTime(now); if (major.getId() == null) { major.setCreateTime(now); teamMajorMapper.insert(major); } else { teamMajorMapper.updateById(major); } return teamMajorMapper.selectById(major.getId()); } @Transactional public void deleteTeamMajor(Long id) { teamMajorMapper.deleteById(id); } public List> tree(String type) { if ("product".equals(type)) { return productTree(); } if ("base".equals(type)) { return baseTree(); } throw new BusinessException("未知树类型"); } public List> selectedProductNodes(List ids) { if (ids == null || ids.isEmpty()) { return Collections.emptyList(); } List source = productNodeMapper.selectList(Wrappers.lambdaQuery() .in(ProductNode::getId, ids)); Map unique = uniqueProductNodes(source); List> result = new ArrayList<>(); Set seen = new HashSet<>(); for (Long id : ids) { ProductNode node = unique.get(id); if (node == null || !seen.add(id)) { continue; } List path = productPath(node); Map row = mapProduct(node, Collections.emptySet()); row.put("pathNames", path.stream().map(ProductNode::getName).collect(Collectors.toList())); row.put("parentPathNames", path.stream() .filter(item -> item != node) .filter(item -> item.getNodeLevel() != null && item.getNodeLevel() > 2) .map(ProductNode::getName) .collect(Collectors.toList())); ProductNode xNode = path.stream() .filter(item -> item.getNodeLevel() != null && item.getNodeLevel() == 2) .findFirst().orElse(null); row.put("xNo", xNode == null ? null : xNode.getName()); result.add(row); } return result; } private List> mapProductTreeNodes(List source, Set forcedBranchIds) { Map unique = uniqueProductNodes(source); List nodes = sortProductNodes(unique.values()); Set branchIds = new HashSet<>(forcedBranchIds); if (!unique.isEmpty()) { List childRows = productNodeMapper.selectList(Wrappers.lambdaQuery() .select(ProductNode::getParentId, ProductNode::getIsDelete) .in(ProductNode::getParentId, unique.keySet())); for (ProductNode child : childRows) { if (!"1".equals(child.getIsDelete()) && child.getParentId() != null) { branchIds.add(child.getParentId()); } } } List> rows = new ArrayList<>(); for (ProductNode node : nodes) { rows.add(mapProduct(node, branchIds)); } return rows; } private Map uniqueProductNodes(Collection source) { Map unique = new LinkedHashMap<>(); if (source == null) { return unique; } for (ProductNode node : source) { if (node.getId() == null || "1".equals(node.getIsDelete())) { continue; } unique.putIfAbsent(node.getId(), node); } return unique; } private List sortProductNodes(Collection source) { List nodes = new ArrayList<>(source); nodes.sort(Comparator.comparingInt(this::productNodeLevel) .thenComparing(ProductNode::getSortNo, Comparator.nullsLast(Integer::compareTo)) .thenComparing(ProductNode::getId, Comparator.nullsLast(Long::compareTo))); return nodes; } private ProductNode findProductRoot(ProductNode node) { ProductNode current = node; Set visited = new HashSet<>(); while (current != null && current.getParentId() != null && current.getParentId() != 0L && visited.add(current.getId())) { current = findProductNode(current.getParentId()); } return current; } private List productPath(ProductNode node) { List reversed = new ArrayList<>(); Set visited = new HashSet<>(); ProductNode current = node; while (current != null && visited.add(current.getId())) { reversed.add(current); if (current.getParentId() == null || current.getParentId() == 0L) { break; } current = findProductNode(current.getParentId()); } Collections.reverse(reversed); return reversed; } public List> productTreeForXNo(String xNo) { if (!StringUtils.hasText(xNo)) { return productTreeRoots(); } List rootNodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .and(wrapper -> wrapper.isNull(ProductNode::getParentId).or().eq(ProductNode::getParentId, 0L)) .orderByAsc(ProductNode::getSortNo).orderByAsc(ProductNode::getId)); List sideNodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .in(ProductNode::getLayer, Arrays.asList("side", "SIDE")) .eq(ProductNode::getName, xNo.trim()) .orderByAsc(ProductNode::getSortNo).orderByAsc(ProductNode::getId)); Map roots = uniqueProductNodes(rootNodes); Map sides = uniqueProductNodes(sideNodes); Set branchIds = new HashSet<>(); branchIds.addAll(roots.keySet()); branchIds.addAll(sides.keySet()); Map> rootRows = new LinkedHashMap<>(); for (ProductNode root : sortProductNodes(roots.values())) { rootRows.put(root.getId(), mapProduct(root, branchIds)); } for (ProductNode side : sortProductNodes(sides.values())) { ProductNode root = findProductRoot(side); Map rootRow = root == null ? null : rootRows.get(root.getId()); if (rootRow != null) { children(rootRow).add(mapProduct(side, branchIds)); } } return new ArrayList<>(rootRows.values()); } public List productXNumbers() { List nodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .in(ProductNode::getLayer, Arrays.asList("side", "SIDE")) .orderByAsc(ProductNode::getSortNo).orderByAsc(ProductNode::getId)); return nodes.stream() .filter(node -> !"1".equals(node.getIsDelete())) .map(ProductNode::getName) .filter(StringUtils::hasText) .map(String::trim) .distinct() .sorted(String.CASE_INSENSITIVE_ORDER) .collect(Collectors.toList()); } public List> productTreeRoots() { List nodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .and(wrapper -> wrapper.isNull(ProductNode::getParentId).or().eq(ProductNode::getParentId, 0L)) .orderByAsc(ProductNode::getSortNo).orderByAsc(ProductNode::getId)); return mapProductTreeNodes(nodes, Collections.emptySet()); } public List> productTreeChildren(Long parentId) { if (parentId == null || parentId == 0L) { return productTreeRoots(); } List nodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .eq(ProductNode::getParentId, parentId) .orderByAsc(ProductNode::getSortNo).orderByAsc(ProductNode::getId)); return mapProductTreeNodes(nodes, Collections.emptySet()); } public List> productTree() { List nodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .orderByAsc(ProductNode::getId).orderByAsc(ProductNode::getSortNo)); Map unique = new LinkedHashMap<>(); for (ProductNode node : nodes) { if (node.getId() == null || "1".equals(node.getIsDelete())) { continue; } unique.putIfAbsent(node.getId(), node); } nodes = new ArrayList<>(unique.values()); nodes.sort(Comparator.comparingInt(this::productNodeLevel) .thenComparing(ProductNode::getSortNo, Comparator.nullsLast(Integer::compareTo)) .thenComparing(ProductNode::getId, Comparator.nullsLast(Long::compareTo))); Map> map = new LinkedHashMap<>(); for (ProductNode node : nodes) { map.put(node.getId(), mapProduct(node)); } List> roots = new ArrayList<>(); for (ProductNode node : nodes) { Map target = map.get(node.getId()); if (node.getParentId() == null || node.getParentId() == 0L || !map.containsKey(node.getParentId())) { roots.add(target); } else { children(map.get(node.getParentId())).add(target); } } return roots; } public List> baseTree() { List nodes = baseEquipmentMapper.selectList(Wrappers.lambdaQuery() .orderByAsc(BaseEquipment::getNodeLevel).orderByAsc(BaseEquipment::getSortNo)); Map> map = new LinkedHashMap<>(); for (BaseEquipment node : nodes) { map.put(node.getId(), mapBase(node)); } List> roots = new ArrayList<>(); for (BaseEquipment node : nodes) { Map target = map.get(node.getId()); if (node.getParentId() == null || node.getParentId() == 0L || !map.containsKey(node.getParentId())) { roots.add(target); } else { children(map.get(node.getParentId())).add(target); } } return roots; } @Transactional public ProductNode saveProductNode(ProductNode node) { if (!StringUtils.hasText(node.getName())) { throw new BusinessException("节点名称不能为空"); } LocalDateTime now = LocalDateTime.now(); String layer = resolveProductLayer(node); node.setLayer(layer); node.setConnectGroup(buildConnectGroup(node.getParentId())); if (node.getId() == null) { node.setId(IdWorker.getId()); node.setRecordId(String.valueOf(node.getId())); node.setProject(StringUtils.hasText(node.getProject()) ? node.getProject().trim() : "0"); node.setSortNo(node.getSortNo() == null ? 1 : node.getSortNo()); node.setIsDelete("0"); node.setCreateBy(StringUtils.hasText(node.getCreateBy()) ? node.getCreateBy().trim() : "system"); node.setCreateTime(now); productNodeMapper.insert(node); } else { ProductNode current = findProductNode(node.getId()); if (current == null) { throw new BusinessException("节点不存在"); } node.setRecordId(current.getRecordId()); node.setProject(StringUtils.hasText(current.getProject()) ? current.getProject() : "0"); node.setIsDelete(StringUtils.hasText(current.getIsDelete()) ? current.getIsDelete() : "0"); node.setCreateBy(current.getCreateBy()); node.setCreateTime(current.getCreateTime()); productNodeMapper.updateById(node); } return findProductNode(node.getId()); } @Transactional public void deleteProductNode(Long id) { assertNoChildren(productNodeMapper.selectCount(Wrappers.lambdaQuery() .eq(ProductNode::getParentId, id).ne(ProductNode::getIsDelete, "1"))); ProductNode current = findProductNode(id); if (current == null) { throw new BusinessException("节点不存在"); } current.setIsDelete("1"); productNodeMapper.updateById(current); } @Transactional public BaseEquipment saveBaseNode(BaseEquipment node) { if (!StringUtils.hasText(node.getName()) || node.getNodeLevel() == null) { throw new BusinessException("节点名称和层级不能为空"); } LocalDateTime now = LocalDateTime.now(); node.setUpdateTime(now); if (node.getId() == null) { node.setCreateTime(now); baseEquipmentMapper.insert(node); } else { baseEquipmentMapper.updateById(node); } return baseEquipmentMapper.selectById(node.getId()); } @Transactional public void deleteBaseNode(Long id) { assertNoChildren(baseEquipmentMapper.selectCount(Wrappers.lambdaQuery().eq(BaseEquipment::getParentId, id))); baseEquipmentMapper.deleteById(id); } public Map menuPermissions(Long roleId) { if (roleId == null) { throw new BusinessException("请选择角色"); } List roleMenuIds = roleMenuMapper.selectList(Wrappers.lambdaQuery() .eq(SysRoleMenu::getRoleId, roleId)) .stream().map(SysRoleMenu::getMenuId).map(String::valueOf).collect(Collectors.toList()); Map result = new LinkedHashMap<>(); result.put("roleMenuIds", roleMenuIds); result.put("effectiveMenuIds", roleMenuIds); return result; } @Transactional public void saveMenuPermissions(Long roleId, List roleMenuIds) { if (roleId == null) { throw new BusinessException("请选择角色"); } roleMenuMapper.delete(Wrappers.lambdaQuery().eq(SysRoleMenu::getRoleId, roleId)); List effectiveRoleMenuIds = expandWithAncestors(roleMenuIds); for (Long menuId : effectiveRoleMenuIds) { SysRoleMenu relation = new SysRoleMenu(); relation.setRoleId(roleId); relation.setMenuId(menuId); relation.setCreateTime(LocalDateTime.now()); roleMenuMapper.insert(relation); } } public Map userPage(String keyword, Long deptId, Long roleId, int current, int size) { List args = new ArrayList<>(); StringBuilder sql = new StringBuilder(); sql.append("SELECT u.USER_ID, u.USER_NAME, u.NICK_NAME, u.DEPT_ID, d.DEPT_NAME, u.PHONENUMBER, u.STATUS, u.LOGIN_DATE "); sql.append("FROM CSICZB_ZB.SYS_USER u LEFT JOIN CSICZB_ZB.SYS_DEPT d ON d.DEPT_ID = u.DEPT_ID "); sql.append("WHERE (u.DEL_FLAG = '0' OR u.DEL_FLAG IS NULL) "); if (StringUtils.hasText(keyword)) { sql.append("AND (u.USER_NAME LIKE ? OR u.NICK_NAME LIKE ?) "); String like = "%" + keyword.trim() + "%"; args.add(like); args.add(like); } if (deptId != null) { sql.append("AND u.DEPT_ID = ? "); args.add(deptId); } if (roleId != null) { sql.append("AND EXISTS (SELECT 1 FROM LX.T_SYS_ROLE_USER ru WHERE ru.USER_ID = u.USER_ID AND ru.ROLE_ID = ? AND ru.DEL_FLAG = 0) "); args.add(roleId); } sql.append("ORDER BY u.USER_ID"); List> all = jdbcTemplate.query(sql.toString(), args.toArray(), (rs, rowNum) -> { Map row = new LinkedHashMap<>(); row.put("userId", String.valueOf(rs.getLong("USER_ID"))); row.put("userName", rs.getString("USER_NAME")); row.put("nickName", rs.getString("NICK_NAME")); Object dept = rs.getObject("DEPT_ID"); row.put("deptId", dept == null ? null : String.valueOf(rs.getLong("DEPT_ID"))); row.put("deptName", rs.getString("DEPT_NAME")); row.put("phoneNumber", rs.getString("PHONENUMBER")); row.put("status", rs.getString("STATUS")); java.sql.Timestamp loginDate = rs.getTimestamp("LOGIN_DATE"); row.put("loginDate", loginDate == null ? null : loginDate.toLocalDateTime().toString().replace('T', ' ')); row.put("roles", new ArrayList>()); return row; }); Map> byId = new HashMap<>(); for (Map row : all) { byId.put(Long.valueOf(String.valueOf(row.get("userId"))), row); } if (!byId.isEmpty()) { List> roleRows = jdbcTemplate.query( "SELECT ru.USER_ID, r.ID, r.NAME, r.CODE, r.ROLE_TYPE FROM LX.T_SYS_ROLE_USER ru JOIN LX.T_SYS_ROLE r ON r.ID = ru.ROLE_ID AND r.DEL_FLAG = 0 WHERE ru.DEL_FLAG = 0 ORDER BY r.SORT_NO", (rs, rowNum) -> { Map role = new LinkedHashMap<>(); role.put("userId", String.valueOf(rs.getLong("USER_ID"))); role.put("roleId", String.valueOf(rs.getLong("ID"))); role.put("roleName", rs.getString("NAME")); role.put("roleCode", rs.getString("CODE")); role.put("roleType", rs.getString("ROLE_TYPE")); return role; }); for (Map role : roleRows) { Map user = byId.get(Long.valueOf(String.valueOf(role.get("userId")))); if (user != null) { @SuppressWarnings("unchecked") List> roles = (List>) user.get("roles"); roles.add(role); } } } int safeSize = size <= 0 ? 20 : size; int safeCurrent = current <= 0 ? 1 : current; int total = all.size(); int from = Math.min(total, (safeCurrent - 1) * safeSize); int to = Math.min(total, from + safeSize); Map result = new LinkedHashMap<>(); result.put("records", new ArrayList<>(all.subList(from, to))); result.put("total", total); result.put("current", safeCurrent); result.put("size", safeSize); result.put("pages", (total + safeSize - 1) / safeSize); return result; } public List> depts() { return jdbcTemplate.query( "SELECT DEPT_ID, DEPT_NAME, PARENT_ID, ORDER_NUM, DEPT_TYPE, LEADER, PHONE, STATUS, DEPT_CODE FROM CSICZB_ZB.SYS_DEPT WHERE (DEL_FLAG = '0' OR DEL_FLAG IS NULL) ORDER BY ORDER_NUM, DEPT_ID", (rs, rowNum) -> { Map row = new LinkedHashMap<>(); row.put("id", String.valueOf(rs.getLong("DEPT_ID"))); row.put("name", rs.getString("DEPT_NAME")); Object parentId = rs.getObject("PARENT_ID"); row.put("parentId", parentId == null ? null : String.valueOf(rs.getLong("PARENT_ID"))); row.put("orderNum", rs.getObject("ORDER_NUM")); row.put("deptType", rs.getString("DEPT_TYPE")); row.put("leader", rs.getString("LEADER")); row.put("phone", rs.getString("PHONE")); row.put("status", rs.getString("STATUS")); row.put("deptCode", rs.getString("DEPT_CODE")); return row; }); } public List userRoleIds(Long userId) { if (userId == null) { return new ArrayList<>(); } return roleUserMapper.selectList(Wrappers.lambdaQuery() .eq(SysRoleUser::getUserId, userId)) .stream().map(item -> String.valueOf(item.getRoleId())).collect(Collectors.toList()); } public Map roleUsers(Long roleId) { if (roleId == null || roleMapper.selectById(roleId) == null) { throw new BusinessException("角色不存在"); } Set assignedUserIds = roleUserMapper.selectList(Wrappers.lambdaQuery() .eq(SysRoleUser::getRoleId, roleId)) .stream().map(SysRoleUser::getUserId).collect(Collectors.toCollection(LinkedHashSet::new)); List> users = jdbcTemplate.query( "SELECT u.USER_ID, u.USER_NAME, u.NICK_NAME, u.DEPT_ID, d.DEPT_NAME, u.STATUS " + "FROM CSICZB_ZB.SYS_USER u LEFT JOIN CSICZB_ZB.SYS_DEPT d ON d.DEPT_ID = u.DEPT_ID " + "WHERE (u.DEL_FLAG = '0' OR u.DEL_FLAG IS NULL) ORDER BY u.USER_ID", (rs, rowNum) -> { Long userId = rs.getLong("USER_ID"); Map user = new LinkedHashMap<>(); user.put("userId", String.valueOf(userId)); user.put("userName", rs.getString("USER_NAME")); user.put("nickName", rs.getString("NICK_NAME")); Object deptId = rs.getObject("DEPT_ID"); user.put("deptId", deptId == null ? null : String.valueOf(rs.getLong("DEPT_ID"))); user.put("deptName", rs.getString("DEPT_NAME")); user.put("status", rs.getString("STATUS")); user.put("assigned", assignedUserIds.contains(userId)); return user; }); Map result = new LinkedHashMap<>(); result.put("records", users); result.put("userIds", assignedUserIds.stream().map(String::valueOf).collect(Collectors.toList())); result.put("total", users.size()); return result; } @Transactional public void saveRoleUsers(Long roleId, List userIds) { if (roleId == null || roleMapper.selectById(roleId) == null) { throw new BusinessException("角色不存在"); } Set distinct = new LinkedHashSet<>(); if (userIds != null) { distinct.addAll(userIds); } distinct.remove(null); for (Long userId : distinct) { Integer exists = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM CSICZB_ZB.SYS_USER WHERE USER_ID = ? AND (DEL_FLAG = '0' OR DEL_FLAG IS NULL)", Integer.class, userId); if (exists == null || exists == 0) { throw new BusinessException("用户不存在"); } } roleUserMapper.delete(Wrappers.lambdaQuery().eq(SysRoleUser::getRoleId, roleId)); for (Long userId : distinct) { SysRoleUser relation = new SysRoleUser(); relation.setRoleId(roleId); relation.setUserId(userId); relation.setCreateTime(LocalDateTime.now()); roleUserMapper.insert(relation); } } @Transactional public void saveUserRoles(Long userId, List roleIds) { if (userId == null) { throw new BusinessException("请选择用户"); } Integer exists = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM CSICZB_ZB.SYS_USER WHERE USER_ID = ? AND (DEL_FLAG = '0' OR DEL_FLAG IS NULL)", Integer.class, userId); if (exists == null || exists == 0) { throw new BusinessException("用户不存在"); } Set distinct = new LinkedHashSet<>(); if (roleIds != null) { distinct.addAll(roleIds); } for (Long roleId : distinct) { if (roleId != null && roleMapper.selectById(roleId) == null) { throw new BusinessException("角色不存在"); } } roleUserMapper.delete(Wrappers.lambdaQuery().eq(SysRoleUser::getUserId, userId)); for (Long roleId : distinct) { if (roleId == null) { continue; } SysRoleUser relation = new SysRoleUser(); relation.setRoleId(roleId); relation.setUserId(userId); relation.setCreateTime(LocalDateTime.now()); roleUserMapper.insert(relation); } } @Transactional public void saveUserRolesBatch(List userIds, List roleIds, String mode) { Set distinctUsers = new LinkedHashSet<>(); if (userIds != null) { distinctUsers.addAll(userIds); } distinctUsers.remove(null); if (distinctUsers.isEmpty()) { throw new BusinessException("\u8bf7\u9009\u62e9\u7528\u6237"); } Set distinctRoles = new LinkedHashSet<>(); if (roleIds != null) { distinctRoles.addAll(roleIds); } distinctRoles.remove(null); for (Long roleId : distinctRoles) { if (roleMapper.selectById(roleId) == null) { throw new BusinessException("\u89d2\u8272\u4e0d\u5b58\u5728"); } } boolean append = !"replace".equalsIgnoreCase(mode == null ? "" : mode.trim()); for (Long userId : distinctUsers) { Integer exists = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM CSICZB_ZB.SYS_USER WHERE USER_ID = ? AND (DEL_FLAG = '0' OR DEL_FLAG IS NULL)", Integer.class, userId); if (exists == null || exists == 0) { throw new BusinessException("\u7528\u6237\u4e0d\u5b58\u5728"); } Set targetRoleIds = new LinkedHashSet<>(); if (append) { targetRoleIds.addAll(roleUserMapper.selectList(Wrappers.lambdaQuery() .eq(SysRoleUser::getUserId, userId)) .stream().map(SysRoleUser::getRoleId).collect(Collectors.toList())); } targetRoleIds.addAll(distinctRoles); roleUserMapper.delete(Wrappers.lambdaQuery().eq(SysRoleUser::getUserId, userId)); for (Long roleId : targetRoleIds) { SysRoleUser relation = new SysRoleUser(); relation.setRoleId(roleId); relation.setUserId(userId); relation.setCreateTime(LocalDateTime.now()); roleUserMapper.insert(relation); } } } public List roleCodes(String username) { Long userId = resolveUserId(username); if (userId == null) { return new ArrayList<>(); } List roleIds = roleUserMapper.selectList(Wrappers.lambdaQuery() .eq(SysRoleUser::getUserId, userId)) .stream().map(SysRoleUser::getRoleId).collect(Collectors.toList()); if (roleIds.isEmpty()) { return new ArrayList<>(); } return roleMapper.selectBatchIds(roleIds).stream() .map(SysRole::getCode).filter(StringUtils::hasText).sorted().collect(Collectors.toList()); } public Set effectiveMenuIdsForUser(String username) { Set result = new LinkedHashSet<>(); if (!StringUtils.hasText(username)) { return result; } if ("admin".equals(username)) { listMenus().forEach(menu -> result.add(menu.getId())); return result; } Long userId = resolveUserId(username); if (userId == null) { return result; } List roleIds = roleUserMapper.selectList(Wrappers.lambdaQuery() .eq(SysRoleUser::getUserId, userId)) .stream().map(SysRoleUser::getRoleId).collect(Collectors.toList()); if (roleIds.isEmpty()) { return result; } Set roleMenuIds = new LinkedHashSet<>(roleMenuMapper.selectList(Wrappers.lambdaQuery() .in(SysRoleMenu::getRoleId, roleIds)) .stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList())); result.addAll(roleMenuIds); return result; } public List menuTreeForUser(String username) { Set allowed = new LinkedHashSet<>(effectiveMenuIdsForUser(username)); if (allowed.isEmpty() && !"admin".equals(username)) { SysMenu dashboard = menuMapper.selectOne(Wrappers.lambdaQuery() .eq(SysMenu::getUrl, "/dashboard").last("LIMIT 1")); if (dashboard != null) { allowed.add(dashboard.getId()); } } final Set allowedIds = allowed; Set visibleIds = new LinkedHashSet<>(expandWithAncestors(new ArrayList<>(allowed))); List navigable = listMenus().stream() .filter(menu -> menu.getMenuType() == null || menu.getMenuType() != 2) .filter(menu -> visibleIds.contains(menu.getId())) .collect(Collectors.toList()); return buildTree(navigable); } public List permissionCodes(String username) { Set menuIds = effectiveMenuIdsForUser(username); return listMenus().stream() .filter(menu -> menuIds.contains(menu.getId())) .map(SysMenu::getPermissions) .filter(StringUtils::hasText) .distinct() .sorted() .collect(Collectors.toList()); } public Map menuButtons(Long menuId) { SysMenu menu = menuMapper.selectById(menuId); if (menu == null) { throw new BusinessException("菜单不存在"); } List> available = new ArrayList<>(); for (ButtonPermissionCatalog.ButtonDefinition definition : buttonPermissionCatalog.buttonsFor(menu.getUrl())) { Map row = new LinkedHashMap<>(); row.put("code", definition.getCode()); row.put("name", definition.getName()); available.add(row); } List selected = menuMapper.selectList(Wrappers.lambdaQuery() .eq(SysMenu::getPid, menuId) .eq(SysMenu::getMenuType, 2)) .stream().map(SysMenu::getPermissions).filter(StringUtils::hasText).collect(Collectors.toList()); Map result = new LinkedHashMap<>(); result.put("menuId", String.valueOf(menuId)); result.put("menuName", menu.getName()); result.put("available", available); result.put("selected", selected); return result; } @Transactional public void syncMenuButtons(Long menuId, List codes) { SysMenu menu = menuMapper.selectById(menuId); if (menu == null) { throw new BusinessException("菜单不存在"); } if (menu.getMenuType() == null || menu.getMenuType() != 1) { throw new BusinessException("只有菜单类型才能配置按钮"); } List definitions = buttonPermissionCatalog.buttonsFor(menu.getUrl()); Map definitionMap = new LinkedHashMap<>(); for (ButtonPermissionCatalog.ButtonDefinition definition : definitions) { definitionMap.put(definition.getCode(), definition); } Set wanted = new LinkedHashSet<>(); if (codes != null) { for (String code : codes) { if (StringUtils.hasText(code) && definitionMap.containsKey(code)) { wanted.add(code); } } } List existing = menuMapper.selectList(Wrappers.lambdaQuery() .eq(SysMenu::getPid, menuId).eq(SysMenu::getMenuType, 2)); Map existingByCode = new HashMap<>(); for (SysMenu child : existing) { existingByCode.put(child.getPermissions(), child); if (!wanted.contains(child.getPermissions())) { menuMapper.deleteById(child.getId()); roleMenuMapper.delete(Wrappers.lambdaQuery().eq(SysRoleMenu::getMenuId, child.getId())); tenantMenuMapper.delete(Wrappers.lambdaQuery().eq(SysTenantMenu::getMenuId, child.getId())); } } LocalDateTime now = LocalDateTime.now(); for (int index = 0; index < definitions.size(); index++) { ButtonPermissionCatalog.ButtonDefinition definition = definitions.get(index); if (!wanted.contains(definition.getCode())) { continue; } SysMenu child = existingByCode.get(definition.getCode()); if (child == null) { child = new SysMenu(); child.setPid(menuId); child.setName(definition.getName()); child.setPermissions(definition.getCode()); child.setMenuType(2); child.setSortNo((index + 1) * 10); child.setVisible(1); child.setCreateTime(now); child.setUpdateTime(now); menuMapper.insert(child); } else { child.setName(definition.getName()); child.setSortNo((index + 1) * 10); child.setUpdateTime(now); menuMapper.updateById(child); } } } public Page loginLogPage(int current, int size, String keyword, String status, String startDate, String endDate) { Page page = new Page<>(current <= 0 ? 1 : current, size <= 0 ? 20 : size); LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); if (StringUtils.hasText(keyword)) { String value = keyword.trim(); wrapper.and(item -> item.like(SysLoginLog::getUserName, value).or().like(SysLoginLog::getNickName, value)); } if (StringUtils.hasText(status)) { wrapper.eq(SysLoginLog::getStatus, status.trim()); } LocalDateTime start = parseStart(startDate); LocalDateTime end = parseEnd(endDate); if (start != null) { wrapper.ge(SysLoginLog::getLoginTime, start); } if (end != null) { wrapper.le(SysLoginLog::getLoginTime, end); } wrapper.orderByDesc(SysLoginLog::getLoginTime); return loginLogMapper.selectPage(page, wrapper); } public Page operationLogPage(int current, int size, String keyword, String module, String operationType, String startDate, String endDate) { Page page = new Page<>(current <= 0 ? 1 : current, size <= 0 ? 20 : size); LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); if (StringUtils.hasText(keyword)) { String value = keyword.trim(); wrapper.and(item -> item.like(SysOperationLog::getUserName, value) .or().like(SysOperationLog::getNickName, value) .or().like(SysOperationLog::getRequestUri, value)); } if (StringUtils.hasText(module)) { wrapper.eq(SysOperationLog::getModule, module.trim()); } if (StringUtils.hasText(operationType)) { wrapper.eq(SysOperationLog::getOperationType, operationType.trim()); } LocalDateTime start = parseStart(startDate); LocalDateTime end = parseEnd(endDate); if (start != null) { wrapper.ge(SysOperationLog::getCreateTime, start); } if (end != null) { wrapper.le(SysOperationLog::getCreateTime, end); } wrapper.orderByDesc(SysOperationLog::getCreateTime); return operationLogMapper.selectPage(page, wrapper); } public Page errorLogPage(int current, int size, String keyword, String module, String exceptionType, String startDate, String endDate) { Page page = new Page<>(current <= 0 ? 1 : current, size <= 0 ? 20 : size); LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.select(SysErrorLog::getId, SysErrorLog::getUserId, SysErrorLog::getUserName, SysErrorLog::getNickName, SysErrorLog::getModule, SysErrorLog::getRequestMethod, SysErrorLog::getRequestUri, SysErrorLog::getExceptionType, SysErrorLog::getMessage, SysErrorLog::getErrorTime); if (StringUtils.hasText(keyword)) { String value = keyword.trim(); wrapper.and(item -> item.like(SysErrorLog::getUserName, value) .or().like(SysErrorLog::getNickName, value) .or().like(SysErrorLog::getRequestUri, value) .or().like(SysErrorLog::getExceptionType, value) .or().like(SysErrorLog::getMessage, value)); } if (StringUtils.hasText(module)) { wrapper.eq(SysErrorLog::getModule, module.trim()); } if (StringUtils.hasText(exceptionType)) { wrapper.like(SysErrorLog::getExceptionType, exceptionType.trim()); } LocalDateTime start = parseStart(startDate); LocalDateTime end = parseEnd(endDate); if (start != null) { wrapper.ge(SysErrorLog::getErrorTime, start); } if (end != null) { wrapper.le(SysErrorLog::getErrorTime, end); } wrapper.orderByDesc(SysErrorLog::getErrorTime); return errorLogMapper.selectPage(page, wrapper); } public SysErrorLog errorLog(Long id) { SysErrorLog log = errorLogMapper.selectById(id); if (log == null) { throw new BusinessException("错误日志不存在"); } return log; } public Long resolveUserId(String username) { if (!StringUtils.hasText(username)) { return null; } List ids = jdbcTemplate.query( "SELECT USER_ID FROM CSICZB_ZB.SYS_USER WHERE USER_NAME = ? AND (DEL_FLAG = '0' OR DEL_FLAG IS NULL)", new Object[]{username}, (rs, rowNum) -> rs.getLong(1)); return ids.isEmpty() ? null : ids.get(0); } private List expandWithAncestors(List ids) { Set result = new LinkedHashSet<>(); if (ids == null) { return new ArrayList<>(result); } for (Long id : ids) { Long cursor = id; int guard = 0; while (cursor != null && cursor != 0L && guard++ < 32) { if (!result.add(cursor)) { break; } SysMenu menu = menuMapper.selectById(cursor); if (menu == null) { break; } cursor = menu.getPid(); } } return new ArrayList<>(result); } private LocalDateTime parseStart(String value) { if (!StringUtils.hasText(value)) { return null; } try { return LocalDate.parse(value.trim()).atStartOfDay(); } catch (Exception ex) { return null; } } private LocalDateTime parseEnd(String value) { if (!StringUtils.hasText(value)) { return null; } try { return LocalDate.parse(value.trim()).atTime(23, 59, 59); } catch (Exception ex) { return null; } } public Map threeMemberOverview() { List roles = listRoles().stream() .filter(item -> Arrays.asList("SYSTEM_ADMIN", "SECURITY_ADMIN", "AUDIT_ADMIN").contains(item.getRoleType())) .collect(Collectors.toList()); Map result = new LinkedHashMap<>(); result.put("roles", roles); result.put("users", Collections.singletonList(row("id", 1L, "name", "admin", "realName", "系统管理员"))); result.put("assignments", roleUserMapper.selectList(null)); return result; } private List flatten(List menus, Long pid) { return menus.stream() .filter(item -> pid == null ? item.getPid() == null || item.getPid() == 0L : pid.equals(item.getPid())) .sorted(Comparator.comparing(SysMenu::getSortNo, Comparator.nullsLast(Integer::compareTo))) .collect(Collectors.toList()); } private void sortTree(List nodes) { nodes.sort(Comparator.comparing(SysMenu::getSortNo, Comparator.nullsLast(Integer::compareTo))); for (SysMenu node : nodes) { sortTree(node.getChildren()); } } private Map mapProduct(ProductNode node) { return mapProduct(node, Collections.emptySet()); } private Map mapProduct(ProductNode node, Set branchIds) { Map row = new LinkedHashMap<>(); row.put("id", String.valueOf(node.getId())); row.put("parentId", node.getParentId() == null ? null : String.valueOf(node.getParentId())); row.put("nodeLevel", node.getNodeLevel()); row.put("nodeType", node.getNodeType()); row.put("layer", node.getLayer()); row.put("connectGroup", node.getConnectGroup()); row.put("name", node.getName()); row.put("code", node.getCode()); row.put("baseEquipmentId", node.getBaseEquipmentId() == null ? null : String.valueOf(node.getBaseEquipmentId())); row.put("project", node.getProject()); row.put("sortNo", node.getSortNo()); row.put("remark", node.getRemark()); row.put("isLeaf", !branchIds.contains(node.getId())); row.put("children", new ArrayList<>()); return row; } private int productNodeLevel(ProductNode node) { Integer level = node.getNodeLevel(); return level == null ? Integer.MAX_VALUE : level; } private String resolveProductLayer(ProductNode node) { String layer = ProductNode.layerForType(node.getNodeType()); if (!StringUtils.hasText(layer)) { layer = ProductNode.layerForLevel(node.getNodeLevel()); } if (!StringUtils.hasText(layer)) { layer = StringUtils.hasText(node.getLayer()) ? node.getLayer().trim().toLowerCase() : null; } if (!StringUtils.hasText(layer)) { throw new BusinessException("节点层级不能为空"); } return layer; } private String buildConnectGroup(Long parentId) { if (parentId == null || parentId == 0L) { return "0"; } ProductNode parent = findProductNode(parentId); if (parent == null) { throw new BusinessException("父节点不存在"); } String prefix = StringUtils.hasText(parent.getConnectGroup()) ? parent.getConnectGroup() : "0"; return prefix + "," + parent.getId(); } private ProductNode findProductNode(Long id) { if (id == null) { return null; } List nodes = productNodeMapper.selectList(Wrappers.lambdaQuery() .eq(ProductNode::getId, id) .orderByAsc(ProductNode::getRecordId) .last("LIMIT 1")); return nodes.isEmpty() ? null : nodes.get(0); } private Map mapBase(BaseEquipment node) { Map row = new LinkedHashMap<>(); row.put("id", String.valueOf(node.getId())); row.put("parentId", node.getParentId() == null ? null : String.valueOf(node.getParentId())); row.put("nodeLevel", node.getNodeLevel()); row.put("nodeType", "BASE_" + node.getNodeLevel()); row.put("name", node.getName()); row.put("code", node.getCode()); row.put("sortNo", node.getSortNo()); row.put("remark", node.getRemark()); row.put("children", new ArrayList<>()); return row; } @SuppressWarnings("unchecked") private List> children(Map node) { return (List>) node.get("children"); } private void assertNoChildren(long count) { if (count > 0) { throw new BusinessException("请先删除下级节点"); } } private Map row(Object... values) { Map row = new LinkedHashMap<>(); for (int i = 0; i < values.length; i += 2) { row.put(String.valueOf(values[i]), values[i + 1]); } return row; } }