|
|
@@ -0,0 +1,241 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.etotem.cfc.entity.SysMenu;
|
|
|
+import com.etotem.cfc.entity.SysRoleMenu;
|
|
|
+import com.etotem.cfc.mapper.SysMenuMapper;
|
|
|
+import com.etotem.cfc.mapper.SysRoleMenuMapper;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class SysMenuService extends ServiceImpl<SysMenuMapper, SysMenu> {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private SysMenuMapper sysMenuMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private SysRoleMenuMapper sysRoleMenuMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 全量菜单树
|
|
|
+ */
|
|
|
+ public List<SysMenu> tree() {
|
|
|
+ List<SysMenu> all = sysMenuMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SysMenu>().orderByAsc(SysMenu::getSort).orderByAsc(SysMenu::getId)
|
|
|
+ );
|
|
|
+ return buildTree(all, 0L);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按 parentId 组装树
|
|
|
+ */
|
|
|
+ private List<SysMenu> buildTree(List<SysMenu> all, Long parentId) {
|
|
|
+ List<SysMenu> result = new ArrayList<>();
|
|
|
+ for (SysMenu m : all) {
|
|
|
+ Long pid = m.getParentId() == null ? 0L : m.getParentId();
|
|
|
+ if (pid.equals(parentId)) {
|
|
|
+ m.setChildren(buildTree(all, m.getId()));
|
|
|
+ result.add(m);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 某角色已授权 menu_id 列表
|
|
|
+ */
|
|
|
+ public List<Long> roleMenuIds(String role) {
|
|
|
+ List<SysRoleMenu> list = sysRoleMenuMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRole, role)
|
|
|
+ );
|
|
|
+ List<Long> ids = new ArrayList<>();
|
|
|
+ for (SysRoleMenu r : list) {
|
|
|
+ ids.add(r.getMenuId());
|
|
|
+ }
|
|
|
+ return ids;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 覆盖式保存角色授权
|
|
|
+ */
|
|
|
+ public void saveRoleMenus(String role, List<Long> menuIds) {
|
|
|
+ sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRole, role));
|
|
|
+ if (menuIds != null) {
|
|
|
+ for (Long menuId : menuIds) {
|
|
|
+ if (menuId == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ SysRoleMenu r = new SysRoleMenu();
|
|
|
+ r.setRole(role);
|
|
|
+ r.setMenuId(menuId);
|
|
|
+ sysRoleMenuMapper.insert(r);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 当前用户可见菜单树
|
|
|
+ * 逻辑: 从 roles 取授权 menu_id 集合;若该集合为空(管理员尚未配置任何授权)→ 返回全量 visible=1 树(保持现状兼容);
|
|
|
+ * 非空 → 返回这些菜单的子树并补全父级链。
|
|
|
+ */
|
|
|
+ public List<SysMenu> userMenus(List<String> roles) {
|
|
|
+ List<SysMenu> all = sysMenuMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SysMenu>().orderByAsc(SysMenu::getSort).orderByAsc(SysMenu::getId)
|
|
|
+ );
|
|
|
+ if (all.isEmpty()) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 收集授权 menu_id
|
|
|
+ Set<Long> authed = new HashSet<>();
|
|
|
+ if (roles != null) {
|
|
|
+ for (String role : roles) {
|
|
|
+ if (role == null || role.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ List<SysRoleMenu> list = sysRoleMenuMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRole, role)
|
|
|
+ );
|
|
|
+ for (SysRoleMenu r : list) {
|
|
|
+ authed.add(r.getMenuId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 无任何授权记录 → 返回全量可见树
|
|
|
+ if (authed.isEmpty()) {
|
|
|
+ List<SysMenu> visible = new ArrayList<>();
|
|
|
+ for (SysMenu m : all) {
|
|
|
+ if (Integer.valueOf(1).equals(m.getVisible())) {
|
|
|
+ visible.add(m);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return buildTree(visible, 0L);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 有授权 → 计算需返回的节点集合(含父级链补全)
|
|
|
+ Set<Long> idSet = new HashSet<>();
|
|
|
+ for (SysMenu m : all) {
|
|
|
+ idSet.add(m.getId());
|
|
|
+ }
|
|
|
+ Map<Long, SysMenu> byId = new HashMap<>();
|
|
|
+ for (SysMenu m : all) {
|
|
|
+ byId.put(m.getId(), m);
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<Long> included = new HashSet<>();
|
|
|
+ for (SysMenu m : all) {
|
|
|
+ if (authed.contains(m.getId()) && Integer.valueOf(1).equals(m.getVisible())) {
|
|
|
+ // 向上补全父级链
|
|
|
+ Long cur = m.getId();
|
|
|
+ while (cur != null && !included.contains(cur) && idSet.contains(cur)) {
|
|
|
+ included.add(cur);
|
|
|
+ SysMenu node = byId.get(cur);
|
|
|
+ Long pid = node.getParentId() == null ? 0L : node.getParentId();
|
|
|
+ if (pid == 0L || !idSet.contains(pid)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ cur = pid;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<SysMenu> filtered = new ArrayList<>();
|
|
|
+ for (SysMenu m : all) {
|
|
|
+ if (included.contains(m.getId())) {
|
|
|
+ filtered.add(m);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return buildTree(filtered, 0L);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建菜单,sort 默认取同级最大值+1
|
|
|
+ */
|
|
|
+ public SysMenu create(SysMenu menu) {
|
|
|
+ Long parentId = menu.getParentId() == null ? 0L : menu.getParentId();
|
|
|
+ menu.setParentId(parentId);
|
|
|
+ if (menu.getSort() == null) {
|
|
|
+ Integer maxSort = sysMenuMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, parentId)
|
|
|
+ ).stream().map(SysMenu::getSort).filter(s -> s != null).max(Comparator.naturalOrder()).orElse(-1);
|
|
|
+ menu.setSort(maxSort + 1);
|
|
|
+ }
|
|
|
+ if (menu.getVisible() == null) {
|
|
|
+ menu.setVisible(1);
|
|
|
+ }
|
|
|
+ this.save(menu);
|
|
|
+ return menu;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新菜单(parentId 变更即层级调整)
|
|
|
+ */
|
|
|
+ public boolean update(SysMenu menu) {
|
|
|
+ return this.updateById(menu);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除菜单,有子菜单则拒绝
|
|
|
+ */
|
|
|
+ public boolean delete(Long id) {
|
|
|
+ Long childCount = sysMenuMapper.selectCount(
|
|
|
+ new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, id)
|
|
|
+ );
|
|
|
+ if (childCount != null && childCount > 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 删除关联授权
|
|
|
+ sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, id));
|
|
|
+ return this.removeById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同级内上移/下移(与相邻兄弟交换 sort)
|
|
|
+ */
|
|
|
+ public boolean move(Long id, String direction) {
|
|
|
+ SysMenu target = this.getById(id);
|
|
|
+ if (target == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Long parentId = target.getParentId() == null ? 0L : target.getParentId();
|
|
|
+ List<SysMenu> siblings = sysMenuMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SysMenu>()
|
|
|
+ .eq(SysMenu::getParentId, parentId)
|
|
|
+ .orderByAsc(SysMenu::getSort)
|
|
|
+ .orderByAsc(SysMenu::getId)
|
|
|
+ );
|
|
|
+ int idx = -1;
|
|
|
+ for (int i = 0; i < siblings.size(); i++) {
|
|
|
+ if (siblings.get(i).getId().equals(id)) {
|
|
|
+ idx = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (idx < 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ int swapIdx = "up".equals(direction) ? idx - 1 : idx + 1;
|
|
|
+ if (swapIdx < 0 || swapIdx >= siblings.size()) {
|
|
|
+ return false; // 已在边界
|
|
|
+ }
|
|
|
+ SysMenu neighbor = siblings.get(swapIdx);
|
|
|
+ int tmp = target.getSort() == null ? 0 : target.getSort();
|
|
|
+ target.setSort(neighbor.getSort() == null ? 0 : neighbor.getSort());
|
|
|
+ neighbor.setSort(tmp);
|
|
|
+ this.updateById(target);
|
|
|
+ this.updateById(neighbor);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|