533 lines
20 KiB
TypeScript
533 lines
20 KiB
TypeScript
/**
|
||
* 签署记录查询(工作台 · 签署记录查询)。
|
||
*
|
||
* 这里回答的是「历史签署记录」,与签署工作台那份「当前待办」不是同一个视角:
|
||
* 工作台按当天操作组织,记录页按条件检索全量历史,因此两边各有一份演示数据 ——
|
||
* 工作台的种子固定在某一天,直接拿它当历史记录,会让「今日 / 近 3 天」这些筛选
|
||
* 在演示里长期空着,看不出筛选到底有没有生效。两份种子的字段口径完全一致
|
||
* (都是 SigningRecord),真实模式下读的也是同一个接口,所以不存在两套业务语义。
|
||
*
|
||
* 真实模式复用已有的签署任务列表接口(GET /v1/sign-tasks):签署记录就是签署任务的
|
||
* 历史视图,后端目前没有单独的记录检索接口,前端不凭空造一个不存在的地址。
|
||
* 已知差异:后端该接口不支持按「文档类别」筛选,记录页会在真实模式下禁用这一项
|
||
* (见 SigningRecordFilterBar 的 categoryEnabled),不做静默忽略。
|
||
*/
|
||
|
||
import { DEMO_SIGNATURE_DATA_URL } from '@/utils/demo-signature'
|
||
import { mockFlags } from '@/utils/mock-flags'
|
||
import { buildFieldSpanHtml } from '@/utils/signing-fields'
|
||
|
||
import {
|
||
campusOfDepartment,
|
||
mockDocumentById,
|
||
mockDocumentCatalog,
|
||
type MockDocumentDef,
|
||
} from './mock-catalog'
|
||
import { getSigningTaskDetail, getSigningTaskEvents, getSigningTasks } from './signing'
|
||
import type {
|
||
PatientSex,
|
||
SigningApiOptions,
|
||
SigningFieldKind,
|
||
SigningMethod,
|
||
SigningRecord,
|
||
SigningRecordListResponse,
|
||
SigningRecordQuery,
|
||
SigningTaskEvent,
|
||
SigningTaskQuery,
|
||
SigningTaskRecord,
|
||
SigningTaskStatus,
|
||
VisitType,
|
||
} from './types'
|
||
|
||
const useMockData = mockFlags.signRecords
|
||
|
||
export const isSigningRecordsMockEnabled = useMockData
|
||
|
||
/** 签署记录的演示数据量上限:导出时逐页取回,避免一条筛选条件意外拉回整个库 */
|
||
const MAX_PAGES = 25
|
||
/** 导出/批量取回时单页条数 */
|
||
const BULK_PAGE_SIZE = 200
|
||
|
||
/**
|
||
* 演示正文。
|
||
*
|
||
* 记录页的「查看」要能打开当时的文书,所以演示记录必须带正文快照。
|
||
* 正文由文书定义现场生成(含结构化占位符,签名位与签署日期都能按记录取值回显),
|
||
* 不是渲染时兜底拼出来的假纸样 —— 那种兜底只在正文真的取不到时才允许出现。
|
||
*
|
||
* 惰性构建:buildFieldSpanHtml 依赖 DOM,模块在 Node 侧被 import 时不该直接抛错。
|
||
*/
|
||
let mockDocumentHtmlCache: Map<string, string> | null = null
|
||
|
||
function buildMockDocumentHtml(document: MockDocumentDef): string {
|
||
const field = (id: string, label: string, kind: SigningFieldKind = 'text', required = false) =>
|
||
buildFieldSpanHtml({ id, label, kind, required, options: [] })
|
||
|
||
return [
|
||
`<h2>${document.name}</h2>`,
|
||
'<h3>一、患者与就诊信息</h3>',
|
||
'<table><tbody>',
|
||
`<tr><td>患者姓名</td><td>${field('patient', '患者姓名', 'text', true)}</td>`,
|
||
`<td>性别</td><td>${field('sex', '性别')}</td></tr>`,
|
||
`<tr><td>年龄</td><td>${field('age', '年龄')}</td>`,
|
||
`<td>住院号/门诊号</td><td>${field('visit', '就诊号')}</td></tr>`,
|
||
'</tbody></table>',
|
||
'<h3>二、风险告知与注意事项</h3>',
|
||
`<ol>${document.items.map((item) => `<li>${item}</li>`).join('')}</ol>`,
|
||
'<p>医务人员已就上述诊疗方案、医疗风险、替代方案及可能出现的不良后果向患者本人(或授权委托人)充分说明,患者已完全理解并表示同意。</p>',
|
||
'<h3>三、签字确认</h3>',
|
||
'<table><tbody>',
|
||
`<tr><td>患者(或授权委托人)签名:${field('signature', '患者签名', 'signature', true)}</td>`,
|
||
`<td>签署日期:${field('signedDate', '签署日期', 'date', true)}</td></tr>`,
|
||
`<tr><td>经治医师签名:${field('doctor', '医师签名', 'signature')}</td><td></td></tr>`,
|
||
'</tbody></table>',
|
||
'<p>注:本知情同意书采用电子方式签署,签名图片与文书原件一并留存,可随时查验。</p>',
|
||
].join('')
|
||
}
|
||
|
||
function getMockDocumentHtml(documentId: string): string {
|
||
mockDocumentHtmlCache ??= new Map(
|
||
mockDocumentCatalog.map((document) => [document.id, buildMockDocumentHtml(document)]),
|
||
)
|
||
|
||
return mockDocumentHtmlCache.get(documentId) ?? ''
|
||
}
|
||
|
||
/* =========================================================================
|
||
演示数据:记录种子
|
||
========================================================================= */
|
||
|
||
/**
|
||
* 一条演示记录的种子。
|
||
*
|
||
* 只写「人 + 事」:患者 ID、就诊号、院区、失效时间这些都能由这几项派生出来
|
||
* (见 buildMockRecord),逐条手写既冗长又容易写错。
|
||
* `days` 是距今天数(0 = 今天),演示数据因此始终落在「今日 / 近 3 天 / 近 7 天」窗口内,
|
||
* 不会像写死日期那样,过几天就全部落到筛选范围之外。
|
||
*/
|
||
interface MockRecordSeed {
|
||
patient: string
|
||
sex: PatientSex
|
||
age: number
|
||
visitType: VisitType
|
||
/** mockDocumentCatalog 的 id */
|
||
doc: string
|
||
status: SigningTaskStatus
|
||
method: SigningMethod
|
||
days: number
|
||
/** 发起时刻 HH:mm */
|
||
at: string
|
||
/** 签署用时(分钟):只有已签署的记录才有 */
|
||
minutes?: number
|
||
source?: string
|
||
voidReason?: string
|
||
}
|
||
|
||
const MOCK_RECORD_SEEDS: MockRecordSeed[] = [
|
||
// 今天
|
||
{ patient: '赵美英', sex: '女', age: 58, visitType: '住院', doc: 'mock-doc-cardiac', status: 'signed', method: 'pad', days: 0, at: '09:12', minutes: 7 },
|
||
{ patient: '李淑芬', sex: '女', age: 67, visitType: '门诊', doc: 'mock-doc-mri', status: 'signed', method: 'sms', days: 0, at: '10:05', minutes: 4 },
|
||
{ patient: '周雅琴', sex: '女', age: 29, visitType: '门诊', doc: 'mock-doc-endoscopy', status: 'pending', method: 'sms', days: 0, at: '11:20' },
|
||
// 昨天
|
||
{ patient: '孙浩然', sex: '男', age: 54, visitType: '住院', doc: 'mock-doc-narcotic', status: 'signed', method: 'pad', days: 1, at: '08:40', minutes: 6, source: '工作台发起' },
|
||
{ patient: '王建国', sex: '男', age: 71, visitType: '住院', doc: 'mock-doc-blood', status: 'signed', method: 'sms', days: 1, at: '14:15', minutes: 9 },
|
||
{ patient: '陈志强', sex: '男', age: 61, visitType: '住院', doc: 'mock-doc-admission', status: 'void', method: 'pad', days: 1, at: '16:02', source: '工作台发起', voidReason: '文书选择错误,已重新发起' },
|
||
// 近 3 天
|
||
{ patient: '吴桂芳', sex: '女', age: 73, visitType: '住院', doc: 'mock-doc-surgery', status: 'signed', method: 'pad', days: 2, at: '09:35', minutes: 5 },
|
||
{ patient: '刘伟', sex: '男', age: 45, visitType: '门诊', doc: 'mock-doc-cardiac', status: 'signed', method: 'sms', days: 2, at: '15:48', minutes: 3, source: '工作台发起' },
|
||
{ patient: '郑海燕', sex: '女', age: 38, visitType: '门诊', doc: 'mock-doc-endoscopy', status: 'expired', method: 'sms', days: 3, at: '10:22' },
|
||
{ patient: '黄志明', sex: '男', age: 66, visitType: '住院', doc: 'mock-doc-mri', status: 'signed', method: 'pad', days: 3, at: '13:07', minutes: 8 },
|
||
// 近 7 天
|
||
{ patient: '徐丽华', sex: '女', age: 50, visitType: '住院', doc: 'mock-doc-blood', status: 'signed', method: 'pad', days: 4, at: '11:40', minutes: 6 },
|
||
{ patient: '马晓东', sex: '男', age: 33, visitType: '其他', doc: 'mock-doc-emergency', status: 'failed', method: 'pad', days: 5, at: '20:18', source: '工作台发起' },
|
||
{ patient: '何秀英', sex: '女', age: 79, visitType: '住院', doc: 'mock-doc-surgery', status: 'signed', method: 'sms', days: 6, at: '09:05', minutes: 12 },
|
||
{ patient: '林俊杰', sex: '男', age: 41, visitType: '门诊', doc: 'mock-doc-narcotic', status: 'signing', method: 'pad', days: 6, at: '14:52' },
|
||
// 近 30 天
|
||
{ patient: '罗美玲', sex: '女', age: 62, visitType: '门诊', doc: 'mock-doc-admission', status: 'expired', method: 'sms', days: 11, at: '17:30' },
|
||
{ patient: '高文斌', sex: '男', age: 57, visitType: '住院', doc: 'mock-doc-cardiac', status: 'signed', method: 'pad', days: 14, at: '10:10', minutes: 7 },
|
||
{ patient: '邓小燕', sex: '女', age: 36, visitType: '门诊', doc: 'mock-doc-mri', status: 'void', method: 'sms', days: 19, at: '08:55', voidReason: '患者拒绝签署,任务作废' },
|
||
{ patient: '苏国华', sex: '男', age: 68, visitType: '住院', doc: 'mock-doc-endoscopy', status: 'signed', method: 'pad', days: 26, at: '15:25', minutes: 6 },
|
||
]
|
||
|
||
function pad(value: number) {
|
||
return String(value).padStart(2, '0')
|
||
}
|
||
|
||
function formatDateTime(date: Date) {
|
||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(
|
||
date.getHours(),
|
||
)}:${pad(date.getMinutes())}`
|
||
}
|
||
|
||
/** 演示数据的就诊号前缀:与医院里门诊 / 住院 / 体检的编号习惯一致 */
|
||
const VISIT_NO_PREFIX: Record<VisitType, string> = {
|
||
门诊: 'MZ',
|
||
住院: 'ZY',
|
||
体检: 'TJ',
|
||
其他: 'JZ',
|
||
}
|
||
|
||
function buildMockRecord(seed: MockRecordSeed, index: number): SigningRecord {
|
||
const document = mockDocumentById.get(seed.doc)
|
||
|
||
if (!document) {
|
||
throw new Error(`演示签署记录引用了不存在的文书:${seed.doc}`)
|
||
}
|
||
|
||
const createdAtDate = new Date()
|
||
createdAtDate.setDate(createdAtDate.getDate() - seed.days)
|
||
const [hour, minute] = seed.at.split(':').map(Number)
|
||
createdAtDate.setHours(hour, minute, 0, 0)
|
||
|
||
const createdAt = formatDateTime(createdAtDate)
|
||
const signedDate = new Date(createdAtDate)
|
||
signedDate.setMinutes(signedDate.getMinutes() + (seed.minutes ?? 0))
|
||
const signedAt = seed.status === 'signed' ? formatDateTime(signedDate) : undefined
|
||
|
||
// 已超时的记录按 24 小时失效,其余按 48 小时;失效时间只做展示,不参与筛选
|
||
const expireHours = seed.status === 'expired' ? 24 : 48
|
||
const expiresAtDate = new Date(createdAtDate)
|
||
expiresAtDate.setHours(expiresAtDate.getHours() + expireHours)
|
||
|
||
const dateKey = `${createdAtDate.getFullYear()}${pad(createdAtDate.getMonth() + 1)}${pad(
|
||
createdAtDate.getDate(),
|
||
)}`
|
||
|
||
return {
|
||
id: `SR${dateKey}${pad(index + 1)}`,
|
||
templateVersionId: `${seed.doc}-v1`,
|
||
campus: campusOfDepartment(document.department),
|
||
patientId: `P2026${10001 + index}`,
|
||
patientName: seed.patient,
|
||
sex: seed.sex,
|
||
age: seed.age,
|
||
visitNo: `${VISIT_NO_PREFIX[seed.visitType]}${dateKey}${pad(index + 1)}`,
|
||
visitType: seed.visitType,
|
||
visitDate: `${createdAtDate.getFullYear()}-${pad(createdAtDate.getMonth() + 1)}-${pad(
|
||
createdAtDate.getDate(),
|
||
)}`,
|
||
documentId: document.id,
|
||
documentName: document.name,
|
||
category: document.category,
|
||
department: document.department,
|
||
signerName: seed.patient,
|
||
method: seed.method,
|
||
status: seed.status,
|
||
source: seed.source ?? '电子病历',
|
||
createdAt,
|
||
updatedAt: signedAt ?? createdAt,
|
||
signedAt,
|
||
expiresAt: formatDateTime(expiresAtDate),
|
||
voidReason: seed.voidReason,
|
||
// 已签署的记录带上签名图,否则「列表说已签署、打开没有签名」自相矛盾
|
||
signatureDataUrl: seed.status === 'signed' ? DEMO_SIGNATURE_DATA_URL : undefined,
|
||
documentContentHtml: getMockDocumentHtml(document.id),
|
||
}
|
||
}
|
||
|
||
/** 演示记录:种子派生一次,进程内复用(只读,不需要落盘) */
|
||
let mockRecordsCache: SigningRecord[] | null = null
|
||
|
||
function getMockRecords(): SigningRecord[] {
|
||
mockRecordsCache ??= MOCK_RECORD_SEEDS.map(buildMockRecord)
|
||
return mockRecordsCache
|
||
}
|
||
|
||
function cloneRecord(record: SigningRecord): SigningRecord {
|
||
return {
|
||
...record,
|
||
selectedItems: record.selectedItems ? [...record.selectedItems] : record.selectedItems,
|
||
fieldAnswers: record.fieldAnswers ? { ...record.fieldAnswers } : record.fieldAnswers,
|
||
}
|
||
}
|
||
|
||
/* =========================================================================
|
||
查询
|
||
========================================================================= */
|
||
|
||
function parseRecordTime(value: string | undefined) {
|
||
if (!value) {
|
||
return null
|
||
}
|
||
|
||
const date = new Date(value.replace(' ', 'T'))
|
||
return Number.isNaN(date.getTime()) ? null : date
|
||
}
|
||
|
||
/** 时间窗口:`to` 为开区间上界(不含),只有「今日 / 昨日」需要 */
|
||
function resolveDateWindow(range: SigningRecordQuery['dateRange']): {
|
||
from: Date
|
||
to: Date
|
||
} | null {
|
||
const todayStart = new Date()
|
||
todayStart.setHours(0, 0, 0, 0)
|
||
const tomorrowStart = new Date(todayStart)
|
||
tomorrowStart.setDate(tomorrowStart.getDate() + 1)
|
||
|
||
const daysBack = (days: number) => {
|
||
const from = new Date(todayStart)
|
||
from.setDate(from.getDate() - days)
|
||
return from
|
||
}
|
||
|
||
switch (range) {
|
||
case 'today':
|
||
return { from: todayStart, to: tomorrowStart }
|
||
case 'yesterday':
|
||
return { from: daysBack(1), to: todayStart }
|
||
case '3d':
|
||
return { from: daysBack(2), to: tomorrowStart }
|
||
case '7d':
|
||
return { from: daysBack(6), to: tomorrowStart }
|
||
case '30d':
|
||
return { from: daysBack(29), to: tomorrowStart }
|
||
default:
|
||
return null
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 记录查询条件 → 签署任务查询条件。
|
||
* 签署记录就是签署任务的历史视图,真实模式直接复用工作台的列表接口,
|
||
* 因此这里只做字段映射;后端不支持的条件(文档类别)在页面层已禁用,不会走到这里。
|
||
*/
|
||
function toTaskQuery(query: SigningRecordQuery): SigningTaskQuery {
|
||
return {
|
||
page: query.page,
|
||
pageSize: query.pageSize,
|
||
keyword: query.keyword,
|
||
status: query.status,
|
||
dateRange: query.dateRange,
|
||
campus: query.campus,
|
||
method: query.method,
|
||
department: query.department,
|
||
}
|
||
}
|
||
|
||
function toRecord(task: SigningTaskRecord): SigningRecord {
|
||
// 任务接口不返回文档类别,这里如实留空,由页面沿用列表里带出的那一份
|
||
return { ...task, category: '' }
|
||
}
|
||
|
||
export async function getSigningRecords(
|
||
query: SigningRecordQuery,
|
||
options: SigningApiOptions = {},
|
||
): Promise<SigningRecordListResponse> {
|
||
if (!useMockData) {
|
||
const page = await getSigningTasks(toTaskQuery(query), options)
|
||
|
||
return {
|
||
records: page.records.map(toRecord),
|
||
total: page.total,
|
||
page: page.page,
|
||
pageSize: page.pageSize,
|
||
}
|
||
}
|
||
|
||
const window = resolveDateWindow(query.dateRange)
|
||
const keyword = query.keyword?.trim().toLowerCase()
|
||
const filtered = getMockRecords().filter((record) => {
|
||
if (window) {
|
||
const createdAt = parseRecordTime(record.createdAt ?? record.updatedAt)
|
||
if (!createdAt || createdAt < window.from || createdAt >= window.to) {
|
||
return false
|
||
}
|
||
}
|
||
|
||
if (query.status && query.status !== 'all' && record.status !== query.status) {
|
||
return false
|
||
}
|
||
|
||
if (query.campus && query.campus !== 'all' && record.campus !== query.campus) {
|
||
return false
|
||
}
|
||
|
||
if (query.method && query.method !== 'all' && record.method !== query.method) {
|
||
return false
|
||
}
|
||
|
||
if (query.department && record.department !== query.department) {
|
||
return false
|
||
}
|
||
|
||
if (query.category && record.category !== query.category) {
|
||
return false
|
||
}
|
||
|
||
if (keyword) {
|
||
const haystack = [
|
||
record.id,
|
||
record.patientName,
|
||
record.patientId,
|
||
record.visitNo,
|
||
record.documentName,
|
||
]
|
||
.join(' ')
|
||
.toLowerCase()
|
||
|
||
if (!haystack.includes(keyword)) {
|
||
return false
|
||
}
|
||
}
|
||
|
||
return true
|
||
})
|
||
|
||
const sorted = filtered.sort(
|
||
(left, right) =>
|
||
(parseRecordTime(right.createdAt)?.getTime() ?? 0) -
|
||
(parseRecordTime(left.createdAt)?.getTime() ?? 0),
|
||
)
|
||
const page = Math.max(query.page, 1)
|
||
const pageSize = Math.max(query.pageSize, 1)
|
||
const start = (page - 1) * pageSize
|
||
|
||
return {
|
||
records: sorted.slice(start, start + pageSize).map(cloneRecord),
|
||
total: sorted.length,
|
||
page,
|
||
pageSize,
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 逐页取回当前筛选条件下的全部记录,供导出使用。
|
||
* 单次查询上限见 MAX_PAGES:宁可在演示/导出时截断并提示,也不要一条筛选条件
|
||
* 意外把整个库拉进浏览器内存。
|
||
*/
|
||
export async function getAllSigningRecords(
|
||
query: SigningRecordQuery,
|
||
options: SigningApiOptions = {},
|
||
): Promise<SigningRecord[]> {
|
||
const firstPage = await getSigningRecords(
|
||
{ ...query, page: 1, pageSize: BULK_PAGE_SIZE },
|
||
options,
|
||
)
|
||
const pageCount = Math.min(
|
||
Math.max(Math.ceil(firstPage.total / firstPage.pageSize), 1),
|
||
MAX_PAGES,
|
||
)
|
||
|
||
if (pageCount === 1) {
|
||
return firstPage.records
|
||
}
|
||
|
||
const rest = await Promise.all(
|
||
Array.from({ length: pageCount - 1 }, (_, index) =>
|
||
getSigningRecords({ ...query, page: index + 2, pageSize: BULK_PAGE_SIZE }, options),
|
||
),
|
||
)
|
||
|
||
return [firstPage, ...rest].flatMap((page) => page.records)
|
||
}
|
||
|
||
/** 记录详情:真实模式按任务接口取回正文快照与固化信息 */
|
||
export async function getSigningRecordDetail(
|
||
id: string,
|
||
options: SigningApiOptions = {},
|
||
): Promise<SigningRecord | null> {
|
||
if (!useMockData) {
|
||
const task = await getSigningTaskDetail(id, options)
|
||
return task ? toRecord(task) : null
|
||
}
|
||
|
||
const record = getMockRecords().find((item) => item.id === id)
|
||
return record ? cloneRecord(record) : null
|
||
}
|
||
|
||
/* =========================================================================
|
||
操作留痕
|
||
========================================================================= */
|
||
|
||
/**
|
||
* 演示留痕:按记录状态推导一条时间线。
|
||
*
|
||
* 与签署工作台的演示留痕同口径(创建 → 发送 → 签署 / 作废 → 结束),
|
||
* 但时间点一律取记录自身固化的时间,不掺"现在"—— 历史记录的操作时间
|
||
* 如果每次刷新都在变,就没法用来核对签署链路了。
|
||
*/
|
||
function buildMockEvents(record: SigningRecord): SigningTaskEvent[] {
|
||
const channel = record.method === 'pad' ? '手写板' : '短信'
|
||
const createdAt = record.createdAt ?? record.updatedAt
|
||
const events: SigningTaskEvent[] = [
|
||
{
|
||
id: `${record.id}-created`,
|
||
time: createdAt,
|
||
text: `张文静创建签署任务(${channel})`,
|
||
eventType: 'TASK_CREATED',
|
||
channel: record.method === 'pad' ? 'PAD' : 'SMS',
|
||
},
|
||
]
|
||
|
||
if (record.method === 'sms') {
|
||
events.push({
|
||
id: `${record.id}-sent`,
|
||
time: createdAt,
|
||
text: `已向 ${record.patientName} 预留手机号发送签署短信`,
|
||
eventType: 'SEND_PREPARED',
|
||
channel: 'SMS',
|
||
attemptNo: 1,
|
||
})
|
||
}
|
||
|
||
if (record.status === 'signing') {
|
||
events.push({
|
||
id: `${record.id}-signing`,
|
||
time: record.updatedAt,
|
||
text: '已打开签名采集,等待患者完成签名',
|
||
eventType: 'SIGNING_STARTED',
|
||
channel: 'PAD',
|
||
})
|
||
}
|
||
|
||
if (record.signedAt) {
|
||
events.push({
|
||
id: `${record.id}-signed`,
|
||
time: record.signedAt,
|
||
text: `患者 ${record.signerName} 完成签名,系统已合成文书并双留存`,
|
||
eventType: 'SIGNED',
|
||
channel: record.method === 'pad' ? 'PAD' : 'SMS',
|
||
})
|
||
}
|
||
|
||
if (record.status === 'expired') {
|
||
events.push({
|
||
id: `${record.id}-expired`,
|
||
time: record.expiresAt,
|
||
text: '签署链接已过期,任务自动结束(可重新发起)',
|
||
eventType: 'EXPIRED',
|
||
})
|
||
}
|
||
|
||
if (record.status === 'failed') {
|
||
events.push({
|
||
id: `${record.id}-failed`,
|
||
time: record.updatedAt,
|
||
text: '签名合成失败,请核对签名图与文书模板后重新发起',
|
||
eventType: 'FAILED',
|
||
reason: '签名合成失败',
|
||
})
|
||
}
|
||
|
||
if (record.status === 'void') {
|
||
events.push({
|
||
id: `${record.id}-voided`,
|
||
time: record.updatedAt,
|
||
text: `任务已作废${record.voidReason ? `,原因:${record.voidReason}` : ''}`,
|
||
eventType: 'VOIDED',
|
||
reason: record.voidReason,
|
||
})
|
||
}
|
||
|
||
return events
|
||
}
|
||
|
||
export async function getSigningRecordEvents(id: string): Promise<SigningTaskEvent[]> {
|
||
if (!useMockData) {
|
||
return getSigningTaskEvents(id)
|
||
}
|
||
|
||
const record = getMockRecords().find((item) => item.id === id)
|
||
return record ? buildMockEvents(record) : []
|
||
}
|