feat(签署工作台): 补代签标签、关联处方卡、线上等待态与只读副本
按原型 V10.2 详情页补齐四块: - 任务列表「代签」标签(原型 .vtag.chk 橙底):SigningTaskRecord 增加 signerType / signerRelation,仅签署人非「本人」时显示。 有意偏离:关系为空时不输出空括号(原型会渲染成「家属代签()」)。 - 「关联处方」可折叠卡(原型 rxCard):新建 api/workbench/prescriptions.ts 统一处方来源,把弹窗里那份搬过来消除重复,并新增详情用的 7 列明细。 原型两处处方口径本就不同(弹窗按就诊号哈希、详情按任务号派生),分开维护不合并。 真实模式返回空 → 整卡不渲染,不显示空表(会被读成「系统查过了,确实没处方」)。 顺带按原型调了详情卡片顺序:文书 → 签署文件 → 关联处方 → 操作留痕。 - 短信 / 公众号待签署的等待态(原型 .tg-wait):号码取后端 smsMobileMasked, 没有值时不拼号码,不拿患者档案里的号码冒充发送目标。 - 已签署的「在线预览(PDF)」与「只读副本」: 预览弹窗复用 SigningDocumentInteractive(只读态),保证预览 / 工作台 / 导出 PDF 三处版式一致;只读副本走 signing-pdf 新增的 watermark 选项, 在 html2canvas 克隆体上平铺斜排水印,审计编号直接用任务号。 水印行数按克隆体 scrollHeight 算,写死行数会让长文书下半部分没水印。
This commit is contained in:
@@ -14,6 +14,7 @@ import { formatSigningMethodTitle, readSigningMethod } from '@/utils/signing-met
|
||||
import SigningDocumentInteractive from '@/components/signing/SigningDocumentInteractive.vue'
|
||||
import SigningDocumentPreview from '@/components/signing/SigningDocumentPreview.vue'
|
||||
import TaskAuditTimeline from '@/components/signing/TaskAuditTimeline.vue'
|
||||
import LinkedPrescriptionCard from './LinkedPrescriptionCard.vue'
|
||||
import SigningArtifactList from './SigningArtifactList.vue'
|
||||
import type { SigningTaskAction } from '../types'
|
||||
|
||||
@@ -68,6 +69,25 @@ function isOnsiteMethod(method: SigningMethod): boolean {
|
||||
return method === 'pad' || method === 'ipad'
|
||||
}
|
||||
|
||||
/**
|
||||
* 线上方式(短信 / 公众号)的等待态提示(原型 renderPreview 里那条 `.tg-wait`)。
|
||||
*
|
||||
* 说的是「任务正等患者签」,这是任务状态本身能确认的事;
|
||||
* 短信再把发送目标带出来 —— 号码取后端返回的**脱敏值**,
|
||||
* 后端没给就只写「已发送」,不拿患者档案里的号码冒充发送目标。
|
||||
*/
|
||||
function waitingHint(task: SigningTaskRecord): string {
|
||||
const { icon, short } = readSigningMethod(task.method)
|
||||
|
||||
if (task.method === 'wx') {
|
||||
return `${icon} ${short}签署消息已推送 · 等待患者签署…`
|
||||
}
|
||||
|
||||
const mobile = task.smsMobileMasked?.trim()
|
||||
|
||||
return `${icon} ${short}${mobile ? `已发送至 ${mobile}` : '已发送'} · 等待患者签署…`
|
||||
}
|
||||
|
||||
/** 供父级「导出 PDF」使用:转发到实际渲染文书的那一层 */
|
||||
function getDocumentElement() {
|
||||
return documentRef.value?.getDocumentElement() ?? null
|
||||
@@ -113,6 +133,8 @@ defineExpose({ getDocumentElement })
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 线上方式先给等待态:这条任务此刻等的是患者,不是操作人 -->
|
||||
<span class="action-wait">{{ waitingHint(task) }}</span>
|
||||
<button
|
||||
v-if="allowLocalSigning"
|
||||
type="button"
|
||||
@@ -152,28 +174,48 @@ defineExpose({ getDocumentElement })
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="task.status === 'signed' && canDownloadArtifact">
|
||||
<!-- 已签署:预览是主入口(原型主按钮就是「在线预览(PDF)」),
|
||||
下载类动作在后;只读副本带水印与审计编号,对外提供时用那一份 -->
|
||||
<template v-else-if="task.status === 'signed'">
|
||||
<button
|
||||
v-if="canViewArtifacts"
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
@click="emit('action', 'download-pdf')"
|
||||
class="action-button"
|
||||
@click="emit('action', 'preview-signed')"
|
||||
>
|
||||
下载签署后 PDF
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
@click="emit('action', 'download-signature')"
|
||||
>
|
||||
签名原图
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
@click="emit('action', 'print')"
|
||||
>
|
||||
打印
|
||||
在线预览(PDF)
|
||||
</button>
|
||||
<template v-if="canDownloadArtifact">
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
@click="emit('action', 'download-pdf')"
|
||||
>
|
||||
下载 PDF 原件
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
title="生成带水印与审计编号的副本,对外提供时使用"
|
||||
@click="emit('action', 'download-readonly-copy')"
|
||||
>
|
||||
只读副本
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
@click="emit('action', 'download-signature')"
|
||||
>
|
||||
签名原图
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
@click="emit('action', 'print')"
|
||||
>
|
||||
打印
|
||||
</button>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<button
|
||||
@@ -208,12 +250,7 @@ defineExpose({ getDocumentElement })
|
||||
@signature-request="emit('signatureRequest', $event)"
|
||||
/>
|
||||
<SigningDocumentPreview v-else :task="task" />
|
||||
<TaskAuditTimeline
|
||||
v-if="canViewAudit"
|
||||
:events="auditEvents"
|
||||
:loading="auditLoading"
|
||||
:error="auditError"
|
||||
/>
|
||||
<!-- 顺序照原型:文书 → 签署文件(归档结果)→ 关联处方 → 操作留痕 -->
|
||||
<SigningArtifactList
|
||||
v-if="canViewArtifacts"
|
||||
:artifacts="artifacts"
|
||||
@@ -222,6 +259,13 @@ defineExpose({ getDocumentElement })
|
||||
:can-download="canDownloadArtifact"
|
||||
@download="emit('downloadArtifact', $event)"
|
||||
/>
|
||||
<LinkedPrescriptionCard :task="task" />
|
||||
<TaskAuditTimeline
|
||||
v-if="canViewAudit"
|
||||
:events="auditEvents"
|
||||
:loading="auditLoading"
|
||||
:error="auditError"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -275,6 +319,17 @@ defineExpose({ getDocumentElement })
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
/* 等待态:原型 .tag.tg-wait(信息蓝),与旁边的主按钮区分开 */
|
||||
.action-wait {
|
||||
align-self: center;
|
||||
padding: 5px 11px;
|
||||
color: var(--info);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
background: var(--info-l);
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 16px;
|
||||
|
||||
Reference in New Issue
Block a user