This commit is contained in:
2026-08-06 19:03:13 +08:00
parent 7034a40aa8
commit 8695eee8c8
28 changed files with 1100 additions and 162 deletions
+6 -6
View File
@@ -46,8 +46,8 @@ type RoleFilters = QueryModel & { keyword: string; status: string }
const filters = ref<RoleFilters>({ keyword: '', status: '' })
const appliedFilters = ref<RoleFilters>({ ...filters.value })
const queryFields: QueryField[] = [
{ key: 'keyword', type: 'input', placeholder: '角色名称、编码或描述' },
{ key: 'status', type: 'select', placeholder: '全部状态', options: [{ label: '启用', value: '启用' }, { label: '停用', value: '停用' }] },
{ key: 'keyword', type: 'input', label: '角色关键词', placeholder: '角色名称、编码或描述' },
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', options: [{ label: '启用', value: '启用' }, { label: '停用', value: '停用' }] },
]
const emptyForm = (): Omit<Role, 'userCount'> => ({ id: '', name: '', code: '', description: '', dataScope: '本部门数据', status: '启用', permissionIds: [], builtIn: false })
const form = reactive(emptyForm())
@@ -76,9 +76,9 @@ const pagedRows = computed(() => filteredRows.value.slice((page.value - 1) * pag
const roleColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 235, fixed: 'left', slotName: 'actions' },
{ key: 'role', label: '角色', minWidth: 210, slotName: 'role' },
{ prop: 'description', label: '说明', minWidth: 240, showOverflowTooltip: true },
{ key: 'description', prop: 'description', label: '说明', minWidth: 240, showOverflowTooltip: true },
{ key: 'permissionSummary', label: '授权范围', minWidth: 170, slotName: 'permissionSummary' },
{ prop: 'userCount', label: '用户数', width: 86, align: 'right' },
{ key: 'userCount', prop: 'userCount', label: '用户数', width: 86, align: 'right' },
{ key: 'roleType', label: '类型', width: 95, slotName: 'roleType' },
{ key: 'status', label: '状态', width: 88, slotName: 'status' },
]
@@ -233,11 +233,11 @@ onMounted(loadRoles)
<template>
<div class="business-page">
<el-alert v-if="loadError" type="error" :closable="false" show-icon role="alert"><template #title><div class="api-error-alert-title"><span>{{ loadError.message }}</span><ApiErrorMeta :details="loadError" /></div><el-button link type="danger" @click="loadRoles">重新加载</el-button></template></el-alert>
<QueryToolbar v-model="filters" class="surface-panel" ariaLabel="角色筛选" :fields="queryFields" @search="applyFilters" />
<QueryToolbar v-model="filters" class="surface-panel" ariaLabel="角色筛选" :fields="queryFields" preference-key="roles-query" @search="applyFilters" />
<section class="surface-panel table-panel">
<header class="panel-heading"><div><h2>角色与授权 <span class="secondary-text">共 {{ filteredRows.length }} 条</span></h2><p>角色负责聚合菜单、操作和数据范围,内部用户可分配多个角色。</p></div><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />新增角色</el-button></header>
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="pagedRows" :columns="roleColumns" :loading="loading" :total="filteredRows.length" row-key="id" empty-text="没有符合条件的角色">
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="pagedRows" :columns="roleColumns" preference-key="roles-table" :loading="loading" :total="filteredRows.length" row-key="id" empty-text="没有符合条件的角色">
<template #actions="{ row }"><div v-if="canEdit || canGrant || access.can('platform:role:status') || access.can('platform:role:delete')" class="table-actions"><el-button v-if="canEdit || canGrant" link type="primary" :disabled="rowActionId === (row as Role).id || (row as Role).builtIn" @click="openEdit(row as Role)"><Pencil :size="15" />配置</el-button><el-button v-if="access.can('platform:role:status')" link :type="(row as Role).status === '启用' ? 'danger' : 'success'" :loading="rowActionId === (row as Role).id" :disabled="(row as Role).builtIn" @click="toggleStatus(row as Role)">{{ (row as Role).status === '启用' ? '停用' : '启用' }}</el-button><el-button v-if="access.can('platform:role:delete')" link type="danger" :disabled="(row as Role).builtIn || (row as Role).userCount > 0 || rowActionId === (row as Role).id" @click="removeRole(row as Role)"><Trash2 :size="15" />删除</el-button></div><span v-else class="secondary-text">仅查看</span></template>
<template #role="{ row }"><div class="role-cell"><span><ShieldCheck :size="18" /></span><div><strong>{{ (row as Role).name }}</strong><small>{{ (row as Role).code }}</small></div></div></template>
<template #permissionSummary="{ row }"><div class="primary-cell"><strong>{{ permissionSummary(row as Role) }}</strong><span>平台 IAM 权限</span></div></template>