feat: 新增角色管理模块,优化API与交互体验
1. 新增角色管理后台页面、路由与国际化文案 2. 重构API请求错误处理逻辑,统一拦截业务与HTTP错误 3. 新增确认弹窗组合式函数,区分取消与请求错误场景 4. 完善表格按钮权限与显示控制逻辑 5. 更新API参数规范与文档说明 6. 修复部分页面分页数据解析问题
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
:visible.sync="visibleProxy"
|
||||
:title="$t(title)"
|
||||
:size="width"
|
||||
:close-on-click-modal="false"
|
||||
direction="rtl"
|
||||
@close="onClose"
|
||||
>
|
||||
<div class="perm-drawer__body" v-loading="treeLoading">
|
||||
<el-tree
|
||||
v-if="treeReady"
|
||||
ref="permTree"
|
||||
node-key="menu_id"
|
||||
:data="treeData"
|
||||
:props="{ label: 'name', children: 'children' }"
|
||||
:default-expand-all="false"
|
||||
:expand-on-click-node="false"
|
||||
:check-strictly="true"
|
||||
show-checkbox
|
||||
@check="onTreeCheck"
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="perm-drawer__tree-node">
|
||||
<span :class="{ 'perm-drawer__tree-node--disabled': !data.status }">
|
||||
<i v-if="data.icon" :class="`fa fa-${data.icon}`" />
|
||||
<i v-else-if="data.children" :class="`el-icon-${node.expanded ? 'folder-opened' : 'folder'}`" />
|
||||
<i v-else class="el-icon-document" />
|
||||
{{ $t(data.name) }}
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</div>
|
||||
|
||||
<div class="perm-drawer__footer">
|
||||
<el-button size="mini" @click="onCancel">
|
||||
{{ $t(cancelText) }}
|
||||
</el-button>
|
||||
<el-button type="primary" size="mini" :loading="submitting" @click="onSubmit">
|
||||
{{ $t(confirmText) }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { i18nMixin } from '@/composables/useI18n'
|
||||
import util from '@/libs/util'
|
||||
import { getMenuAll } from '@/api/menu'
|
||||
import { giveRoleMenu, getRoleMenu } from '@/api/system-administration/role'
|
||||
|
||||
export default {
|
||||
name: 'RolePermDrawer',
|
||||
mixins: [i18nMixin('page.system_administration.user_management.role')],
|
||||
props: {
|
||||
visible: { type: Boolean, default: false },
|
||||
roleId: { type: Number, default: 0 },
|
||||
title: { type: String, default: '' },
|
||||
confirmText: { type: String, default: '' },
|
||||
cancelText: { type: String, default: '' },
|
||||
width: { type: String, default: '360px' }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
treeLoading: false,
|
||||
submitting: false,
|
||||
treeReady: false,
|
||||
treeData: [],
|
||||
checkedMenuIds: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleProxy: {
|
||||
get () { return this.visible },
|
||||
set (val) { this.$emit('update:visible', val) }
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible (val) {
|
||||
if (val) { this.loadData() }
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadData () {
|
||||
this.treeReady = false
|
||||
this.treeLoading = true
|
||||
try {
|
||||
const [menuRes, roleMenuRes] = await Promise.all([
|
||||
getMenuAll()
|
||||
])
|
||||
const menuData = Array.isArray(menuRes) ? menuRes : (menuRes.data || [])
|
||||
const roleData = Array.isArray(roleMenuRes) ? roleMenuRes : (roleMenuRes.data || [])
|
||||
this.checkedMenuIds = roleData.map(item => item.menu_id)
|
||||
this.treeData = util.formatDataToTree(menuData)
|
||||
this.treeReady = true
|
||||
await this.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
this.$refs.permTree.setCheckedKeys(this.checkedMenuIds)
|
||||
} finally {
|
||||
this.treeLoading = false
|
||||
}
|
||||
},
|
||||
onTreeCheck () {},
|
||||
onClose () {
|
||||
this.treeReady = false
|
||||
this.treeData = []
|
||||
this.checkedMenuIds = []
|
||||
},
|
||||
onCancel () {
|
||||
this.visibleProxy = false
|
||||
},
|
||||
async onSubmit () {
|
||||
this.submitting = true
|
||||
try {
|
||||
const menuIds = this.$refs.permTree.getCheckedKeys()
|
||||
await giveRoleMenu({ role_id: this.roleId, role_menu: menuIds })
|
||||
this.$message.success(this.$t(this.key('operation_success')))
|
||||
this.visibleProxy = false
|
||||
this.$emit('saved')
|
||||
} finally {
|
||||
this.submitting = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.perm-drawer__body {
|
||||
height: calc(100vh - 140px);
|
||||
overflow-y: auto;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.perm-drawer__footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
padding: 10px 20px;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
background: #fff;
|
||||
text-align: right;
|
||||
}
|
||||
.perm-drawer__tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.perm-drawer__tree-node--disabled {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user