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

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
@@ -24,11 +24,20 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
24
24
 
25
25
  1. 先读 `references/core-kernel.md`
26
26
  2. 复用仓库已有 `Re*` / Hook / utils;选型表指定库勿擅自替换
27
- 3. 按命中模块内完整示例编写
27
+ 3. 按命中模块内**强制完整样板**整段编写(禁止只抄 API 签名、丢掉 meta/配套段落)
28
28
  4. 无对应能力 → 标注「待确认」,未经同意不引入新依赖
29
29
  5. 真相源:`仓库已有封装` > `本 Skill 示例` > 通用 Vue 习惯
30
30
  6. 命中 addon / 缺依赖时再读 `project-inventory.md` 第九节;精确版本安装,禁止 `@latest`
31
31
 
32
+ ## 抗略读(全模块 · 提高命中率)
33
+
34
+ 按需模块 ≠ 可浅读。命中即须落到该文件的**完整样板 / Must-do**,生成后靠 `code-quality` 硬失败表兜底。
35
+
36
+ 1. **样板字段默认写出**:示例里写明的 `activePath` / `keepAlive` / `roles` / `responseType: "blob"` 等不得改成 `//` 注释再当可选项;仅业务明确不需要时才删除
37
+ 2. **关联能力同批落盘**:列表→详情 = `crud-pages` + `detail-page` 三件套;有 API = 同步 `http-api`;有删除 = 确认框;有编辑回显 = `Object.assign`
38
+ 3. **Hook ≠ 壳层自动**:`toDetail` 写 tag;侧栏高亮 / keepAlive 靠路由 meta;`http` 加解密靠环境开关,不靠单请求配置
39
+ 4. **大范围交付仍须逐模块核对硬失败表**,禁止「lint 过了就算完」
40
+
32
41
  ## 模块路由表
33
42
 
34
43
  ### 始终加载
@@ -112,7 +121,8 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
112
121
 
113
122
  - HTTP:`import { http } from '@/utils/http'`;方法跟后端(允许 GET/POST);`Result<T>`;`VITE_API_BASE_URL` → `http-api`
114
123
  - 列表:`onSearch` / `reset` + 黄金样板 → `crud-pages`
115
- - 独立详情:`toDetail` + 路由 meta → `detail-page`
124
+ - 独立详情:`toDetail` **不能替代** `activePath` / `keepAlive` / `moreTags`;三件套 → `detail-page`
125
+ - 权限:`meta.roles` + `v-auth`/`ReAuth` → `permission-auth`
116
126
  - 不二次挂 Layout;`script setup` + `defineOptions({ name })`;`$t('中文')`;样式契约 → `core-kernel`
117
127
 
118
128
  ## 工作流
