gaoshp
2024-11-03 3931e2728f618d0090f129b2665bc1285c4440c3
src/views/console/authority/role/index.vue
@@ -1,75 +1,374 @@
<template>
   <el-container>
      <el-header>
   <div class="rolePage">
      <div class="roleContainer">
         <div class="roleContainer-title">角色</div>
         <ul>
            <li v-for="(item,index) in tableData" @click="changeTabaleLi(item,index)">
               <span :class="{active: item.active}">{{item.roleName}}</span>
               <div class="scopeBtn">
                  <span style="margin-right: 12px;cursor: pointer;" @click.stop="table_edit(item, index)">重命名</span>
                  <span @click="table_del(item, index)">删除</span>
               </div>
            </li>
         </ul>
         <div class="left-panel">
            <el-button type="primary" icon="el-icon-plus" @click="add"></el-button>
            <el-button type="danger" plain icon="el-icon-delete" :disabled="selection.length==0" @click="batch_del"></el-button>
            <el-button type="primary" plain :disabled="selection.length!=1" @click="permission">权限设置</el-button>
            <el-button type="primary" icon="el-icon-plus" @click="addRole">添加角色</el-button>
         </div>
         <div class="right-panel">
            <div class="right-panel-search">
               <el-input v-model="search.keyword" placeholder="角色名称" clearable></el-input>
               <el-button type="primary" icon="el-icon-search" @click="upsearch"></el-button>
            </div>
      </div>
      <div class="role-main-tabs">
         <div class="role-main-header">
            <div class="role-main-title">账号</div>
            <ul>
               <li v-for="(item,index) in roleHeaderList" @click="changeHeaderLi(item,index)" :class="{titleActive: item.active}">{{item.realName}}</li>
               <li class="role-header-add" @click="addUser">+ 添加账号</li>
            </ul>
            <div class="role-main-title">权限管理</div>
         </div>
      </el-header>
      <el-main class="nopadding">
         <scTable ref="table" :apiObj="apiObj" row-key="id" @selection-change="selectionChange" stripe>
            <el-table-column type="selection" width="50"></el-table-column>
            <el-table-column label="#" type="index" width="50"></el-table-column>
            <el-table-column label="角色名称" prop="label" width="150"></el-table-column>
            <el-table-column label="排序" prop="sort" width="80"></el-table-column>
            <el-table-column label="操作" fixed="right" align="right" width="170">
               <template #default="scope">
                  <el-button-group>
                     <el-button text type="primary" size="small" @click="table_show(scope.row, scope.$index)">查看</el-button>
                     <el-button text type="primary" size="small" @click="table_edit(scope.row, scope.$index)">编辑</el-button>
                     <el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)">
                        <template #reference>
                           <el-button text type="primary" size="small">删除</el-button>
                        </template>
                     </el-popconfirm>
                  </el-button-group>
               </template>
            </el-table-column>
         <el-tabs tab-position="top" class="topStyle" @tab-click="topHandleClick">
            <el-tab-pane label="菜单">
               <div class="treeMain">
                  <el-tabs tab-position="left" class="demo-tabs" v-model="menuActiveName" @tab-click="(tab,event)=>menuHandleClick(tab,event,'0')">
                     <el-tab-pane v-for="(item,index) in menuGrantList" :label="item.title" :name="item.title">
                        <el-tree ref="tree0" v-if="showtree" :data="treeData" :props="{ label: 'title',children: 'children'}" node-key="id" show-checkbox @check-change="(item,isCheck)=>treeHandleCheckChange(item,isCheck,index)" :default-checked-keys="treeCheck" default-expand-all :check-strictly="true"/>
                     </el-tab-pane>
                  </el-tabs>
               </div>
            </el-tab-pane>
            <el-tab-pane label="卡片">
               <div class="treeMain">
                  <el-tabs tab-position="left" class="demo-tabs" v-model="menuActiveName" @tab-click="(tab,event)=>menuHandleClick(tab,event,'1')">
                     <el-tab-pane v-for="(item,index) in menuGrantList" :label="item.title" :name="item.title">
                        <el-tree ref="tree1" v-if="showtree" :data="treeData1" :props="{ label: 'title',children: 'children'}" node-key="id" show-checkbox @check-change="(item,isCheck)=>treeHandleCheckChange(item,isCheck,index)" :default-checked-keys="treeCheck" default-expand-all :check-strictly="true"/>
                     </el-tab-pane>
                  </el-tabs>
               </div>
            </el-tab-pane>
         </el-tabs>
         <div class="roleSubmit"><el-button type="primary" :loading="submitIsSaveing" @click="roleSubmit()">保 存</el-button></div>
      </div>
         </scTable>
      </el-main>
   </el-container>
   <save-dialog v-if="dialog.save" ref="saveDialog" @success="handleSaveSuccess" @closed="dialog.save=false"></save-dialog>
   <permission-dialog v-if="dialog.permission" ref="permissionDialog" @closed="dialog.permission=false"></permission-dialog>
      <el-dialog title="人员选择" v-model="userVisible" :width="500" destroy-on-close>
         <div>
            <el-table ref="userVisibleRef" :data="userVisibleData" style="width: 100%" @selection-change="userVisibleChange">
            <el-table-column type="selection" width="55" />
            <el-table-column label="姓名" prop="realName" />
            <el-table-column label="当前角色" prop="roleName" />
            <el-table-column label="手机号" prop="phone" />
            <el-table-column label="邮箱" prop="email" />
         </el-table>
         <el-pagination @current-change="handleCurrentChange" style="margin-top: 12px;" layout="total, prev, pager, next" :total="total" />
         </div>
         <template #footer>
            <el-button @click="userVisible=false" >取 消</el-button>
            <el-button type="primary" :loading="isSaveing" @click="userSubmit()">确 定</el-button>
         </template>
      </el-dialog>
      <save-dialog v-if="dialog.save" ref="saveDialog" @success="handleSaveSuccess" @closed="dialog.save=false"></save-dialog>
   </div>
