优化
This commit is contained in:
@@ -382,28 +382,30 @@ onMounted(loadInitialData)
|
||||
<template>
|
||||
<AdminPage class="admin-density iam-density" as="div">
|
||||
<ListPageLayout aria-label="内部用户管理">
|
||||
<template #toolbar>
|
||||
|
||||
|
||||
|
||||
<section :aria-busy="loading"><DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!loadError" v-model:page="page" v-model:page-size="pageSize" :data="users" :columns="userColumns" preference-key="internal-users-table"
|
||||
:loading="loading" :total="total" aria-label="内部用户列表" row-key="membershipId" empty-text="没有符合筛选条件的内部用户">
|
||||
<template #toolbar-start><h1>用户管理</h1></template>
|
||||
<template #filters>
|
||||
<QueryToolbar
|
||||
v-model="filters"
|
||||
class="surface-panel"
|
||||
ariaLabel="用户筛选"
|
||||
:fields="queryFields"
|
||||
preference-key="internal-users-query"
|
||||
@search="applyFilters"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="loadError" #state>
|
||||
<template #notices><template v-if="loadError">
|
||||
<LoadErrorState title="内部用户列表暂时无法加载" :message="loadError.message" :loading="loading" @retry="loadInitialData">
|
||||
<template #details><ApiErrorMeta :details="loadError" /></template>
|
||||
</LoadErrorState>
|
||||
</template>
|
||||
</template></template>
|
||||
|
||||
|
||||
<section v-if="!loadError" class="surface-panel table-panel" :aria-busy="loading">
|
||||
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="users" :columns="userColumns" preference-key="internal-users-table"
|
||||
:loading="loading" :total="total" aria-label="内部用户列表" row-key="membershipId" empty-text="没有符合筛选条件的内部用户">
|
||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />新增用户</el-button></template>
|
||||
<template #actions="{ row }">
|
||||
<div class="table-actions density-actions">
|
||||
<template #actions="{ row }"><div class="table-actions density-actions row-actions admin-text-actions">
|
||||
<el-button class="density-action" v-if="canEdit || canChangeStatus || canResetPassword" size="small" data-tone="neutral" @click="openEdit(row as PlatformManagedUser)">
|
||||
编辑
|
||||
</el-button>
|
||||
@@ -414,8 +416,7 @@ onMounted(loadInitialData)
|
||||
@click="toggleStatus(row as PlatformManagedUser)">
|
||||
{{ (row as PlatformManagedUser).status === 'ACTIVE' ? '禁用' : '启用' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div></template>
|
||||
<template #roles="{ row }">
|
||||
<div class="tag-list">
|
||||
<el-tag v-for="role in (row as PlatformManagedUser).roleNames" :key="role" effect="plain" size="small">{{ role }}</el-tag>
|
||||
@@ -425,8 +426,7 @@ onMounted(loadInitialData)
|
||||
<template #status="{ row }"><StatusBadge :status="(row as PlatformManagedUser).status === 'ACTIVE' ? '正常' : '禁用'" /></template>
|
||||
<template #lastLoginAt="{ row }">{{ formatLogin((row as PlatformManagedUser).lastLoginAt) }}</template>
|
||||
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 条</span></template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</DataTable></section>
|
||||
</ListPageLayout>
|
||||
|
||||
<AppDialog v-model="editorOpen" :title="editorLabel" width="min(650px, calc(100vw - 28px))" class="internal-user-editor-dialog admin-density-dialog iam-density" destroy-on-close :confirm-loading="saving" :confirm-text="editingUser ? '保存修改' : '确认添加'" @confirm="saveUser">
|
||||
|
||||
@@ -58,7 +58,7 @@ function mountServerView(permissionCodes = ['platform:permission:list', 'platfor
|
||||
LoadErrorState: { props: ['message'], template: '<div role="alert">{{ message }}<slot name="details" /></div>' },
|
||||
DataTable: {
|
||||
props: ['data'],
|
||||
template: '<section><slot name="toolbar-actions" /><div v-for="row in data" :key="row.id" class="row-actions" :data-row-id="row.id"><slot name="actions" :row="row" /></div><span data-testid="row-count">{{ data.length }}</span></section>',
|
||||
template: '<section><slot name="toolbar-start" /><slot name="toolbar-actions" /><slot name="filters" /><slot name="notices" /><slot name="before-results" /><div v-for="row in data" :key="row.id" class="row-actions" :data-row-id="row.id"><slot name="actions" :row="row" /></div><span data-testid="row-count">{{ data.length }}</span></section>',
|
||||
},
|
||||
'el-alert': { props: ['title'], template: '<div role="alert">{{ title }}<slot name="title" /></div>' },
|
||||
'el-input': true,
|
||||
@@ -91,7 +91,7 @@ describe('PermissionsView IAM mode', () => {
|
||||
expect(permissionsSource).toContain("{ key: 'edit', label: '编辑', priority: 300")
|
||||
expect(permissionsSource).toContain("{ key: 'status', label: row.status === '启用' ? '停用' : '启用'")
|
||||
expect(permissionsSource).toContain("{ key: 'delete', label: '删除', tone: 'danger', divided: true")
|
||||
expect(permissionsSource).toContain('<RowActions v-if="permissionActions(row as Permission).some')
|
||||
expect(permissionsSource).toContain('<RowActions text-actions v-if="permissionActions(row as Permission).some')
|
||||
expect(permissionsSource).toContain('<el-button link type="primary" @click="expandAllRows">展开全部</el-button>')
|
||||
expect(permissionsSource).not.toContain('canAddChild(row as Permission)" link')
|
||||
expect(permissionsSource).not.toContain('canEditRow(row as Permission)" link')
|
||||
|
||||
@@ -275,25 +275,28 @@ onMounted(loadPermissions)
|
||||
<template>
|
||||
<AdminPage class="admin-density iam-density" as="div">
|
||||
<ListPageLayout aria-label="平台权限资源管理">
|
||||
<template #toolbar><QueryToolbar v-model="filters" class="surface-panel" ariaLabel="权限筛选" :fields="queryFields" preference-key="permissions-query" @search="applyFilters" /></template>
|
||||
<template v-if="loadError" #state>
|
||||
|
||||
|
||||
|
||||
<section><DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!loadError" :key="tableRenderKey" v-model:page="page" v-model:page-size="pageSize" :data="pagedTreeRows" :columns="permissionColumns" preference-key="permissions-table" :loading="loading" :total="treeRows.length" row-key="id" aria-label="平台权限资源列表" :expand-row-keys="expandedRowKeys" :tree-props="{ children: 'children' }" empty-text="没有符合条件的权限资源">
|
||||
<template #toolbar-start><h1>菜单权限</h1></template>
|
||||
<template #filters><QueryToolbar v-model="filters" ariaLabel="权限筛选" :fields="queryFields" preference-key="permissions-query" @search="applyFilters" /></template>
|
||||
<template #notices><template v-if="loadError">
|
||||
<LoadErrorState title="权限资源暂时无法加载" :message="loadError.message" :loading="loading" @retry="loadPermissions">
|
||||
<template #details><ApiErrorMeta :details="loadError" /></template>
|
||||
</LoadErrorState>
|
||||
</template>
|
||||
</template></template>
|
||||
<template #before-results><div class="permission-tree-tools"><div class="legend-list"><span><i class="is-menu" />目录 / 菜单</span><span><i class="is-action" />操作</span><span><i class="is-api" />接口预留</span><span class="permission-protection-hint">受保护资源不可编辑、停用或删除</span></div><div class="tree-view-actions"><el-button link type="primary" @click="expandAllRows">展开全部</el-button><el-button link @click="collapseActionRows">收起操作权限</el-button></div></div></template>
|
||||
|
||||
|
||||
<section v-if="!loadError" class="surface-panel table-panel">
|
||||
<DataTable :key="tableRenderKey" v-model:page="page" v-model:page-size="pageSize" :data="pagedTreeRows" :columns="permissionColumns" preference-key="permissions-table" :loading="loading" :total="treeRows.length" row-key="id" aria-label="平台权限资源列表" :expand-row-keys="expandedRowKeys" :tree-props="{ children: 'children' }" empty-text="没有符合条件的权限资源">
|
||||
<template #toolbar-start><div class="permission-tree-tools"><div class="legend-list"><span><i class="is-menu" />目录 / 菜单</span><span><i class="is-action" />操作</span><span><i class="is-api" />接口预留</span><span class="permission-protection-hint">受保护资源不可编辑、停用或删除</span></div><div class="tree-view-actions"><el-button link type="primary" @click="expandAllRows">展开全部</el-button><el-button link @click="collapseActionRows">收起操作权限</el-button></div></div></template>
|
||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate(null)"><Plus :size="16" />新增权限</el-button></template>
|
||||
<template #actions="{ row }"><RowActions v-if="permissionActions(row as Permission).some(action => action.visible !== false)" :actions="permissionActions(row as Permission)" :more-label="moreActionsLabel(row as Permission)" @action="handlePermissionAction($event, row as Permission)" /><span v-else class="secondary-text">仅查看</span></template>
|
||||
<template #actions="{ row }"><RowActions text-actions v-if="permissionActions(row as Permission).some(action => action.visible !== false)" :actions="permissionActions(row as Permission)" :more-label="moreActionsLabel(row as Permission)" @action="handlePermissionAction($event, row as Permission)" /><span v-else class="secondary-text">仅查看</span></template>
|
||||
<template #name="{ row }"><div class="permission-name"><span :class="`is-${typeClass((row as Permission).type)}`"><FolderTree v-if="['目录', '菜单', '页面'].includes((row as Permission).type)" :size="16" /><ShieldCheck v-else-if="(row as Permission).type === '按钮'" :size="16" /><Braces v-else :size="16" /></span><div><strong>{{ (row as Permission).name }}</strong><small v-if="(row as PermissionTreeNode).children?.length">{{ permissionSummary(row as PermissionTreeNode) }}</small></div></div></template>
|
||||
<template #code="{ row }"><code class="code-value">{{ (row as Permission).code }}</code></template>
|
||||
<template #endpoint="{ row }"><div class="endpoint-cell"><span v-if="(row as Permission).method !== '-'">{{ (row as Permission).method }}</span><code>{{ (row as Permission).path || '-' }}</code></div></template>
|
||||
<template #status="{ row }"><StatusBadge :status="(row as Permission).status || '—'" /></template>
|
||||
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 项</span></template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</DataTable></section>
|
||||
</ListPageLayout>
|
||||
|
||||
<AppDialog v-model="editorOpen" :title="form.id ? '编辑权限资源' : '新增权限资源'" width="min(720px, calc(100vw - 28px))" class="permission-editor-dialog admin-density-dialog iam-density" :confirm-loading="saving" :confirm-text="form.id ? '保存修改' : '保存权限'" :show-confirm="form.id ? canEdit : canCreate" @confirm="savePermission">
|
||||
|
||||
@@ -45,7 +45,7 @@ function mountView(pinia = createPinia()) {
|
||||
FormSection: { template: '<section><slot /></section>' },
|
||||
AppDialog: { template: '<section><slot /><slot name="footer" /></section>' },
|
||||
LoadErrorState: { props: ['message'], template: '<div role="alert">{{ message }}<slot name="details" /></div>' },
|
||||
DataTable: { props: ['data'], template: '<section><slot name="toolbar-actions" /><span data-testid="row-count">{{ data.length }}</span></section>' },
|
||||
DataTable: { props: ['data'], template: '<section><slot name="toolbar-start" /><slot name="toolbar-actions" /><slot name="filters" /><slot name="notices" /><span data-testid="row-count">{{ data.length }}</span></section>' },
|
||||
'el-alert': { props: ['title'], template: '<div role="alert">{{ title }}<slot name="title" /></div>' },
|
||||
'el-input': true,
|
||||
'el-option': true,
|
||||
@@ -76,7 +76,7 @@ describe('RolesView', () => {
|
||||
expect(rolesSource).toContain("(row as Role).status || '—'")
|
||||
})
|
||||
it('uses bordered striped tables and semantic role operation buttons', () => {
|
||||
expect(rolesSource).toContain('border stripe')
|
||||
expect(rolesSource).toContain('appearance="integrated" :stripe="false"')
|
||||
expect(rolesSource).toContain('size="small" data-tone="neutral"')
|
||||
expect(rolesSource).toContain('size="small" :data-tone=')
|
||||
expect(rolesSource).toContain('size="small" data-tone="danger"')
|
||||
|
||||
@@ -238,24 +238,27 @@ onMounted(loadRoles)
|
||||
<template>
|
||||
<AdminPage class="admin-density iam-density" as="div">
|
||||
<ListPageLayout aria-label="平台角色管理">
|
||||
<template #toolbar><QueryToolbar v-model="filters" class="surface-panel" ariaLabel="角色筛选" :fields="queryFields" preference-key="roles-query" @search="applyFilters" /></template>
|
||||
<template v-if="loadError" #state>
|
||||
|
||||
|
||||
|
||||
<section><DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!loadError" 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" border aria-label="平台角色列表" empty-text="没有符合条件的角色">
|
||||
<template #toolbar-start><h1>角色权限</h1></template>
|
||||
<template #filters><QueryToolbar v-model="filters" ariaLabel="角色筛选" :fields="queryFields" preference-key="roles-query" @search="applyFilters" /></template>
|
||||
<template #notices><template v-if="loadError">
|
||||
<LoadErrorState title="角色列表暂时无法加载" :message="loadError.message" :loading="loading" @retry="loadRoles">
|
||||
<template #details><ApiErrorMeta :details="loadError" /></template>
|
||||
</LoadErrorState>
|
||||
</template>
|
||||
</template></template>
|
||||
|
||||
|
||||
<section v-if="!loadError" class="surface-panel table-panel">
|
||||
<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" border stripe aria-label="平台角色列表" empty-text="没有符合条件的角色">
|
||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />新增角色</el-button></template>
|
||||
<template #actions="{ row }"><div v-if="canEdit || canGrant || access.can('platform:role:status') || access.can('platform:role:delete')" class="table-actions density-actions"><el-button class="density-action" v-if="canEdit || canGrant" size="small" data-tone="neutral" :disabled="rowActionId === (row as Role).id || (row as Role).builtIn" @click="openEdit(row as Role)">配置</el-button><el-button class="density-action" v-if="access.can('platform:role:status')" size="small" :data-tone="(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 class="density-action" v-if="access.can('platform:role:delete')" size="small" data-tone="danger" :disabled="(row as Role).builtIn || (row as Role).userCount > 0 || rowActionId === (row as Role).id" @click="removeRole(row as Role)">删除</el-button></div><span v-else class="secondary-text">仅查看</span></template>
|
||||
<template #actions="{ row }"><div class="row-actions density-actions admin-text-actions"><div v-if="canEdit || canGrant || access.can('platform:role:status') || access.can('platform:role:delete')" class="table-actions density-actions"><el-button class="density-action" v-if="canEdit || canGrant" size="small" data-tone="neutral" :disabled="rowActionId === (row as Role).id || (row as Role).builtIn" @click="openEdit(row as Role)">配置</el-button><el-button class="density-action" v-if="access.can('platform:role:status')" size="small" :data-tone="(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 class="density-action" v-if="access.can('platform:role:delete')" size="small" data-tone="danger" :disabled="(row as Role).builtIn || (row as Role).userCount > 0 || rowActionId === (row as Role).id" @click="removeRole(row as Role)">删除</el-button></div><span v-else class="secondary-text">仅查看</span></div></template>
|
||||
<template #role="{ row }"><div class="role-cell"><span><ShieldCheck :size="18" /></span><div><strong>{{ (row as Role).name }}</strong></div></div></template>
|
||||
<template #permissionSummary="{ row }"><div class="primary-cell"><strong>{{ permissionSummary(row as Role) }}</strong><span>平台 IAM 权限</span></div></template>
|
||||
<template #roleType="{ row }"><el-tag :type="(row as Role).builtIn ? 'warning' : 'info'" effect="plain" size="small">{{ (row as Role).builtIn ? '系统内置' : '自定义' }}</el-tag></template>
|
||||
<template #status="{ row }"><StatusBadge :status="(row as Role).status || '—'" /></template>
|
||||
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 条</span></template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</DataTable></section>
|
||||
</ListPageLayout>
|
||||
|
||||
<AppDialog v-model="editorOpen" :title="form.id ? '配置角色' : '新增角色'" width="min(860px, calc(100vw - 28px))" class="role-editor-dialog admin-density-dialog iam-density" :confirm-loading="saving" confirm-text="保存角色" :show-confirm="form.id ? canEdit || canGrant : canCreate" destroy-on-close @opened="initializePermissionSelection" @confirm="saveRole">
|
||||
|
||||
@@ -5,18 +5,18 @@ export const iamRoutes = [
|
||||
path: 'system/users',
|
||||
name: 'users',
|
||||
component: () => import('@/modules/iam/pages/InternalUsersView.vue'),
|
||||
meta: { title: '用户管理', description: '统一管理平台内部用户、状态及角色', permission: 'platform:user:list' },
|
||||
meta: { showPageHeading: false, title: '用户管理', description: '统一管理平台内部用户、状态及角色', permission: 'platform:user:list' },
|
||||
},
|
||||
{
|
||||
path: 'system/roles',
|
||||
name: 'roles',
|
||||
component: () => import('@/modules/iam/pages/RolesView.vue'),
|
||||
meta: { title: '角色权限', description: '维护平台角色并配置菜单及操作权限', permission: 'platform:role:list' },
|
||||
meta: { showPageHeading: false, title: '角色权限', description: '维护平台角色并配置菜单及操作权限', permission: 'platform:role:list' },
|
||||
},
|
||||
{
|
||||
path: 'system/permissions',
|
||||
name: 'permissions',
|
||||
component: () => import('@/modules/iam/pages/PermissionsView.vue'),
|
||||
meta: { title: '菜单权限', description: '维护菜单、页面、按钮和接口权限编码', permission: 'platform:permission:list' },
|
||||
meta: { showPageHeading: false, title: '菜单权限', description: '维护菜单、页面、按钮和接口权限编码', permission: 'platform:permission:list' },
|
||||
},
|
||||
] satisfies RouteRecordRaw[]
|
||||
|
||||
Reference in New Issue
Block a user