Files
BMS/src/views/system/role/index.vue
T
wuweihua 3e9b34e0fd feat: 封装公共表单/表格组件 BasicForm/BasicTable,并替换业务页面表格
- 新增 BasicForm 配置驱动表单组件,支持多种控件、字典自动加载、校验、插槽扩展
- 新增 BasicTable 公共表格组件,集成搜索栏+工具栏+表格+分页,基于 columns/searchColumns 配置驱动
- 替换 18 个业务页面 el-table 为 BasicTable(post/user/role/dict/config/notice/job/log/logininfor/operlog/online/gen 等)
- 全局注册 BasicForm、BasicTable 组件
- 项目标题由若依管理系统改为 BMS
2026-08-28 11:35:26 +08:00

486 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="roleId"
:search-label-width="'68px'"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:role:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:role:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:role:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:role:export']"
>导出</el-button>
</el-col>
</template>
<template #col-status="{ row }">
<el-switch
v-model="row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(row)"
></el-switch>
</template>
<template #col-action="{ row }">
<el-tooltip content="修改" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="Delete" @click="handleDelete(row.roleId)" v-hasPermi="['system:role:remove']"></el-button>
</el-tooltip>
<el-tooltip content="数据权限" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="CircleCheck" @click="handleDataScope(row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="分配用户" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="User" @click="handleAuthUser(row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
</template>
</basic-table>
<!-- 添加或修改角色配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
</el-form-item>
<el-form-item prop="roleKey">
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
</span>
</template>
<el-input v-model="form.roleKey" placeholder="请输入权限字符" />
</el-form-item>
<el-form-item label="角色顺序" prop="roleSort">
<el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:value="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单权限">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menuRef"
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 分配角色数据权限对话框 -->
<el-dialog :title="title" v-model="openDataScope" width="500px" append-to-body>
<el-form :model="form" label-width="80px">
<el-form-item label="角色名称">
<el-input v-model="form.roleName" :disabled="true" />
</el-form-item>
<el-form-item label="权限字符">
<el-input v-model="form.roleKey" :disabled="true" />
</el-form-item>
<el-form-item label="权限范围">
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限" v-show="form.dataScope == 2">
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="deptOptions"
show-checkbox
default-expand-all
ref="deptRef"
node-key="id"
:check-strictly="!form.deptCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDataScope"> </el-button>
<el-button @click="cancelDataScope"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Role">
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role"
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
const router = useRouter()
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const tableRef = ref()
const open = ref(false)
const title = ref("")
const dateRange = ref([])
const menuOptions = ref([])
const menuExpand = ref(false)
const menuNodeAll = ref(false)
const deptExpand = ref(true)
const deptNodeAll = ref(false)
const deptOptions = ref([])
const openDataScope = ref(false)
const menuRef = ref(null)
const deptRef = ref(null)
// 搜索项配置
const searchColumns = [
{ label: "角色名称", prop: "roleName", component: "input", placeholder: "请输入角色名称", width: "240px" },
{ label: "权限字符", prop: "roleKey", component: "input", placeholder: "请输入权限字符", width: "240px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "角色状态", width: "240px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "308px" }
]
// 表格列配置
const columns = [
{ label: "角色编号", prop: "roleId", width: 120 },
{ label: "角色名称", prop: "roleName", width: 150, showOverflowTooltip: true },
{ label: "权限字符", prop: "roleKey", width: 150, showOverflowTooltip: true },
{ label: "显示顺序", prop: "roleSort", width: 100 },
{ label: "状态", prop: "status" },
{ label: "创建时间", prop: "createTime", parseTime: true },
{ label: "操作", prop: "action", showInToolbar: false }
]
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listRole(p)
}
/** 数据范围选项*/
const dataScopeOptions = ref([
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
])
const data = reactive({
form: {},
rules: {
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
},
})
const { form, rules } = toRefs(data)
/** 删除按钮操作 */
function handleDelete(roleIds) {
proxy.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function () {
return delRole(roleIds)
}).then(() => {
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/role/export", {
...tableRef.value.getQueryParams()
}, `role_${new Date().getTime()}.xlsx`)
}
/** 角色状态修改 */
function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
proxy.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
return changeRoleStatus(row.roleId, row.status)
}).then(() => {
proxy.$modal.msgSuccess(text + "成功")
}).catch(function () {
row.status = row.status === "0" ? "1" : "0"
})
}
/** 分配用户 */
function handleAuthUser(row) {
router.push("/system/role-auth/user/" + row.roleId)
}
/** 查询菜单树结构 */
function getMenuTreeselect() {
menuTreeselect().then(response => {
menuOptions.value = response.data
})
}
/** 所有部门节点数据 */
function getDeptAllCheckedKeys() {
// 目前被选中的部门节点
let checkedKeys = deptRef.value.getCheckedKeys()
// 半选中的部门节点
let halfCheckedKeys = deptRef.value.getHalfCheckedKeys()
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
return checkedKeys
}
/** 重置新增的表单以及其他数据 */
function reset() {
if (menuRef.value != undefined) {
menuRef.value.setCheckedKeys([])
}
menuExpand.value = false
menuNodeAll.value = false
deptExpand.value = true
deptNodeAll.value = false
form.value = {
roleId: undefined,
roleName: undefined,
roleKey: undefined,
roleSort: 0,
status: "0",
menuIds: [],
deptIds: [],
menuCheckStrictly: true,
deptCheckStrictly: true,
remark: undefined
}
proxy.resetForm("roleRef")
}
/** 添加角色 */
function handleAdd() {
reset()
getMenuTreeselect()
open.value = true
title.value = "添加角色"
}
/** 修改角色 */
function handleUpdate(row) {
reset()
const roleId = row.roleId
const roleMenu = getRoleMenuTreeselect(roleId)
getRole(roleId).then(response => {
form.value = response.data
form.value.roleSort = Number(form.value.roleSort)
open.value = true
title.value = "修改角色"
nextTick(() => {
roleMenu.then((res) => {
let checkedKeys = res.checkedKeys
checkedKeys.forEach((v) => {
nextTick(() => {
menuRef.value.setChecked(v, true, false)
})
})
})
})
})
}
/** 根据角色ID查询菜单树结构 */
function getRoleMenuTreeselect(roleId) {
return roleMenuTreeselect(roleId).then(response => {
menuOptions.value = response.menus
return response
})
}
/** 根据角色ID查询部门树结构 */
function getDeptTree(roleId) {
return deptTreeSelect(roleId).then(response => {
deptOptions.value = response.depts
return response
})
}
/** 树权限(展开/折叠)*/
function handleCheckedTreeExpand(value, type) {
if (type == "menu") {
let treeList = menuOptions.value
for (let i = 0; i < treeList.length; i++) {
menuRef.value.store.nodesMap[treeList[i].id].expanded = value
}
} else if (type == "dept") {
let treeList = deptOptions.value
for (let i = 0; i < treeList.length; i++) {
deptRef.value.store.nodesMap[treeList[i].id].expanded = value
}
}
}
/** 树权限(全选/全不选) */
function handleCheckedTreeNodeAll(value, type) {
if (type == "menu") {
menuRef.value.setCheckedNodes(value ? menuOptions.value : [])
} else if (type == "dept") {
deptRef.value.setCheckedNodes(value ? deptOptions.value : [])
}
}
/** 树权限(父子联动) */
function handleCheckedTreeConnect(value, type) {
if (type == "menu") {
form.value.menuCheckStrictly = value ? true : false
} else if (type == "dept") {
form.value.deptCheckStrictly = value ? true : false
}
}
/** 所有菜单节点数据 */
function getMenuAllCheckedKeys() {
// 目前被选中的菜单节点
let checkedKeys = menuRef.value.getCheckedKeys()
// 半选中的菜单节点
let halfCheckedKeys = menuRef.value.getHalfCheckedKeys()
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
return checkedKeys
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["roleRef"].validate(valid => {
if (valid) {
if (form.value.roleId != undefined) {
form.value.menuIds = getMenuAllCheckedKeys()
updateRole(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
tableRef.value.refresh()
})
} else {
form.value.menuIds = getMenuAllCheckedKeys()
addRole(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
tableRef.value.refresh()
})
}
}
})
}
/** 取消按钮 */
function cancel() {
open.value = false
reset()
}
/** 选择角色权限范围触发 */
function dataScopeSelectChange(value) {
if (value !== "2") {
deptRef.value.setCheckedKeys([])
}
}
/** 分配数据权限操作 */
function handleDataScope(row) {
reset()
const deptTreeSelect = getDeptTree(row.roleId)
getRole(row.roleId).then(response => {
form.value = response.data
openDataScope.value = true
title.value = "分配数据权限"
nextTick(() => {
deptTreeSelect.then(res => {
nextTick(() => {
if (deptRef.value) {
deptRef.value.setCheckedKeys(res.checkedKeys)
}
})
})
})
})
}
/** 提交按钮(数据权限) */
function submitDataScope() {
if (form.value.roleId != undefined) {
form.value.deptIds = getDeptAllCheckedKeys()
dataScope(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
openDataScope.value = false
tableRef.value.refresh()
})
}
}
/** 取消按钮(数据权限)*/
function cancelDataScope() {
openDataScope.value = false
reset()
}
</script>