Files
xh-medical-sign-web/clinical-web/src/views/management/document-permissions/index.vue

341 lines
8.7 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.
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getDepartments } from '@/api/management/organization'
import { getDocuments } from '@/api/management/documents'
import {
createTemplatePermission,
deleteTemplatePermission,
getTemplatePermissions,
isPermissionMockEnabled,
} from '@/api/management/document-permissions'
import { getRoles } from '@/api/management/roles'
import { getUsers } from '@/api/management/users'
import type { DocumentRecord, TemplatePermissionRecord } from '@/api/management/types'
import DepartmentPermissionTable from './components/DepartmentPermissionTable.vue'
import RolePermissionMatrix from './components/RolePermissionMatrix.vue'
import TemplatePermissionPanel from './components/TemplatePermissionPanel.vue'
import { departmentPermissionRows, permissionColumns, rolePermissionRows } from './mock'
import type {
DepartmentPermissionRow,
PermissionKey,
PermissionSubjectOption,
RolePermissionRow,
TemplatePermissionForm,
} from './types'
const loading = ref(true)
const roles = ref<RolePermissionRow[]>([])
const departments = ref<DepartmentPermissionRow[]>([])
const templates = ref<DocumentRecord[]>([])
const selectedTemplateId = ref('')
const templatePermissions = ref<TemplatePermissionRecord[]>([])
const permissionSubjects = ref<PermissionSubjectOption[]>([])
const permissionLoading = ref(false)
const permissionSaving = ref(false)
async function loadPermissions() {
loading.value = true
try {
if (isPermissionMockEnabled) {
roles.value = rolePermissionRows.map((role) => ({
...role,
permissions: { ...role.permissions },
}))
departments.value = departmentPermissionRows.map((row) => ({ ...row }))
return
}
const [templatesResult, rolesResult, departmentsResult, usersResult] = await Promise.allSettled(
[
getDocuments({ page: 1, pageSize: 200, status: 'all' }),
getRoles(),
getDepartments(),
getUsers({ page: 1, pageSize: 200, status: 'all' }),
],
)
if (templatesResult.status === 'rejected') {
throw templatesResult.reason
}
templates.value = templatesResult.value.records
selectedTemplateId.value = templates.value[0]?.id ?? ''
permissionSubjects.value = [
...(rolesResult.status === 'fulfilled'
? rolesResult.value.map((role) => ({
type: 'ROLE' as const,
id: role.id,
label: role.name,
}))
: []),
...(departmentsResult.status === 'fulfilled'
? departmentsResult.value.map((department) => ({
type: 'DEPARTMENT' as const,
id: department.id,
label: department.name,
}))
: []),
...(usersResult.status === 'fulfilled'
? usersResult.value.records.map((user) => ({
type: 'USER' as const,
id: user.id,
label: `${user.name}${user.employeeNo ? `${user.employeeNo}` : ''}`,
}))
: []),
]
await loadTemplatePermissions()
} catch {
templates.value = []
permissionSubjects.value = []
templatePermissions.value = []
ElMessage.error('权限配置加载失败,请稍后重试')
} finally {
loading.value = false
}
}
async function loadTemplatePermissions() {
if (!selectedTemplateId.value || isPermissionMockEnabled) {
templatePermissions.value = []
return
}
permissionLoading.value = true
try {
templatePermissions.value = await getTemplatePermissions(selectedTemplateId.value)
} catch {
templatePermissions.value = []
ElMessage.error('模板权限加载失败,请稍后重试')
} finally {
permissionLoading.value = false
}
}
function toggleRolePermission(roleId: string, permission: PermissionKey) {
const role = roles.value.find((item) => item.id === roleId)
if (!role) {
return
}
role.permissions[permission] = !role.permissions[permission]
ElMessage.info('权限已调整并记录审计日志')
}
function adjustDepartmentPermission(row: DepartmentPermissionRow) {
ElMessage.info(`原型演示:调整${row.department}文档权限`)
}
async function addTemplatePermission(form: TemplatePermissionForm) {
if (!selectedTemplateId.value) {
return
}
permissionSaving.value = true
try {
await createTemplatePermission(selectedTemplateId.value, form)
await loadTemplatePermissions()
ElMessage.success('模板权限已添加')
} catch {
ElMessage.error('模板权限添加失败,请稍后重试')
} finally {
permissionSaving.value = false
}
}
async function deleteTemplatePermissionRecord(permissionId: string) {
if (!selectedTemplateId.value || !window.confirm('确定删除这条模板权限吗?')) {
return
}
permissionSaving.value = true
try {
await deleteTemplatePermission(selectedTemplateId.value, permissionId)
await loadTemplatePermissions()
ElMessage.success('模板权限已删除')
} catch {
ElMessage.error('模板权限删除失败,请稍后重试')
} finally {
permissionSaving.value = false
}
}
function selectTemplate(templateId: string) {
selectedTemplateId.value = templateId
void loadTemplatePermissions()
}
onMounted(loadPermissions)
</script>
<template>
<section class="permissions-page">
<section class="page-card intro-card">
<div class="card-heading">
<h2>文档库权限矩阵</h2>
<span>可见 / 可用 / 可维护 分级授权下级继承上级</span>
</div>
<p>
可见=可浏览模板可用=可发起签署可维护=可编辑/停用模板科室签署员默认继承本科室可用权限调整即时生效并记录审计日志
</p>
</section>
<template v-if="loading">
<section class="page-card loading-card" aria-label="正在加载权限配置">
<span class="loading-title" />
<span class="loading-row" />
<span class="loading-row" />
<span class="loading-row short" />
</section>
</template>
<template v-else-if="isPermissionMockEnabled">
<section class="page-card">
<div class="card-heading">
<h2>按角色授权</h2>
</div>
<RolePermissionMatrix
:rows="roles"
:columns="permissionColumns"
@toggle="toggleRolePermission"
/>
</section>
<section class="page-card department-card">
<div class="card-heading">
<h2>按科室授权</h2>
<span>科室级别的文档可用范围</span>
</div>
<DepartmentPermissionTable :rows="departments" @adjust="adjustDepartmentPermission" />
</section>
</template>
<section v-else class="page-card">
<div class="card-heading">
<h2>模板权限</h2>
<span>按模板配置角色科室和用户的可见/可用/可维护权限</span>
</div>
<TemplatePermissionPanel
:templates="templates"
:selected-template-id="selectedTemplateId"
:permissions="templatePermissions"
:subjects="permissionSubjects"
:loading="permissionLoading"
:saving="permissionSaving"
@update:selected-template-id="selectTemplate"
@add="addTemplatePermission"
@delete="deleteTemplatePermissionRecord"
/>
</section>
</section>
</template>
<style scoped>
.permissions-page {
width: 100%;
max-width: 1440px;
margin: 0 auto;
}
.page-card {
padding: 16px 18px;
margin-bottom: 16px;
background: var(--card);
border-radius: var(--r);
box-shadow: var(--sh);
}
.intro-card {
margin-bottom: 14px;
}
.card-heading {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 14px;
}
.card-heading h2 {
margin: 0;
color: var(--ink);
font-size: 14.5px;
line-height: 1.4;
}
.card-heading span {
margin-left: auto;
color: var(--mut);
font-size: 12px;
}
.intro-card p {
margin: 0;
color: var(--mut);
font-size: 12px;
line-height: 1.8;
}
.department-card {
margin-top: 16px;
margin-bottom: 0;
}
.loading-card {
display: flex;
flex-direction: column;
gap: 14px;
min-height: 180px;
}
.loading-card span {
display: block;
background: linear-gradient(90deg, #edf3f5 25%, #f7fafb 37%, #edf3f5 63%);
background-size: 400% 100%;
border-radius: 6px;
animation: skeleton-shimmer 1.4s ease infinite;
}
.loading-title {
width: 28%;
height: 20px;
}
.loading-row {
width: 100%;
height: 14px;
}
.loading-row.short {
width: 70%;
}
@keyframes skeleton-shimmer {
0% {
background-position: 100% 0;
}
100% {
background-position: -100% 0;
}
}
@media (max-width: 600px) {
.card-heading {
align-items: flex-start;
flex-direction: column;
}
.card-heading span {
margin-left: 0;
}
}
</style>