实现角色管理

This commit is contained in:
洛洛希雅Lolosia 2023-02-23 15:24:59 +08:00
parent a7613c88ec
commit f327bc6cb6
6 changed files with 497 additions and 1 deletions

View File

@ -19,6 +19,9 @@
#app-navs > * {
margin: 0 12px;
}
#app-navs .el-form-item{
margin-bottom: 0;
}
</style>
</head>
<body>

55
src/api/roleManagement.ts Normal file
View File

@ -0,0 +1,55 @@
import request from '@/utils/request'
export function getList(data) {
return request({
url: '/role/queryRoleByPage',
method: 'post',
data,
})
}
export function doAdd(data) {
return request({
url: '/role/create',
method: 'post',
data,
})
}
export function doUpdate(data) {
return request({
url: '/role/update',
method: 'post',
data,
})
}
export function doDelete(data) {
return request({
url: '/role/destroy',
method: 'post',
data,
})
}
/**
*
* @return {Promise<AxiosResponse<{id: number, type:string, roleName: string}[]>>}
*/
export function getRoleList() {
return request({
url: '/role/list',
method: 'get',
})
}
/**
* ID获取角色ID
*/
export function getRoleByUserId(userId) {
return request({
url: '/userRole/getByUserId',
method: 'get',
params: {
userId,
},
})
}

View File

@ -133,3 +133,13 @@ export function allIcons(): string[] {
.filter((it) => !it.endsWith('-1'))
return aIcons
}
/**
*
* @param ms
*/
export async function delay(ms: number) {
await new Promise((r) => {
setTimeout(r, ms)
})
}

View File

