fix: 完善文档权限接口接入

This commit is contained in:
xy
2026-09-03 12:33:16 +08:00
parent 48e5293509
commit 925d8c9202
4 changed files with 193 additions and 39 deletions
@@ -12,12 +12,16 @@ const props = defineProps<{
subjects: PermissionSubjectOption[]
loading: boolean
saving: boolean
error: boolean
previewUserId: string
}>()
const emit = defineEmits<{
'update:selectedTemplateId': [value: string]
'update:previewUserId': [value: string]
add: [form: TemplatePermissionForm]
delete: [permissionId: string]
retry: []
}>()
const form = reactive<TemplatePermissionForm>({
@@ -48,6 +52,8 @@ const availableSubjects = computed(() =>
props.subjects.filter((subject) => subject.type === form.subjectType),
)
const previewUsers = computed(() => props.subjects.filter((subject) => subject.type === 'USER'))
const selectedTemplate = computed(() =>
props.templates.find((template) => template.id === props.selectedTemplateId),
)
@@ -56,6 +62,10 @@ function handleTemplateChange(event: Event) {
emit('update:selectedTemplateId', (event.target as HTMLSelectElement).value)
}
function handlePreviewUserChange(event: Event) {
emit('update:previewUserId', (event.target as HTMLSelectElement).value)
}
function handleSubjectTypeChange() {
form.subjectId = availableSubjects.value[0]?.id ?? ''
}
@@ -105,10 +115,23 @@ watch(
<span v-if="selectedTemplate" class="template-meta">
{{ selectedTemplate.code || selectedTemplate.id }} · {{ selectedTemplate.category }}
</span>
<label class="template-select preview-select">
<span>继承预览用户</span>
<select :value="previewUserId" :disabled="loading" @change="handlePreviewUserChange">
<option value="">当前登录用户</option>
<option v-for="user in previewUsers" :key="user.id" :value="user.id">
{{ user.label }}
</option>
</select>
</label>
</div>
<div v-if="!selectedTemplateId" class="empty-state">暂无模板,请先选择一个模板。</div>
<div v-else-if="loading" class="loading-state">正在加载模板权限…</div>
<div v-else-if="error" class="error-state">
<span>模板权限加载失败</span>
<button type="button" class="retry-button" @click="emit('retry')">重新加载</button>
</div>
<template v-else>
<div class="permission-list">
<div class="list-heading">
@@ -128,7 +151,18 @@ watch(
</tr>
</thead>
<tbody>
<tr v-for="permission in permissions" :key="permission.id">
<tr
v-for="permission in permissions"
:key="
permission.id ??
[
permission.subjectType,
permission.subjectId,
permission.permissionLevel,
permission.effect,
].join('-')
"
>
<td>
<span class="subject-type">{{ subjectTypeLabels[permission.subjectType] }}</span>
{{ formatSubject(permission.subjectType, permission.subjectId) }}
@@ -232,6 +266,10 @@ watch(
min-width: min(420px, 100%);
}
.preview-select {
min-width: min(280px, 100%);
}
select {
min-width: 0;
padding: 7px 10px;
@@ -356,13 +394,37 @@ td {
}
.empty-state,
.loading-state {
.loading-state,
.error-state {
padding: 32px 16px;
color: var(--mut);
font-size: 12.5px;
text-align: center;
}
.error-state {
display: flex;
gap: 10px;
align-items: center;
justify-content: center;
color: var(--err);
background: #f8fbfc;
border-radius: 6px;
}
.retry-button {
padding: 4px 10px;
color: var(--brand);
font-size: 12px;
background: #fff;
border: 1px solid var(--brand);
border-radius: 5px;
}
.retry-button:hover {
background: var(--brand-l);
}
.empty-state.compact {
padding: 18px 12px;
margin: 0;
@@ -2,7 +2,7 @@
import { computed, onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getDepartments } from '@/api/management/organization'
import { getAllDepartments } from '@/api/management/organization'
import { getDocuments } from '@/api/management/documents'
import {
createTemplatePermission,
@@ -11,7 +11,7 @@ import {
isPermissionMockEnabled,
} from '@/api/management/document-permissions'
import { getUsers } from '@/api/management/users'
import { getRoleSummaries } from '@/api/management/roles'
import { getRoleSummaries, getRoles } from '@/api/management/roles'
import type {
DepartmentRecord,
DocumentRecord,
@@ -54,6 +54,7 @@ const templatePermissions = ref<TemplatePermissionRecord[]>([])
const permissionLoading = ref(false)
const permissionSaving = ref(false)
const permissionError = ref(false)
const permissionPreviewUserId = ref('')
let permissionRequestId = 0
const selectedTemplate = computed(() =>
@@ -94,14 +95,14 @@ function resolvePermission(
const hasInheritedDeny = records.some((record) => record.inherited && record.effect === 'DENY')
const hasInheritedAllow = records.some((record) => record.inherited && record.effect === 'ALLOW')
if (hasDirectDeny) {
return { enabled: false, state: 'direct-deny' }
}
if (hasInheritedDeny) {
return { enabled: false, state: 'inherited-deny' }
}
if (hasDirectDeny) {
return { enabled: false, state: 'direct-deny' }
}
if (hasDirectAllow) {
return { enabled: true, state: 'direct-allow' }
}
@@ -132,7 +133,8 @@ function syncPermissionRows() {
name: role.name,
color: role.color ?? ['#6b5bd2', '#0e6e8c', '#0f9d6c', '#d9821f'][index % 4],
description: role.description,
userCount: role.userCount ?? 0,
userCount:
role.userCount ?? userRecords.value.filter((user) => user.roleIds?.includes(role.id)).length,
...buildPermissionMaps('ROLE', role.id),
}))
@@ -143,6 +145,41 @@ function syncPermissionRows() {
}))
}
async function getAllTemplatesForPermission() {
const firstPage = await getDocuments({ page: 1, pageSize: 200, status: 'all' })
const pageCount = Math.ceil(firstPage.total / firstPage.pageSize)
if (pageCount <= 1) {
return firstPage.records
}
const remainingPages = await Promise.all(
Array.from({ length: pageCount - 1 }, (_, index) =>
getDocuments({ page: index + 2, pageSize: firstPage.pageSize, status: 'all' }),
),
)
return [firstPage, ...remainingPages].flatMap((page) => page.records)
}
async function getRolesForPermission(): Promise<{
records: RoleRecord[]
usedFallback: boolean
}> {
try {
return { records: await getRoleSummaries(), usedFallback: false }
} catch (summaryError) {
try {
return {
records: await getRoles({ page: 1, pageSize: 200 }),
usedFallback: true,
}
} catch {
throw summaryError
}
}
}
async function getAllUsersForPermission() {
const firstPage = await getUsers({ page: 1, pageSize: 200, status: 'all' })
const pageCount = Math.ceil(firstPage.total / firstPage.pageSize)
@@ -178,9 +215,9 @@ async function loadPermissions() {
const [templatesResult, rolesResult, departmentsResult, usersResult] = await Promise.allSettled(
[
getDocuments({ page: 1, pageSize: 200, status: 'all' }),
getRoleSummaries(),
getDepartments(),
getAllTemplatesForPermission(),
getRolesForPermission(),
getAllDepartments(),
getAllUsersForPermission(),
],
)
@@ -189,8 +226,8 @@ async function loadPermissions() {
throw templatesResult.reason
}
templates.value = templatesResult.value.records
roleRecords.value = rolesResult.status === 'fulfilled' ? rolesResult.value : []
templates.value = templatesResult.value
roleRecords.value = rolesResult.status === 'fulfilled' ? rolesResult.value.records : []
departmentRecords.value =
departmentsResult.status === 'fulfilled' ? departmentsResult.value : []
userRecords.value = usersResult.status === 'fulfilled' ? usersResult.value : []
@@ -202,9 +239,17 @@ async function loadPermissions() {
usersResult.status === 'rejected'
) {
ElMessage.warning('角色、科室或用户列表加载不完整,部分授权对象暂不可配置')
} else if (rolesResult.value.usedFallback) {
ElMessage.warning('角色人数统计接口暂不可用,已回退到角色列表,人数仅按当前用户列表估算')
}
selectedTemplateId.value = templates.value[0]?.id ?? ''
if (!userRecords.value.some((user) => user.id === permissionPreviewUserId.value)) {
permissionPreviewUserId.value = ''
}
if (!templates.value.some((template) => template.id === selectedTemplateId.value)) {
selectedTemplateId.value = templates.value[0]?.id ?? ''
}
await loadTemplatePermissions()
} catch {
roleRecords.value = []
@@ -228,6 +273,7 @@ async function loadTemplatePermissions() {
if (!templateId || isPermissionMockEnabled) {
templatePermissions.value = []
permissionError.value = false
permissionLoading.value = false
return
}
@@ -235,7 +281,10 @@ async function loadTemplatePermissions() {
permissionError.value = false
try {
const records = await getTemplatePermissions(templateId)
const records = await getTemplatePermissions(
templateId,
permissionPreviewUserId.value || undefined,
)
if (requestId !== permissionRequestId || templateId !== selectedTemplateId.value) {
return
@@ -349,7 +398,7 @@ async function setSubjectPermission(
subjectId: string,
permission: PermissionKey,
) {
if (!selectedTemplateId.value || permissionSaving.value) {
if (!selectedTemplateId.value || permissionSaving.value || permissionError.value) {
return
}
@@ -381,7 +430,7 @@ async function setSubjectPermission(
}
async function addTemplatePermission(form: TemplatePermissionForm) {
if (!selectedTemplateId.value || permissionSaving.value) {
if (!selectedTemplateId.value || permissionSaving.value || permissionError.value) {
return
}
@@ -399,7 +448,7 @@ async function addTemplatePermission(form: TemplatePermissionForm) {
}
async function removeTemplatePermission(permissionId: string) {
if (!selectedTemplateId.value || permissionSaving.value) {
if (!selectedTemplateId.value || permissionSaving.value || permissionError.value) {
return
}
@@ -426,6 +475,11 @@ function handlePanelTemplateChange(templateId: string) {
void loadTemplatePermissions()
}
function handlePermissionPreviewUserChange(userId: string) {
permissionPreviewUserId.value = userId
void loadTemplatePermissions()
}
function retryTemplatePermissions() {
void loadTemplatePermissions()
}
@@ -541,9 +595,13 @@ onMounted(loadPermissions)
:subjects="templateSubjects"
:loading="permissionLoading"
:saving="permissionSaving"
:error="permissionError"
:preview-user-id="permissionPreviewUserId"
@update:selected-template-id="handlePanelTemplateChange"
@update:preview-user-id="handlePermissionPreviewUserChange"
@add="addTemplatePermission"
@delete="removeTemplatePermission"
@retry="retryTemplatePermissions"
/>
</section>
</template>