ludc
2023-07-26 16d2a38e7bb7a31d6e355d031115a58bffd0109d
增加菜单管理中,从其他菜单克隆按钮功能、
已修改7个文件
已添加1个文件
380 ■■■■■ 文件已修改
Source/UBCS-WEB/src/api/system/menu.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS-WEB/src/views/system/menu.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS-WEB/vue.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-system-api/src/main/java/com/vci/ubcs/system/vo/ButtonCloneVO.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeClassifyTemplateAttrServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-system/src/main/java/com/vci/ubcs/system/controller/MenuController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-system/src/main/java/com/vci/ubcs/system/service/IMenuService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-system/src/main/java/com/vci/ubcs/system/service/impl/MenuServiceImpl.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS-WEB/src/api/system/menu.js
@@ -106,3 +106,9 @@
    topMenuId,
  }
});
export const cloneMenuButton = (data) => request({
  url: '/api/ubcs-system/menu/cloneMenuButton',
  method: 'post',
  data: data
});
Source/UBCS-WEB/src/views/system/menu.vue
@@ -32,7 +32,7 @@
          size="small"
          icon="el-icon-connection"
          plain
          @click="cloneButton">从其他菜单克隆按钮
          @click="cloneMenuButton">从其他菜单克隆按钮
        </el-button>
      </template>
      <template slot-scope="scope" slot="menu">
@@ -52,25 +52,40 @@
        </div>
      </template>
    </avue-crud>
    <!-- ä»Žå…¶ä»–菜单克隆按钮 -->
    <el-dialog title="从其他菜单克隆按钮"
        append-to-body
        :visible.sync="cloneButtonSettingBox"
        width="800px"
        style="height: 116vh; margin-top: -10vh;">
        <avue-crud
          :option="dialogeOption"
          :table-loading="dialogLoading"
          :data="useRangeData"
          @refresh-change="refreshUseRangeChange">
        :visible.sync="cloneOtherMenuButtons.cloneButtonSettingBox"
        width="1100px"
        @close="cleanCloneSelections"
        style="height: 110vh; margin-top: -10vh;">
        <avue-crud :option="cloneOtherMenuButtons.cloneOption"
          :table-loading="cloneOtherMenuButtons.cloneLoading"
          :data="cloneOtherMenuButtons.cloneData"
          ref="cloneCrud"
          @search-change="searchCloneChange"
          @search-reset="searchCloneReset"
          @selection-change="selectionCloneChange"
          @row-click="clickRowCloneChange"
          @refresh-change="refreshCloneChange"
          @on-load="cloneOnLoad"
          @tree-load="treeLoad">
          <template slot-scope="{row}" slot="source">
            <div style="text-align:center">
              <i :class="row.source"/>
            </div>
          </template>
        </avue-crud>
      </el-dialog>
        <div slot="footer" class="dialog-footer">
          <el-button type="primary" @click="cloneButtonsToMenu">保 å­˜</el-button>
          <el-button @click="cloneOtherMenuButtons.cloneButtonSettingBox = false">取 æ¶ˆ</el-button>
        </div>
    </el-dialog>
  </basic-container>
</template>
<script>
  import {getLazyList, remove, update, add, getMenu} from "@/api/system/menu";
  import {getLazyList, remove, update, add, getMenu ,cloneMenuButton} from "@/api/system/menu";
  import {mapGetters} from "vuex";
  import iconList from "@/config/iconList";
  import func from "@/util/func";