@@ -134,6 +144,7 @@ tags: [vue3, typescript, element-plus, vant, pinia, vite, unocss, crud, componen
134
144
  ## 代码质量审查
135
145
  - 闸门:已执行 code-quality(生成后)
136
146
  - 清单:选型 / 类型 / 组件 / API / 安全 / 业务 / 列表→详情(如适用) / 列表布局(如适用) / 风格 → 通过 | 已修正:…
147
+ - 硬失败:无 | 已拦截并修正:…
137
148
  - 命令:`pnpm lint:fix` → …;`pnpm type-check` → …
138
149
  - 待确认:…
139
150
 
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.14",
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,29 @@ 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` / 无 `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
+
30
48
  ## 选型与硬约束
31
49
 
32
50
  - [ ] 已读 `core-kernel`;addon/缺依赖时已读 `project-inventory`
@@ -34,7 +52,7 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
34
52
  - [ ] addon 缺包按 inventory 第九节精确版本(禁止 `@latest`)
35
53
  - [ ] 列表方法名 `onSearch` / `reset`;HTTP 用 `@/utils/http` + `Result<T>`
36
54
  - [ ] 业务路由未二次挂 Layout
37
- - [ ] 独立详情:`showLink:false` + `activePath` + `toDetail` + `initToDetail`(细则 `detail-page`)
55
+ - [ ] 独立详情:对照路由文件确认 `showLink:false` + `activePath` + `keepAlive`/`moreTags`(默认)+ `toDetail` + `initToDetail`
38
56
  - [ ] 列表布局按 `crud-pages` 黄金样板(`el-card.vts-page-card`+`content`+固定 height、`tableHeight`、`otherRef`、分页在 ReTableBar 内;内容区无外层滚动条)
39
57
 
40
58
  ## TypeScript
@@ -88,13 +106,12 @@ tags: [code-review, quality, checklist, lint, typescript, vue3, security, perfor
88
106
  ## 业务
89
107
 
90
108
  - [ ] 提交前 `validate()`;删除有确认;提交有 loading;列表有 `v-loading`
91
- - [ ] 编辑回显正确;分页切换会拉数
109
+ - [ ] 编辑回显正确(`Object.assign`);分页切换会拉数
92
110
 
93
- ### 列表→详情(命中 detail-page 时)
111
+ ### 列表→详情(改动含 toDetail / *Detail 路由时强制,禁止 N/A 糊弄)
94
112
 
95
- - [ ] 兄弟绝对 path;`showLink:false`;`activePath`=列表 path;非空 `title`
96
- - [ ] 仅 `toDetail`;详情 `initToDetail`;`name` 对齐
97
- - [ ] 按需 `keepAlive` / `moreTags`
113
+ - [ ] **打开落盘路由文件**核对:兄弟绝对 path;`showLink:false`;`activePath`=列表 path;非空 `title`;默认 `keepAlive`+`moreTags`
114
+ - [ ] 仅 `toDetail`;详情 `initToDetail`;`name` 对齐;`toDetail` 第 3 参 title 可辨识
98
115
 
99
116
  ### 列表布局(命中 crud-pages 时)
100
117
 
@@ -18,7 +18,7 @@ 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')` |
@@ -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
@@ -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
@@ -238,6 +240,8 @@ function handleSizeChange(size: number) {
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,7 +336,7 @@ 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
 
@@ -325,6 +346,7 @@ async function onSubmit() {
325
346
  | `ref="content"` 挂 div / 只用 minHeight / 缺 `vts-page-card` | `el-card.vts-page-card` + 固定 height |
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
  ### 新增/编辑页
@@ -9,18 +9,13 @@ tags: [vue3, detail, toDetail, useDetail, activePath, showLink, multiTags, keepA
9
9
 
10
10
  真相源:模版 `useDetail.ts`、`multiTags`、侧栏 `NavVertical`。列表打开独立路由页时按本文件落地。
11
11
 
12
- ## 概念
12
+ **反认知偏差(必读)**:`toDetail` 只负责写顶部 tag 并跳转;**侧栏高亮靠 `meta.activePath`,缓存/多开靠 `meta.keepAlive` / `moreTags`**。三者缺一不可,禁止只写 `toDetail`。
13
13
 
14
- | 能力 | 字段 / API |
15
- |------|------------|
16
- | 不进左侧菜单 | 路由 `meta.showLink: false` |
17
- | 顶部 tag(multiTags) | `useDetail().toDetail` → `handleTags('push')` |
18
- | 侧栏高亮 | 路由 `meta.activePath` = 列表 path |
19
- | 页面缓存 | `meta.keepAlive`;多开 tag 再加 `moreTags: true` |
14
+ ## 详情三件套(强制完整样板 · 整段照抄再改名)
20
15
 
21
- `showLink` 只管侧栏是否显示,不控制顶部 tag。详情不在菜单里 必须用 `toDetail` 写 tag;裸 `router.push` 只换路由。
16
+ 缺任一段 = 未完成。样板内字段**默认全部写出**(勿改成 `//` 注释再「按需打开」)。仅当业务明确不要缓存/多开时,才删掉对应行。
22
17
 
23
- ## 路由(与列表兄弟)
18
+ ### ① 兄弟路由 meta
24
19
 
25
20
  ```typescript
26
21
  {
@@ -31,36 +26,27 @@ tags: [vue3, detail, toDetail, useDetail, activePath, showLink, multiTags, keepA
31
26
  title: "客户详情",
32
27
  showLink: false,
33
28
  activePath: "/customer/list",
34
- // keepAlive: true,
35
- // moreTags: true,
29
+ keepAlive: true,
30
+ moreTags: true,
36
31
  },
37
32
  },
38
33
  ```
39
34
 
40
- | 字段 | 要求 |
41
- |------|------|
42
- | `title` | 非空 |
43
- | `showLink: false` | 必填 |
44
- | `activePath` | = 列表 path |
45
- | `name` | = `defineOptions({ name })` |
46
-
47
- ## 列表打开
35
+ ### 列表页打开
48
36
 
49
37
  ```typescript
50
38
  import { useDetail } from "@/hooks/useDetail";
51
39
  const { toDetail } = useDetail();
52
40
 
53
41
  toDetail("CustomerDetail", { webId: "0" }, "(新增)");
54
- toDetail("CustomerDetail", { id: row.id, text: row.name, mark: "edit" }, `(编辑)【${row.name}】`);
42
+ toDetail(
43
+ "CustomerDetail",
44
+ { id: row.id, text: row.name, mark: "edit" },
45
+ `(编辑)【${row.name}】`,
46
+ );
55
47
  ```
56
48
 
57
- ```typescript
58
- toDetail(name, parameter, title?, model = "query") // model: "query" | "params"
59
- ```
60
-
61
- 写入 tag 时不要把路由上的 `showLink: false` 原样塞进 `handleTags` 的 meta。
62
-
63
- ## 详情页
49
+ ### ③ 详情页初始化
64
50
 
65
51
  ```vue
66
52
  <script setup lang="ts">
@@ -72,12 +58,36 @@ const { id, mark } = getParameter as DetailParameter;
72
58
  </script>
73
59
  ```
74
60
 
75
- `initToDetail` 标题:无 id → `(新增)`;`mark===edit'` → `(编辑)【text】`;`view` → `(查看)【text】`。
61
+ ## 概念
62
+
63
+ | 能力 | 字段 / API | 谁负责 |
64
+ |------|------------|--------|
65
+ | 不进左侧菜单 | `meta.showLink: false` | 路由 |
66
+ | 顶部 tag | `toDetail` → `handleTags('push')` | Hook |
67
+ | 侧栏高亮 | `meta.activePath` = 列表 path | 路由 |
68
+ | 页面缓存 / 多开 | `meta.keepAlive` + `moreTags: true` | 路由 |
69
+
70
+ `showLink` 只管侧栏是否显示,不控制顶部 tag。裸 `router.push` 只换路由、不写 tag。
71
+
72
+ | 字段 | 要求 |
73
+ |------|------|
74
+ | `title` | 非空 |
75
+ | `showLink: false` | 必填 |
76
+ | `activePath` | = 列表 path(必填) |
77
+ | `keepAlive` / `moreTags` | 默认 `true`;不要缓存/多开再删 |
78
+ | `name` | = `defineOptions({ name })` |
79
+
80
+ ```typescript
81
+ toDetail(name, parameter, title?, model = "query") // model: "query" | "params"
82
+ ```
83
+
84
+ 写入 tag 时不要把路由上的 `showLink: false` 原样塞进 `handleTags` 的 meta。
85
+
86
+ `initToDetail` 标题:无 id → `(新增)`;`mark==='edit'` → `(编辑)【text】`;`view` → `(查看)【text】`。
76
87
 
77
88
  ## Must-do
78
89
 
79
- 1. 兄弟路由 + `showLink: false` + `activePath` + 非空 `title`
80
- 2. 列表只用 `toDetail`,禁止裸 `router.push`
81
- 3. 详情页必调 `initToDetail`;`name` 对齐
82
- 4. 参数用 `getParameter`
83
- 5. 需缓存 / 多开时配 `keepAlive` / `moreTags`
90
+ 1. 三件套整段落盘(路由 + `toDetail` + `initToDetail`)
91
+ 2. `showLink: false` + `activePath` + 非空 `title` + 默认 `keepAlive`/`moreTags`
92
+ 3. 列表只用 `toDetail`,禁止裸 `router.push`
93
+ 4. 详情页必调 `initToDetail`;`name` 对齐;参数用 `getParameter`
@@ -4,6 +4,26 @@
4
4
 
5
5
  规范文件下载、模板下载、文件流导出与附件预览。在需要下载文件、导出表格或预览附件时参照。
6
6
 
7
+ **抗略读**:导出/下载 API **必须**带 `responseType: "blob"`(默认写出,勿当可选项注释掉);前端用 `blobDown` / 项目已有 `download*`,禁止手写 `URL.createObjectURL` 另起一套(除非仓库无封装)。
8
+
9
+ ## 强制样板(导出)
10
+
11
+ ```typescript
12
+ // api
13
+ export function exportExcel(data: Recordable) {
14
+ return http.request<Result<Blob>>(
15
+ "post",
16
+ `${import.meta.env.VITE_API_BASE_URL}/xxx/export`,
17
+ { data },
18
+ { responseType: "blob" },
19
+ );
20
+ }
21
+
22
+ // 页面
23
+ const res = await exportExcel(params);
24
+ blobDown(res.data, "导出.xlsx", res);
25
+ ```
26
+
7
27
  ## 常用工具
8
28
 
9
29
  项目集成了 `@pureadmin/utils` 与自定义工具:
@@ -4,6 +4,25 @@
4
4
 
5
5
  规范系统 Loading、Message、MessageBox、NoticeBar 等反馈组件的使用。在需要提示用户或阻塞操作时参照。
6
6
 
7
+ **抗略读**:删除/危险操作**默认写出** `ElMessageBox.confirm`;列表请求接 `v-loading`;提交默认 `loading` 防重复。提示文案一律 `$t()`。
8
+
9
+ ## 强制样板(删除确认)
10
+
11
+ ```typescript
12
+ import { ElMessageBox } from "element-plus";
13
+ import { message } from "@/utils/message";
14
+
15
+ async function onDelete(row: { id: string }) {
16
+ await ElMessageBox.confirm($t("确定删除吗?"), $t("温馨提醒"), {
17
+ confirmButtonText: $t("确定"),
18
+ cancelButtonText: $t("取消"),
19
+ type: "warning",
20
+ });
21
+ // await deleteApi({ id: row.id })
22
+ message($t("删除成功"), { type: "success" });
23
+ }
24
+ ```
25
+
7
26
  ## Loading
8
27
 
9
28
  ### 局部 Loading
@@ -10,6 +10,8 @@ tags: [form, dialog, ReDialog, ReDialogResize, ReSelectQuery, ReCascader, iconPi
10
10
  > 核心选择器与 CRUD 列表筛选项高频相关。
11
11
  > **弹窗**:业务弹窗统一用 `ReDialog` / `ReDialogResize`,禁止业务页直接堆裸 `el-dialog`(除非用户明确要求)。
12
12
 
13
+ **抗略读**:弹窗走项目 `ReDialog` 黄金样板(含销毁/禁点遮罩等默认项),勿降级为裸 `el-dialog`。远程下拉用 `ReSelectQuery` 真实 props(`url`/`value`/`label`/`edit-data`),禁止臆造 `:api`。
14
+
13
15
  ## 依赖(缺则先装)
14
16
 
15
17
  按用到的能力安装(先查 `package.json`):
@@ -9,6 +9,31 @@ tags: [axios, http, api, encryption, rsa, aes, download, request]
9
9
 
10
10
  > 实现落点:`src/utils/http.ts`、`src/api/**`、全局 `Result<T>`。
11
11
 
12
+ **抗略读**:接口文件须整段按下方「强制样板」落盘;禁止组件内直接 `axios`/`fetch`。加解密靠 `VITE_ENCODE_SWITCH`,禁止臆造单请求 `crypto: true`。下载接口**默认写出** `responseType: "blob"`(勿注释掉)。
13
+
14
+ ## 强制样板(新建 API 照抄)
15
+
16
+ ```typescript
17
+ import { http } from "@/utils/http";
18
+
19
+ export function getCustomerList(data: CustomerQuery) {
20
+ return http.request<Result<CustomerPage>>(
21
+ "post",
22
+ `${import.meta.env.VITE_API_BASE_URL}/customer/list`,
23
+ { data },
24
+ );
25
+ }
26
+
27
+ export function downloadCustomer(data: Recordable) {
28
+ return http.request<Result<Blob>>(
29
+ "post",
30
+ `${import.meta.env.VITE_API_BASE_URL}/customer/export`,
31
+ { data },
32
+ { responseType: "blob" },
33
+ );
34
+ }
35
+ ```
36
+
12
37
  ## Http 封装架构
13
38
 
14
39
  项目使用自定义 `Http` 类封装 Axios,位于 `src/utils/http.ts`。核心特性:
@@ -11,6 +11,18 @@ tags: [vue3, icon, svg-icon, ReSvgIcon, ReIconPicker, iconify, ep, ri, unocss, m
11
11
  > **真相源**:`src/components/ReSvgIcon`、`src/components/ReIconPicker`、`src/icons/svg`、`main.ts`、`uno.config.ts`、`build/plugins/SvgSpriteLoader.ts` / `SvgLoader.ts`。
12
12
  > 选型表见 `project-inventory`「图标」节;勿另起 IconFont / 未约定的图标库。
13
13
 
14
+ **抗略读**:新建菜单/父级路由时 **`meta.icon` 默认写出**(如 `ep:user`),禁止交无图标菜单。页面内优先 `<svg-icon name="..." />`,勿散落未约定图标库。
15
+
16
+ ## 强制样板(菜单 icon)
17
+
18
+ ```typescript
19
+ meta: { title: "客户管理", icon: "ep:user", rank: 10 }
20
+ ```
21
+
22
+ ```vue
23
+ <svg-icon name="ep:search" />
24
+ ```
25
+
14
26
  ---
15
27
 
16
28
  ## 依赖(core,模板已装)
@@ -7,6 +7,20 @@ tags: [vue3, permission, auth, directive, hooks, v-auth, role, access-control]
7
7
 
8
8
  # 权限控制与自定义指令
9
9
 
10
+ **抗略读**:有权限需求时,`meta.roles` 与 `v-auth`/`ReAuth` **默认写出**(勿注释成可选项)。禁止 `v-if="roles.includes(...)"` 手写角色判断。
11
+
12
+ ## 强制样板(页面 + 按钮)
13
+
14
+ ```typescript
15
+ // 路由:roles 默认写出
16
+ meta: { title: "用户管理", roles: ["admin", "common"] }
17
+ ```
18
+
19
+ ```vue
20
+ <el-button v-auth="['admin']" @click="onDelete">{{ $t("删除") }}</el-button>
21
+ <ReAuth :value="['admin']"><!-- 区域级 --></ReAuth>
22
+ ```
23
+
10
24
  ## 权限体系概览
11
25
 
12
26
  项目权限分为三个层级:
@@ -33,7 +47,7 @@ export default {
33
47
  component: () => import("@/views/system/user/index.vue"),
34
48
  meta: {
35
49
  title: "用户管理",
36
- roles: ["admin", "editor"], // 只有这些角色可以访问
50
+ roles: ["admin", "editor"],
37
51
  },
38
52
  },
39
53
  {
@@ -42,7 +56,7 @@ export default {
42
56
  component: () => import("@/views/system/config/index.vue"),
43
57
  meta: {
44
58
  title: "系统配置",
45
- roles: ["admin"], // 仅管理员可访问
59
+ roles: ["admin"],
46
60
  },
47
61
  },
48
62
  ],