dirname: command not found,ls/grep/wc/cd 全废。不要用 Bash 工具。> 临时文件,再用 Read 读,读完删掉。Remove-Item 被 safe-delete 钩子拦截 → 删文件用 [System.IO.File]::Delete('绝对路径')。<script setup lang="ts"> + ant-design-vue + vite + less + pnpm。ai-frontend/):
pnpm build(= vite build --mode production,不做类型检查,约 2 分钟)pnpm type:check(= vue-tsc --noEmit --skipLibCheck,约 25 秒)pnpm type:check 本来就过不了:仓库有约 89 条既有报错,集中在
src/call/、src/trans/、src/graph/、src/otg/、src/person/ 等无关文件。
判断自己有没有写坏,看的是「报错文件里有没有自己动的文件」,不是退出码。tsconfig.json:isolatedModules: true,无 verbatimModuleSyntax;noUnusedLocals: false(所以多余的 import 不报错)。@/* → src/*;路由表在 src/core/router/routes/index.ts。build/theme/modifyVars.ts 里的
hack: 'true; @import (reference) "src/core/design/var/index.less";' 注入,
所以任意 .vue style 块和任意 .less 文件都能直接用 @modal-header-bg-color 这类变量,
SFC 的 style 抽成独立 .less 再 @import 回来是安全的。wrapClassName + 全局类名命中。src/case/views/data/cleaning.vue)当前进度(2026-09-18):12029 → 944 行(−92%),30+ 新文件,type:check 0 报错 + build 通过。
依赖顺序(单向、无环):useCaseDataCleaningShared(底层状态)→ useCleaningRules / useFieldMapping / useRecognitionRules / useTemplateLibrary
→ useCaseDataCleaningActions(叶子动作域,放在最后所以能直接用上游产物)。
剩余(压到 ≤400):① 把顶层 watch([...]) 移进 composable(watcher 在 composable 内注册仍绑定页面实例)→ 21 个退回声明可搬走;
② 清未使用 import(匹配标识符要允许 ... 展开);③ useCaseDataCleaningActions(1310) 可按域再拆成 useFileTree / usePreviewData / useColumnOps。
生成器可复用件(写这类脚本直接照搬):
watch( / provide( / onMounted( 等非声明的顶层语句,否则上一个声明的范围会吞掉它们{{ }} + : / v- / @ / ref 绑定值 + 标签名;表达式剥掉 '…'/"…" 但保留 ${...} 插值.ts 补 export;跨文件相对路径按新层级重算;deps 类型显式写 interface(否则类型循环 → Object.entries(any) → [string, unknown][])provide 放在 setup 末尾;
wiring 插在「最后一个依赖声明」之后(锚点是依赖声明的最后一行)方案文档:仓库根 cleaning-refactor-plan.md。已拍板:路由不动(cleaning.vue 留作入口)、
通信走 provide/inject + 领域 composable、样式保持全局 less 非 scoped、业务逻辑一律不许动、
每阶段停下来 review。
目录:cleaning/{types,constants,context}.ts + cleaning/{utils,composables,components,styles}/
沟通模式(Phase 3 起确定的主力模式,后续阶段照这个来):
composables/useXxx.ts,由页面在 setup 里实例化const { a, b } = useXxx(...))→ 页面原有代码与模板零改动useXxx 实例放进 provide(CleaningContextKey, { ..., xxx }),子组件从 context 取provide() 放在 setup 末尾(避开 const 声明顺序的 TDZ);composable 的调用位置 = 「最后一个依赖声明之后」Record<string, any>,而 Object.entries(<any>) 会产出 [string, unknown][] 引发一片 unknown 报错验证必须 type:check + build 双跑:vue-tsc 抓不到 Vue 模板标签不平衡,
抽块边界写错(多删一个 </div>)时 type:check 是 0 报错、pnpm build 才报 Element is missing end tag。
抽模板块时边界要取「配对的 </div> 行」,不要凭缩进猜(这个文件缩进本身不严格)。
已踩实的坑:
.ts 必须补 export(无 import/export 的 .ts 会被 TS 当全局脚本 → TS2306)@/ 别名例外)let/var 标量不能注入:跨文件是按值快照,两边各改一份(请求序号守卫之类会失效)ref<\n Record<...> 会让深度中途归零、把声明切一半)${...} 插值,只剥 '…' / "…"(整段 strip 会把 `is-${x}` 里的 x 抹掉)provide(...) 也是顶层语句,会假阳性);
watch([...refs]) 整条都算立即求值;「可搬集合 ↔ wiring 位置」要迭代到收敛const { x } = someComposable; 解构出来的,类型要写成 ReturnType<typeof someComposable>['x'](否则退化成 any → Object.entries(any) → unknown);
依赖类型文本里出现的类型名(Ref<TemplateTab> 里的 TemplateTab)也要补 import验证「重构没改业务逻辑」的可靠做法:拿 git show HEAD:<原文件> 当基准,和「当前入口 + 抽出目录整棵树」做
逐行多集合比对(归一化:去 export 前缀 / 折叠空白 / 去行尾 ,;,跳过注释与 import),
判定条件 = 原始每行在当前树里的出现次数 ≥ 原始次数。本项目已验证 script 丢失/被改动 = 0。
注意:扫描范围只圈自己那一棵(别把同目录其它页面算进来)、SFC 的 template 结束点是 <script 不是 <style、
取原始文件用 node execSync(...,{encoding:'buffer'})(PowerShell > 会写成 UTF-16,且 cmd /c 被拦)。