@@ -275,7 +290,130 @@
        // ä»Žå…¶ä»–菜单克隆按钮
        cloneOtherMenuButtons: {
          cloneButtonSettingBox: false,
          selectCloneButtons: [],
          cloneOption: {
            height: "auto",
            menu: false,
            addBtn: false,
            lazy: true,
            tip: false,
            simplePage: true,
            searchShow: true,
            searchMenuSpan: 6,
            dialogWidth: "60%",
            tree: true,
            border: true,
            index: true,
            selection: true,
            columnBtn: false,
            searchShowBtn: false,
            menuWidth: 300,
            dialogClickModal: false,
            highlightCurrentRow: true, //行选中时高亮
            column: [
              {
                label: "菜单名称",
                prop: "name",
                search: true,
              },
              {
                label: "路由地址",
                prop: "path",
              },
              {
                label: "上级菜单",
                prop: "parentId",
                type: "tree",
                hide: true,
                addDisabled: false,
                props: {
                  label: "title"
                },
              },
              {
                label: "菜单图标",
                prop: "source",
                type: "icon",
                slot: true,
                iconList: iconList,
              },
              {
                label: "菜单编号",
                prop: "code",
                search: true,
              },
              {
                label: "菜单类型",
                prop: "category",
                type: "radio",
                dicData: [
                  {
                    label: "菜单",
                    value: 1
                  },
                  {
                    label: "按钮",
                    value: 2
                  }
                ],
              },
              {
                label: "菜单别名",
                prop: "alias",
                search: true,
              },
              {
                label: "新窗口",
                prop: "isOpen",
                type: "radio",
                dicData: [
                  {
                    label: "否",
                    value: 1
                  },
                  {
                    label: "是",
                    value: 2
                  }
                ],
              },
              {
                label: "菜单排序",
                prop: "sort",
                type: "number",
              },
              {
                label: "路由缓存",
                prop: "keepAlive",
                type: "switch",
                dicData: [
                  {
                    label: "否",
                    value: "false"
                  },
                  {
                    label: "是",
                    value: "true"
                  }
                ],
              },
              {
                label: "菜单备注",
                prop: "remark",
                type: "textarea",
                span: 24,
                minRows: 2,
              }
            ]
          },
          cloneLoading: false,
          cloneData: [],
          cloneQuery: {},
          clonePage: {
            pageSize: 10,
            currentPage: 1,
            total: 0,
          },
        }
      };
    },
