feat(documents): 文档归属按院区分组并改用科室 id 落库
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import { computed, reactive, watch } from 'vue'
|
import { computed, reactive, watch } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
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 { DEFAULT_DOCUMENT_TYPE, DOCUMENT_TYPES, GENERAL_OWNERSHIP } from '../library'
|
||||||
import { DOC_TEMPLATE_PERMISSIONS } from '../permissions'
|
import { DOC_TEMPLATE_PERMISSIONS } from '../permissions'
|
||||||
@@ -14,6 +14,8 @@ const props = defineProps<{
|
|||||||
template: DocumentTemplate | null
|
template: DocumentTemplate | null
|
||||||
/** 可归属的科室(真实模式取组织接口,演示模式取演示字典) */
|
/** 可归属的科室(真实模式取组织接口,演示模式取演示字典) */
|
||||||
departments: DepartmentRecord[]
|
departments: DepartmentRecord[]
|
||||||
|
/** 院区字典,与组织架构页同源;用来给上面的科室分组 */
|
||||||
|
campuses: CampusRecord[]
|
||||||
/**
|
/**
|
||||||
* 是否可以把文档设为「通用(全院)」。
|
* 是否可以把文档设为「通用(全院)」。
|
||||||
*
|
*
|
||||||
@@ -54,19 +56,63 @@ const form = reactive<DocumentPropsForm>({
|
|||||||
description: '',
|
description: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
interface OwnershipOption {
|
||||||
* 归属勾选列表。
|
/** 落库值:科室取 DepartmentRecord.id,「通用(全院)」取固定哨兵 */
|
||||||
* 顺序与原型 docDeptOpts 一致:科室名在前、「通用(全院)」在最后,
|
value: string
|
||||||
* 勾了通用(全院)就等于全院可见,其余科室勾选不再参与落库。
|
label: string
|
||||||
*/
|
}
|
||||||
const ownershipOptions = computed(() => {
|
|
||||||
const names = props.departments.map((department) => department.name)
|
|
||||||
|
|
||||||
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))
|
const generalSelected = computed(() => form.ownership.includes(GENERAL_OWNERSHIP))
|
||||||
|
|
||||||
|
/** option 是勾选值:科室 id,或 GENERAL_OWNERSHIP */
|
||||||
function toggleOwnership(option: string) {
|
function toggleOwnership(option: string) {
|
||||||
if (option === GENERAL_OWNERSHIP) {
|
if (option === GENERAL_OWNERSHIP) {
|
||||||
// 勾上「通用(全院)」就清掉科室勾选,取消则回到空选择——
|
// 勾上「通用(全院)」就清掉科室勾选,取消则回到空选择——
|
||||||
@@ -104,7 +150,8 @@ watch(
|
|||||||
versionNo: template?.version ?? 'v1.0.0',
|
versionNo: template?.version ?? 'v1.0.0',
|
||||||
ownership: template
|
ownership: template
|
||||||
? template.departmentId
|
? template.departmentId
|
||||||
? [template.departmentName ?? ''].filter(Boolean)
|
? // 回填主科室用 departmentId 本身:勾选值就是科室 id,不再经名字中转
|
||||||
|
[template.departmentId]
|
||||||
: [GENERAL_OWNERSHIP]
|
: [GENERAL_OWNERSHIP]
|
||||||
: // 新增时预选当前用户所属科室(对得上就直接用,对不上就空着让科室自己勾)
|
: // 新增时预选当前用户所属科室(对得上就直接用,对不上就空着让科室自己勾)
|
||||||
[],
|
[],
|
||||||
@@ -176,20 +223,23 @@ function submit() {
|
|||||||
|
|
||||||
<div class="form-field span-2">
|
<div class="form-field span-2">
|
||||||
<span>文档归属 <i>*</i></span>
|
<span>文档归属 <i>*</i></span>
|
||||||
<div class="ownership">
|
<div v-for="group in ownershipGroups" :key="group.key" class="ownership-group">
|
||||||
<label
|
<p class="ownership-group-title">{{ group.title }}</p>
|
||||||
v-for="option in ownershipOptions"
|
<div class="ownership">
|
||||||
:key="option"
|
<label
|
||||||
class="ownership-option"
|
v-for="option in group.options"
|
||||||
:class="{ 'is-general': option === GENERAL_OWNERSHIP }"
|
:key="option.value"
|
||||||
>
|
class="ownership-option"
|
||||||
<input
|
:class="{ 'is-general': option.value === GENERAL_OWNERSHIP }"
|
||||||
type="checkbox"
|
>
|
||||||
:checked="form.ownership.includes(option)"
|
<input
|
||||||
@change="toggleOwnership(option)"
|
type="checkbox"
|
||||||
/>
|
:checked="form.ownership.includes(option.value)"
|
||||||
<span>{{ option }}</span>
|
@change="toggleOwnership(option.value)"
|
||||||
</label>
|
/>
|
||||||
|
<span>{{ option.label }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="field-tip">
|
<p class="field-tip">
|
||||||
勾选科室设置可见范围,支持多科室与通用(全院)。勾选「通用(全院)」后各科室均可见。
|
勾选科室设置可见范围,支持多科室与通用(全院)。勾选「通用(全院)」后各科室均可见。
|
||||||
@@ -390,7 +440,21 @@ function submit() {
|
|||||||
* 容器是浅底带框的 3 列网格,每项一张白卡(原生 checkbox + 科室名),
|
* 容器是浅底带框的 3 列网格,每项一张白卡(原生 checkbox + 科室名),
|
||||||
* 「通用(全院)」独占一行并用浅蓝底区分(原型 grid-column:1/-1)。
|
* 「通用(全院)」独占一行并用浅蓝底区分(原型 grid-column:1/-1)。
|
||||||
* 科室名过长时截断:原型同一处就是 nowrap + ellipsis。
|
* 科室名过长时截断:原型同一处就是 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 {
|
.ownership {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import { toHistoryRows } from './history'
|
|||||||
import {
|
import {
|
||||||
canInitiateSigning,
|
canInitiateSigning,
|
||||||
DOCUMENT_LIBRARY_STATUSES,
|
DOCUMENT_LIBRARY_STATUSES,
|
||||||
|
GENERAL_OWNERSHIP,
|
||||||
readLibraryStatus,
|
readLibraryStatus,
|
||||||
resolveOwnershipDepartmentId,
|
resolveOwnershipDepartmentId,
|
||||||
templateWorkflowAction,
|
templateWorkflowAction,
|
||||||
@@ -461,6 +462,19 @@ function generateTemplateCode(name: string) {
|
|||||||
return `TPL-ED-${suffix}-${stamp}`
|
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,
|
departmentName,
|
||||||
campusId: campuses.value[0]?.id ?? '',
|
campusId: campuses.value[0]?.id ?? '',
|
||||||
contentHtml: '',
|
contentHtml: '',
|
||||||
sharedDepartments: form.ownership.filter((name) => name !== departmentName),
|
sharedDepartments: sharedDepartmentNames(form.ownership, departmentId),
|
||||||
}
|
}
|
||||||
|
|
||||||
category.documents.push(record)
|
category.documents.push(record)
|
||||||
@@ -562,7 +576,7 @@ function updateLocalProps(form: DocumentPropsForm, departmentId: string | null)
|
|||||||
document.departmentId = departmentId
|
document.departmentId = departmentId
|
||||||
document.departmentName = targetName
|
document.departmentName = targetName
|
||||||
// 主科室进 departmentId,其余勾选科室留在 sharedDepartments(与新建时同一口径)
|
// 主科室进 departmentId,其余勾选科室留在 sharedDepartments(与新建时同一口径)
|
||||||
document.sharedDepartments = form.ownership.filter((name) => name !== targetName)
|
document.sharedDepartments = sharedDepartmentNames(form.ownership, departmentId)
|
||||||
|
|
||||||
if (group.key !== targetKey) {
|
if (group.key !== targetKey) {
|
||||||
category.documents = category.documents.filter((item) => item.id !== document.id)
|
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) {
|
async function handlePropsSubmit(form: DocumentPropsForm) {
|
||||||
const departmentId = resolveOwnershipDepartmentId(form.ownership, departments.value)
|
const departmentId = resolveOwnershipDepartmentId(form.ownership)
|
||||||
|
|
||||||
if (useMockLibrary) {
|
if (useMockLibrary) {
|
||||||
if (form.id) {
|
if (form.id) {
|
||||||
@@ -1166,6 +1180,7 @@ onMounted(() => {
|
|||||||
:visible="propsDialogVisible"
|
:visible="propsDialogVisible"
|
||||||
:template="propsTemplate"
|
:template="propsTemplate"
|
||||||
:departments="departments"
|
:departments="departments"
|
||||||
|
:campuses="campuses"
|
||||||
:can-set-general="canSetGeneral"
|
:can-set-general="canSetGeneral"
|
||||||
:is-mock="useMockLibrary"
|
:is-mock="useMockLibrary"
|
||||||
:saving="propsSaving"
|
:saving="propsSaving"
|
||||||
|
|||||||
@@ -145,18 +145,18 @@ export function templateWorkflowLabel(
|
|||||||
*/
|
*/
|
||||||
export const GENERAL_OWNERSHIP = '通用(全院)'
|
export const GENERAL_OWNERSHIP = '通用(全院)'
|
||||||
|
|
||||||
/** 归属选项 → 后端可落库的科室 id(勾了通用(全院)就没有科室 id) */
|
/**
|
||||||
export function resolveOwnershipDepartmentId(
|
* 归属勾选 → 后端可落库的科室 id(勾了通用(全院)就没有科室 id)。
|
||||||
ownership: string[],
|
*
|
||||||
departments: Array<{ id: string; name: string }>,
|
* 勾选值本身就是 DepartmentRecord.id:同名科室在不同院区是两条记录,
|
||||||
): string | null {
|
* 这里不再拿名字去反查(反查只能取到第一条,会把院区指错)。
|
||||||
|
*/
|
||||||
|
export function resolveOwnershipDepartmentId(ownership: string[]): string | null {
|
||||||
if (ownership.includes(GENERAL_OWNERSHIP)) {
|
if (ownership.includes(GENERAL_OWNERSHIP)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const first = ownership.find((name) => name !== GENERAL_OWNERSHIP)
|
return ownership.find((value) => value !== GENERAL_OWNERSHIP) ?? null
|
||||||
|
|
||||||
return first ? (departments.find((department) => department.name === first)?.id ?? null) : null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 归属徽标文案:全院通用用 🌐,科室用 🏥(与原型 tpl-card 的标签一致) */
|
/** 归属徽标文案:全院通用用 🌐,科室用 🏥(与原型 tpl-card 的标签一致) */
|
||||||
|
|||||||
@@ -49,7 +49,13 @@ export interface DocumentPropsForm {
|
|||||||
/** 文档类型,取自 library.DOCUMENT_TYPES */
|
/** 文档类型,取自 library.DOCUMENT_TYPES */
|
||||||
category: string
|
category: string
|
||||||
versionNo: string
|
versionNo: string
|
||||||
/** 文档归属:科室名数组,可能含 GENERAL_OWNERSHIP(通用(全院)) */
|
/**
|
||||||
|
* 文档归属的勾选结果。
|
||||||
|
*
|
||||||
|
* 科室取 DepartmentRecord.id 而不是科室名:同一个科室名在不同院区是两条独立记录
|
||||||
|
* (组织架构里就是分开的两条),拿名字既分不出院区、也定位不到唯一的科室。
|
||||||
|
* 可能含 GENERAL_OWNERSHIP(通用(全院))。
|
||||||
|
*/
|
||||||
ownership: string[]
|
ownership: string[]
|
||||||
description: string
|
description: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user