/** * 文档库的展示口径:状态、归属、文档类型。 * * 状态筛选只有**两组**:启用中 / 停用(2026-09-28 收敛)。卡片可以显示「待发布」等 * 具体版本状态,但不为这些状态增加独立页签。 * 后端仍保留完整版本状态;readLibraryStatus 在这里将它们归入两个筛选组。 * * 后端模板状态枚举(DRAFT / PENDING_REVIEW / APPROVED / PUBLISHED / DISABLED / * ARCHIVED)在接口中保留,因此这里提供**折叠**:把原始状态压成两个筛选组。 * 反向映射(口径 → 后端)只保留「按状态过滤」这一处需要,见 toBackendStatusFilter。 */ import type { DocumentRecord, DocumentStatus } from '@/api/management/types' import type { TemplateVersionAction } from '@/api/management/documents' /** 文档库页签与卡片上的状态,取值即显示文案 */ export type DocumentLibraryStatus = '启用中' | '停用' /** 页签固定顺序:启用中排最前,停用排最后 */ export const DOCUMENT_LIBRARY_STATUSES: DocumentLibraryStatus[] = ['启用中', '停用'] /** 状态色调:决定徽标配色 */ export type DocumentStatusTone = 'enabled' | 'stopped' const STATUS_TONES: Record = { 启用中: 'enabled', 停用: 'stopped', } /** 状态徽标前的圆点颜色 */ export const DOCUMENT_STATUS_DOT: Record = { enabled: '#0f9d6c', stopped: '#c0c8cd', } /** * 后端原始状态 → 页面两档口径。 * * 折叠规则只有一条:**能确定已下线的算「停用」,其余一律「启用中」**。 * - DISABLED / ARCHIVED 都是下线语义(前者可再启用,后者是终态),一并算「停用」; * - DRAFT / PENDING_REVIEW / REJECTED / APPROVED / PUBLISHED 与未知取值都算「启用中」: * 审核链路已废弃,新建的文书也直接按「启用中」处理(不再有草稿这一档)。 * * 兜底取「启用中」而不是「停用」:口径只有两档时,把不认识的状态显示成「停用」 * 会让科室以为文书被下线了,而它其实只是状态取值没对齐——那是更坏的误报。 */ export function readLibraryStatus(record: { status: DocumentStatus backendStatus?: string }): DocumentLibraryStatus { switch (record.backendStatus) { case 'DISABLED': case 'ARCHIVED': return '停用' case 'DRAFT': case 'PENDING_REVIEW': case 'REJECTED': case 'APPROVED': case 'PUBLISHED': return '启用中' default: break } // 没有 backendStatus 的历史数据(演示文库、早期本地缓存)按归一后的状态反推 return record.status === 'archived' ? '停用' : '启用中' } export function readStatusTone(status: DocumentLibraryStatus): DocumentStatusTone { return STATUS_TONES[status] } /** * 状态页签 → 后端查询参数。 * * 只用于「真实模式按状态向服务端过滤」;页面上默认仍是一次拉全量再本地过滤 * (口径折叠后一个页签对应多个后端状态,服务端做不到一次查全)。 * 后端接口重写后这里的取值要跟着改;改不动就返回 undefined, * 调用方据此退回本地过滤,而不是拿一个错的状态去查。 */ export function toBackendStatusFilter(status: DocumentLibraryStatus): string | undefined { switch (status) { case '启用中': return 'PUBLISHED' case '停用': return 'DISABLED' default: return undefined } } /** 只有「启用中」的文书能发起签署:停用已下线 */ export function canInitiateSigning(status: DocumentLibraryStatus): boolean { return status === '启用中' } /** * 后端版本状态对应的文书操作。DRAFT 和 DISABLED 使用 enable;APPROVED 使用 publish; * 已发布版本使用 disable。审核中、驳回和归档状态不提供切换。 */ export function templateWorkflowAction( record: Pick, ): TemplateVersionAction | null { switch (record.backendStatus?.toUpperCase()) { case 'DRAFT': case 'DISABLED': return 'enable' case 'APPROVED': return 'publish' case 'PUBLISHED': return 'disable' case 'PENDING_REVIEW': case 'REJECTED': case 'ARCHIVED': return null default: // 演示文库没有后端状态,仍按启用中 / 停用两档切换。 if (record.backendStatus) return null return readLibraryStatus(record) === '停用' ? 'enable' : 'disable' } } export function templateWorkflowLabel( record: Pick, ): string { switch (record.backendStatus?.toUpperCase()) { case 'DRAFT': case 'APPROVED': return '发布' case 'DISABLED': return '启用' case 'PUBLISHED': return '停用' default: return record.backendStatus ? '' : readLibraryStatus(record) === '停用' ? '启用' : '停用' } } /** * 文档归属:原型把「通用(全院)」当作科室清单里的一个选项一起勾选, * 勾中它就等于全院通用,其余科室勾选一并作废(见 docDeptPicks / openDocProps)。 */ export const GENERAL_OWNERSHIP = '通用(全院)' /** 归属选项 → 后端可落库的科室 id(勾了通用(全院)就没有科室 id) */ export function resolveOwnershipDepartmentId( ownership: string[], departments: Array<{ id: string; name: 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 } /** 归属徽标文案:全院通用用 🌐,科室用 🏥(与原型 tpl-card 的标签一致) */ export function readOwnershipLabel(record: DocumentRecord): string { if (!record.departmentId) { return '🌐 全院通用' } const name = record.departmentName ?? '未知科室' return `🏥 ${name}` } /** 归属是否为全院通用:卡片标签配色与归属勾选回填都要用同一个判据 */ export function isGeneralOwnership(record: DocumentRecord): boolean { return !record.departmentId } /** * 文档类型。 * 与原型 docTypes 同一份取值,属性弹窗用下拉而不是自由输入: * 类型是分组的键,自由输入会让「知情同意书 / 知情同意书 」这类写法分成两组。 */ export const DOCUMENT_TYPES = [ '知情同意书', '风险告知书', '入院告知', '检查预约单', '授权委托', ] export const DEFAULT_DOCUMENT_TYPE = '知情同意书'