</template>
<script>
   import saveDialog from './save'
   import permissionDialog from './permission'
   export default {
      name: 'role',
      components: {
         saveDialog,
         permissionDialog
         saveDialog
      },
      data() {
         return {
            templateGrantTreeCard: [],  //临时存储/menu/grant-tree中的card
            menuHandleText: "",
            showtree: true,
            treeCheck: [],
            menuActiveName: "",
            treeData: [],
            treeData1: [],
            menuGrantList: [],
            total: 0,
            searchData: {
               current: 1,
               size: 10
            },
            tableLiId: "", //当前角色id
            isSaveing: false,
            submitIsSaveing: false,
            userVisibleData: [],
            userVisible: false,
            roleHeaderList: [],
            menu: {
               list: [],
               checked: [],
               props: {
                  label: (data)=>{
                     return data.meta.title
                  }
               }
            },
            grid: {
               list: [],
               checked: ["welcome", "ver", "time", "progress", "echarts", "about"],
               props: {
                  label: (data)=>{
                     return data.title
                  },
                  disabled: (data)=>{
                     return data.isFixed
                  }
               }
            },
            dialog: {
               save: false,
               permission: false
            },
            //apiObj: this.$API.system.role.list,
            apiObj: "",
            selection: [],
            search: {
               keyword: null
            }
            tableData: "",
            userSelection: []
         }
      },
      mounted(){
         this.getRoleList();  //角色列表
         this.getUser();  //获取全部账号
      },
      methods: {
         roleSubmit() {  //保存
            var cardIdArrId = [];  //默认增加全局卡片
            this.templateGrantTreeCard.forEach(item=> {
               if(item.code == "desk") {
                  cardIdArrId.push(item.id);
                  item.children.forEach(item1=> {
                     cardIdArrId.push(item1.id);
                  })
               }
            })
            var list = [...new Set([...cardIdArrId, ...this.treeCheck])];;  //新数组,cardIdArr和this.treeCheck合并
            var obj = {
               apiScopeIds: [],
               dataScopeIds: [],
               menuIds: list,
               roleIds: [this.tableLiId]
            }
            this.isSaveing = true;
            this.$HTTP.post(`/api/blade-system/role/grant`,obj).then(res=> {
               this.isSaveing = false;
               if(res.code == 200) {
                  this.$message.success("操作成功");
               }
            })
         },
         topHandleClick(tab,event) {
            if(this.menuHandleText == "") {
               this.menuHandleText = this.menuGrantList[0].title;
            }
            if(event.target.innerText == "菜单") {
               this.setTreeList(this.menuGrantList,this.menuHandleText,'0');  //tree
            }
            if(event.target.innerText == "卡片") {
               this.setTreeList(this.menuGrantList1,this.menuHandleText,'1');  //tree
            }
         },
         menuHandleClick(tab, event,index) {
            if(index == 0) {
               this.setTreeList(this.menuGrantList,event.target.innerText,index);  //tree
            }
            if(index == 1) {
               this.setTreeList(this.menuGrantList1,event.target.innerText,index);  //tree
            }
            this.menuHandleText = event.target.innerText;
         },
         treeHandleCheckChange(item,isCheck,index) {
            var that = this;
            if(isCheck) {
               function checkoutId(val){
                  if(!that.treeCheck.includes(val.id)) {
                     that.treeCheck.push(val.id);
                  }
                  if(val.children) {
                     val.children.forEach(item1=> {
                        checkoutId(item1);
                     })
                  }
               }
               checkoutId(item);
               that.$refs.tree0[index].setCheckedKeys(this.treeCheck,false);
            }else {  //取消选中
               if(item.children) {  //有children
                  function delCheckoutId(val){
                     that.treeCheck.forEach((val1,valIndex)=> {
                        if(val1 == val.id) {
                           that.treeCheck.splice(valIndex,1);
                        }
                     })
                     if(val.children) {
                        val.children.forEach(item1=> {
                           delCheckoutId(item1);
                        })
                     }
                  }
                  delCheckoutId(item);
                  that.$refs.tree0[index].setCheckedKeys(this.treeCheck,false);
               }else {  //没有children
                  if(this.treeCheck.length != 0) {
                     this.treeCheck.forEach((val,valIndex)=> {
                        if(val == item.id) {
                           this.treeCheck.splice(valIndex,1);
                        }
                     })
                  }
               }
            }
         },
         setTreeList(arr,name,index=0) {
            this.treeData = [];
            this.treeData1 = [];
            arr.forEach(item=> {
               if(item.title == name) {
                  if(index == '0') {
                     this.treeData = item.children;
                  }
                  if(index == '1') {
                     this.treeData1 = item.children;
                  }
               }
            })
         },
         extractLastLevelIds(array) {  //递归获取children最后一级的id的数组
            let ids = [];
            for (let i = 0; i < array.length; i++) {
               const obj = array[i];
               if (obj.children) {
                  // 递归调用以提取更深层级的children中的id
                  ids = ids.concat(this.extractLastLevelIds(obj.children));
               } else {
                  // 如果没有children属性,则假定当前对象是最后一级
                  if (obj.id) {
                     ids.push(obj.id);
                  }
               }
            }
            return ids;
         },
         findOverlap(array1, array2) {   //找出两个数组重合的部分
            // 创建一个集合(Set)来存储第二个数组中的元素,以便于快速查找
            const set = new Set(array2);
            // 使用filter方法过滤出第一个数组中在集合中存在的元素
            const overlap = array1.filter(item => set.has(item));
            return overlap;
         },
         getSelectTree(res,id,index) {//获取已选数据
            this.$HTTP.get(`/api/blade-system/menu/role-tree-keys?roleIds=${id}`).then(resp=> {
               if(resp.code == 200) {
                  this.tableData.forEach(item=> {
                     item.active = false;
                  })
                  this.tableData[index].active = true;  //左侧切换角色选中
                  this.showtree = false;
                  this.tableLiId = id;  //角色id
                  this.$nextTick(()=> {
                     this.showtree = true;
                     //菜单
                     this.menuGrantList = res.data.menu.filter(item=> { //过滤掉没有children的,这里是res,不是resp,是菜单tree左侧的选项
                        return item.children;
                     });
                     //卡片
                     this.menuGrantList1 = [];  //card的tree左侧的选项
                     res.data.card.forEach(item=> {
                        this.menuGrantList.forEach(item1=> {
                           if(item.id == item1.id) {
                              this.menuGrantList1.push(item);
                           }
                        })
                     })
                     this.menuActiveName = this.menuGrantList[0].title;//默认第一个菜单
                     this.setTreeList(this.menuGrantList,this.menuActiveName);//展示树(左侧菜单list,左侧菜单名字)
                     var idarr = resp.data.menu.concat(resp.data.card);
                     this.treeCheck = [...new Set(idarr)];  //获取选中数据
                     // var lastId = [];
                     // var lastId = this.extractLastLevelIds(this.menuGrantList);  //获取最后一级id
                     // var idarr = this.findOverlap(lastId,resp.data.menu); //找出两个数组重合的部分
                     // var lastId1 = [];
                     // var lastId1 = this.extractLastLevelIds(this.menuGrantList1);  //获取最后一级id
                     // var idarr1 = this.findOverlap(lastId1,resp.data.card); //找出两个数组重合的部分
                     // this.treeCheck = [...idarr,...idarr1];  //获取选中数据
                  })
               }
            })
         },
         getMenuGrant(row,index) {
            this.$HTTP.get(`/api/blade-system/menu/grant-tree`).then(res=> {
               if(res.code == 200) {
                  this.templateGrantTreeCard = res.data.card;  //临时存储/menu/grant-tree中的card
                  //获取已选数据  (树的数据,角色id)
                  this.getSelectTree(res,row.id,index);
               }
            })
         },
         userSubmit() {
            var ids = [];
            this.userSelection.forEach(item=> {
               ids.push(item.id);
            })
            this.isSaveing = true;
            this.$HTTP.post(`/api/blade-user/${this.tableLiId}/save`,{ids}).then(res=> {
               this.isSaveing = false;
               if(res.code == 200) {
                  this.userVisible = false;
                  this.$message.success("操作成功");
                  this.$HTTP.get(`/api/blade-user/${this.tableLiId}/list`).then(res=> {
                     if(res.code == 200) {
                        this.roleHeaderList = res.data;
                     }
                  })
               }
            })
         },
         userVisibleChange(selection) {
            this.userSelection = selection;
         },
         addUser() {  //添加账号
            this.userVisible = true;
         },
         getUser() {  //获取全部账号
            this.$HTTP.get(`/api/blade-user/page?current=${this.searchData.current}&size=10&deptId=`).then(res=> {
               if(res.code == 200) {
                  this.userVisibleData = res.data.records;
                  this.total = res.data.total;
               }
            })
         },
         getBladeList(row,index) {  //人员列表
            this.$HTTP.get(`/api/blade-user/${row.id}/list`).then(res=> {
               if(res.code == 200) {
                  this.roleHeaderList = res.data;
                  this.getMenuGrant(row,index);   //获取tree
               }
            })
         },
         changeHeaderLi(row,index) {
            this.roleHeaderList.forEach(item=> {
               item.active = false;
            })
            this.roleHeaderList[index].active = true;
         },
         changeTabaleLi(row,index) {
            this.getBladeList(row,index);  //获取人员列表
         },
         getRoleList() {
            this.$HTTP.get("/api/blade-system/role/list?current=1&size=1000").then(res=> {
               if(res.code == 200) {
                  res.data[0].active = true;
                  this.tableData = res.data;
                  this.getBladeList(this.tableData[0],0);  //默认第一个角色获
               }
            })
         },
         //添加
         add(){
         addRole(){
            this.dialog.save = true
            this.$nextTick(() => {
               this.$refs.saveDialog.open()
@@ -79,7 +378,7 @@
         table_edit(row){
            this.dialog.save = true
            this.$nextTick(() => {
               this.$refs.saveDialog.open('edit').setData(row)
               this.$refs.saveDialog.open('edit').setData(row);
            })
         },
         //查看
@@ -89,33 +388,18 @@
               this.$refs.saveDialog.open('show').setData(row)
            })
         },
         //权限设置
         permission(){
            this.dialog.permission = true
            this.$nextTick(() => {
               this.$refs.permissionDialog.open()
            })
         },
         //删除
         async table_del(row){
            var reqData = {id: row.id}
            var res = await this.$API.demo.post.post(reqData);
            if(res.code == 200){
               this.$refs.table.refresh()
               this.$message.success("删除成功")
            }else{
               this.$alert(res.message, "提示", {type: 'error'})
            }
         },
         //批量删除
         async batch_del(){
            this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?如果删除项中含有子集将会被一并删除`, '提示', {
         table_del(row) {
            var that = this;
            this.$confirm(`是否删除角色-${row.roleName}?`, '', {
               type: 'warning'
            }).then(() => {
               const loading = this.$loading();
               this.$refs.table.refresh()
               loading.close();
               this.$message.success("操作成功")
               this.$HTTP.post("/api/blade-system/role/remove?ids="+row.id).then(res=> {
                  if(res.code == 200) {
                     that.$message.success("操作成功");
                     that.getRoleList();  //角色列表
                  }
               })
            }).catch(() => {
            })
@@ -133,10 +417,6 @@
               row.status = val;
               this.$message.success("操作成功")
            }, 500)
         },
         //搜索
         upsearch(){
         },
         //根据ID获取树结构
         filterTree(id){
@@ -156,15 +436,122 @@
         },
         //本地更新数据
         handleSaveSuccess(data, mode){
            if(mode=='add'){
               this.$refs.table.refresh()
            }else if(mode=='edit'){
               this.$refs.table.refresh()
            }
            this.getRoleList();  //角色列表
         },
         handleCurrentChange(val) {
            console.log(`当前页: ${val}`);
            this.searchData.current = val;
            this.getUser();
         }
      }
   }
</script>
<style scoped>
.rolePage {
   display: flex;
}
.rolePage .roleContainer {
   max-width:300px;
   width:300px;
   margin-right: 8px;
   height: 100%;
   margin-top:8px;
   margin-left:8px;
   background-color: #fff;
   padding-bottom:8px;
}
.roleContainer-title {
   height: 41px;
   line-height: 41px;
   font-size: 14px;
   text-align: center;
   background-color: #409eff;
   color: #fff;
}
.rolePage .roleContainer ul {
}
.rolePage .roleContainer ul li{
   height:42px;
   line-height: 42px;
   list-style-type: none;
   color: #606266;
   display: flex;
   justify-content: space-between;
   border-bottom: 1px solid #ebeef5;
   padding-left: 8px;
   padding-right: 8px;
   cursor: pointer;
}
.rolePage .roleContainer ul li .active {
   font-weight: bold;
   color: #409eff;
}
.rolePage .roleContainer ul li:hover {
   background-color: #f5f7fa;
}
.rolePage .roleContainer ul li .scopeBtn {
   color: #409eff;
}
.rolePage .roleContainer .left-panel {
   text-align: center;
   margin-top:8px;
}
.rolePage .role-main-tabs {
   flex: 1;
   background-color: #fff;
   padding: 8px;
   margin-top:8px;
   margin-right:8px;
}
.role-main-title {
   padding: 6px 10px;
    font-size: 14px;
    background-color: #9dc7f2;
    margin-bottom: 8px;
    border-radius: 2px;
}
.role-main-header ul {
   padding: 20px 20px 10px;
}
.role-main-header ul li {
   list-style-type: none;
   display: inline-block;
   width: 200px;
    padding: 8px 20px;
    margin: 0 10px 10px 0;
    border: 1px solid #e5e5e5;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.role-main-header ul li.titleActive {
   border: 1px solid #409eff;
}
.role-main-header ul li.role-header-add {
   display: inline-block;
   border: 1px dashed #e5e5e5;
}
.treeMain {
   position: relative;
   margin-bottom: 60px;
}
.roleSubmit {
   bottom: 0;
    position: fixed;
    width: 100%;
    text-align: right;
    right: 0;
    padding-right: 20px;
    padding-bottom: 12px;
    background: #fff;
    z-index: 11;
}
</style>
<style>
.topStyle .el-tabs__header .el-tabs__nav-scroll .el-tabs__item{
   padding-left: 20px;
}
</style>