Files
xh-medical-sign-web/clinical-web/src/views/management/documents/mock.ts
T
yelan 97c5182ba4 feat(文书管理): 增加版本工作流与版本历史
- 模板状态按后端原始状态展示与筛选,待审核与已驳回分开展示
- 仅已发布模板可发起签署,新增提交审核/审核通过/驳回等动作
- 新增版本历史弹窗,复用统一的模板时间格式化方法
- 演示数据补齐已签署任务的签名图,并提供获取签名 dataURL 的接口
- 修复编辑器插入占位符时未定位光标导致内容落到文首的问题
2026-09-17 16:44:54 +08:00

227 lines
8.0 KiB
TypeScript
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.
/**
* 文档库的演示数据与展示文案。
*
* 状态标签放在这里而不是随演示数据一起删掉:标签是纯展示映射,
* 接真实接口后照样要用,不能和"演示数据"捆在一起。
*
* 演示文书库的种子与读写逻辑在 utils/mock-document-library:
* 文档库页面和签署工作台必须读同一份数据,否则会出现「文档库里维护的模板,签署端选不到」,
* 或者签署端混着一批文档库里看不到、也无法维护的模板。
*/
import type { DocumentRecord } from '@/api/management/types'
import type { LocalDocument, LocalDepartment } from '@/utils/mock-document-library'
import { readDocumentLibrary, writeDocumentLibrary } from '@/utils/mock-document-library'
import type { DocumentDepartment, DocumentBackendStatus, DocumentStatus } from './types'
/**
* 演示文库与页面模型之间的归一。
*
* utils/mock-document-library 刻意只声明自己用到的字段(不反向依赖 views 的类型),
* 它返回的文书缺了页面模型要求的 category / updatedBy / updatedAt,code 也可能为空。
* 两种口径不一致会在 loadLibrary / saveDocumentLibrary 处直接报类型错误,
* 因此在这一层做一次显式补齐——而不是让 utils 反过来依赖 views,
* 也不是把页面的必填字段放宽成可选(放宽会掩盖真实接口返回缺字段的问题)。
*
* 补齐用的值都标注了是演示数据的缺省值,不冒充真实字段:
* updatedAt 留空串,页面会显示成"—",不会假装有一份真实的更新时间。
*/
function toDocumentRecord(document: LocalDocument, categoryName: string): DocumentRecord {
return {
...document,
code: document.code ?? '',
category: categoryName,
updatedBy: '演示数据',
updatedAt: document.updatedAt ?? '',
}
}
export function toDocumentDepartment(department: LocalDepartment): DocumentDepartment {
return {
...department,
categories: department.categories.map((category) => ({
...category,
documents: category.documents.map((document) => toDocumentRecord(document, category.name)),
})),
}
}
/** 读取演示文书库:优先用本地保存的,没有则用种子(调用方负责再克隆一份使用) */
export function loadDocumentLibrary(): DocumentDepartment[] {
return readDocumentLibrary().map(toDocumentDepartment)
}
/**
* 保存演示文书库。
* 落本地时要把 category 摘掉(LocalDocument 没有 category 字段,
* 分类信息在 categories 这一层的 name 上),否则多存一个字段会在下次读取时对不上。
* updatedBy 同理:它是页面模型为「必须有人维护」补的展示字段,不是演示文库的数据。
*/
export function saveDocumentLibrary(library: DocumentDepartment[]): void {
writeDocumentLibrary(
library.map((department) => ({
...department,
categories: department.categories.map((category) => ({
name: category.name,
documents: category.documents.map(toLocalDocument),
})),
})),
)
}
/**
* 页面模型的文书 → 演示文库存储结构。
*
* 逐字段列出而不是解构剔除:解构剔除(`const { category, ...rest }`)会因为
* 被剔除的变量未使用而触发 lint,且多加一个页面专用字段时容易忘掉同步。
* 这里明确列出演示文库认识哪些字段,多出来的页面字段(category / updatedBy)自然被丢掉。
*/
function toLocalDocument(document: DocumentRecord): LocalDocument {
return {
id: document.id,
name: document.name,
code: document.code,
version: document.version,
status: document.status,
backendStatus: document.backendStatus,
description: document.description ?? '',
versionId: document.versionId,
departmentId: document.departmentId,
departmentName: document.departmentName,
campusId: document.campusId,
campusName: document.campusName,
updatedAt: document.updatedAt,
contentHtml: document.contentHtml,
contentSha256: document.contentSha256,
}
}
/**
* 状态标签。键集合与后端模板状态枚举一一对应
* (见 api/management/types.ts 的 BackendTemplateStatus 与 documents.ts 的 normalizeDocumentStatus),
* 不再有后端枚举里不存在的 enabled。
*/
export const documentStatusLabels: Record<DocumentStatus, string> = {
draft: '草稿',
review: '需复审',
published: '已发布',
archived: '已归档',
}
/**
* 后端原始状态 → 中文标签。
*
* 卡片与预览弹窗用它,而不是归一后的 documentStatusLabels:归一过程把
* PENDING_REVIEW(待审核)和 REJECTED(已驳回)都并成了 review,
* 只看「需复审」分不清是「还等着审」还是「已经被打回」。
*/
export const backendStatusLabels: Record<DocumentBackendStatus, string> = {
DRAFT: '草稿',
PENDING_REVIEW: '待审核',
REJECTED: '已驳回',
APPROVED: '审核通过',
PUBLISHED: '已发布',
DISABLED: '已停用',
ARCHIVED: '已归档',
}
/**
* 状态页签的固定展示顺序:按文书生命周期排列(草稿 → 送审 → 驳回/通过 → 发布 → 停用 → 归档)。
* 固定顺序而不是按接口返回顺序,否则同一个库里状态一多,页签会来回跳。
*/
export const backendStatusOrder: DocumentBackendStatus[] = [
'DRAFT',
'PENDING_REVIEW',
'REJECTED',
'APPROVED',
'PUBLISHED',
'DISABLED',
'ARCHIVED',
]
/** 取状态标签:优先用后端原始状态(更精确),拿不到再退回归一后的状态 */
export function readStatusLabel(template: {
status: DocumentStatus
backendStatus?: string
}): string {
const backendLabel = template.backendStatus
? backendStatusLabels[template.backendStatus as DocumentBackendStatus]
: undefined
return backendLabel ?? documentStatusLabels[template.status]
}
/**
* 按后端状态取标签。
* 版本历史只有后端状态,没有归一后的 status,因此单独开一个入口。
* 遇到未知状态原样显示,不显示成空白——后端新增状态时至少能看见它是什么。
*/
export function readBackendStatusLabel(status: string | null | undefined): string {
if (!status) {
return '—'
}
return backendStatusLabels[status as DocumentBackendStatus] ?? status
}
/**
* 状态色调:决定状态徽标用哪一套配色。
*
* 不能直接用归一后的 DocumentStatus 当配色键——PENDING_REVIEW 与 REJECTED
* 归一后都是 review,两者会共用同一个颜色,页签与文字已经区分开了、颜色却还糊在一起。
*/
export type DocumentStatusTone = 'draft' | 'review' | 'rejected' | 'published' | 'archived'
export function readStatusTone(template: {
status: DocumentStatus
backendStatus?: string
}): DocumentStatusTone {
switch (readBackendStatus(template)) {
case 'PENDING_REVIEW':
return 'review'
case 'REJECTED':
return 'rejected'
case 'APPROVED':
case 'PUBLISHED':
return 'published'
case 'DISABLED':
case 'ARCHIVED':
return 'archived'
case 'DRAFT':
default:
return 'draft'
}
}
/**
* 取文书的后端原始状态,供状态页签归类。
*
* 真实模式的列表接口会给 backendStatus;演示库与部分历史数据可能没有,
* 这时按归一后的 status 反推一个等价状态,避免这类文书在页签里被漏掉。
*
* 反推对 'review' 是有损的:归一过程把 PENDING_REVIEW 与 REJECTED 合并了,
* 只能归到 PENDING_REVIEW。这只是缺字段时的兜底,不改变页签按真实状态过滤的口径。
*/
export function readBackendStatus(template: {
status: DocumentStatus
backendStatus?: string
}): DocumentBackendStatus {
const known = backendStatusOrder.find((status) => status === template.backendStatus)
if (known) {
return known
}
switch (template.status) {
case 'published':
return 'PUBLISHED'
case 'review':
return 'PENDING_REVIEW'
case 'archived':
return 'ARCHIVED'
case 'draft':
default:
return 'DRAFT'
}
}