Files
form-center-service/docs/T5-report.md
T

20 KiB
Raw Blame History

T5 执行说明 · 前端·壳与管理端框架

任务书 T5(v1.1)|执行手册 §1 模板组合「前端 = fork notice/front」+ §2.1(一个 SPA 承载全部形态)+ §2.2(模块行表与 path 空行口径)|方案 v1.4 §3.3(页面即组件、self != top 剥壳)+ §7.3(《云海子应用前端接入规范》v1.11)+ §9 V22 主体改动 = front 仓(form-center/form-center-front);service 仓两处 T4 验收遗留小改;YschTheme 仓 consumers.json 登记。 本轮不自创设计:值形状、控件、接口口径全部沿用契约,前端只做壳与骨架。


1. 做了什么

1.1 notice/front 基线整体迁入并剥领域(不是改造 T1 裸壳)

T1 留的 front 只有 App.vue + main.ts + 仅 vue 依赖。本轮把 notice/front 的壳基础设施落进来并剥净领域,形成 47 个源文件(另 25 个 svg 资产)的工程:

迁入件 来源 说明
index.html Notice 现行版 env-config 同步引导 + A 类 loader(§2.1 原文照抄,未改一字);title 走 createHtmlPlugin 注入「表单中心」
vite.config.ts Notice 现行版 vue / svg-icons / vite-plugin-mock / auto-import / html / UnoCSS 六插件 + base:"."(P11 已就位)+ port 8089(P6) + /api→8086、/static→中央通道(YH_THEME_PROXY_TARGET 可覆盖)代理 + 产物恒 dist 根(zip 根含 index.html,§7 坑)
src/utils/alova/{alova-core,alova-iview}.ts Notice 信封解包(code==0→data、302→挂起 Promise 跳 CAS)、yschapirequest/yschreferer 头、800ms 延迟 Spin
src/components/layout.vue Notice refined 版(13afb22) 菜单 icon 兜底 icon-list + 面包屑首页图标行内基线流 -0.125em(规范 §4 两行)+ Logo yh-logo-url 平台键优先/本仓兜底 + yh-appearance-updated 监听 + 无配色切换器(§3 红线)
src/utils/hook/useElementHeight.ts、src/components/TablePageAlovaNew.vue Notice/flow-center 同构 通道撑满高度模型(§4.3 三硬约束)+ .ysch-spin loading 插槽形态(§4 表格加载行)
src/utils/tableActions.ts UserBase 同构源 actionColumn/normalizeActions/splitActions/actionCell,显式 mode(§5.1)+ disabledWhen 置灰保位(§5.2 红线)
src/utils/{index,menuRoute,mitt}.ts、src/utils/directive/*、src/assets/styles/*、src/assets/icons/* Notice Utils 类(旧 operatingHandle 保留为薄封装,§5.4)、main.scss 含 .op-cell/.table-spin-load/固定层事件/省略号 Tooltip 四段
src/components/{UserAvatar.vue,utils/avatar.ts} YschTheme npm run sync 下发 与通道源 MD5 逐字节一致(9ac72f8b/1fa7163c),sync --check 报「全部对齐」

剥除清单(任务书「剥 notice 全部领域 views 与 mobiapi」):views/notice/* 8 页、api/module/{notice,approval,cc}.ts、assets/mock/noticeapi.ts、assets/config/menu.ts(本地菜单兜底=假象,与后端「不保留本地 MENUS 兜底」同口径,一并剥)、utils/alova/alova-vant.ts(mobiapi 腿,指向 /mobiapi 的移动端实例)、NoticeUpload/ThemeSwitcher/GradeClassSel/BschSubjectSelect/UserCheckModal/MyTree* 等领域或切换器组件、utils/{axios,diagramImg,bschSsoRedirect,flowLayout…} 与 index.html 的 ztree+jquery 库引用(树件随 T8 需要时按平台件再引)。重量依赖 @wangeditor、pdfjs-dist、@open-file-viewer、vuedraggable、axios、lodash、@alova/wormhole 未装(各自属 T6/T7 的编辑/预览/拖拽需求,届时显式加)。

1.2 左导航(GetUserMod)与 path 空跳过

  • src/utils/menuNav.ts(新增,本轮唯一的导航判定实现):纯函数 + 解析器注入(buildNavTree(modList, resolve)),三条规则写在文件头——① 跳过判据取平台原始 path 是否为空(不取解析结果:靠名字/modId 猜出路由再显示就是把权限锚点画成死菜单);② 有可渲染子节点的分组行保留为分组头(不可点),子节点全被跳则整组不渲染;③ 原始 path 非空但解析不出已注册路由的行照常显示、点击时 Message.warning 点名配置错误(不静默少一条菜单)。
  • 高亮/面包屑按 flattenNav 对照(分组头不入表),firstNavPage 决定登录后的默认落地,isSingleNav 承 Notice 的「单模块独占」语义。
  • App.vue:拿 GetUserInfo + GetUserMod → buildNavTree → 交 layout.vue 渲染;失败只降成"导航为空",不造兜底树(后端注释同口径)。DEV 下 console.table 同时打原始树与过滤后导航,冒烟可直接对比。

1.3 api/module/base.ts 形态与 appCode 参

BASE="/api/base" 的 getUserInfo() / getUserMod(appCode?)(参数名按 P2 定稿 appCode)。文件头写明:path 空行只由后端 DataScopeService 扫描消费、接口不过滤,前端只在导航层跳过。P3 口径:H4 未上线时该请求返回空树,页面即空态,不回落本应用树(mock 侧同一条判定已实现并在冒烟 D 段断言)。

一处必要偏离:Notice 的 new Method<T>("GET", …) 在 alova 3.5.5 类型下不合法(Method 的第一泛型位是 AlovaGenerics 而非响应类型,strict vue-tsc 报 TS2344),本端改 alovaInstance.Get<T>() ——同一个 Method 对象、同一套拦截器与信封解包,行为等价(P49)。

1.4 路由骨架:一个 SPA 四形态(手册 §2.1)

createWebHashHistory(Notice/flow-center 同族),路由表即 /admin/{forms,data,stats,dicts}、/f/:code、/app/:appCode[/:view]、/my,/ = 入口页、/:pathMatch(.*)* → /(外部深链不白屏)。产物部署在 /form-center/front/,故手册写的 /form-center/f/{code} = ctx + #/f/{code}。

  • meta.modId 全部不写(规范 §4「modId 全量对齐后端 GetUserMod,禁臆造」):本应用模块行除 fc:scope:all 外 customId 均未配(手册 §2.2 表为「—」),后端 resolveModId 因此回退 app_module 主键 id,该值跨环境不稳定,写进路由必然失配;高亮与面包屑按 path 匹配。
  • 占位页 7 个(views/admin/* 4 + Fill + AppContext + My + Entry),统一走 components/PageStub.vue 的 page-wrapper.yh-fill > main-container 骨架 + 常驻 Alert type=info show-icon(§4.2 无 closable/banner)。占位页刻意不挂 .table-region——没有 Table 却铺一个"应当被量高"的容器,会留下假范式(§4.3 三硬约束的成立前提是有 Table 喂回高度)。零领域逻辑、零接口调用(Fill/AppContext 只把 code/appCode 与形态显示出来)。

1.5 self != top 剥壳(方案 §3.3)

App.vue 顶层判 window.self !== window.top → 嵌入态裸渲染 <router-view>:不画 layout、不发两个鉴权请求(嵌入上下文取不到本应用会话,失败会弹错误并画出带壳页),并内联旁路 _base.scss 的 body{min-width:1200px}(740px Drawer 里不旁路就整体右偏+右裁,flow-center 同款手法)。显式 ?mode= 闭集留给 T7,本轮只做 self!=top 这一条兜底。

1.6 主题通道登记(YschTheme 仓)

consumers.json 新增 form-center 条目(path:"../form-center/front"、target:"pc"、files 只登记 avatar 两件——按 §3 红线不建配色切换器,故不登记 theme.ts/ThemeSwitcher.vue;ctx=/form-center/ 写进 note);同步更新 tests/scripts.spec.ts 的「消费端清单显式可控」断言(清单加一条 + form-center files 显式断言)。npm run sync → form-center 两件报「一致」;npx vitest run → 8 文件 84 例全绿,其中 iview-version.spec 即「消费端 lock 实装版本 === 通道 devDependencies 精确版本」的版本锁测试,form-center 通过=1.3.24 锁红不再失守。

1.7 service 仓两处顺带(T4 验收遗留,不喧宾夺主)

  • 勘误③ 真落:docs/T3-report.md §2 的 V32 行「两个不同教师」后补注「(实为两个 roleId=7 操作者——教师(1) 按 P21 无代填权)」。已核源码:AnswerSubmitIT.onceLimitIsPerSubjectWhenSubjectPresent 用的是 user(10001, SCH, 7) 与 user(10002, SCH, 7),注释属实。T4 报告 §1.6 声称已改、实测未改,本轮落到文本。
  • P47 收紧:FormModuleKeys 的 customId 扫描改为只收 path 空节点(新方法 anchorCustomIds,collect 单处分支;旧 customIds 无其他调用方,一并收敛不留死代码),DataScopeService.hasScopeAllAnchor 切过去。补测 DataScopeServiceTest.customIdOnNavRowDoesNotUpgradeScope:带 path 的导航行误配 fc:scope:all → 仍 SELF_SUBMITTED;同一用户同一值改挂 path 空行 → 立刻 ALL(证明收窄生效、不是扫描整体失效)。配套给 InMemoryModuleTreeSource 加 grantPathWithCustomId 桩方法。契约未改(§8 的「锚点行形态」注记 T4 已补)。

2. 自验证据(逐条)

取证脚本:form-center/local-debug/t5-shell-smoke.sh(13 断言,ASCII 锚点,JSON 交 node 解析不在 shell grep 中文)。终态运行结果 13 pass / 0 fail / 1 skip。

项 判据 证据
npm run build 必须过 ✅ ✓ built in 5.54s(脚本 A 段 PASS build)
npm run type-check 必须过(vue-tsc --noEmit,strict + noUnusedLocals/Parameters) ✅ 0 错误(脚本 A 段 PASS type-check)。Notice 基线在本机 vue-tsc 是坏的(store/index.ts 无 IModule、Basics.d.ts 写 page: !number),本轮按 T1~T4「本地门禁 + CI 只证构建链」的口径把 type-check 做成硬门禁,故对迁入件做了最小整形(P49/P50)
V22 build 通过 方案 §9 原文 ✅ 上一行
V22 consumers.json 已登记 规范 §2.3 ✅ 脚本 B 段 PASS consumers.json 已登记 form-center(ctx=/form-center/);npm run sync 报 一致 form-center src/utils/avatar.ts / UserAvatar.vue、[sync] 全部对齐;npx vitest run 84/84 绿
V22 view-ui-plus 锁 1.3.24 规范 §1/§2.3 ✅ package.json 声明 "1.3.24"(无 ^)+ package-lock.json 实装 1.3.24(脚本 B 段)+ 通道 iview-version.spec 通过 + npm ls view-ui-plus → 1.3.24
V22 本地无 layout.css/icons.css 规范 §2.2 回收步 ✅ 脚本 B 段 PASS no-local-layout-css-icons-css(find src -name layout.css -o -name icons.css 为空);main.scss 无相关 import;dist/index.html 保留 yh-theme-init.js loader 与 api/env-config 引导、%VITE_THEME_HOST% 未被烧值
V22 控件目录含 app.vue 槽位 — ⏭ 任务书已注明:app.vue 槽位一条留 T6 验(控件目录随设计器产生,本轮无控件)
登录出壳 + 左导航(菜单树=手册 §2.2 表) 任务书自验 降级取证(P48,原因见 §3):npm run dev:mock + in-app browser a11y 快照——顶栏 Logo|分隔线|表单中心|Mock 管理员|退出、左导航恰 5 项(表单设计/数据管理/统计/字典管理/我的填写)、「数据全量」(path 空) 未出现、面包屑 首页 > 表单中心 > 表单设计、URL 自动落 #/admin/forms(首个可跳转项)。截图不可用(in-app browser 无可见 viewport),以结构化快照为据
path 空跳过 / 分组收敛 / 无授权仅「我的填写」 手册 §2.2 验证口径 ✅ 脚本 C 段:esbuild 单独转译 utils/menuNav.ts 后在 node 里断言——6 行树(含 1 行 path 空)→ 导航 5 项且锚点不在;[我的填写, 锚点] → 1 项且 isSingleNav=true;子项全锚点的分组整组不渲染、分组头不入高亮表
外指 appCode 空树不回落 P2/P3 ✅ 脚本 D 段:mock 侧与后端同一条判定(appCode=some-other-app → data=[]);前端 getUserMod(appCode) 是唯一入口、无任何「失败即取本应用树」的代码路径
self != top 剥壳 方案 §3.3 ✅ 同源 iframe 探针(dev:mock 页内动态挂 740px iframe 指 #/f/DEMO_PROBE):顶层 .header-container/.left-menu/.path-nav 各 1,iframe 内各 0、self!==top=true、body.style.minWidth="0px"、正文显示「形态 = 页面块(self != top,已剥壳)」
P6 本地端口 手册 §5 ✅ front dev=8089(vite.config.ts)、service=8086(/api 代理 target)
P11 壳的平台约定补齐 手册 §5 ✅ loader/alova/router/auto-import/svg-icons/env-config 引导/base:"./" 全落,T1 留在 vite.config.ts 的 TODO 注释已删
service 两处小改 本地 mvn test 门禁 ✅ mvn -B -o clean package → BUILD SUCCESS,Tests run: 178, Failures: 0, Errors: 0(T4 基线 177 + 本轮 P47 新增 1 条)

3. 问题单(本轮登记,编号接续 P47;供执行手册 §5 裁决)

# 日期 批次 问题 本轮取值(最保守解读) 是否回文档修订
P48 10-14 T5 任务书要求的「登录态冒烟(CAS/UserBase 本地起 → 真会话出壳 + 菜单树=§2.2 表)」不可执行 按 P1 先例降级取证,两条独立事实:①本机 CAS(8443)/UserBase(8060) 未运行(curl 均无响应),Redis 亦未起;②更本质的缺口——本地 bsch_userbase 里 application_info 中 app_code='form-center' 的行数=0、app_module 无任何 form-center 模块行(查得 select count(*) … where a.app_code='form-center' → 0,app_module 按 app_id 分组无对应 id),即 H2(UserBase 建中心应用行 + §2.2 模块行 + 组授权)未做。即便把三件服务起齐,GetUserMod 也只能返回空树,拿不到 §2.2 那棵树。补证=脚本 C 段纯函数断言 + D 段 mock 树 + 浏览器结构化快照(§2 表)。H2 完成后 T8/T9 需真会话复跑一次 否(缺口在外部数据,非设计)
P49 10-14 T5 Notice 的 api/module 形态 new Method<T>("GET", …) 与 alova 3.5.5 的类型不兼容(Method 第一泛型位是 AlovaGenerics),strict vue-tsc 恒报 TS2344;flow-center/open-gateway 同病(它们的 npm run type-check 从没跑绿过,规范 §8 也写「vue-tsc 损坏勿依赖」) 本端改 alovaInstance.Get<T>(url, {params}):同一个 Method 对象、同一套 beforeRequest/responded 与信封解包,行为等价、类型正确。T6~T8 的 api/module 文件沿此写法(其余形态:BASE 常量 + class + export const xxxApi 不变)。不改 Notice 已验收工程 否(工程写法,非契约)
P50 10-14 T5 四端同构件 utils/tableActions.ts 落第五端(本端 type-check 是门禁) 照 open-gateway 先例:顶部补 // @ts-nocheck + 4 行说明,正文与同构源逐字节一致(MD5 973393684783c740399b8eb9e97369bc,与 UserBase/flow-center 全等),strict 下两处告警均无害(h 被形参遮蔽、it.on() 已在 normalize 闭包绑定)。规范 §8「与四端 MD5 对齐」的判据按"正文对齐 + 端顶补丁"执行,同 open-gateway 一轮的既有先例 否
P51 10-14 T5 新端的操作列形态(§5.1 要求「工程级恒定」,Notice=icon / UserBase=text)本轮没有列表页可定 暂按同族 center 应用取 text 恒定(flow-center/svc-hall/open-gateway 皆 text),mode 显式声明、缺省 text;T8 出第一个真实列表页时若用户要 icon 形态,改的是各页 mode 参数而非工具件 否
P52 10-14 T5 剥领域后的「回补时机」未写:index.html 的 ztree+jquery、@wangeditor/pdfjs-dist/@open-file-viewer/vuedraggable/axios/lodash 均未随 fork 带入 一律按需再引(设计器 T6、附件预览与拖拽 T6/T7、组树选择器 T8),不提前铺空依赖:本轮 npm ci 518 包、构建 5.5s,若照搬 notice 全量依赖会显著拖慢 CI 且产物里多份未用图形资产(§4 表格加载红线:应用侧零图形资产)。回补时在对应批次报告里点名 否
P53 10-14 T5 入口页 / 的落地语义方案未写:Notice 把 / 做成真实业务页(已收到),flow-center 用 redirect / = 真实入口页(无模块时的可诊断空态),登录后由壳 replace 到首个可跳转项;兜底 /:pathMatch(.*)* → / 而非某个具体管理页(无授权用户不该被送到他进不去的页面)。若用户希望 / 恒落「我的填写」,改 routes.ts 一行 否

另记两条非问题事实,供接手的人少踩:①local-debug/ 不在任何仓库工作树内(form-center 根无 .git,仓库根是 service/ 与 front/),本轮新增的 t5-shell-smoke.sh 不入库(沿 T1~T4 同一事实);②YschTheme 仓无 git 远端(git remote -v 空),consumers.json/tests 的登记改动只落本机工作区,未 commit、未 push,通道发布仍走该仓 release.mjs/release.py 人工动作。


4. 推送与 CI

仓 提交 推送 CI run 结论
form-center-front fdd9aaa(81 条路径:73 新增 + 7 修改 + 1 删除(T1 的 src/env.d.ts 并入 src/vite-env.d.ts),逐条 git add) cebc32f..fdd9aaa main -> main run 1496(head_sha fdd9aaa,run_number=2) status=completed / conclusion=success(Gitea Actions API 实测 HTTP 200)
form-center-service 2c68d6b(6 条路径:docs/T3-report.md 勘误③、docs/T5-report.md、FormModuleKeys.java、DataScopeService.java、DataScopeServiceTest.java、InMemoryModuleTreeSource.java) c0a0df4..2c68d6b main -> main run 1497(head_sha 2c68d6b,run_number=10) completed / success
YschTheme consumers.json + tests/scripts.spec.ts 两文件改动 无远端可推(git remote -v 为空) — 登记落本机工作区,未 commit;通道发布仍是该仓 release.mjs/release.py 人工动作(规范 §7 坑表「通道应用实名 yschtheme/web」)
  • 暂存方式:两仓都按显式路径逐条 git add,提交前 git status 核对无残留未跟踪项、无 add -A、无敏感文件;front 的 node_modules/、dist/、*.log 由 .gitignore 排除(.gitignore 未改),src/auto-imports.d.ts 按 Notice 先例入库(npm ci 后首次 vue-tsc 需要它)。
  • 取证方式:沿用 T4——git credential fill 会拉起 GCM 图形框(本会话非交互直接超时),改从 ~/.git-credentials 取 192.168.10.160 这条已存凭据调 GET /api/v1/repos/.../actions/runs/{id},凭据不回显、不落盘、不入库。
  • 前端 CI 只证构建链(node:20 容器 npm ci + npm run build,同后端「CI 不跑单测」先例):type-check 与 local-debug/t5-shell-smoke.sh 是本地门禁,本轮两者均绿(§2)。
  • local-debug/t5-shell-smoke.sh 不入库(沿 T1~T4 同一事实:form-center 根无 .git,两个仓库根分别是 service/ 与 front/,该目录在两侧工作树之外;手册 §4.2 的「脚本入 local-debug」按目录本身落,入库需另建脚本仓或调整仓库根,不在本轮擅自动)。
  • 本节回填本身是一次 docs-only 提交(只改本文,不动任何构建输入),其后同流水线再跑一次;该 run 的结果只在本轮收尾说明里报,不再追加自指回填提交(T4 已定此纪律)。

—— 全文完 ——