feat: enable patient form interactions and revision-aware signing

This commit is contained in:
cnxianyi
2026-09-29 21:37:30 +08:00
parent dc94265703
commit 9173d623a1
17 changed files with 451 additions and 49 deletions
+67 -1
View File
@@ -1,8 +1,14 @@
import { reactive } from 'vue'
import { consumeSigningToken, fetchSigningContext, uploadSigningSignature } from '@/api'
import {
consumeSigningToken,
fetchSigningContext,
saveSigningForm,
uploadSigningSignature,
} from '@/api'
import type {
SignDeliveryChannel,
PatientAnswer,
SignatureUploadResponse,
SigningContextResponse,
} from '@/api/types'
@@ -58,6 +64,9 @@ const initialState: SignFlowState = {
documentContentHtml: '',
contentSha256: '',
staffAnswers: {},
form: null,
formSaving: false,
formError: '',
fields: [],
signatureFields: [],
documentLoaded: false,
@@ -88,6 +97,51 @@ let pendingToken: string | null = null
let consumeIdempotencyKey: string | null = null
let uploadIdempotencyKey: string | null = null
let formQueue: Promise<void> = Promise.resolve()
export function updatePatientAnswer(id: string, value: PatientAnswer) {
const form = signingState.form
const proof = currentProof()
if (!form?.editable || !proof || signingState.status === 'submitting' || signingState.formError)
return
if (!form.fields.some((field) => field.id === id && field.editable)) return
form.answers = { ...form.answers, [id]: value }
const answers = JSON.parse(JSON.stringify(form.answers)) as Record<string, PatientAnswer>
signingState.formSaving = true
formQueue = formQueue.then(async () => {
if (signingState.form !== form || signingState.formError) return
try {
const saved = await saveSigningForm(proof, form.revision, answers)
form.revision = saved.revision
} catch {
signingState.formError = '填写内容保存失败,请重新加载并核对后再签署。'
}
})
const current = formQueue
void current.finally(() => {
if (current === formQueue) signingState.formSaving = false
})
}
export async function flushPatientAnswers() {
await formQueue
if (signingState.formError) throw new Error(signingState.formError)
const form = signingState.form
if (!form) return
for (const field of form.fields) {
if (!field.editable || !field.required) continue
const value = form.answers[field.id]
if (
value === undefined ||
value === false ||
(typeof value === 'string' && !value.trim()) ||
(Array.isArray(value) && !value.length)
) {
throw new Error(`请完成必填项:${field.label}`)
}
}
}
export function resetSignFlow() {
Object.assign(signingState, {
...initialState,
@@ -287,6 +341,12 @@ function applyContext(context: SigningContextResponse) {
signingState.staffAnswers = { ...context.staffAnswers }
}
signingState.form = context.form
? { ...context.form, answers: { ...context.form.answers } }
: null
if (context.form) signingState.documentContentHtml = context.form.contentHtml
signingState.formError = ''
if (context.fields) {
signingState.fields = [...context.fields]
}
@@ -547,7 +607,9 @@ export async function submitRealSignature(input: {
const pending = await readPendingSigningUpload(signingState.taskId)
const idempotencyKey = pending?.idempotencyKey ?? uploadIdempotencyKey ?? createIdempotencyKey()
uploadIdempotencyKey = idempotencyKey
if (!pending) await flushPatientAnswers()
const signer = {
answerRevision: signingState.form?.revision,
type: signerType,
name: signerName,
relation,
@@ -603,6 +665,10 @@ export async function submitRealSignature(input: {
persistSession()
return null
}
if ([400, 409, 422].includes(getHttpStatus(error) ?? 0)) {
await removePendingSigningUpload(signingState.taskId).catch(() => undefined)
uploadIdempotencyKey = null
}
signingState.status = 'ready'
signingState.errorMessage = getErrorMessage(error)
throw error