From 1369b103ee1d252eb4e08c6373ae6591f7c09eb7 Mon Sep 17 00:00:00 2001 From: chenxing Date: Thu, 15 Oct 2026 14:51:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(condition):=20=E6=9D=A1=E4=BB=B6=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=8F=98=E9=87=8F=E5=A5=91=E7=BA=A6=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=20+=20=E5=AD=90=E5=BA=94=E7=94=A8=E5=AF=B9=E6=8E=A5=E5=81=A5?= =?UTF-8?q?=E5=BA=B7=E5=BA=A6=E9=9D=A2=E6=9D=BF=EF=BC=88=E8=AE=AE=E9=A2=98?= =?UTF-8?q?=E4=B8=80=20P0/P1=20+=20=E8=AE=AE=E9=A2=98=E4=BA=8C=20P2?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 议题一(条件路由体验收口): - 编辑器动作入口上移顶栏与「保存草稿」同排,右栏「快捷入口」整块删除(流程图痛点 7) - 发布期变量引用静态校验:validateModel 增加 knownVars 参数,出边表达式引用未在已知变量中的标识符给 warn 级提示。只提示不阻断——拼错与「运行时才有的动态变量」在静态期无法区分,宁可放过 - CONDITION 判断方式文案业务语言化:「服务(外部判断接口)/表达式」→「到达该节点时才能确定/提交时就已确定」,各补一行说明;syncFromNode 取值归一化逻辑未动,零兼容风险 - 内置 8 变量与表达式变量提取抽到 def-editor/model.ts 单一来源(EXPR_BUILTIN_VARS/extractExprVars/unknownExprVars),ConditionBox 与 ExprEvalModal 改为消费,去掉两份本地重复实现 议题二(子应用接入健康度): - AppSetting.vue 新增 tab3「对接健康度」:每应用一行(评分色块/结论/六项检查 chips/结论说明),问题应用 bad>warn>ok 置顶;首次切入该 tab 才请求,避免进页面就多打一次聚合查询 - Callbacks.vue 新增 appKey 筛选框 + query.appKey 预填,承接健康度面板「查推送日志」跳转 - api 层新增 callbackHealth() 数据来源为已有资产(flw_callback_reg / flw_callback_log),零新增表。对齐《子应用接入流程中心规范.md》§4.2/§7 与《条件路由与子应用接入-痛点调研-20261014.md》。vite build --mode base 通过,产物已构建进 front/dist/。 --- src/api/module/flow.ts | 4 + src/views/flow/admin/AppSetting.vue | 141 +++++++++++++++++- src/views/flow/admin/Callbacks.vue | 28 +++- .../def-editor/components/ConditionBox.vue | 35 ++--- .../def-editor/components/ConditionDrawer.vue | 28 +++- src/views/flow/admin/def-editor/index.vue | 30 ++-- src/views/flow/admin/def-editor/model.ts | 54 +++++++ src/views/flow/admin/def-editor/validate.ts | 26 +++- src/views/flow/components/ExprEvalModal.vue | 9 +- 9 files changed, 305 insertions(+), 50 deletions(-) diff --git a/src/api/module/flow.ts b/src/api/module/flow.ts index 18decd6..b75b7bc 100644 --- a/src/api/module/flow.ts +++ b/src/api/module/flow.ts @@ -252,6 +252,10 @@ class FlowApi { callbackRepush(ids: number[]) { return post(`${ROOT}/admin/callback/repush`, ids); } + /** 对接健康度体检(2026-10-15 P2):每应用一行六项检查 + 综合评分,零新增表 */ + callbackHealth() { + return get(`${ROOT}/admin/callback/health`); + } // ==================== 管理面:条件路由注册 / 重跑 ==================== diff --git a/src/views/flow/admin/AppSetting.vue b/src/views/flow/admin/AppSetting.vue index c997688..1ad0e36 100644 --- a/src/views/flow/admin/AppSetting.vue +++ b/src/views/flow/admin/AppSetting.vue @@ -2,8 +2,9 @@ // 应用设置(2026-10-10 四议题):tab1 应用管理(flw_app 白名单 + 学校池同步 + 开关); // tab2 科室管理(flw_dept 组+成员模型,取代旧「办理人映射」页——deptKey=本地自增 id, // 切源后旧流程定义引用的 UserBase 组 id 需重建科室后重新配置)。 -import { ref, onMounted } from "vue"; -import { Message, Tag } from "view-ui-plus"; +import { ref, onMounted, watch } from "vue"; +import { useRouter } from "vue-router"; +import { Message, Tag, Button } from "view-ui-plus"; import MyConfirm from "@/components/MyConfirm"; import UserCheckModal from "@/components/UserCheckModal.vue"; import { flowApi } from "@/api/module/flow"; @@ -11,6 +12,7 @@ import { actionColumn } from "@/utils/tableActions"; import { useElementHeight } from "@/utils/hook/useElementHeight"; const tab = ref("apps"); +const router = useRouter(); // ==================== tab1 应用管理 ==================== const loading = ref(false); @@ -343,6 +345,101 @@ onMounted(() => { load(); loadDepts(); }); + +// ==================== tab3 对接健康度(2026-10-15 议题二 P2) ==================== +// 每应用一行六项检查 + 综合评分;数据全部来自已有接口(/callback/health 聚合),零新增表。 +// 应用无注册行 = 未接入(由接入向导负责),不参与体检。 +const healthLoading = ref(false); +const healthRows = ref([]); + +const healthColumns = [ + { + title: "应用", + key: "appName", + minWidth: 180, + render: (h: any, p: any) => + h("div", { class: "hc-app" }, [ + h("span", { class: "hc-app-n" }, p.row.appName), + h("span", { class: "hc-app-k" }, p.row.appKey), + ]), + }, + { + title: "评分", + width: 96, + align: "center", + render: (h: any, p: any) => + h("span", { class: ["hc-score", "is-" + p.row.level] }, String(p.row.score)), + }, + { + title: "结论", + width: 90, + align: "center", + render: (h: any, p: any) => { + const map: Record = { + ok: ["正常", "green"], + warn: ["关注", "orange"], + bad: ["异常", "red"], + }; + const [txt, color] = map[p.row.level] || ["未知", "default"]; + return h(Tag, { color }, () => txt); + }, + }, + { + title: "检查项", + minWidth: 460, + render: (h: any, p: any) => + h("div", { class: "hc-checks" }, (p.row.checks || []).map((c: any) => + h("span", { + class: ["hc-chip", "is-" + c.level], + attrs: { title: (c.advice ? c.advice + "\n" : "") + "实测:" + (c.value || "-") }, + }, [ + h("i", { class: ["hc-dot", "is-" + c.level] }), + h("span", { class: "hc-chip-n" }, c.name), + c.value ? h("em", { class: "hc-chip-v" }, c.value) : null, + ]))), + }, + { + title: "结论说明", + key: "summary", + minWidth: 220, + render: (h: any, p: any) => h("span", { class: "hc-sum" }, p.row.summary || "-"), + }, + { + title: "操作", + width: 110, + align: "center", + render: (h: any, p: any) => + h(Button, { + props: { type: "text", size: "small" }, + on: { click: () => onViewLogs(p.row) }, + }, () => "查推送日志"), + }, +]; + +function onViewLogs(row: any) { + router.push({ path: "/admin/callbacks", query: { appKey: row.appKey } }); +} + +async function loadHealth() { + healthLoading.value = true; + try { + healthRows.value = ((await (flowApi as any).callbackHealth().send()) as any[]) || []; + } catch (e: any) { + Message.error(e?.message || "健康度加载失败"); + healthRows.value = []; + } finally { + healthLoading.value = false; + } +} + +// 首次切到「对接健康度」时按需加载(避免进页面就多打一次聚合查询) +let healthLoaded = false; +watch(tab, (t) => { + if (t === "health" && !healthLoaded) { + healthLoaded = true; + loadHealth(); + } +});