feat(documents): 文档归属按院区分组并改用科室 id 落库
This commit is contained in:
@@ -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<DocumentPropsForm>({
|
||||
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<OwnershipGroup[]>(() => {
|
||||
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,21 +223,24 @@ function submit() {
|
||||
|
||||
<div class="form-field span-2">
|
||||
<span>文档归属 <i>*</i></span>
|
||||
<div v-for="group in ownershipGroups" :key="group.key" class="ownership-group">
|
||||
<p class="ownership-group-title">{{ group.title }}</p>
|
||||
<div class="ownership">
|
||||
<label
|
||||
v-for="option in ownershipOptions"
|
||||
:key="option"
|
||||
v-for="option in group.options"
|
||||
:key="option.value"
|
||||
class="ownership-option"
|
||||
:class="{ 'is-general': option === GENERAL_OWNERSHIP }"
|
||||
:class="{ 'is-general': option.value === GENERAL_OWNERSHIP }"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="form.ownership.includes(option)"
|
||||
@change="toggleOwnership(option)"
|
||||
:checked="form.ownership.includes(option.value)"
|
||||
@change="toggleOwnership(option.value)"
|
||||
/>
|
||||
<span>{{ option }}</span>
|
||||
<span>{{ option.label }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="field-tip">
|
||||
勾选科室设置可见范围,支持多科室与通用(全院)。勾选「通用(全院)」后各科室均可见。
|
||||
</p>
|
||||
@@ -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));
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 的标签一致) */
|
||||
|
||||
@@ -49,7 +49,13 @@ export interface DocumentPropsForm {
|
||||
/** 文档类型,取自 library.DOCUMENT_TYPES */
|
||||
category: string
|
||||
versionNo: string
|
||||
/** 文档归属:科室名数组,可能含 GENERAL_OWNERSHIP(通用(全院)) */
|
||||
/**
|
||||
* 文档归属的勾选结果。
|
||||
*
|
||||
* 科室取 DepartmentRecord.id 而不是科室名:同一个科室名在不同院区是两条独立记录
|
||||
* (组织架构里就是分开的两条),拿名字既分不出院区、也定位不到唯一的科室。
|
||||
* 可能含 GENERAL_OWNERSHIP(通用(全院))。
|
||||
*/
|
||||
ownership: string[]
|
||||
description: string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user