|
|
@@ -0,0 +1,237 @@
|
|
|
+package cn.reghao.oss.web.account.service.impl;
|
|
|
+
|
|
|
+import cn.reghao.oss.web.account.db.repository.MenuRepository;
|
|
|
+import cn.reghao.oss.web.account.db.repository.RoleRepository;
|
|
|
+import cn.reghao.oss.web.account.model.constant.MenuType;
|
|
|
+import cn.reghao.oss.web.account.service.MenuService;
|
|
|
+import cn.reghao.jutil.jdk.result.Result;
|
|
|
+import cn.reghao.jutil.jdk.result.ResultStatus;
|
|
|
+import cn.reghao.oss.web.account.model.dto.MenuDTO;
|
|
|
+import cn.reghao.oss.web.account.model.po.Menu;
|
|
|
+import cn.reghao.oss.web.account.model.po.Role;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author reghao
|
|
|
+ * @date 2021-05-17 17:16:19
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class MenuServiceImpl implements MenuService {
|
|
|
+ private final MenuRepository menuRepository;
|
|
|
+ private final RoleRepository roleRepository;
|
|
|
+
|
|
|
+ public MenuServiceImpl(MenuRepository menuRepository, RoleRepository roleRepository) {
|
|
|
+ this.menuRepository = menuRepository;
|
|
|
+ this.roleRepository = roleRepository;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public synchronized Result addMenu(Menu menu) {
|
|
|
+ Result result = moreThanTwoParents(menu.getPid());
|
|
|
+ if (result.getCode() != ResultStatus.SUCCESS.getCode()) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调整 menu 组内元素的位置
|
|
|
+ insertNewMenu(menu);
|
|
|
+ menu.setEnabled(true);
|
|
|
+ Menu menuEntity = menuRepository.save(menu);
|
|
|
+
|
|
|
+ //Set<Role> roles = menu.getRoles();
|
|
|
+ Set<Role> roles = Collections.emptySet();
|
|
|
+ roles.forEach(role -> role.getMenus().add(menuEntity));
|
|
|
+ roleRepository.saveAll(new ArrayList<>(roles));
|
|
|
+ return Result.result(ResultStatus.SUCCESS);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查菜单的层级, Menu 最多只能有两个 parent, 即最多只能有三级菜单
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ * @date 2021-07-15 上午11:15
|
|
|
+ */
|
|
|
+ private Result moreThanTwoParents(int pid) {
|
|
|
+ if (pid != 0) {
|
|
|
+ Menu menu1 = menuRepository.getOne(pid);
|
|
|
+ int pid1 = menu1.getPid();
|
|
|
+ if (pid1 != 0) {
|
|
|
+ Menu menu2 = menuRepository.getOne(pid1);
|
|
|
+ int pid2 = menu2.getPid();
|
|
|
+ if (pid2 != 0) {
|
|
|
+ return Result.result(ResultStatus.FAIL, "Menu 最多只能有两个 parent,即最多只能有三级菜单");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result.result(ResultStatus.SUCCESS);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向 menu 组插入元素时调整组内 menu 的位置
|
|
|
+ *
|
|
|
+ * @date 2021-05-18 上午9:54
|
|
|
+ */
|
|
|
+ private void insertNewMenu(Menu menu) {
|
|
|
+ int pid = menu.getPid();
|
|
|
+ if (pid != 0) {
|
|
|
+ Menu pMenu = menuRepository.getOne(pid);
|
|
|
+ if (pMenu.getType().equals(MenuType.page.name())) {
|
|
|
+ log.error("父级菜单的类型不能是 PAGE");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Menu> menus = menuRepository.findByPid(pid);
|
|
|
+ menus.sort(Comparator.comparingInt(Menu::getPos));
|
|
|
+ // 组内没有 menu 或新增的 menu 在组内排在最后一位
|
|
|
+ if (menus.isEmpty()) {
|
|
|
+ menu.setPos(1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // menu 的新位置
|
|
|
+ int pos = menu.getPos()+1;
|
|
|
+ int size = menus.size();
|
|
|
+ if (pos == 1) {
|
|
|
+ // menu 的位置在 menu 组的首位, 组内的其他元素位置向后移一位
|
|
|
+ menu.setPos(1);
|
|
|
+ moveBackward(menus, 1);
|
|
|
+ } else if (pos >= size+1) {
|
|
|
+ // menu 的位置在 menu 组的末尾, 组内的其他元素位置不变
|
|
|
+ menu.setPos(size+1);
|
|
|
+ } else {
|
|
|
+ // menu 的位置在 menu 组的中间, pos 开始的元素位置向后移一位
|
|
|
+ menu.setPos(pos);
|
|
|
+ moveBackward(menus, pos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向后移动元素(向 menu 组新增元素时调用)
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ * @date 2021-07-15 下午5:07
|
|
|
+ */
|
|
|
+ private void moveBackward(List<Menu> menus, int startPos) {
|
|
|
+ for (int i = startPos-1; i < menus.size(); i++) {
|
|
|
+ Menu tmpMenu = menus.get(i);
|
|
|
+ int newPos = tmpMenu.getPos()+1;
|
|
|
+ tmpMenu.setPos(newPos);
|
|
|
+ }
|
|
|
+ menuRepository.saveAll(menus);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向前移动元素(从 menu 组删除元素时调用)
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ * @date 2021-07-15 下午5:41
|
|
|
+ */
|
|
|
+ private void moveForward(List<Menu> menus, int startPos) {
|
|
|
+ for (int i = startPos; i < menus.size(); i++) {
|
|
|
+ Menu tmpMenu = menus.get(i);
|
|
|
+ int newPos = tmpMenu.getPos()-1;
|
|
|
+ tmpMenu.setPos(newPos);
|
|
|
+ }
|
|
|
+ menuRepository.saveAll(menus);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public synchronized Result updateMenu(MenuDTO menuDTO) {
|
|
|
+ int menuId = menuDTO.getMenuId();
|
|
|
+ Menu menuEntity = menuRepository.getOne(menuId);
|
|
|
+ if (menuEntity == null) {
|
|
|
+ return Result.result(ResultStatus.FAIL, String.format("ID 为 %s 的 Menu 不存在", menuId));
|
|
|
+ }
|
|
|
+
|
|
|
+ int oldPos = menuEntity.getPos();
|
|
|
+ // menu 的新位置
|
|
|
+ int newPos = menuDTO.getPos()+1;
|
|
|
+ int pid = menuDTO.getPid();
|
|
|
+ if (pid != menuEntity.getPid()) {
|
|
|
+ Result result = moreThanTwoParents(pid);
|
|
|
+ if (result.getCode() != ResultStatus.SUCCESS.getCode()) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // menu 更换到了新的 menu 组
|
|
|
+ menuEntity.setPid(pid);
|
|
|
+ menuEntity.setPos(menuDTO.getPos());
|
|
|
+ insertNewMenu(menuEntity);
|
|
|
+ } else if (newPos != oldPos) {
|
|
|
+ reOrderMenus(pid, oldPos, newPos);
|
|
|
+ menuEntity.setPos(newPos);
|
|
|
+ }
|
|
|
+
|
|
|
+ menuEntity.setName(menuDTO.getName());
|
|
|
+ menuEntity.setUrl(menuDTO.getUrl());
|
|
|
+ menuEntity.setIcon(menuDTO.getIcon());
|
|
|
+ menuEntity.setUpdateTime(LocalDateTime.now());
|
|
|
+ menuRepository.save(menuEntity);
|
|
|
+
|
|
|
+ Set<Role> roles = menuDTO.getRoles();
|
|
|
+ roles.forEach(role -> role.getMenus().add(menuEntity));
|
|
|
+ roleRepository.saveAll(new ArrayList<>(roles));
|
|
|
+ return Result.result(ResultStatus.SUCCESS);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void updateMenusStatus(boolean status, List<Integer> menuIds) {
|
|
|
+ menuRepository.findAllById(menuIds).forEach(menu -> {
|
|
|
+ menu.setEnabled(status);
|
|
|
+ menuRepository.save(menu);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 对组内的菜单进行重排序,只需调整 oldPos~newPos 之间的元素位置
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ * @date 2021-07-21 上午11:07
|
|
|
+ */
|
|
|
+ private void reOrderMenus(int pid, int oldPos, int newPos) {
|
|
|
+ Map<Integer, Menu> map = menuRepository.findByPid(pid).stream()
|
|
|
+ .collect(Collectors.toMap(Menu::getPos, menu -> menu));
|
|
|
+ map.remove(oldPos);
|
|
|
+ if (newPos < oldPos) {
|
|
|
+ // 向前移动
|
|
|
+ for (int i = newPos, j = 1; i < oldPos; i++, j++) {
|
|
|
+ map.get(i).setPos(newPos+j);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 向后移动
|
|
|
+ for (int i = newPos-1, j = 1; i > oldPos; i--, j++) {
|
|
|
+ map.get(i).setPos(newPos-j);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ menuRepository.saveAll(new ArrayList<>(map.values()));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public synchronized Result deleteMenu(Integer menuId) {
|
|
|
+ Menu menu = menuRepository.getOne(menuId);
|
|
|
+
|
|
|
+ // 删除 Role 关联的 Menu
|
|
|
+ for (Role role : menu.getRoles()) {
|
|
|
+ role.getMenus().remove(menu);
|
|
|
+ roleRepository.save(role);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重新调整组内排序
|
|
|
+ int pid = menu.getPid();
|
|
|
+ List<Menu> menus = menuRepository.findByPid(pid);
|
|
|
+ menus.sort(Comparator.comparingInt(Menu::getPos));
|
|
|
+ int pos = menu.getPos();
|
|
|
+ moveForward(menus, pos);
|
|
|
+ menuRepository.delete(menu);
|
|
|
+ return Result.result(ResultStatus.SUCCESS);
|
|
|
+ }
|
|
|
+}
|