From eda13a42c372ede97675ada269457dffe4567d70 Mon Sep 17 00:00:00 2001 From: yelan Date: Tue, 6 Oct 2026 19:56:47 +0800 Subject: [PATCH] =?UTF-8?q?feat(documents):=20=E6=96=87=E6=A1=A3=E5=BD=92?= =?UTF-8?q?=E5=B1=9E=E6=8C=89=E9=99=A2=E5=8C=BA=E5=88=86=E7=BB=84=E5=B9=B6?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E7=A7=91=E5=AE=A4=20id=20=E8=90=BD=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/DocumentPropsDialog.vue | 112 ++++++++++++++---- .../src/views/management/documents/index.vue | 21 +++- .../src/views/management/documents/library.ts | 16 +-- .../src/views/management/documents/types.ts | 8 +- 4 files changed, 121 insertions(+), 36 deletions(-) diff --git a/clinical-web/src/views/management/documents/components/DocumentPropsDialog.vue b/clinical-web/src/views/management/documents/components/DocumentPropsDialog.vue index 12e6dbd..2e13559 100644 --- a/clinical-web/src/views/management/documents/components/DocumentPropsDialog.vue +++ b/clinical-web/src/views/management/documents/components/DocumentPropsDialog.vue @@ -2,7 +2,7 @@ import { computed, reactive, watch } from 'vue' import { ElMessage } from 'element-plus' -import type { DepartmentRecord } from '@/api/management/types' +import type { CampusRecord, DepartmentRecord } from '@/api/management/types' import { DEFAULT_DOCUMENT_TYPE, DOCUMENT_TYPES, GENERAL_OWNERSHIP } from '../library' import { DOC_TEMPLATE_PERMISSIONS } from '../permissions' @@ -14,6 +14,8 @@ const props = defineProps<{ template: DocumentTemplate | null /** 可归属的科室(真实模式取组织接口,演示模式取演示字典) */ departments: DepartmentRecord[] + /** 院区字典,与组织架构页同源;用来给上面的科室分组 */ + campuses: CampusRecord[] /** * 是否可以把文档设为「通用(全院)」。 * @@ -54,19 +56,63 @@ const form = reactive({ description: '', }) -/** - * 归属勾选列表。 - * 顺序与原型 docDeptOpts 一致:科室名在前、「通用(全院)」在最后, - * 勾了通用(全院)就等于全院可见,其余科室勾选不再参与落库。 - */ -const ownershipOptions = computed(() => { - const names = props.departments.map((department) => department.name) +interface OwnershipOption { + /** 落库值:科室取 DepartmentRecord.id,「通用(全院)」取固定哨兵 */ + value: string + label: string +} - return props.canSetGeneral ? [...names, GENERAL_OWNERSHIP] : names +interface OwnershipGroup { + key: string + title: string + options: OwnershipOption[] +} + +/** + * 归属勾选列表:**按院区分组**,一个院区一个 .ownership 容器。 + * + * 组织架构里的科室本来就挂在院区下面(同名科室在不同院区是两条记录), + * 只摊平显示名字的话既看不出属于哪个院区、勾了也定位不到唯一的科室 id, + * 所以这里按科室的 campusId 归到对应院区下:显示院区名 + 科室名,取值用科室 id。 + * 「通用(全院)」不是科室、没有院区,单独放最后一组。 + */ +const ownershipGroups = computed(() => { + const groups: OwnershipGroup[] = [] + + for (const campus of props.campuses) { + const options = props.departments + .filter((department) => department.campusId === campus.id) + .map((department) => ({ value: department.id, label: department.name })) + + if (options.length) { + groups.push({ key: campus.id, title: campus.name, options }) + } + } + + // 院区字典里没有的科室单独兜底成一组,否则这些科室在弹窗里直接没得勾 + const campusIds = new Set(props.campuses.map((campus) => campus.id)) + const unassigned = props.departments + .filter((department) => !campusIds.has(department.campusId)) + .map((department) => ({ value: department.id, label: department.name })) + + if (unassigned.length) { + groups.push({ key: '__unassigned__', title: '未指定院区', options: unassigned }) + } + + if (props.canSetGeneral) { + groups.push({ + key: '__general__', + title: '全院', + options: [{ value: GENERAL_OWNERSHIP, label: GENERAL_OWNERSHIP }], + }) + } + + return groups }) const generalSelected = computed(() => form.ownership.includes(GENERAL_OWNERSHIP)) +/** option 是勾选值:科室 id,或 GENERAL_OWNERSHIP */ function toggleOwnership(option: string) { if (option === GENERAL_OWNERSHIP) { // 勾上「通用(全院)」就清掉科室勾选,取消则回到空选择—— @@ -104,7 +150,8 @@ watch( versionNo: template?.version ?? 'v1.0.0', ownership: template ? template.departmentId - ? [template.departmentName ?? ''].filter(Boolean) + ? // 回填主科室用 departmentId 本身:勾选值就是科室 id,不再经名字中转 + [template.departmentId] : [GENERAL_OWNERSHIP] : // 新增时预选当前用户所属科室(对得上就直接用,对不上就空着让科室自己勾) [], @@ -176,20 +223,23 @@ function submit() {
文档归属 * -
- +
+

{{ group.title }}

+
+ +

勾选科室设置可见范围,支持多科室与通用(全院)。勾选「通用(全院)」后各科室均可见。 @@ -390,7 +440,21 @@ function submit() { * 容器是浅底带框的 3 列网格,每项一张白卡(原生 checkbox + 科室名), * 「通用(全院)」独占一行并用浅蓝底区分(原型 grid-column:1/-1)。 * 科室名过长时截断:原型同一处就是 nowrap + ellipsis。 + * + * 与原型唯一的差别:这里按院区分成若干个 .ownership(一个院区一个), + * 每组上面带院区标题 —— 科室字典是多院区的,摊平成一列会分不出同名科室属于谁。 */ +.ownership-group + .ownership-group { + margin-top: 10px; +} + +.ownership-group-title { + margin: 0 0 6px; + color: var(--brand-d); + font-size: 11.5px; + font-weight: 700; +} + .ownership { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); diff --git a/clinical-web/src/views/management/documents/index.vue b/clinical-web/src/views/management/documents/index.vue index 5929ec0..ff9a693 100644 --- a/clinical-web/src/views/management/documents/index.vue +++ b/clinical-web/src/views/management/documents/index.vue @@ -41,6 +41,7 @@ import { toHistoryRows } from './history' import { canInitiateSigning, DOCUMENT_LIBRARY_STATUSES, + GENERAL_OWNERSHIP, readLibraryStatus, resolveOwnershipDepartmentId, templateWorkflowAction, @@ -461,6 +462,19 @@ function generateTemplateCode(name: string) { return `TPL-ED-${suffix}-${stamp}` } +/** + * 归属勾选结果 → 共享科室名清单(演示文库的 sharedDepartments 存的是科室名)。 + * + * 勾选值现在是科室 id(同名科室跨院区会重名,名字定位不到唯一一条), + * 这里在落本地前换回名字;「通用(全院)」与主科室本身不进这份清单。 + */ +function sharedDepartmentNames(ownership: string[], primaryDepartmentId: string | null): string[] { + return ownership + .filter((value) => value !== GENERAL_OWNERSHIP && value !== primaryDepartmentId) + .map((id) => departments.value.find((department) => department.id === id)?.name) + .filter((name): name is string => Boolean(name)) +} + /** * 在本地文库里定位一份文书(连同它所在的分组与类别)。 * @@ -526,7 +540,7 @@ function addLocalTemplate(form: DocumentPropsForm, departmentId: string | null): departmentName, campusId: campuses.value[0]?.id ?? '', contentHtml: '', - sharedDepartments: form.ownership.filter((name) => name !== departmentName), + sharedDepartments: sharedDepartmentNames(form.ownership, departmentId), } category.documents.push(record) @@ -562,7 +576,7 @@ function updateLocalProps(form: DocumentPropsForm, departmentId: string | null) document.departmentId = departmentId document.departmentName = targetName // 主科室进 departmentId,其余勾选科室留在 sharedDepartments(与新建时同一口径) - document.sharedDepartments = form.ownership.filter((name) => name !== targetName) + document.sharedDepartments = sharedDepartmentNames(form.ownership, departmentId) if (group.key !== targetKey) { category.documents = category.documents.filter((item) => item.id !== document.id) @@ -593,7 +607,7 @@ function updateLocalProps(form: DocumentPropsForm, departmentId: string | null) } async function handlePropsSubmit(form: DocumentPropsForm) { - const departmentId = resolveOwnershipDepartmentId(form.ownership, departments.value) + const departmentId = resolveOwnershipDepartmentId(form.ownership) if (useMockLibrary) { if (form.id) { @@ -1166,6 +1180,7 @@ onMounted(() => { :visible="propsDialogVisible" :template="propsTemplate" :departments="departments" + :campuses="campuses" :can-set-general="canSetGeneral" :is-mock="useMockLibrary" :saving="propsSaving" diff --git a/clinical-web/src/views/management/documents/library.ts b/clinical-web/src/views/management/documents/library.ts index 61550dd..1ee72b4 100644 --- a/clinical-web/src/views/management/documents/library.ts +++ b/clinical-web/src/views/management/documents/library.ts @@ -145,18 +145,18 @@ export function templateWorkflowLabel( */ export const GENERAL_OWNERSHIP = '通用(全院)' -/** 归属选项 → 后端可落库的科室 id(勾了通用(全院)就没有科室 id) */ -export function resolveOwnershipDepartmentId( - ownership: string[], - departments: Array<{ id: string; name: string }>, -): string | null { +/** + * 归属勾选 → 后端可落库的科室 id(勾了通用(全院)就没有科室 id)。 + * + * 勾选值本身就是 DepartmentRecord.id:同名科室在不同院区是两条记录, + * 这里不再拿名字去反查(反查只能取到第一条,会把院区指错)。 + */ +export function resolveOwnershipDepartmentId(ownership: string[]): string | null { if (ownership.includes(GENERAL_OWNERSHIP)) { return null } - const first = ownership.find((name) => name !== GENERAL_OWNERSHIP) - - return first ? (departments.find((department) => department.name === first)?.id ?? null) : null + return ownership.find((value) => value !== GENERAL_OWNERSHIP) ?? null } /** 归属徽标文案:全院通用用 🌐,科室用 🏥(与原型 tpl-card 的标签一致) */ diff --git a/clinical-web/src/views/management/documents/types.ts b/clinical-web/src/views/management/documents/types.ts index f1db22f..c47f7b0 100644 --- a/clinical-web/src/views/management/documents/types.ts +++ b/clinical-web/src/views/management/documents/types.ts @@ -49,7 +49,13 @@ export interface DocumentPropsForm { /** 文档类型,取自 library.DOCUMENT_TYPES */ category: string versionNo: string - /** 文档归属:科室名数组,可能含 GENERAL_OWNERSHIP(通用(全院)) */ + /** + * 文档归属的勾选结果。 + * + * 科室取 DepartmentRecord.id 而不是科室名:同一个科室名在不同院区是两条独立记录 + * (组织架构里就是分开的两条),拿名字既分不出院区、也定位不到唯一的科室。 + * 可能含 GENERAL_OWNERSHIP(通用(全院))。 + */ ownership: string[] description: string }