@ -138,7 +138,7 @@
},
}
</script>
<style lang="scss">
<style scoped lang="scss">
.icon {
font-size: 1.5em !important;
padding: 5px !important;

View File

@ -0,0 +1,235 @@
<template>
<el-drawer v-model="drawer" :title="title" :before-close="close">
<div v-loading="loading" class="drawer__content">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="角色名称:" prop="roleName">
<el-input
v-model.trim="form.roleName"
autocomplete="off"
placeholder="请输入角色名称"
/>
</el-form-item>
<el-form-item label="角色key" prop="type">
<el-input
v-model.trim="form.type"
autocomplete="off"
placeholder="请输入角色key"
/>
</el-form-item>
<el-form-item label="菜单列表:" prop="menuId">
<el-select
v-model="form.menuTitle"
class="vab-tree-select"
clearable
collapse-tags
multiple
popper-class="select-tree-popper"
@clear="selectTreeClearHandle()"
@remove-tag="removeSelectTreeTag"
>
<!-- <el-select-->
<!-- v-model="form.menuTitle"-->
<!-- class="vab-tree-select"-->
<!-- clearable-->
<!-- multiple-->
<!-- popper-class="select-tree-popper"-->
<!-- @clear="selectTreeClearHandle()"-->
<!-- @remove-tag="removeSelectTreeTag"-->
<!-- >-->
<el-option :value="form.menuId" style="height: 250px; overflow: auto; background-color: white">
<el-tree
id="multipleSelectTree"
ref="multipleSelectTree"
:data="menu"
:default-expanded-keys="form.menuId"
:highlight-current="true"
:props="selectTreeDefaultProps"
node-key="id"
show-checkbox
@check="multipleSelectTreeCheckNode"
/>
</el-option>
</el-select>
</el-form-item>
</el-form>
<div class="drawer__footer">
<el-button size="default" @click="close(true)"> </el-button>
<el-button size="default" type="primary" @click="save"> </el-button>
</div>
</div>
</el-drawer>
</template>
<script>
import { doAdd, doUpdate } from "@/api/roleManagement";
import { getTree } from "@/api/menuManagement";
import { delay } from "@/utils/common-util";
export default {
name: "RoleManagementEdit",
data() {
return {
form: {
roleName: "",
type: "",
menuId: [],
menuTitle: []
},
rules: {
roleName: [
{ required: true, trigger: "blur", message: "请输入角色名称" }
],
menuId: [{ required: true, trigger: "blur", message: "请选择菜单" }]
},
formBackup: {
roleName: "",
type: "",
menuId: [],
menuTitle: []
},
title: "",
loading: false,
drawer: false,
/* 单选树-多选树---------开始 */
menu: [],
selectTreeDefaultProps: {
children: "children",
label: "title"
}
/* 单选树-多选树---------结束 */
};
},
created() {
},
methods: {
/* 单选/多选树方法-------------------开始 */
//
async initSingleTree() {
this.menu = await getTree();
this.$nextTick(() => {
//
this.form.menuId.forEach((item) => {
const node = this.$refs.multipleSelectTree.getNode(item);
if (node && node.isLeaf) {
this.$refs.multipleSelectTree.setChecked(node, true);
}
});
});
},
//
selectTreeClearHandle() {
this.form.menuTitle = [];
this.form.menuId = [];
this.$refs.multipleSelectTree.setCheckedKeys([]);
},
// select
removeSelectTreeTag(val) {
const stack = JSON.parse(JSON.stringify(this.menu));
while (stack.length) {
const curr = stack.shift();
if (curr.title == val) {
this.form.menuId.splice(this.form.menuId.indexOf(curr.id), 1);
return this.$refs.multipleSelectTree.setChecked(curr.id, false);
}
if (curr.children && curr.children.length) {
stack.unshift(...curr.children);
}
}
},
//
multipleSelectTreeCheckNode(data, node, el) {
const checkedNodes = this.$refs.multipleSelectTree.getCheckedNodes();
const halfCheckedNodes =
this.$refs.multipleSelectTree.getHalfCheckedNodes();
const allNodes = checkedNodes.concat(halfCheckedNodes);
const keyArr = [];
const valueArr = [];
allNodes.forEach((item) => {
keyArr.push(item.id);
valueArr.push(item.title);
});
this.form.menuTitle = valueArr;
this.form.menuId = keyArr;
},
/* 单选/多选树方法-------------------结束 */
showEdit(row) {
if (!row) {
this.title = "添加";
} else {
this.title = "编辑";
this.form = Object.assign({}, row);
}
this.loading = true;
this.drawer = true;
this.$nextTick(() => {
this.formBackup = Object.assign({}, this.form);
this.initSingleTree();
});
setTimeout(() => {
this.loading = false;
}, 1500);
},
async close(confirm) {
if (this.loading) return;
const compare =
JSON.stringify(this.form) !== JSON.stringify(this.formBackup);
if (confirm && compare) {
const rs = await elConfirmNoCancelBtn(null,
"编辑数据将会清空,确认退出?"
);
if (rs !== "confirm") return;
this.resetDrawer();
} else {
this.resetDrawer();
}
},
resetDrawer() {
this.$refs["form"].resetFields();
this.form = this.$options.data().form;
this.formBackup = this.$options.data().formBackup;
this.drawer = false;
},
save() {
this.$refs["form"].validate(async (valid) => {
if (valid) {
let msg;
if (this.title === "添加") {
const resp = await doAdd(this.form);
msg = resp.msg;
} else {
const resp = await doUpdate(this.form);
msg = resp.msg;
}
elMessage(msg, "success");
this.$emit("fetch-data");
this.close(false);
} else {
return false;
}
});
}
}
};
</script>
<style lang="scss" scoped>
.drawer__content {
display: flex;
flex-direction: column;
height: 100%;
form {
flex: 1;
}
.drawer__footer {
display: flex;
button {
flex: 1;
}
}
}
</style>

View File

@ -0,0 +1,193 @@
<template>
<div class="roleManagement-container">
<teleport to="#app-navs">
<el-form :inline="true" :model="queryForm" class="nav" @submit.prevent>
<el-form-item>
<el-input
v-model.trim="queryForm.roleName"
placeholder="请输入查询条件"
@keyup.enter="queryData"
>
<template #suffix>
<i
class="el-icon-search el-input__icon i-search"
@click="queryData"
/>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleEdit">添加</el-button>
</el-form-item>
<!-- <el-form-item>-->
<!-- <el-button-->
<!-- icon="el-icon-delete"-->
<!-- type="danger"-->
<!-- @click="handleDestroy"-->
<!-- >-->
<!-- 批量删除-->
<!-- </el-button>-->
<!-- </el-form-item>-->
</el-form>
</teleport>
<div class="container-inner">
<el-table
v-loading="listLoading"
:data="list"
:element-loading-text="elementLoadingText"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:header-cell-style="{ background: '#F7F9FB', textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
:height="height"
@selection-change="setSelectRows"
>
<!-- <el-table-column show-overflow-tooltip type="selection"></el-table-column>-->
<el-table-column
show-overflow-tooltip
width="120"
prop="id"
label="id"
/>
<el-table-column
show-overflow-tooltip
width="200"
prop="roleName"
label="角色名称"
/>
<el-table-column
show-overflow-tooltip
width="200"
prop="type"
label="角色类型"
/>
<el-table-column show-overflow-tooltip label="菜单列表">
<template #default="{ row }">
<span>{{ row.menuTitle.toString() }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button class="icon" type="primary" link @click="handleEdit(row)">
<i class="bi bi-pencil-square"/>
</el-button>
<el-button class="icon" type="primary" link @click="handleDestroy(row)">
<i class="bi bi-trash"/>
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
background
:current-page="queryForm.pageNo"
:page-size="queryForm.pageSize"
:layout="layout"
:total="total"
style="justify-content: center"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<edit ref="edit" @fetch-data="fetchData"/>
</div>
</div>
</template>
<script>
import { doDelete, getList } from '@/api/roleManagement'
import Edit from './components/RoleManagementEdit.vue'
export default {
name: 'RoleManagement',
components: { Edit },
data() {
return {
list: null,
listLoading: true,
layout: 'total, sizes, prev, pager, next, jumper',
total: 0,
selectRows: '',
elementLoadingText: '正在加载...',
queryForm: {
pageNo: 1,
pageSize: 10,
roleName: '',
},
}
},
computed: {
height() {
return 'auto'
},
},
created() {
this.fetchData()
},
methods: {
setSelectRows(val) {
this.selectRows = val
},
handleEdit(row) {
if (row.id) {
this.$refs['edit'].showEdit(row)
} else {
this.$refs['edit'].showEdit()
}
},
async handleDestroy(row) {
// if (row.id) {
// this.$baseConfirm('', null, async () => {
// const { msg } = await doDelete({ ids: row.id })
// this.$baseMessage(msg, 'success')
// this.fetchData()
// })
// } else {
// if (this.selectRows.length > 0) {
// const ids = this.selectRows.map((item) => item.id).join()
// this.$baseConfirm('', null, async () => {
// const { msg } = await doDelete({ ids })
// this.$baseMessage(msg, 'success')
// this.fetchData()
// })
// } else {
// this.$baseMessage('', 'error')
// return false
// }
// }
const rs = await elConfirmNoCancelBtn(null, '你确定要删除当前项吗');
if (rs !== "confirm") return;
const { msg } = await doDelete({
id: row.id,
})
elMessage(msg, 'success')
this.fetchData()
},
handleSizeChange(val) {
this.queryForm.pageSize = val
this.fetchData()
},
handleCurrentChange(val) {
this.queryForm.pageNo = val
this.fetchData()
},
queryData() {
this.queryForm.pageNo = 1
this.fetchData()
},
async fetchData() {
this.listLoading = true
const { data } = await getList(this.queryForm)
this.list = data.rows
this.total = data.total
setTimeout(() => {
this.listLoading = false
}, 300)
},
},
}
</script>
<style scoped lang="scss">
.icon{
font-size: 1.5em !important;
padding: 5px !important;
}
</style>