@@ -311,6 +449,108 @@
      }
    },
    methods: {
      /** ä»Žå…¶ä»–菜单克隆按钮 */
      cloneMenuButton(){
        if(this.selectionList.length != 1 || this.selectionList[0].category === 2){
          this.$message({
            type: "warning",
            message: "请选择一条非按钮类型的数据!"
          });
          return;
        }
        this.cloneOtherMenuButtons.cloneButtonSettingBox = true;
      },
      /** å…‹éš†æŒ‰é’®åˆ°é€‰ä¸­çš„菜单下 */
      cloneButtonsToMenu(){
        if(this.selectionList.length != 1){
          this.$message({
            type: "warning",
            message: "要克隆按钮的菜单信息已丢失,请重新选择!"
          });
          return;
        }
        if(this.cloneOtherMenuButtons.selectCloneButtons.length <= 0){
          this.$message({
            type: "warning",
            message: "请选择要克隆按钮数据!"
          });
          return;
        }
        this.$confirm("确定将选中的按钮克隆到【"+this.selectionList[0].name+"】菜单中?", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "info"
        })
        .then(() => {
          let buttonIds = [];
          let flag = true;
          this.cloneOtherMenuButtons.selectCloneButtons.forEach(function(item) {
            if(item.category != 2){
              flag = false;
            }else {
              buttonIds.push(item.id);
            }
          });
          // é€‰æ‹©äº†éžæŒ‰é’®ç±»åž‹çš„æ•°æ®
          if(!flag){
            this.$message({
              type: "warning",
              message: "只能选择按钮类型的表格行!"
            });
            return;
          }
          // console.log(buttonIds);
          return cloneMenuButton({"menuId":this.selectionList[0].id,"buttonIds": buttonIds});
        })
        .then(res => {
          this.$message({
            type: res.data.success ? "success":"error",
            message: res.data.msg,
          });
          this.cloneOtherMenuButtons.cloneButtonSettingBox = false;
          // æ•°æ®å›žè°ƒè¿›è¡Œåˆ·æ–°
          this.onLoad(this.page);
        });
      },
      /** é€‰ä¸­è¢«å…‹éš†çš„æŒ‰é’®æ—¶è§¦å‘ */
      selectionCloneChange(list) {
        this.cloneOtherMenuButtons.selectCloneButtons = list;
        this.$refs.cloneCrud.setCurrentRow(this.cloneOtherMenuButtons.selectCloneButtons[list.length-1]);
      },
      clickRowCloneChange(row){
        this.cloneOtherMenuButtons.selectCloneButtons.push(row);
        this.$refs.cloneCrud.setCurrentRow(row);
        this.$refs.cloneCrud.toggleRowSelection(row); //选中当前行
      },
      /** å…³é—­å¯¹è¯æ¡†æ—¶æ¸…空选中的列表 */
      cleanCloneSelections(){
        this.cloneOtherMenuButtons.selectCloneButtons = [];
        this.$refs.cloneCrud.toggleSelection();
      },
      cloneOnLoad(page, params = {}) {
        this.cloneOtherMenuButtons.cloneLoading = true;
        getLazyList(this.parentId, Object.assign(params, this.cloneOtherMenuButtons.cloneQuery)).then(res => {
          this.cloneOtherMenuButtons.cloneData = res.data.data;
          this.cloneOtherMenuButtons.cloneLoading = false;
        });
      },
      searchCloneChange(params, done){
        this.cloneOtherMenuButtons.cloneQuery = params;
        this.parentId = '';
        this.cloneOtherMenuButtons.clonePage.currentPage = 1;
        this.cloneOnLoad(this.cloneOtherMenuButtons.clonePage, params);
        done();
      },
      searchCloneReset(){
        this.cloneOtherMenuButtons.cloneQuery = {};
        this.parentId = 0;
        this.cloneOnLoad(this.cloneOtherMenuButtons.clonePage);
      },
      refreshCloneChange(){
        this.onLoad(this.cloneOtherMenuButtons.clonePage, this.cloneOtherMenuButtons.cloneQuery);
      },
      initData() {
        getMenuTree().then(res => {
          const column = this.findObject(this.option.column, "parentId");
@@ -359,17 +599,17 @@
          cancelButtonText: "取消",
          type: "warning"
        })
          .then(() => {
            return remove(row.id);
          })
          .then(() => {
            this.$message({
              type: "success",
              message: "操作成功!"
            });
            // æ•°æ®å›žè°ƒè¿›è¡Œåˆ·æ–°
            done(row);
        .then(() => {
          return remove(row.id);
        })
        .then(() => {
          this.$message({
            type: "success",
            message: "操作成功!"
          });
          // æ•°æ®å›žè°ƒè¿›è¡Œåˆ·æ–°
          done(row);
        });
      },
      handleDelete() {
        if (this.selectionList.length === 0) {
@@ -397,10 +637,6 @@
              message: "操作成功!"
            });
          });
      },
      /** ä»Žå…¶ä»–菜单克隆按钮 */
      cloneButton(){
      },
      searchReset() {
        this.query = {};
Source/UBCS-WEB/vue.config.js
@@ -26,10 +26,10 @@
    proxy: {
      '/api': {
        //本地服务接口地址
        // target: 'http://localhost:37000',
        target: 'http://localhost:37000',
        // target: 'http://192.168.1.51:37000',
        // target: 'http://192.168.1.46:37000',
        target: 'http://dev.vci-tech.com:37000',
        // target: 'http://dev.vci-tech.com:37000',
        // target: 'http://192.168.1.51:37000/',
        // target: 'http://192.168.1.104:37000',
        // target: 'http://192.168.1.63:37000',
Source/UBCS/ubcs-service-api/ubcs-system-api/src/main/java/com/vci/ubcs/system/vo/ButtonCloneVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.vci.ubcs.system.vo;
import lombok.Data;
import java.util.List;
/**
 * @author ludc
 * @date 2023/7/26 12:11
 */
@Data
public class ButtonCloneVO {
    private Long menuId;
    private List<String> buttonIds;
}
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeClassifyTemplateAttrServiceImpl.java
@@ -712,7 +712,7 @@
            return dataGrid;
        }
        //这个业务类型下的所有属性
        R<BtmTypeVO> btmTypeVOR = btmTypeClient.getAllAttributeByBtmOid(codeClassifyTemplateDO.getBtmTypeId());
        R<BtmTypeVO> btmTypeVOR = btmTypeClient.getAllAttributeByBtmId(codeClassifyTemplateDO.getBtmTypeId());
        if(!btmTypeVOR.isSuccess()){
            throw new ServiceException("业务类型feign调用错误!");
        }
Source/UBCS/ubcs-service/ubcs-system/src/main/java/com/vci/ubcs/system/controller/MenuController.java
@@ -24,6 +24,7 @@
import com.vci.ubcs.system.entity.TopMenu;
import com.vci.ubcs.system.service.IMenuService;
import com.vci.ubcs.system.service.ITopMenuService;
import com.vci.ubcs.system.vo.ButtonCloneVO;
import com.vci.ubcs.system.vo.CheckedTreeVO;
import com.vci.ubcs.system.vo.GrantTreeVO;
import com.vci.ubcs.system.vo.MenuVO;
@@ -285,4 +286,15 @@
        }
        return R.data(menuService.authRoutes(user));
    }
    /**
     * å…‹éš†å…¶ä»–菜单下按钮
     * @param buttonCloneVO è¦å…‹éš†çš„菜单按钮主键 è¢«å…‹éš†çš„æŒ‰é’®ä¸»é”®
     * @return
     */
    @PostMapping("/cloneMenuButton")
    public R cloneMenuButton(@RequestBody ButtonCloneVO buttonCloneVO) {
        return menuService.cloneMenuButton(buttonCloneVO.getMenuId(), buttonCloneVO.getButtonIds());
    }
}
Source/UBCS/ubcs-service/ubcs-system/src/main/java/com/vci/ubcs/system/service/IMenuService.java
@@ -182,4 +182,12 @@
     */
    void handleKeepAlive(List<MenuVO> childMenu);
    /**
     * å…‹éš†å…¶ä»–菜单下按钮
     * @param menuId è¦å…‹éš†çš„菜单按钮主键
     * @param buttonIds è¢«å…‹éš†çš„æŒ‰é’®ä¸»é”®
     * @return
     */
    R cloneMenuButton(Long menuId, List<String> buttonIds);
}
Source/UBCS/ubcs-service/ubcs-system/src/main/java/com/vci/ubcs/system/service/impl/MenuServiceImpl.java
@@ -323,4 +323,44 @@
        });
    }
    /**
     * å…‹éš†å…¶ä»–菜单下按钮
     * @param menuId è¦å…‹éš†çš„菜单按钮主键
     * @param buttonIds è¢«å…‹éš†çš„æŒ‰é’®ä¸»é”®
     * @return
     */
    @Override
    public R cloneMenuButton(Long menuId, List<String> buttonIds) {
        if(Func.isEmpty(menuId)){
            return R.fail("要克隆的菜单主键不能为空!");
        }
        if(buttonIds.isEmpty() || buttonIds.size() <= 0){
            return R.fail("被克隆的按钮主键不能为空!");
        }
        // å…ˆæ ¹æ®ä¸»é”®æŸ¥è¯¢å‡ºæ‰€æœ‰æŒ‰é’®çš„信息
        List<Menu> buttons = this.listByIds(buttonIds);
        List<Menu> newButtons = new ArrayList<>();
        List<String> addButtonCodes = new ArrayList();
        buttons.parallelStream().forEach(item->{
            // åˆ¤æ–­æ˜¯å¦ä¸ºæŒ‰é’®ï¼ŒéžæŒ‰é’®ä¸å¤„理
            if(item.getCategory().equals(2)){
                // æ”¹å˜çˆ¶èŠ‚ç‚¹ä¿¡æ¯
                item.setParentId(menuId);
                // å°†ä¸»é”®èµ‹ç©º
                item.setId(null);
                addButtonCodes.add(item.getCode());
                newButtons.add(item);
            }
        });
        //检验是否重复菜单别名,只校验同一父分类菜单下的编号是否重复
        LambdaQueryWrapper<Menu> menuQueryWrapper = Wrappers.<Menu>lambdaQuery()
            .eq(Menu::getParentId,menuId)
            .and(a -> a.in( Menu::getCode, addButtonCodes));
        Long cnt = baseMapper.selectCount(menuQueryWrapper);
        if (cnt > 0L) {
            return R.fail("该菜单下已存在的编号与要克隆的按钮编号存在重复!");
        }
        return this.saveBatch(newButtons) ? R.success("按钮克隆成功!"):R.fail("按钮克隆失败!");
    }
}