feat(xumu): 新增应用角色权限管理功能
- 添加 AppRoleRightsManager 组件,实现角色管理、权限分配等功能 - 新增 rightsAdd 组件,用于添加和编辑应用角色 - 新增 rightsGraph 组件,用于展示权限关系图 - 集成 ECharts 实现复杂的权限关系可视化
This commit is contained in:
416
project/xumu/AppRoleRightsManager/AppRoleRightsManager.vue
Normal file
416
project/xumu/AppRoleRightsManager/AppRoleRightsManager.vue
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
<template>
|
||||||
|
<section class="AppRoleRightsManager">
|
||||||
|
<ai-list v-if="!showDetail">
|
||||||
|
<ai-title slot="title" title="角色管理" isShowBottomBorder/>
|
||||||
|
<template #content>
|
||||||
|
<ai-search-bar>
|
||||||
|
<template #left>
|
||||||
|
<el-button size="small" type="primary" icon="iconfont iconAdd"
|
||||||
|
@click="$router.push({hash:'#add'})"
|
||||||
|
v-if="$permissions('admin_sysapprole_add')">
|
||||||
|
添加
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
icon="iconfont iconDelete"
|
||||||
|
:disabled="!multipleSelection.length"
|
||||||
|
class="del-btn-list"
|
||||||
|
@click="deleteApp('all')"
|
||||||
|
v-if="$permissions('admin_sysapprole_del')"
|
||||||
|
>删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<template #right>
|
||||||
|
<el-input
|
||||||
|
size="small"
|
||||||
|
v-model="search.roleName"
|
||||||
|
placeholder="角色名称"
|
||||||
|
clearable
|
||||||
|
@change="searchList()"
|
||||||
|
suffix-icon="iconfont iconSearch"/>
|
||||||
|
</template>
|
||||||
|
</ai-search-bar>
|
||||||
|
<ai-table :tableData="adminList" :colConfigs="colConfigs" :total="total" :current.sync="page.pageNum"
|
||||||
|
:size.sync="page.pageSize"
|
||||||
|
@getList="getTableData" :col-configs="colConfigs" :dict="dict"
|
||||||
|
@selection-change="v=>multipleSelection=v">
|
||||||
|
<el-table-column label="角色用户" slot="users" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tooltip
|
||||||
|
effect="light"
|
||||||
|
placement="top"
|
||||||
|
:disabled="scope.row.users.length <= 2"
|
||||||
|
content="更多角色用户请点击详情按钮">
|
||||||
|
<span v-if="scope.row.users.length">
|
||||||
|
{{
|
||||||
|
scope.row.users
|
||||||
|
.slice(0, 2)
|
||||||
|
.map((e) => e.name + "(" + e.phone + ")")
|
||||||
|
.join(";")
|
||||||
|
}}
|
||||||
|
<span v-if="scope.row.users.length > 2">...</span>
|
||||||
|
</span>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column slot="options" label="操作" fixed="right" align="center">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button type="text" @click="beforeCopy(row)" v-if="$permissions('admin_sysapprole_edit')">复制
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" @click="viewApp(row)" v-if="$permissions('admin_sysapprole_detail')">详情
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" @click="openRightsGraph(row)" v-if="$permissions('admin_sysapprole_detail')">关系图
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" @click="toAddAppRole(row)" v-if="$permissions('admin_sysapprole_edit')">编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" @click="deleteApp(row)" v-if="$permissions('admin_sysapprole_del')">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</ai-table>
|
||||||
|
<ai-dialog
|
||||||
|
title="应用角色详情"
|
||||||
|
:visible.sync="viewShow"
|
||||||
|
width="600px"
|
||||||
|
customFooter>
|
||||||
|
<ai-card title="基本信息">
|
||||||
|
<template #content>
|
||||||
|
<ai-wrapper>
|
||||||
|
<ai-info-item label="应用角色名称" :value="viewInfo.name" isLine/>
|
||||||
|
</ai-wrapper>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
<ai-card title="权限信息">
|
||||||
|
<template #content>
|
||||||
|
<div style="margin-bottom: 16px" v-text="roleList.map(e => e.name).join('、')"/>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
<ai-card title="角色账号">
|
||||||
|
<template #right>
|
||||||
|
<span style="text-align: right; color: #999">
|
||||||
|
共<span style="color: #26f" v-text="userList.length"/>个账号
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<div class="datail-table-body" v-if="userList.length">
|
||||||
|
<div class="datail-item" v-for="(item, index) in userList" :key="index">
|
||||||
|
<span class="item-name">{{ item.name }}</span>
|
||||||
|
<span style="color: #999">{{ item.phone }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
<template #footer>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="toAddAppRole(viewInfo)"
|
||||||
|
v-if="$permissions('admin_sysapprole_edit')"
|
||||||
|
>编辑角色
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</ai-dialog>
|
||||||
|
<ai-dialog title="权限关系图" :visible.sync="rightsGraph" class="rightsGraphDialog" customFooter>
|
||||||
|
<rights-graph :instance="instance" :dict="dict" :app="selectApp"/>
|
||||||
|
<el-button slot="footer" @click="rightsGraph=false">关闭</el-button>
|
||||||
|
</ai-dialog>
|
||||||
|
<!--复制角色-->
|
||||||
|
<el-dialog
|
||||||
|
class="editStyle"
|
||||||
|
:visible.sync="copyDialog"
|
||||||
|
width="520px"
|
||||||
|
@close="dataInit()"
|
||||||
|
title="复制角色">
|
||||||
|
<el-form :model="form" label-width="80px">
|
||||||
|
<el-form-item label="角色名" :rules="[{ required: true, message: '', trigger: 'blur' }]">
|
||||||
|
<el-input
|
||||||
|
v-model="editName"
|
||||||
|
placeholder="请输入..."
|
||||||
|
size="small"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" style="text-align: center">
|
||||||
|
<el-button
|
||||||
|
style="width: 92px"
|
||||||
|
size="small"
|
||||||
|
@click="copyDialog = false"
|
||||||
|
>取消
|
||||||
|
</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
style="width: 92px"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="copyFn()"
|
||||||
|
:disabled="!editName"
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
</ai-list>
|
||||||
|
<rights-add v-else :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import RightsAdd from "./rightsAdd";
|
||||||
|
import RightsGraph from "./rightsGraph";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "AppRoleRightsManager",
|
||||||
|
components: {RightsGraph, RightsAdd},
|
||||||
|
label: "角色管理",
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
top: this
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
instance: Function,
|
||||||
|
dict: Object,
|
||||||
|
permissions: Function,
|
||||||
|
actions: {
|
||||||
|
default: () => ({
|
||||||
|
list: '/admin/role/page',
|
||||||
|
apps: '/admin/role/list-all',
|
||||||
|
delete: '/admin/role/del',
|
||||||
|
detail: '/admin/role/queryById-checked',
|
||||||
|
modify: '/admin/role/modify',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
colConfigs() {
|
||||||
|
return [
|
||||||
|
{type: "selection"},
|
||||||
|
{label: "角色名", prop: "name", width: '100px'},
|
||||||
|
{label: "所属端", prop: "type", width: '100px', dict: "roleType"},
|
||||||
|
{label: "用户数量", prop: "roleCount", align: 'center', width: '80px'},
|
||||||
|
{slot: "users"},
|
||||||
|
{slot: "options"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
showDetail() {
|
||||||
|
return this.$route.hash == "#add"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
page: {pageNum: 1, pageSize: 10},
|
||||||
|
search: {roleName: ''},
|
||||||
|
adminList: [], //列表数据
|
||||||
|
total: 0,
|
||||||
|
multipleSelection: [],
|
||||||
|
delShow: false,
|
||||||
|
delParams: "",
|
||||||
|
delIds: [],
|
||||||
|
viewShow: false,
|
||||||
|
viewInfo: {},
|
||||||
|
roleList: [], //详情权限列表
|
||||||
|
row: {},
|
||||||
|
copyDialog: false,
|
||||||
|
titleDel: "",
|
||||||
|
form: {},
|
||||||
|
editName: "",
|
||||||
|
userList: [],
|
||||||
|
rightsGraph: false,
|
||||||
|
selectApp: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getTableData();
|
||||||
|
this.dict.load('roleType')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
//查询table列表
|
||||||
|
getTableData() {
|
||||||
|
this.adminList = [];
|
||||||
|
this.instance.post(this.actions.list, null, {
|
||||||
|
params: {...this.page, ...this.search}
|
||||||
|
}).then(res => {
|
||||||
|
if (res?.data) {
|
||||||
|
this.total = res.data.total;
|
||||||
|
this.adminList = res.data.records;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//查询
|
||||||
|
searchList() {
|
||||||
|
this.page.pageNum = 1;
|
||||||
|
this.getTableData();
|
||||||
|
},
|
||||||
|
//添加按钮
|
||||||
|
toAddAppRole(item) {
|
||||||
|
this.$router.push({
|
||||||
|
hash: "#add",
|
||||||
|
query: {
|
||||||
|
id: item.id,
|
||||||
|
name: item.name
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//删除
|
||||||
|
deleteApp(e) {
|
||||||
|
if (e == "all") {
|
||||||
|
this.multipleSelection.map((item) => {
|
||||||
|
this.delIds.push(item.id);
|
||||||
|
});
|
||||||
|
this.delParams = `ids=${this.delIds}`;
|
||||||
|
this.titleDel = "确定要执行删除操作吗?";
|
||||||
|
} else {
|
||||||
|
this.delParams = `ids=${e.id}`;
|
||||||
|
this.titleDel = "确定需要删除该角色吗?";
|
||||||
|
}
|
||||||
|
this.$confirm(this.titleDel, {
|
||||||
|
type: "error",
|
||||||
|
}).then(() => {
|
||||||
|
this.instance.post(`${this.actions.delete}?${this.delParams}`).then(res => {
|
||||||
|
if (res?.msg == "success") {
|
||||||
|
this.getTableData();
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(() => 0);
|
||||||
|
},
|
||||||
|
//查看信息
|
||||||
|
viewApp(e) {
|
||||||
|
this.userList = e.users;
|
||||||
|
this.viewInfo = e;
|
||||||
|
this.viewShow = true;
|
||||||
|
this.getRowInfo(this.viewInfo.appId, this.viewInfo.id);
|
||||||
|
},
|
||||||
|
//查询 row 信息
|
||||||
|
getRowInfo(appId, id) {
|
||||||
|
this.roleList = [];
|
||||||
|
this.instance.post(`${this.actions.detail}?id=${appId}&roleId=${id}`)
|
||||||
|
.then(res => {
|
||||||
|
if (res?.data) {
|
||||||
|
this.roleList = res.data.filter(e => e.checked)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//复制
|
||||||
|
beforeCopy(row) {
|
||||||
|
this.row = row;
|
||||||
|
this.copyDialog = true;
|
||||||
|
this.getRowInfo(this.row.appId, this.row.id);
|
||||||
|
},
|
||||||
|
//确认复制
|
||||||
|
copyFn() {
|
||||||
|
let crr = [];
|
||||||
|
let appRoleList = this.roleList;
|
||||||
|
for (let i = 0; i < appRoleList.length; i++) {
|
||||||
|
if (appRoleList[i].checked) {
|
||||||
|
crr.push(appRoleList[i].id);
|
||||||
|
if (appRoleList[i].list.length) {
|
||||||
|
for (let j = 0; j < appRoleList[i].list.length; j++) {
|
||||||
|
if (appRoleList[i].list[j].checked) {
|
||||||
|
crr.push(appRoleList[i].list[j].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.instance.post(`${this.actions.modify}?menus=${crr}`, null, {
|
||||||
|
params: {
|
||||||
|
roleName: this.editName,
|
||||||
|
appId: this.row.appId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
this.$message({message: "复制成功", type: "success"});
|
||||||
|
this.copyDialog = false;
|
||||||
|
this.searchList()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dataInit() {
|
||||||
|
this.multipleSelection = [];
|
||||||
|
this.row = {};
|
||||||
|
},
|
||||||
|
openRightsGraph(row) {
|
||||||
|
this.rightsGraph = true
|
||||||
|
this.selectApp = row
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.AppRoleRightsManager {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
:deep( .ai-dialog ) {
|
||||||
|
.ai-card {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
|
||||||
|
.aibar {
|
||||||
|
height: 40px;
|
||||||
|
background: #f3f6f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-card__body {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep( .rightsGraphDialog ) {
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-dialog__content {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep( .datail-table-body ) {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.datail-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 50%;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
width: 102px;
|
||||||
|
padding-left: 16px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.datail-item:nth-of-type(2n - 1) {
|
||||||
|
border-right: 1px solid rgba(208, 212, 220, 1);
|
||||||
|
width: calc(50% - 1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.padd-l0 {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad-l16 {
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
196
project/xumu/AppRoleRightsManager/rightsAdd.vue
Normal file
196
project/xumu/AppRoleRightsManager/rightsAdd.vue
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
<template>
|
||||||
|
<ai-detail class="rightsAdd">
|
||||||
|
<ai-title :title="addTitle" slot="title" isShowBottomBorder isShowBack @onBackClick="back"/>
|
||||||
|
<template #content>
|
||||||
|
<el-form size="small" ref="rightsForm" :model="form" label-width="120px" :rules="rules">
|
||||||
|
<ai-card title="基本信息">
|
||||||
|
<template #content>
|
||||||
|
<div class="grid">
|
||||||
|
<el-form-item label="应用角色名称" prop="roleName">
|
||||||
|
<el-input v-model="form.roleName" placeholder="请输入应用角色名称" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色标记" prop="type">
|
||||||
|
<ai-select v-model="form.type" dict="roleType" placeholder="请选择角色标记" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
<ai-card title="权限信息">
|
||||||
|
<template #content>
|
||||||
|
<el-form-item label="权限列表" prop="menus">
|
||||||
|
<div class="roleList">
|
||||||
|
<el-input v-model="filterText" placeholder="请输入..." clearable suffix-icon="iconfont iconSearch"
|
||||||
|
@change="$refs.tree.filter(filterText)" :validate-event="false"/>
|
||||||
|
<div class="tree_list">
|
||||||
|
<el-tree class="filter-tree" ref="roleTree"
|
||||||
|
:data="roleList"
|
||||||
|
show-checkbox
|
||||||
|
:props="defaultProps"
|
||||||
|
default-expand-all
|
||||||
|
:check-strictly="false"
|
||||||
|
node-key="id"
|
||||||
|
:default-checked-keys="form.menus"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
@check="handleMenusSelect"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="back()">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirm">保存</el-button>
|
||||||
|
</template>
|
||||||
|
</ai-detail>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "rightsAdd",
|
||||||
|
inject: ['top'],
|
||||||
|
props: {
|
||||||
|
instance: Function,
|
||||||
|
dict: Object,
|
||||||
|
permissions: Function
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {},
|
||||||
|
roleName: '',
|
||||||
|
id: '',
|
||||||
|
appList: [],
|
||||||
|
roleList: [],
|
||||||
|
defaultProps: {
|
||||||
|
children: 'list',
|
||||||
|
label: 'name'
|
||||||
|
},
|
||||||
|
treeList: [],
|
||||||
|
filterText: '',
|
||||||
|
msgTitle: '添加'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.isEdit) {
|
||||||
|
let {id, name: roleName} = this.$route.query
|
||||||
|
this.form = {menus: [], id, roleName}
|
||||||
|
this.msgTitle = '编辑'
|
||||||
|
}
|
||||||
|
this.getPermissions()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isEdit() {
|
||||||
|
return this.$route.query.id
|
||||||
|
},
|
||||||
|
addTitle() {
|
||||||
|
return this.isEdit ? '编辑应用角色' : '新增应用角色'
|
||||||
|
},
|
||||||
|
rules() {
|
||||||
|
return {
|
||||||
|
roleName: {required: true, message: '请输入应用角色名称'},
|
||||||
|
roleType: {required: true, message: '请选择角色标记'},
|
||||||
|
menus: {required: true, message: '请选择权限列表内容'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
filterNode(value, data) {
|
||||||
|
if (!value) return true;
|
||||||
|
return data.name.indexOf(value) !== -1;
|
||||||
|
},
|
||||||
|
//应用名称选择 获取权限列表
|
||||||
|
getId(data) {
|
||||||
|
if (data.list.length) {
|
||||||
|
data.list.forEach(item => {
|
||||||
|
this.getId(item)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (data.checked) {
|
||||||
|
this.form.menus?.push(data.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getPermissions() {
|
||||||
|
this.filterText = ''
|
||||||
|
let {id: roleId} = this.form
|
||||||
|
this.instance.post(this.top.actions.detail, null, {
|
||||||
|
params: {roleId}
|
||||||
|
}).then(res => {
|
||||||
|
if (res?.data) {
|
||||||
|
this.roleList = res.data;
|
||||||
|
if (this.isEdit) {
|
||||||
|
this.roleList.forEach(e => this.getId(e))
|
||||||
|
}
|
||||||
|
this.roleList = this.roleList.filter(item => !(item.component && item.isApp == 0 && item.isMenu == 0))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleMenusSelect(node, selected) {
|
||||||
|
this.$set(this.form, 'menus', [...selected?.checkedKeys])
|
||||||
|
this.$refs.rightsForm.validateField('menus')
|
||||||
|
},
|
||||||
|
//保存提交
|
||||||
|
confirm() {
|
||||||
|
this.$refs.rightsForm.validate(v => {
|
||||||
|
if (v) {
|
||||||
|
let menus = [this.$refs.roleTree?.getHalfCheckedKeys(), this.$refs.roleTree?.getCheckedKeys()]?.flat()?.toString()
|
||||||
|
this.instance.post(this.top.actions.modify, null, {
|
||||||
|
params: {...this.form, menus}
|
||||||
|
}).then(res => {
|
||||||
|
if (res?.msg == "success") {
|
||||||
|
this.$message.success(`${this.msgTitle}应用角色成功`)
|
||||||
|
this.back()
|
||||||
|
this.top.searchList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//取消 返回
|
||||||
|
back() {
|
||||||
|
this.$router.push({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.rightsAdd {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
.el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-error {
|
||||||
|
.roleList {
|
||||||
|
border-color: #f46;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.roleList {
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: solid 1px #d0d4dc;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree_list {
|
||||||
|
padding: 5px;
|
||||||
|
height: 370px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
192
project/xumu/AppRoleRightsManager/rightsGraph.vue
Normal file
192
project/xumu/AppRoleRightsManager/rightsGraph.vue
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
<template>
|
||||||
|
<section class="rightsGraph">
|
||||||
|
<div id="RightGraph"/>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "rightsGraph",
|
||||||
|
inject: ['top'],
|
||||||
|
props: {
|
||||||
|
instance: Function,
|
||||||
|
dict: Object,
|
||||||
|
app: Object
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
graphData() {
|
||||||
|
let data = [...this.users, ...this.nodes].map(e => {
|
||||||
|
if (e.x) {
|
||||||
|
return e
|
||||||
|
} else return {...e, ...this.renderPosition(e)}
|
||||||
|
})
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
data,
|
||||||
|
links: this.links,
|
||||||
|
categories: data.map(e => e.category).flat().map(name => ({name}))
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
graph: null,
|
||||||
|
nodes: [],
|
||||||
|
links: [],
|
||||||
|
users: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
graphData: {
|
||||||
|
deep: true, handler() {
|
||||||
|
this.refreshGraph()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initGraph() {
|
||||||
|
let dom = document.querySelector("#RightGraph")
|
||||||
|
if (dom) {
|
||||||
|
this.graph = echarts.init(dom)
|
||||||
|
this.graph.setOption({
|
||||||
|
tooltip: {},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
layout: 'none',
|
||||||
|
roam: true,
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'right',
|
||||||
|
formatter: '{b}'
|
||||||
|
},
|
||||||
|
labelLayout: {
|
||||||
|
hideOverlap: true,
|
||||||
|
},
|
||||||
|
scaleLimit: {
|
||||||
|
min: 0.4,
|
||||||
|
max: 4
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: 'target',
|
||||||
|
curveness: 0.1
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'adjacency',
|
||||||
|
lineStyle: {
|
||||||
|
width: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
this.graph.on('click', this.handleNodeClick)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
refreshGraph() {
|
||||||
|
this.graph?.setOption({
|
||||||
|
series: this.graphData
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getAppRoles(role) {
|
||||||
|
if (role) {
|
||||||
|
this.nodes.push({...role, category: '应用角色', value: "应用角色", symbolSize: 15})
|
||||||
|
} else this.instance.post(this.top.actions.list, null, {
|
||||||
|
params: {pageSize: 999}
|
||||||
|
}).then(res => {
|
||||||
|
if (res?.data) {
|
||||||
|
res.data.records.map(e => {
|
||||||
|
this.getUsers(e.users, e.id)
|
||||||
|
this.nodes.push({...e, category: '应用角色', value: "应用角色"})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getUsers(pending, source) {
|
||||||
|
pending?.map(e => {
|
||||||
|
if (!this.users.some(u => u.id == e.phone)) {
|
||||||
|
this.users.push({id: e.phone, name: e.name, symbolSize: 5, category: '用户', value: "用户"})
|
||||||
|
}
|
||||||
|
this.links.push({source, target: e.phone})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getPermissions({id: roleId, name: category, dataIndex}) {
|
||||||
|
const addNodes = (list, source, category, pos) => {
|
||||||
|
list?.map(e => {
|
||||||
|
let node = {
|
||||||
|
...e,
|
||||||
|
symbolSize: 5,
|
||||||
|
category,
|
||||||
|
value: e.list?.length > 0 ? "应用" : "权限",
|
||||||
|
}
|
||||||
|
node = {...node, ...this.renderPosition(pos || node)}
|
||||||
|
this.nodes.splice(dataIndex, 0, node)
|
||||||
|
if (e.checked == 1) {
|
||||||
|
this.links.push({source, target: e.id})
|
||||||
|
}
|
||||||
|
addNodes(e.list, e.id, e.label, node)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
roleId && this.instance.post(this.top.actions.detail, null, {
|
||||||
|
params: {roleId}
|
||||||
|
}).then(res => {
|
||||||
|
if (res?.data) {
|
||||||
|
addNodes(res.data, roleId, category)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleNodeClick(v) {
|
||||||
|
let {data: role, dataIndex} = v
|
||||||
|
if (!this.nodes.some(e => e.category == role?.name)) {
|
||||||
|
role && this.getPermissions({...role, dataIndex})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderPosition(node) {
|
||||||
|
node = JSON.parse(JSON.stringify(node))
|
||||||
|
let pos = {x: 0, y: 0}
|
||||||
|
if (node?.x) {
|
||||||
|
pos.x = Math.max(this.graph?.getWidth() / 3 * 2, node.x) + 100 + Math.random() * 50
|
||||||
|
pos.y = node.y + Math.random() * 100 - 50
|
||||||
|
} else if (node.value == '应用角色') {
|
||||||
|
pos.x = this.graph?.getWidth() / 3 - 200 + Math.random() * 200
|
||||||
|
pos.y = this.graph?.getHeight() / 2 - 100 + Math.random() * 200
|
||||||
|
} else if (node.value == '应用') {
|
||||||
|
pos.x = this.graph?.getWidth() / 3 * 2 - 100 + Math.random() * 100
|
||||||
|
pos.y = Math.random() * this.graph?.getHeight()
|
||||||
|
} else if (node.value == '用户') {
|
||||||
|
pos.x = Math.random() * 50
|
||||||
|
pos.y = Math.random() * this.graph?.getHeight()
|
||||||
|
} else {
|
||||||
|
pos.x = this.graph?.getWidth() - 100 + Math.random() * 100
|
||||||
|
pos.y = Math.random() * this.graph?.getHeight()
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getAppRoles(this.app)
|
||||||
|
this.getUsers(this.app.users, this.app.id)
|
||||||
|
this.getPermissions(this.app)
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.initGraph()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.rightsGraph {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
:deep( #RightGraph ){
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user