- 已按任务固化的文书版本渲染(填写项已按患者信息预填)
+
{{ signatureStateLabel }}
diff --git a/patient-h5/src/api/index.ts b/patient-h5/src/api/index.ts
index 33509a9..7f162cb 100644
--- a/patient-h5/src/api/index.ts
+++ b/patient-h5/src/api/index.ts
@@ -5,6 +5,7 @@ import type {
ApiResponse,
SignatureUploadInput,
SignatureUploadResponse,
+ SigningContextResponse,
TokenConsumeRequest,
TokenConsumeResponse,
} from './types'
@@ -19,6 +20,21 @@ export function consumeSigningToken(payload: TokenConsumeRequest): Promise {
+ return request
+ .get>('/v1/sign-deliveries/token/context', {
+ params: { token },
+ })
+ .then(unwrapApiResponse)
+}
+
function createIdempotencyKey(value?: string) {
if (value) {
return value
diff --git a/patient-h5/src/api/types.ts b/patient-h5/src/api/types.ts
index 9b04ec7..cf2a174 100644
--- a/patient-h5/src/api/types.ts
+++ b/patient-h5/src/api/types.ts
@@ -6,10 +6,20 @@ export interface ApiResponse {
timestamp?: string
}
-export type SignDeliveryChannel = 'PAD' | 'SMS'
+/**
+ * 投递渠道。
+ *
+ * - `PAD`:现场手写板,设备上跑的就是本 H5;
+ * - `SMS`:短信链接;
+ * - `WX`:微信公众号(2026-09-28 补 —— 原契约只有 PAD / SMS,公众号一直没落点)。
+ *
+ * 注意 **Pad 移动端签署不走这里**:那是在医护端工作台里用平板现场签的,不产生投递。
+ */
+export type SignDeliveryChannel = 'PAD' | 'SMS' | 'WX'
export interface TokenConsumeRequest {
token: string
+ /** 允许不传:渠道由 token 决定,前端不该替后端写死一个 */
channel?: SignDeliveryChannel
taskId?: string
}
@@ -23,6 +33,82 @@ export interface TokenConsumeResponse {
timestamp?: string | null
}
+/** 患者端看到的任务状态。不是 `WAITING_SIGN` 时不该放行签署 */
+export type SigningTaskSignStatus =
+ | 'WAITING_SIGN'
+ | 'SIGNED'
+ | 'EXPIRED'
+ | 'VOIDED'
+ | 'FAILED'
+ | string
+
+export interface SigningContextPatient {
+ name?: string | null
+ sex?: string | null
+ age?: number | null
+ visitNo?: string | null
+ department?: string | null
+}
+
+/** 签署人信息。按业务口径由医生在医护端填好,患者端只展示、不修改 */
+export interface SigningContextSigner {
+ /** `SELF` = 本人;`FAMILY` = 家属代签 */
+ type?: string | null
+ name?: string | null
+ relation?: string | null
+}
+
+export interface SigningContextTemplate {
+ name?: string | null
+ category?: string | null
+ versionNo?: string | null
+}
+
+export interface SigningContextDocument {
+ contentHtml?: string | null
+ contentSha256?: string | null
+}
+
+export interface SigningContextFieldOption {
+ value: string
+ label?: string | null
+}
+
+export interface SigningContextField {
+ id: string
+ label?: string | null
+ kind?: string | null
+ required?: boolean | null
+ options?: SigningContextFieldOption[] | null
+}
+
+/**
+ * 患者端读取本次签署的完整上下文。
+ *
+ * 与 `token/consume` 的职责**分开**:consume 是「消费一次」换投递凭证,
+ * 这个接口要能**重复调用**(患者刷新、返回上一步都要能重进)。
+ */
+export interface SigningContextResponse {
+ taskId: string
+ deliveryId?: string | null
+ channel?: SignDeliveryChannel | null
+ status?: SigningTaskSignStatus | null
+ expiresAt?: string | null
+ patient?: SigningContextPatient | null
+ signer?: SigningContextSigner | null
+ template?: SigningContextTemplate | null
+ document?: SigningContextDocument | null
+ /**
+ * 医生已填的结果(含医师签名图),患者端**只读**渲染进正文占位符。
+ *
+ * 刻意与 `document.contentHtml` 分开:医生填了什么要能单独追溯,
+ * 烙进正文 HTML 就查不出「谁在什么时候填了什么」。
+ */
+ staffAnswers?: Record | null
+ /** 患者端可交互的字段。按约定只有主签名位(`id === 'signature'`) */
+ fields?: SigningContextField[] | null
+}
+
export type SignatureUploadStatus =
'CREATED' | 'WAITING_SIGN' | 'SIGNED' | 'EXPIRED' | 'VOIDED' | 'GENERATING' | 'FAILED' | string
diff --git a/patient-h5/src/components/DocumentPaper.vue b/patient-h5/src/components/DocumentPaper.vue
new file mode 100644
index 0000000..5fe636d
--- /dev/null
+++ b/patient-h5/src/components/DocumentPaper.vue
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+
diff --git a/patient-h5/src/components/SignatureCanvas.vue b/patient-h5/src/components/SignatureCanvas.vue
index e3adc2e..250cdc1 100644
--- a/patient-h5/src/components/SignatureCanvas.vue
+++ b/patient-h5/src/components/SignatureCanvas.vue
@@ -1,44 +1,111 @@
@@ -115,16 +216,19 @@ defineExpose({ clearSignature, isEmpty })
请在框内手写签名
签名需清晰完整
-
+
+
+ {{ placeholder }}
+