@qilitt-mickey/vue3-temp-skill 1.1.13 → 1.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md CHANGED
@@ -13,6 +13,7 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
13
13
 
14
14
  - 面向由 **vue3-web-temp** 脚手架搭出的业务项目(目录名/安装路径因人而异,以当前工作区为准)
15
15
  - 业务写法以本包 `references/` 为准;壳层行为(顶部 tag / 侧栏 / keep-alive / `useDetail`)以**当前项目**已有实现为准
16
+ - **双轨**:无设计 handoff → 保持模版出厂令牌;有设计落地 → 读 `design-handoff.md`,按设计规范回填令牌(视觉关键尺寸须为 CSS 变量)
16
17
 
17
18
  ## 使用方式
18
19
 
@@ -24,11 +25,20 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
24
25
 
25
26
  1. 先读 `references/core-kernel.md`
26
27
  2. 复用仓库已有 `Re*` / Hook / utils;选型表指定库勿擅自替换
27
- 3. 按命中模块内完整示例编写
28
+ 3. 按命中模块内**强制完整样板**整段编写(禁止只抄 API 签名、丢掉 meta/配套段落)
28
29
  4. 无对应能力 → 标注「待确认」,未经同意不引入新依赖
29
30
  5. 真相源:`仓库已有封装` > `本 Skill 示例` > 通用 Vue 习惯
30
31
  6. 命中 addon / 缺依赖时再读 `project-inventory.md` 第九节;精确版本安装,禁止 `@latest`
31
32
 
33
+ ## 抗略读(全模块 · 提高命中率)
34
+
35
+ 按需模块 ≠ 可浅读。命中即须落到该文件的**完整样板 / Must-do**,生成后靠 `code-quality` 硬失败表兜底。
36
+
37
+ 1. **样板字段默认写出**:示例里写明的 `activePath` / `keepAlive` / `roles` / `responseType: "blob"` 等不得改成 `//` 注释再当可选项;仅业务明确不需要时才删除
38
+ 2. **关联能力同批落盘**:列表→详情 = `crud-pages` + `detail-page` 三件套;有 API = 同步 `http-api`;有删除 = 确认框;有编辑回显 = `Object.assign`
39
+ 3. **Hook ≠ 壳层自动**:`toDetail` 写 tag;侧栏高亮 / keepAlive 靠路由 meta;`http` 加解密靠环境开关,不靠单请求配置
40
+ 4. **大范围交付仍须逐模块核对硬失败表**,禁止「lint 过了就算完」
41
+
32
42
  ## 模块路由表
33
43
 
34
44
  ### 始终加载
@@ -43,7 +53,7 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
43
53
  |------|------|
44
54
  | addon / 查 Re* 名 / 装依赖 | `references/project-inventory.md` |
45
55
  | 写完代码后(闸门,非功能命中) | `references/code-quality.md` |
46
- | 设计交接块 / 上游令牌产出落地 | `references/design-handoff.md`(+ `design-system`) |
56
+ | 设计交接块 / **design-handoff/v1 JSON** / 上游令牌产出落地 | `references/design-handoff.md`(+ `design-system`) |
47
57
 
48
58
  ### 标准业务面
49
59
 
@@ -60,7 +70,7 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
60
70
  | **feedback-loading** | message、loading、确认框 |
61
71
  | **base-code-dict** | 字典、baseCode、码表 |
62
72
  | **api-check** | 联调、mock、契约、对接后端 |
63
- | **ui-components** | Re组件、公共组件、type.ts |
73
+ | **ui-components** | 新建 Re*、type.ts、组件目录;**用法见各功能模块**(本文件仅索引) |
64
74
 
65
75
  ### 专项能力包
66
76
 
@@ -112,7 +122,8 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
112
122
 
113
123
  - HTTP:`import { http } from '@/utils/http'`;方法跟后端(允许 GET/POST);`Result<T>`;`VITE_API_BASE_URL` → `http-api`
114
124
  - 列表:`onSearch` / `reset` + 黄金样板 → `crud-pages`
