From f7804d476d1400df339e9a8d4887288db36acb64 Mon Sep 17 00:00:00 2001 From: xy Date: Mon, 28 Sep 2026 21:04:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(sign):=20=E8=A1=A5=E9=BD=90=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E6=9F=A5=E8=AF=A2=E9=99=A2=E5=8C=BA=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- clinical-web/src/api/workbench/signing.ts | 10 ++++----- .../signing/NewSigningTaskDialog.vue | 9 ++++++++ .../src/composables/useSigningTaskForm.ts | 21 +++++++++++++++++-- .../src/views/workbench/signing/index.vue | 15 ++++++++++--- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7c47159..671c50e 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ medical-sign/ ## 签署接口契约 - 模板版本的 `formFields` 保存文书字段定义,`signatureFields` 单独保存患者签名在 PDF 中的页码、坐标、宽高和坐标系;编辑器中的坐标单位为 PDF point。发布模板前必须配置 `signature` 字段的位置。 -- `GET /api/v1/templates/available-versions` 返回 `formFields` 和 `needConfirm`。创建任务时将人工填写值放入 `staffAnswers`,并传入 `signerType`、`signerName`、`signerRelation`;患者、性别、年龄、就诊号和电话等已知字段仍由后端快照覆盖。 +- `GET /api/v1/templates/available-versions` 必须传入当前选择的 `campusId`,并返回 `formFields` 和 `needConfirm`。创建任务时将人工填写值放入 `staffAnswers`,并传入 `signerType`、`signerName`、`signerRelation`;患者、性别、年龄、就诊号和电话等已知字段仍由后端快照覆盖。 - H5 先调用 `POST /api/v1/sign-deliveries/token/consume`,再用返回的 `taskId`、`deliveryId`、`uploadToken` 调用 `POST /api/v1/sign-deliveries/token/context`。上传使用 `POST /api/v1/sign-deliveries/{taskId}/signature` multipart,包含 `file`、`metadata` 和 `signer` JSON 部分,并复用 `Idempotency-Key` 安全重试。 - 患者签署后,任务可能处于 `GENERATING`、`WAITING_CONFIRM` 或 `SIGNED`。刷新结果页时 H5 使用只读 context 查询恢复服务端状态,不能将这些状态退回为可重复签署。 diff --git a/clinical-web/src/api/workbench/signing.ts b/clinical-web/src/api/workbench/signing.ts index 597a6dd..8138863 100644 --- a/clinical-web/src/api/workbench/signing.ts +++ b/clinical-web/src/api/workbench/signing.ts @@ -1146,12 +1146,10 @@ export async function getPatientProfile(keyword: string): Promise { +export async function getSigningTemplates(query: { + campusId: string + departmentId?: string +}): Promise { if (!useMockData) { const response = await request.get< ApiResponseOf< diff --git a/clinical-web/src/components/signing/NewSigningTaskDialog.vue b/clinical-web/src/components/signing/NewSigningTaskDialog.vue index 4ef549a..755a81f 100644 --- a/clinical-web/src/components/signing/NewSigningTaskDialog.vue +++ b/clinical-web/src/components/signing/NewSigningTaskDialog.vue @@ -70,6 +70,7 @@ const { visits, } = useSigningTaskForm({ campus: computed(() => appStore.selectedCampus), + campusId: computed(() => appStore.selectedCampusId), initialTemplate, }) @@ -165,6 +166,14 @@ watch( return } + await appStore.loadCampuses() + if (!appStore.selectedCampusId) { + ElMessage.error( + appStore.campusLoadFailed ? '院区加载失败,无法加载文书模板' : '当前没有可用院区', + ) + return + } + resetForm() await loadTemplates() await nextTick() diff --git a/clinical-web/src/composables/useSigningTaskForm.ts b/clinical-web/src/composables/useSigningTaskForm.ts index 53d1ac2..526f612 100644 --- a/clinical-web/src/composables/useSigningTaskForm.ts +++ b/clinical-web/src/composables/useSigningTaskForm.ts @@ -23,6 +23,7 @@ import type { export interface UseSigningTaskFormOptions { campus: MaybeRefOrGetter + campusId: MaybeRefOrGetter initialTemplate?: MaybeRefOrGetter } @@ -85,6 +86,7 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) { /** 左列选中的科室与分类(原型 ntDeptSel / ntCatSel) */ const selectedDepartment = ref('') const selectedCategory = ref('') + let loadedTemplateCampusId = '' const errors = reactive({ patient: '', @@ -382,11 +384,26 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) { } async function loadTemplates() { - if (!templates.value.length) { + const campusId = toValue(options.campusId) + if (!campusId) { + templates.value = [] + loadedTemplateCampusId = '' + ElMessage.error('请先选择院区,再加载文书模板') + return + } + + if (loadedTemplateCampusId !== campusId) { + if (loadedTemplateCampusId) { + selectedTemplateId.value = '' + selectedDepartment.value = '' + selectedCategory.value = '' + } + loadingTemplates.value = true try { - templates.value = await getSigningTemplates() + templates.value = await getSigningTemplates({ campusId }) + loadedTemplateCampusId = campusId } catch { ElMessage.error('文档模板加载失败,请稍后重试') } finally { diff --git a/clinical-web/src/views/workbench/signing/index.vue b/clinical-web/src/views/workbench/signing/index.vue index c5c76d8..2e75e13 100644 --- a/clinical-web/src/views/workbench/signing/index.vue +++ b/clinical-web/src/views/workbench/signing/index.vue @@ -234,8 +234,14 @@ function syncFilterFromRoute() { } async function loadTemplates() { + const campusId = appStore.selectedCampusId + if (!campusId) { + templates.value = [] + return + } + try { - templates.value = await getSigningTemplates() + templates.value = await getSigningTemplates({ campusId }) } catch { ElMessage.error('文档模板加载失败,请稍后重试') } @@ -1088,9 +1094,12 @@ watch( /** 切换全局院区:列表跟着换(院区不再是筛选条里的一个下拉,见 syncFilterFromRoute) */ watch( - () => appStore.selectedCampus, - () => { + () => appStore.selectedCampusId, + (campusId, previousCampusId) => { page.value = 1 + if (campusId && previousCampusId) { + void loadTemplates() + } void loadTasks() }, )