From 509fc6d20c12c0c6749c85a01eec9ff39f769424 Mon Sep 17 00:00:00 2001 From: chenxing Date: Thu, 22 Oct 2026 09:55:49 +0800 Subject: [PATCH] =?UTF-8?q?t1:=20=E4=BA=8B=E9=A1=B9=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E6=8E=A5=E8=A1=A8=E5=8D=95=E4=B8=AD=E5=BF=83=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=EF=BC=88=E8=A1=A8=E5=8D=95=E7=9B=AE=E5=BD=95=E9=80=89=E6=8B=A9?= =?UTF-8?q?/=E8=AE=BE=E8=AE=A1=E5=99=A8=E5=AF=B9=E9=BD=90svc=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/module/svc.ts | 15 + src/types/svc.ts | 32 +++ src/views/svc/FormDesigner.vue | 436 +++++++----------------------- src/views/svc/ServiceItemEdit.vue | 62 ++++- 4 files changed, 193 insertions(+), 352 deletions(-) diff --git a/src/api/module/svc.ts b/src/api/module/svc.ts index 354ebdf..8454d49 100644 --- a/src/api/module/svc.ts +++ b/src/api/module/svc.ts @@ -3,6 +3,7 @@ import { alovaInstance } from "@/utils/alova/alova-iview"; import config from "@/assets/config/host.config"; import type { ApplyVo, + FcFormCatalogPage, FlowProgressVo, FlowSummary, PageResult, @@ -135,6 +136,20 @@ class SvcDictApi { } class SvcFormApi { + /** + * 表单中心目录(v3/TASK_1):事项编辑页的表单选择器数据源。 + * 走本应用同源代理,浏览器不持 appKey/secret、也不出现 form-center 地址(同 flow 能力的纪律); + * 校域由后端从 CAS 会话派生,前端没有 schId 入参——这是有意的,别"顺手加一个"。 + */ + centerForms(siteCode: string, filter: { keyword?: string; page?: number; pageSize?: number } = {}) { + return get(`${SVC}/formCenter/forms`, { + siteCode, + keyword: filter.keyword || undefined, + page: filter.page, + pageSize: filter.pageSize + }); + } + /** 本地表单清单(存量回显用;v3 起不再新增定义,save/publish 已在后端明确退出) */ list(siteCode: string) { return get(`${SVC}/form/list`, { siteCode }); } diff --git a/src/types/svc.ts b/src/types/svc.ts index 089ca55..3a53349 100644 --- a/src/types/svc.ts +++ b/src/types/svc.ts @@ -97,6 +97,9 @@ export interface SvcItemEditVo { ruleCategoryId?: number; coverImage?: string; formCode?: string; + /** 表单中心绑定坐标(v3/TASK_1,成对;保存时后端会再向中心核验一次才落库) */ + fcFormUuid?: string; + fcFormVersion?: number; flowGuid?: string; applyUrl?: string; sortNo?: number; @@ -127,7 +130,13 @@ export interface SvcItemSaveRequest { noticeCategoryId?: number; ruleCategoryId?: number; coverImage?: string; + /** + * 本地表单 code:v3/TASK_1 起**只读**——编辑存量事项时原样回传即保留历史绑定, + * 写一个新值会被后端拒(保存链路的 form_code 已停写)。新表单一律走 fcFormUuid + fcFormVersion。 + */ formCode?: string; + fcFormUuid?: string; + fcFormVersion?: number; flowGuid?: string; applyUrl?: string; // ===== 服务承诺(P1-1):与后端 SvcModels.SvcItemSaveRequest 同名,勿改 ===== @@ -149,6 +158,29 @@ export interface SvcItemAttachmentVo { fileSize?: number; } +// ===== 表单中心目录(v3/TASK_1)===== + +/** + * 目录行 = 后端 `SvcFormCatalogVo`(形状对齐 form-center `GET /oapi/form/forms` 的 items)。 + * 浏览器不直连表单中心:这条走本应用同源代理 `/api/svc/formCenter/forms`, + * 校域由后端从 CAS 会话派生,应用签名也不在前端出现。 + */ +export interface FcFormCatalogItem { + formUuid: string; + code: string; + name: string; + appCode: string; + /** 中心当前发布版本:选中即成对存下 formUuid + version */ + version: number; + audience: string[]; +} + +export interface FcFormCatalogPage { + items: FcFormCatalogItem[]; + /** 中心侧"已发布 ∩ 本应用可读"过滤后的总条数(先过滤再分页) */ + total: number; +} + // ===== 表单 ===== export interface SvcFormVo { diff --git a/src/views/svc/FormDesigner.vue b/src/views/svc/FormDesigner.vue index d98b9ff..279666b 100644 --- a/src/views/svc/FormDesigner.vue +++ b/src/views/svc/FormDesigner.vue @@ -1,364 +1,124 @@ \ No newline at end of file + diff --git a/src/views/svc/ServiceItemEdit.vue b/src/views/svc/ServiceItemEdit.vue index 49ea9c3..c2ad57c 100644 --- a/src/views/svc/ServiceItemEdit.vue +++ b/src/views/svc/ServiceItemEdit.vue @@ -10,7 +10,7 @@ import { svcFormApi, svcItemApi, } from "@/api/module/svc"; -import type { SvcDeptVo, SvcFormVo, SvcItemAttachmentVo, SvcItemSaveRequest } from "@/types/svc"; +import type { FcFormCatalogItem, SvcDeptVo, SvcItemAttachmentVo, SvcItemSaveRequest } from "@/types/svc"; import { useSite } from "@/utils/site"; import RichTextEditor from "@/components/RichTextEditor.vue"; @@ -43,7 +43,10 @@ const form = ref({ const objects = ref<{ dictKey: string; dictName: string }[]>([]); const categories = ref<{ dictKey: string; dictName: string }[]>([]); const depts = ref([]); -const forms = ref([]); +/** 表单中心目录(v3/TASK_1:办理表单只能从这里选;本地表单定义已停写) */ +const fcForms = ref([]); +const fcFormsDisabled = ref(false); +const fcFormsReason = ref(""); const flows = ref<{ flowGuid: string; name: string; version: number }[]>([]); const flowDisabled = ref(false); const flowDisabledReason = ref(""); @@ -53,11 +56,22 @@ const uploadingCover = ref(false); const editing = computed(() => !!route.query.id); const pageTitle = computed(() => (editing.value ? "编辑事项" : "新建事项")); -/** 选中表单的最新版本是否为草稿/停用(草稿可先绑,但发起页要等发布才生效) */ -const selectedFormDraft = computed(() => { - if (!form.value.formCode) return false; - const f = forms.value.find((x) => x.code === form.value.formCode); - return !!f && f.status !== 1; +/** + * 选中即成对存 uuid + 中心当时的发布版(v3 §4:只保存服务器验证过的坐标,不接受手填版本)。 + * 清空=两列一起清——后端要求成对,留一个没人认领的版本号没有意义。 + */ +function onFcFormChange(uuid?: string) { + const hit = uuid ? fcForms.value.find((f) => f.formUuid === uuid) : undefined; + form.value.fcFormUuid = hit ? hit.formUuid : undefined; + form.value.fcFormVersion = hit ? hit.version : undefined; +} + +/** 绑定回显:存的是当时核验过的版本,中心又发新版时页面要点出来(不自动改绑) */ +const fcBinding = computed(() => { + if (!form.value.fcFormUuid) return ""; + const newest = fcForms.value.find((f) => f.formUuid === form.value.fcFormUuid)?.version; + const base = `已绑定 ${form.value.fcFormUuid} v${form.value.fcFormVersion}`; + return newest && newest !== form.value.fcFormVersion ? `${base}(中心最新已发布 v${newest},需换版请重新选择)` : base; }); /** 部门树扁平化(缩进展示,承袭 CMS flattenDepts) */ @@ -84,7 +98,20 @@ async function loadAll() { objects.value = ((await svcDictApi.list(siteCode, "object").send()) as any[]) || []; categories.value = ((await svcDictApi.list(siteCode, "category").send()) as any[]) || []; depts.value = (await svcDictApi.deptTree(siteCode).send()) || []; - forms.value = ((await svcFormApi.list(siteCode).send()) as SvcFormVo[]) || []; + // 表单中心目录(同源代理):授权没配/中心不可达时降级为"选不了",不阻塞事项其余字段的编辑 + try { + const page = await svcFormApi.centerForms(siteCode, { page: 1, pageSize: 100 }).send(); + fcForms.value = page?.items || []; + fcFormsDisabled.value = false; + fcFormsReason.value = ""; + } catch (e: any) { + fcForms.value = []; + fcFormsDisabled.value = true; + const msg = String(e?.message || e || ""); + fcFormsReason.value = msg.includes("不可达") || msg.includes("返回空") + ? msg + : `表单中心目录获取失败:${msg}`; + } try { flows.value = ((await svcFlowApi.list(siteCode).send()) as any[]) || []; flowDisabled.value = false; @@ -312,15 +339,22 @@ onMounted(loadAll); - + -
- 该表单尚未发布,发布后才能在发起页实际填写;请到「表单管理」发布。 +
+ {{ fcFormsReason || "表单中心目录不可达" }} +
+
{{ fcBinding }}
+
+ 目录只列中心已发布、且已授权给本应用的表单;保存时服务端会再向中心核验一次坐标 +
+
+ 历史本地表单「{{ form.formCode }}」只读保留(本地表单定义已停用,改绑请选表单中心的表)
-
发起页按表单编码取最新已发布版本渲染