feat: enable patient form interactions and revision-aware signing
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user