- 勘误③真落:docs/T3-report.md §2 V32「两个不同教师」补注(实为两个 roleId=7 操作者,教师(1) 按 P21 无代填权) - P47 收紧:FormModuleKeys.anchorCustomIds 只认 path 空节点的 customId,DataScopeService.hasScopeAllAnchor 切过去;补「带 path 的导航行误配 fc:scope:all 不升级范围」用例(mvn -o clean package 178 例全绿) - docs/T5-report.md:T5 做了什么 / 逐条自验证据 / 问题单 P48~P53 / 两仓推送与 CI
18 KiB
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) |
见下 | — | — |
| form-center-service | 勘误③ + P47 + 本文 | 见下 | — | — |
(提交号、run 号与终态在本轮推送后回填,沿用 T1~T4 的「feat → docs 回填」两次提交形态。)
- 暂存方式:按显式路径逐条
git add,提交前git status核对无残留未跟踪项、无add -A、无敏感文件;node_modules/、dist/、*.log已由 front 仓.gitignore排除;src/auto-imports.d.ts按 Notice 先例入库(CInpm ci后首次vue-tsc需要它)。 - 前端 CI 只证构建链(
npm ci+npm run build,同后端「CI 不跑单测」先例),type-check 与冒烟是本地门禁——本轮两者均绿(§2)。 - YschTheme:无远端,登记改动留本机工作区(见 §3 末)。
—— 全文完 ——