115
- - 独立详情:`toDetail` + 路由 meta → `detail-page`
125
+ - 独立详情:`toDetail` **不能替代** `activePath` / `keepAlive` / `moreTags`;三件套 → `detail-page`
126
+ - 权限:`meta.roles` + `v-auth`/`ReAuth` → `permission-auth`
116
127
  - 不二次挂 Layout;`script setup` + `defineOptions({ name })`;`$t('中文')`;样式契约 → `core-kernel`
117
128
 
118
129
  ## 工作流
@@ -134,6 +145,7 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
134
145
  ## 代码质量审查
135
146
  - 闸门:已执行 code-quality(生成后)
136
147
  - 清单:选型 / 类型 / 组件 / API / 安全 / 业务 / 列表→详情(如适用) / 列表布局(如适用) / 风格 → 通过 | 已修正:…
148
+ - 硬失败:无 | 已拦截并修正:…
137
149
  - 命令:`pnpm lint:fix` → …;`pnpm type-check` → …
138
150
  - 待确认:…
139
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qilitt-mickey/vue3-temp-skill",
3
- "version": "1.1.13",
3
+ "version": "1.1.15",
4
4
  "description": "Vue 3 企业级中后台项目开发规范技能包 — core-kernel 架构、按需功能模块",
5
5
  "bin": {
6
6
  "vue3-temp-skill": "./bin/cli.js"
@@ -9,6 +9,8 @@ tags: [api, backend, integration, contract, http, checklist, mock]
9
9
 
10
10
  写法与示例 → **`http-api`**。本文件只做联调核对。权威源:`types/global.d.ts`、`src/utils/http.ts`、`src/api/**`、`mock/**`、`useTableSearch`。
11
11
 
12
+ **抗略读**:联调阶段仍须核对「下载是否带 blob」「分页字段是否 content/totalCount」;契约不过 = API 未完成,禁止只靠 lint 放行。
13
+
12
14
  ## 基本信息
13
15
 
14
16
  - [ ] 业务 path 与后端文档一致;忌把 `/mock/...` 当生产约定
@@ -12,7 +12,7 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
12
12
  ## 协议(按序)
13
13
 
14
14
  1. 重读本文件
15
- 2. 列出本轮改动路径,对照下方清单
15
+ 2. 列出本轮改动路径,对照下方清单;**硬失败表命中则先改代码再继续**
16
16
  3. 业务项目根目录必跑:`pnpm lint:fix` → `pnpm type-check`(无脚本则 `pnpm lint` / `pnpm exec eslint . --fix`;`pnpm exec vue-tsc --noEmit`)
17
17
  4. 失败则修代码并重跑,直至通过或写明阻塞
18
18
  5. 最终回复追加:
@@ -22,11 +22,30 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
22
22
  - 闸门:已执行 code-quality(生成后)
23
23
  - 改动文件:`path/a`、`path/b`、…
24
24
  - 清单:选型 ✅ / 类型 ✅ / 组件 ✅ / API ✅ / 安全 ✅ / 业务 ✅ / 列表→详情 ✅或N/A / 列表布局 ✅或N/A / 风格 ✅
25
+ - 硬失败:无 | 已拦截并修正:…
25
26
  - 已修正:…(无则写「无」)
26
27
  - 命令:`pnpm lint:fix` → …;`pnpm type-check` → …
27
28
  - 待确认:…
28
29
  ```
29
30
 
31
+ ## 硬失败(对照落盘文件;命中即未通过)
32
+
33
+ lint / type-check **过了也不能放过**下列项。发现即改代码,禁止「已知问题后续再说」。
34
+
35
+ | 触发条件(改动里出现) | 未通过条件 | 正确做法 |
36
+ |------------------------|------------|----------|
37
+ | `toDetail` / 独立 `*Detail` 路由 | 路由无 `activePath`,或 `showLink` 非 `false` | `detail-page` 三件套 |
38
+ | 同上 | 默认场景缺 `keepAlive`/`moreTags`(业务未声明不要缓存) | 样板默认写出;不要缓存再删 |
39
+ | 同上 | 详情页无 `initToDetail`,或 `name` 与路由不一致 | 对齐 `defineOptions` |
40
+ | 列表页 | 无 `el-card.vts-page-card` / `100vh` 减顶栏定高 / 无 `tableHeight` / 分页在 ReTableBar 外 | `crud-pages` L1–L8 |
41
+ | `src/api/**` | 绕过 `@/utils/http`,或虚构 `/api` 前缀,或响应当 `success`/`code` | `http-api` |
42
+ | 下载/导出 API | 无 `responseType: "blob"` | `http-api` / `download-export` |
43
+ | 删除/危险操作 | 无确认框 | `feedback-loading` |
44
+ | 编辑回显 | 整表 `formData = res.data` 破坏响应式 | `Object.assign`(`data-writeback`) |
45
+ | 按钮权限需求 | 裸 `v-if` 角色判断,未用 `v-auth`/`ReAuth` | `permission-auth` |
46
+ | 新菜单路由 | 父级无 `icon` 或业务页二次挂 `Layout` | `icons` + `core-kernel` |
47
+ | 列表查询区 `el-form` / 查询按钮 | 写了 `size="small"`(紧凑主题用户未要求) | 不写 size,用 default=`--control-height` |
48
+
30
49
  ## 选型与硬约束
31
50
 
32
51
  - [ ] 已读 `core-kernel`;addon/缺依赖时已读 `project-inventory`
@@ -34,8 +53,9 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
34
53
  - [ ] addon 缺包按 inventory 第九节精确版本(禁止 `@latest`)
35
54
  - [ ] 列表方法名 `onSearch` / `reset`;HTTP 用 `@/utils/http` + `Result<T>`
36
55
  - [ ] 业务路由未二次挂 Layout
37
- - [ ] 独立详情:`showLink:false` + `activePath` + `toDetail` + `initToDetail`(细则 `detail-page`)
38
- - [ ] 列表布局按 `crud-pages` 黄金样板(`el-card.vts-page-card`+`content`+固定 height、`tableHeight`、`otherRef`、分页在 ReTableBar 内;内容区无外层滚动条)
56
+ - [ ] 独立详情:对照路由文件确认 `showLink:false` + `activePath` + `keepAlive`/`moreTags`(默认)+ `toDetail` + `initToDetail`
57
+ - [ ] 列表布局按 `crud-pages` 黄金样板(`el-card.vts-page-card`+`content`、无 `100vh` 减顶栏、`tableHeight`、`otherRef`、分页在 ReTableBar 内;内容区无外层滚动条)
58
+ - [ ] 顶栏高度仅 `--header-height` 等 CSS 令牌;禁止 JS 测顶栏 / `platform-config` 顶栏像素字段 / `useApp` 导出顶栏高度
39
59
 
40
60
  ## TypeScript
41
61
 
@@ -73,7 +93,7 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
73
93
  ## 样式
74
94
 
75
95
  - [ ] `scoped`;色用 CSS 变量;优先 UnoCSS 连字符类(`p-5` 非 `p5`)
76
- - [ ] 语义色 `bg-bg_color` / `--el-*`;尺寸档位见 `core-kernel` 样式契约
96
+ - [ ] 语义色 `bg-bg_color` / `--el-*`;尺寸档位见 `core-kernel` 样式契约(查询区 default 32,禁止误用 small 24)
77
97
  - [ ] 图标见 `icons`;忌滥 `!important`;选择器 ≤3 层
78
98
  - [ ] 全局 EP 覆盖在 `element-plus.scss`;侧栏色用 `html[data-theme]`
79
99
  - [ ] 主色经 `setEpThemeColor()`;颜色处理用 `chroma-js`
@@ -83,18 +103,19 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
83
103
  - [ ] 规范识别回执;令牌 / `platform-config.json` / 侧栏主题一致
84
104
  - [ ] 已建 `design-tokens.scss`;`index.scss` 中其 `@use` 最前
85
105
  - [ ] 冲突清单已逐条处理(见 `design-system`)
86
- - [ ] 有上游设计产出时已读 `design-handoff`;`EpThemeColor`/`Theme`/侧栏桥接/`Version` 一致
106
+ - [ ] 有上游设计产出时已读 `design-handoff`:JSON 优先;按**全量令牌核对表 A~E**回填或回执「保留出厂」;`ShowModel: card`;错误色 `#F5222D`;弹窗/壳层改令牌即生效
107
+ - [ ] **无**设计落地时未改出厂主色 / ShowModel / 壳层 / 弹窗几何默认
108
+ - [ ] 组件尺寸三档已落地并桥接 `--el-component-size*`;缺档落到 default;未全局强制 `size="small"`;**查询区不写 size**(三档对照表 ≠ 查询区要用 small)
87
109
 
88
110
  ## 业务
89
111
 
90
112
  - [ ] 提交前 `validate()`;删除有确认;提交有 loading;列表有 `v-loading`
91
- - [ ] 编辑回显正确;分页切换会拉数
113
+ - [ ] 编辑回显正确(`Object.assign`);分页切换会拉数
92
114
 
93
- ### 列表→详情(命中 detail-page 时)
115
+ ### 列表→详情(改动含 toDetail / *Detail 路由时强制,禁止 N/A 糊弄)
94
116
 
95
- - [ ] 兄弟绝对 path;`showLink:false`;`activePath`=列表 path;非空 `title`
96
- - [ ] 仅 `toDetail`;详情 `initToDetail`;`name` 对齐
97
- - [ ] 按需 `keepAlive` / `moreTags`
117
+ - [ ] **打开落盘路由文件**核对:兄弟绝对 path;`showLink:false`;`activePath`=列表 path;非空 `title`;默认 `keepAlive`+`moreTags`
118
+ - [ ] 仅 `toDetail`;详情 `initToDetail`;`name` 对齐;`toDetail` 第 3 参 title 可辨识
98
119
 
99
120
  ### 列表布局(命中 crud-pages 时)
100
121
 
@@ -18,13 +18,13 @@ tags: [vue3, kernel, conventions, layout, router, http, crud, inventory]
18
18
  | 3 | 方法跟后端文档,**允许 GET / POST**;POST → `data`,GET → `params` |
19
19
  | 4 | 列表用 `useTableSearch`,方法名 **`onSearch` / `reset`** |
20
20
  | 5 | 业务路由 **禁止** 再挂 `component: Layout` |
21
- | 6 | 独立详情/编辑:路由与跳转按 **`detail-page`**(`showLink` / `activePath` / `toDetail` / `initToDetail`) |
21
+ | 6 | 独立详情/编辑:按 **`detail-page` 三件套**(`showLink`+`activePath`+默认`keepAlive`/`moreTags` + `toDetail` + `initToDetail`);`toDetail`≠自动侧栏高亮/缓存 |
22
22
  | 7 | 页面权限 `meta.roles`;按钮 `v-auth` / `ReAuth` |
23
23
  | 8 | 环境只用 `import.meta.env.VITE_*` |
24
24
  | 9 | i18n:`$t('中文key')` |
25
25
  | 10 | 禁止用 `v-html` 渲染不可信内容 |
26
26
  | 11 | 新依赖须用户确认;已有封装须复用;选型表指定库勿擅自替换 |
27
- | 12 | 列表布局按 **`crud-pages` 黄金样板**(`el-card.vts-page-card`+`content`+固定 height、`tableHeight`、`otherRef`、分页在 ReTableBar 内;仅表格体内滚动) |
27
+ | 12 | 列表布局按 **`crud-pages` 黄金样板**(`el-card.vts-page-card`+`content`、无 `100vh` 减顶栏定高、`tableHeight`、`otherRef`、分页在 ReTableBar 内;仅表格体内滚动) |
28
28
  | 13 | addon 按 `project-inventory` 第九节精确版本安装;禁止 `@latest` |
29
29
  | 14 | 样式契约见下文「样式契约」 |
30
30
 
@@ -44,11 +44,15 @@ export default {
44
44
  component: () => import("@/views/xxx/list/index.vue"),
45
45
  meta: { title: "客户列表", roles: ["admin", "common"] },
46
46
  },
47
- // 独立详情:兄弟路由 + showLink/activePath,完整约定见 detail-page
47
+ // 独立详情:兄弟路由 + showLink + activePath + keepAlive/moreTags,见 detail-page 三件套
48
48
  ],
49
49
  } satisfies RouteConfigsTable;
50
50
  ```
51
51
 
52
+ ### 抗略读
53
+
54
+ 命中模块须照其**强制完整样板**落盘;样板中的字段默认写出。壳层行为(tag / 侧栏 / keep-alive)以路由 meta + 项目已有实现为准,不假设 Hook 会「全自动」。
55
+
52
56
  ### 权限
53
57
 
54
58
  ```vue
@@ -78,7 +82,7 @@ export function getCustomerList(data: CustomerQuery, url: string) {
78
82
 
79
83
  | Hook | 用途 | 详例 |
80
84
  |------|------|------|
81
- | `useApp` | headerHeight、字典、svgLoading | — |
85
+ | `useApp` | 字典、svgLoading | — |
82
86
  | `useTableSearch` | 列表查询分页 | `crud-pages` |
83
87
  | `useDetail` | 详情跳转与顶部 tag | `detail-page` |
84
88
  | `useFormCheck` | 多表单校验 | `data-writeback` |
@@ -107,28 +111,27 @@ export function getCustomerList(data: CustomerQuery, url: string) {
107
111
 
108
112
  ### 组件尺寸
109
113
 
110
- | 场景 | 档位 |
111
- |------|------|
112
- | 查询区表单/按钮、工具栏按钮 | default(不写 size) |
113
- | 表格 / 分页 | `:size="size"`(ReTableBar 透出) |
114
- | 弹窗内表单 | default |
115
- | 登录/整屏主表单 | `large` |
116
- | 移动端 Vant | 见 `mobile-h5` |
114
+ | 场景 | 档位 | 像素(令牌) |
115
+ |------|------|--------------|
116
+ | 查询区表单/按钮、工具栏按钮、弹窗内表单 | **default(不写 size)** | `--control-height`(设计 `--component-size-base`,默认 32px) |
117
+ | 表格 / 分页 | `:size="size"`(ReTableBar 透出) | 随密度切换,与表单档位独立 |
118
+ | 表格行内操作、紧凑工具条 | `small` | `--control-height-sm`(24px) |
119
+ | 登录/整屏主表单主按钮 | `large` | `--control-height-lg`(40px) |
120
+ | 移动端 Vant | 见 `mobile-h5` | — |
117
121
 
118
- 存在 `design-tokens.scss` 时:零新增硬编码裸值;适配流程见 `design-system`。
122
+ - **禁止**查询区 / 标准业务表单写 `size="small"`,也**禁止** `el-config-provider` 全局强制 `small`(除非用户明确要求紧凑主题)。
123
+ - 存在 `design-tokens.scss` 时:零新增硬编码裸值;三档桥接与 EP 映射见 `design-system` 7.5.8。
124
+ - 适配流程见 `design-system`。
119
125
 
120
126
  ### 独立功能页容器
121
127
 
122
- 定高且内部滚动(与列表卡同类场景):
128
+ 定高且内部滚动(与列表卡同类场景)——优先 `el-card.vts-page-card`;非 Card 根节点用 `vts-page-fill`:
123
129
 
124
130
  ```vue
125
- <div
126
- :style="{ height: `calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)` }"
127
- class="pos-relative bg-bg_color p-5 overflow-hidden"
128
- >
131
+ <div class="vts-page-fill h-full pos-relative bg-bg_color p-5 overflow-hidden">
129
132
  ```
130
133
 
131
- 查询列表定高卡 → `crud-pages`(`el-card.vts-page-card` + `tableHeight`)。
134
+ 查询列表定高卡 → `crud-pages`(`el-card.vts-page-card` + `tableHeight`,禁止 `100vh` 减顶栏定高)。
132
135
  ## 六、资产分层
133
136
 
134
137
  附加 Hook/组件按功能模块加载(WebSocket、微信、附件、图表等)→ 见各专项与 `project-inventory`。
@@ -9,6 +9,8 @@ tags: [vue3, crud, list, form, detail, table, useTableSearch, page, layout]
9
9
 
10
10
  遵守 `core-kernel` / `http-api`。独立详情路由 → 同时加载 `detail-page`。回显 → `data-writeback`。
11
11
 
12
+ **抗略读**:列表页必须整段照抄「列表黄金样板」;有独立详情时 **同批** 落 `detail-page` 三件套(禁止只写 `toDetail`)。方法名固定 `onSearch` / `reset`。
13
+
12
14
  ## useTableSearch
13
15
 
14
16
  ```typescript
@@ -27,17 +29,20 @@ useTableSearch(formQuery, searchFn, url)
27
29
 
28
30
  | 场景 | 做法 |
29
31
  |------|------|
30
- | 查询列表(定高) | `el-card.vts-page-card` + 固定 `height: calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)`;表格绑 `tableHeight`;**仅表格体内滚动**;分页在表格下方;整页无外层滚动条 |
32
+ | 查询列表(定高) | `el-card.vts-page-card`(禁止 `100vh` 减顶栏定高);表格绑 `tableHeight`;仅表格体内滚动;分页在表格下方;整页无外层滚动条 |
31
33
  | 树 + 表分栏 | 同上;左侧树、右侧表共用定高卡,高度仍走 `useTableSearch` 几何实测 |
32
- | 长表单 / 详情 / 说明类 | 可用 `minHeight` 同公式;内容超出时由 `.app-main` 内 `el-scrollbar` 滚动 |
33
- | Card 内边距 | 一律走 `--vts-card-padding`(桥接 `--card-padding`);换规范只改令牌,列表高度由 Hook 跟随 |
34
+ | 长表单 / 详情 / 说明类 | 根节点 `min-height: 100%`(或 `:style="{ minHeight: '100%' }"`);超出由 `.app-main` 内 `el-scrollbar` 滚动 |
35
+ | Card 整页填满 | 根节点加 `class="vts-page-fill"` + `height: 100%` / `h-full` |
36
+ | Card 内边距 | 一律走 `--vts-card-padding`(桥接 `--card-padding`);换规范 / `--vts-margin` 变化由壳层 flex 链 + Hook 自动跟随 |
37
+
38
+ > **壳层原理**(`lay-content`):`.main-content` 用 `padding: var(--vts-margin)`(不用 margin);定高页 `.main-content:has(.vts-page-card)` / `.vts-page-fill` 为 `height: 100%`;`.vts-page-card` 填满。`html/body/#app/.app-wrapper/.main-container/.app-main` 均为 `height:100%; overflow:hidden`。禁止业务页 `100vh` 减顶栏定高。
34
39
 
35
40
  ## 列表黄金样板(唯一完整示例)
36
41
 
37
42
  | # | 必须 |
38
43
  |---|------|
39
44
  | L1 | `el-card` + `class="vts-page-card"` + `ref="content"`(禁止挂 `div`) |
40
- | L2 | 固定 `height: calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)`(禁止只用 `minHeight`) |
45
+ | L2 | 不要写 `height: calc(100vh - …)` / 不要用 JS 测顶栏定高(壳层 + `.vts-page-card` 已填满) |
41
46
  | L3 | 查询区 `bg-bg_color p-5`;展示区 `ReTableBar class="bg-bg_color"` |
42
47
  | L4 | `ReGrid` `:gap="[0,20]"` + cols;表单项 `w-[100%] !mr-0`;`@should-show-collapse` |
43
48
  | L5 | 操作列 `<ReGridItem suffix>` |
@@ -61,7 +66,7 @@ import { message } from "@/utils/message";
61
66
 
62
67
  defineOptions({ name: "CustomerList" });
63
68
 
64
- const { headerHeight, svgLoading } = useApp();
69
+ const { svgLoading } = useApp();
65
70
  const formQuery = reactive<CustomerQuery>({ keyword: "", status: undefined });
66
71
 
67
72
  const {
@@ -123,9 +128,6 @@ function handleSizeChange(size: number) {
123
128
  ref="content"
124
129
  class="vts-page-card"
125
130
  shadow="never"
126
- :style="{
127
- height: `calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)`,
128
- }"
129
131
  >
130
132
  <div>
131
133
  <el-form
@@ -234,10 +236,12 @@ function handleSizeChange(size: number) {
234
236
  </template>
235
237
  ```
236
238
 
237
- 补充:`ReTableOperate` 用 `:list`;`defineOptions.name` === 路由 `name`;`headerHeight` / `svgLoading` 来自 `useApp()`。
239
+ 补充:`ReTableOperate` 用 `:list`;`defineOptions.name` === 路由 `name`;`svgLoading` 来自 `useApp()`;列表定高走壳层令牌 + `vts-page-card`。
238
240
 
239
241
  ## 列表 → 详情/编辑
240
242
 
243
+ 有独立详情/编辑路由时:**必须同时命中并深读 `detail-page`**。禁止只抄下面的 `toDetail` 就交卷。
244
+
241
245
  ```typescript
242
246
  import { useDetail } from "@/hooks/useDetail";
243
247
  const { toDetail } = useDetail();
@@ -254,7 +258,24 @@ function onEdit(row: Customer, mark: "edit" | "view") {
254
258
  }
255
259
  ```
256
260
 
257
- 路由 meta 与详情页 `initToDetail` → **`detail-page`**。
261
+ **同批必落兄弟路由 meta**(完整三件套见 `detail-page`;此处不可省略):
262
+
263
+ ```typescript
264
+ {
265
+ path: "/customer/detail",
266
+ name: "CustomerDetail",
267
+ component: () => import("@/views/customer/detail/index.vue"),
268
+ meta: {
269
+ title: "客户详情",
270
+ showLink: false,
271
+ activePath: "/customer/list",
272
+ keepAlive: true,
273
+ moreTags: true,
274
+ },
275
+ },
276
+ ```
277
+
278
+ 详情页 `initToDetail` + `defineOptions({ name })` 对齐 → **`detail-page`**。
258
279
 
259
280
  ## 表单页
260
281
 
@@ -315,16 +336,17 @@ async function onSubmit() {
315
336
  },
316
337
  ```
317
338
 
318
- 独立详情兄弟路由 `detail-page`。禁止业务模块再挂 Layout。
339
+ 独立详情兄弟路由(含 `activePath` / `keepAlive` / `moreTags`)→ `detail-page`。禁止业务模块再挂 Layout。
319
340
 
320
341
  ## 反例(短表)
321
342
 
322
343
  | 错误 | 正确 |
323
344
  |------|------|
324
345
  | `handleSearch` / 手写分页 | `onSearch` / `useTableSearch` |
325
- | `ref="content"` 挂 div / 只用 minHeight / 缺 `vts-page-card` | `el-card.vts-page-card` + 固定 height |
346
+ | `ref="content"` 挂 div / `100vh` 减顶栏定高 / 缺 `vts-page-card` | `el-card.vts-page-card`(高度交给壳层) |
326
347
  | 不绑 `tableHeight` / 分页在卡片外 / 手写魔法数扣高度 | 样板 L6/L7;高度交给 `useTableSearch` |
327
348
  | 额外模块不绑 `otherRef` | L8 |
328
- | `router.push` 开详情 | `toDetail`(见 detail-page) |
349
+ | 只写 `toDetail`、详情路由缺 `activePath` | 三件套整段落盘(见 detail-page) |
350
+ | 裸 `router.push` 开详情 | `toDetail` + meta(见 detail-page) |
329
351
  | `ReTableOperate :buttons` | `:list` |
330
352
  | `@show-collapse` | `@should-show-collapse` |
@@ -2,6 +2,19 @@
2
2
 
3
3
  > 按本文件示例编写,复用项目已有回显/回填约定与选择器回写方式,勿另起一套表单赋值实现。
4
4
 
5
+ **抗略读**:编辑回显**必须** `Object.assign(formData, res.data)`,禁止 `formData = res.data` 破坏响应式。提交按钮默认带 `loading`。
6
+
7
+ ## 强制样板(编辑回显)
8
+
9
+ ```typescript
10
+ async function getDetail() {
11
+ const { id } = getParameter.value;
12
+ if (!id) return;
13
+ const res = await getDetailApi({ id });
14
+ if (res.status === 200 && res.data) Object.assign(formData, res.data);
15
+ }
16
+ ```
17
+
5
18
  ## 表单回显
6
19
 
7
20
  ### 新增/编辑页