@qilitt-mickey/vue3-temp-skill 1.0.12 → 1.1.2

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.
Files changed (42) hide show
  1. package/README.md +66 -214
  2. package/SKILL.md +165 -527
  3. package/package.json +2 -2
  4. package/references/api-check.md +187 -128
  5. package/references/base-code-dict.md +49 -48
  6. package/references/chart-echarts.md +61 -0
  7. package/references/code-quality.md +44 -15
  8. package/references/core-kernel.md +305 -0
  9. package/references/crud-pages.md +87 -261
  10. package/references/data-compare.md +502 -501
  11. package/references/data-mapping.md +218 -213
  12. package/references/data-screen.md +94 -79
  13. package/references/data-writeback.md +104 -104
  14. package/references/detail-page.md +100 -99
  15. package/references/directives-advanced.md +27 -4
  16. package/references/download-export.md +70 -68
  17. package/references/feedback-loading.md +62 -60
  18. package/references/feedback-ui.md +125 -111
  19. package/references/file-management.md +28 -7
  20. package/references/flowchart-g6.md +249 -244
  21. package/references/form-advanced.md +264 -26
  22. package/references/graph-relation.md +12 -7
  23. package/references/http-api.md +138 -103
  24. package/references/icons.md +326 -0
  25. package/references/layout-theme.md +1 -1
  26. package/references/mobile-h5.md +20 -0
  27. package/references/particles.md +143 -0
  28. package/references/permission-auth.md +8 -31
  29. package/references/project-inventory.md +175 -120
  30. package/references/qrcode-barcode.md +107 -92
  31. package/references/rich-text.md +85 -73
  32. package/references/seamless-scroll.md +40 -38
  33. package/references/table-vxe.md +114 -0
  34. package/references/tree-table.md +2 -1
  35. package/references/ui-components.md +5 -1
  36. package/references/verify-captcha.md +110 -96
  37. package/references/websocket-realtime.md +2 -1
  38. package/references/wechat-js.md +58 -0
  39. package/references/workflow-bpmn.md +207 -206
  40. package/references/advanced-ui.md +0 -302
  41. package/references/build-optim.md +0 -282
  42. package/references/vue-core.md +0 -209
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilitt-mickey/vue3-temp-skill",
3
- "version": "1.0.12",
4
- "description": "Vue 3 企业级中后台项目开发规范技能包 — 让 AI 编程助手按照团队规范生成代码,并自动审查代码质量",
3
+ "version": "1.1.2",
4
+ "description": "Vue 3 企业级中后台项目开发规范技能包 — core-kernel 架构、按需功能模块",
5
5
  "bin": {
6
6
  "vue3-temp-skill": "./bin/cli.js"
7
7
  },
@@ -1,45 +1,54 @@
1
1
  ---
2
2
  skill: api-check
3
- description: 前后端接口对接检查清单。在对接后端 API 或 AI 生成接口调用代码后,必须对照此清单验证接口契约的正确性,确保前后端数据流通畅。适用于接口联调、AI 生成 API 代码自检场景。
3
+ description: 前后端接口对接检查清单。在对接后端 API 或 AI 生成接口调用代码后,必须对照此清单验证接口契约的正确性,确保前后端数据流通畅。适用于接口联调、AI 生成 API 代码自检、本地 Mock 场景。
4
4
  scope: project
5
- tags: [api, backend, integration, contract, http, request, response, debug, checklist]
5
+ tags: [api, backend, integration, contract, http, request, response, debug, checklist, mock]
6
6
  ---
7
7
 
8
8
  # 前后端接口对接检查清单
9
9
 
10
- > **使用说明**:在对接后端 API 或 AI 生成接口调用代码后,逐项对照检查。确保前端调用方式与后端接口定义完全匹配,避免联调阶段反复返工。
10
+ > **使用说明**:在对接后端 API 或 AI 生成接口调用代码后,逐项对照检查。确保前端调用方式与后端接口定义完全匹配,避免联调阶段反复返工。
11
+ > **权威来源**:以仓库代码为准——`types/global.d.ts`(`Result` / 分页)、`src/utils/http.ts`、`src/api/**`、`mock/**`、`src/hooks/useTableSearch.ts`。
11
12
 
12
13
  ## 一、接口基本信息核对
13
14
 
14
15
  ### 必须确认
15
16
 
16
- - [ ] **请求地址**:URL 路径与后端接口文档一致,注意前缀 `/api`。
17
- - [ ] **请求方法**:本项目统一使用 POST,确认后端没有要求 GET/PUT/DELETE。
17
+ - [ ] **请求地址**:业务接口路径与后端文档一致;**禁止**把本地 Mock 前缀(如 `/mock/...`)当成前后端约定。
18
+ - [ ] **域名来源**:真实接口使用 `import.meta.env.VITE_API_BASE_URL` 拼接业务 path,禁止硬编码域名。
19
+ - [ ] **请求方法**:与后端接口文档一致即可。**允许 GET / POST**(项目未禁止 GET);常见业务写操作用 POST,查询/下载/签名等后端要求 GET 时用 GET。
20
+ - [ ] **参数位置**:POST 业务体用 `data`;GET 查询串用 `params`。二者按方法匹配,不要混用错位置。
18
21
  - [ ] **Content-Type**:默认 `application/json`,文件上传使用 `multipart/form-data`。
19
- - [ ] **认证方式**:需要 Token 的接口,确认请求头携带了 `Authorization`。
20
- - [ ] **加密要求**:敏感接口(登录、修改密码等)需要设置 `crypto: true`。
22
+ - [ ] **认证方式**:拦截器自动注入请求头 `token`、`userCode`(不是 `Authorization: Bearer`)。
23
+ - [ ] **加解密**:由环境变量 `VITE_ENCODE_SWITCH` 全局控制(见 `src/utils/http.ts`),**没有**单请求 `crypto: true` 开关;GET 默认不走加解密。
21
24
 
22
- ### URL 规范
25
+ ### URL 约定(务必区分「真实联调」与「本地 Mock」)
23
26
 
24
27
  ```typescript
25
- // ✅ 项目标准 URL 格式
26
- "/api/system/user/list" // 列表
27
- "/api/system/user/detail" // 详情
28
- "/api/system/user/save" // 保存(新增+编辑)
29
- "/api/system/user/delete" // 删除
30
- "/api/system/user/export" // 导出
31
-
32
- // ❌ 避免 RESTful 风格(本项目统一 POST)
33
- "/api/users" // 不对
34
- "/api/users/:id" // 不对
28
+ // ✅ 真实业务接口:环境变量 + 后端业务 path(示例,path 以接口文档为准)
29
+ `${import.meta.env.VITE_API_BASE_URL}/console/common/attachment/list`
30
+ `${import.meta.env.VITE_API_BASE_URL}/baseCode/search?uuid=${buildUUID()}`
31
+
32
+ // ✅ 本地 Fake Server(vite-plugin-fake-server,目录 mock/)
33
+ // 仅开发 Mock 使用,不是前后端规范前缀
34
+ "/mock/login"
35
+ "/mock/console/customerPortrait/queryCustomerRelation"
36
+ "/get-table-list" // 部分 Fake Server 路径也可能不带 /mock 前缀
37
+
35
38
  ```
36
39
 
40
+ 说明:
41
+
42
+ 1. **`/mock/...`、部分裸路径**:服务本地 `mock/*.ts`(`defineFakeRoute`),用于后端未就绪时的前端开发。
43
+ 2. **真实联调**:换成 `VITE_API_BASE_URL` + 后端真实 path;path 形态由后端文档决定,**不是**统一的 `/api` 前缀规范。
44
+ 3. **方法以接口文档为准**:允许 GET;不要为了“统一 POST”去改后端已定义的 GET 接口。也勿无依据地套路径参数式 REST(如 `/users/:id`),除非文档就是这样定义。
45
+
37
46
  ## 二、请求参数核对
38
47
 
39
48
  ### 必须确认
40
49
 
41
- - [ ] **参数位置**:本项目统一通过 `data` 传递(POST body),不是 `params`(query string)。
42
- - [ ] **字段名称**:与后端接口文档的字段名完全一致,注意大小写。
50
+ - [ ] **参数位置**:POST → `data`(body);GET → `params`(query)。与方法匹配即可。
51
+ - [ ] **字段命名**:前后端统一 **驼峰 camelCase**(如 `userName`、`userCode`、`pageNo`),与接口文档一致。
43
52
  - [ ] **字段类型**:字符串/数字/布尔/数组/对象,与后端定义匹配。
44
53
  - [ ] **必填字段**:所有后端标记为必填的字段,前端必须传递。
45
54
  - [ ] **默认值**:后端有默认值的字段,前端不传时使用后端默认值。
@@ -50,104 +59,134 @@ tags: [api, backend, integration, contract, http, request, response, debug, chec
50
59
  | 后端 Java 类型 | 前端 TypeScript 类型 | 注意事项 |
51
60
  |---------------|---------------------|---------|
52
61
  | `String` | `string` | 空字符串 `""` 与 `null` 不同 |
53
- | `Integer` / `Long` | `number` | 注意 `Long` 精度问题(超过 `Number.MAX_SAFE_INTEGER` 需用 `string`) |
62
+ | `Integer` | `number` | 普通整型可用 number |
63
+ | `Long` | `string` | 超过 `Number.MAX_SAFE_INTEGER` 会丢精度,统一用 `string` |
54
64
  | `Boolean` | `boolean` | `0/1` 与 `true/false` 需确认后端用哪种 |
55
65
  | `BigDecimal` | `string` | 金额类字段必须用 `string` 避免精度丢失 |
56
66
  | `Date` / `LocalDateTime` | `string` | 确认格式:`yyyy-MM-dd` 还是 `yyyy-MM-dd HH:mm:ss` |
57
67
  | `List<T>` | `T[]` | 确认数组元素的类型 |
58
- | `Map<String, Object>` | `Record<string, any>` | 尽量避免,要求后端定义明确结构 |
68
+ | `Map<String, Object>` | `Record<string, unknown>` | 尽量避免,要求后端定义明确结构 |
59
69
 
60
70
  ### 常见参数错误
61
71
 
62
72
  ```typescript
63
- // ❌ 错误:参数放在 params 中(query string)
64
- http.request("post", "/api/user/list", { params: { page: 1, pageSize: 10 } });
73
+ import { http } from "@/utils/http";
74
+
75
+ const base = import.meta.env.VITE_API_BASE_URL;
76
+
77
+ // ❌ 错误:POST 却把业务参数放在 params
78
+ http.request("post", `${base}/console/user/list`, { params: { pageNo: 1, pageSize: 10 } });
65
79
 
66
- // ✅ 正确:参数放在 data 中(request body)
67
- http.request("post", "/api/user/list", { data: { page: 1, pageSize: 10 } });
80
+ // ✅ 正确:POST 业务参数放 data
81
+ http.request("post", `${base}/console/user/list`, { data: { pageNo: 1, pageSize: 10 } });
68
82
 
69
- // ❌ 错误:字段名不匹配
70
- { userName: "张三" } // 后端期望 username
83
+ // ✅ 正确:后端约定 GET 时使用 get + params(项目允许)
84
+ http.request("get", `${base}/console/common/downLoadTemplate`, {
85
+ params: { fileName: "模板.xlsx" },
86
+ responseType: "blob",
87
+ });
71
88
 
72
- // ✅ 正确:与后端字段名一致
89
+ // ❌ 错误:写成全小写 username(本项目前后端约定驼峰)
73
90
  { username: "张三" }
74
91
 
92
+ // ✅ 正确:驼峰命名,与后端字段一致
93
+ { userName: "张三", userCode: "zhangsan" }
94
+
75
95
  // ❌ 错误:金额使用 number(精度丢失)
76
- { amount: 99999999.99 } // 可能变成 99999999.989999999
96
+ { amount: 99999999.99 }
77
97
 
78
98
  // ✅ 正确:金额使用 string
79
99
  { amount: "99999999.99" }
100
+
101
+ // ❌ 错误:分页字段名套用通用脚手架习惯
102
+ { page: 1, pageSize: 10 } // 或 pageNum
103
+
104
+ // ✅ 正确:本项目分页入参(见 QueryData / useTableSearch)
105
+ { pageNo: 1, pageSize: 10 }
80
106
  ```
81
107
 
82
108
  ## 三、响应数据核对
83
109
 
84
110
  ### 必须确认
85
111
 
86
- - [ ] **响应结构**:后端返回 `Result<T>` 包装结构 `{ success, data, message, code }`。
87
- - [ ] **数据类型**:`data` 字段的类型与前端声明的泛型 `T` 一致。
88
- - [ ] **列表结构**:列表接口返回 `{ list: T[], total: number }` 还是直接返回数组。
89
- - [ ] **分页字段**:确认分页字段名(`total` vs `totalCount`,`page` vs `pageNum`)。
90
- - [ ] **空值处理**:后端可能返回 `null` 的字段,前端类型要包含 `| null`。
112
+ - [ ] **响应结构**:后端返回全局 `Result<T>`(`types/global.d.ts`),成功判断用 **`status === 200`**,文案用 **`statusText`**。
113
+ - [ ] **数据类型**:`data` 字段的类型与前端声明的泛型 `T` 一致(`data` 可能为 `null`)。
114
+ - [ ] **列表结构**:分页列表标准为 `{ content, totalCount, pageNo, pageSize, pageCount? }`,**不是** `{ list, total }`。
115
+ - [ ] **空值处理**:后端可能返回 `null` 的字段,前端类型要包含 `| null`,展示用可选链。
91
116
  - [ ] **嵌套结构**:复杂对象的嵌套层级与后端返回一致。
92
117
  - [ ] **日期格式**:后端返回的日期字符串格式,前端展示时是否需要格式化。
93
118
 
94
- ### 响应类型定义
119
+ ### 响应类型定义(与仓库一致)
95
120
 
96
121
  ```typescript
97
- // ✅ 正确:定义完整的响应类型
98
- interface UserListResult {
99
- list: UserInfo[];
100
- total: number;
122
+ // types/global.d.ts(权威定义,勿另造 success/code/message 结构)
123
+ interface Result<T = unknown> {
124
+ att?: unknown[];
125
+ data?: T | null;
126
+ exceptionName?: null;
127
+ status?: number;
128
+ statusText?: string;
129
+ name?: string; // blob 下载等场景可能附带文件名
101
130
  }
102
131
 
132
+ interface Data {
133
+ pageNo?: number;
134
+ pageSize?: number;
135
+ pageCount?: number;
136
+ totalCount?: number;
137
+ content?: Content[];
138
+ }
139
+
140
+ // 业务示例
103
141
  interface UserInfo {
104
142
  id: string;
105
- username: string;
106
- phone: string | null; // 可能为空
107
- createTime: string; // "2024-01-15 10:30:00"
108
- department: { // 嵌套对象
109
- id: string;
110
- name: string;
111
- };
112
- roles: string[]; // 角色编码数组
143
+ userName: string; // 驼峰
144
+ userCode: string;
145
+ phone: string | null;
146
+ createTime: string;
113
147
  }
114
148
 
115
- // API 调用
116
- function getUserListApi(params: UserQuery) {
117
- return http.request<Result<UserListResult>>(
118
- "post", "/api/system/user/list", { data: params }
149
+ function getUserListApi(data: CombinedQueryData) {
150
+ return http.request<Result<Data>>(
151
+ "post",
152
+ `${import.meta.env.VITE_API_BASE_URL}/console/user/list`,
153
+ { data },
119
154
  );
120
155
  }
121
156
 
122
157
  // 组件中使用
123
- const { data } = await getUserListApi(query);
124
- // data.list — 用户列表
125
- // data.total — 总条数
126
- // data.list[0].department.name — 部门名称
158
+ const res = await getUserListApi(query);
159
+ if (res.status === 200) {
160
+ const list = res.data?.content ?? [];
161
+ const total = res.data?.totalCount ?? 0;
162
+ }
127
163
  ```
128
164
 
129
165
  ### 常见响应处理错误
130
166
 
131
167
  ```typescript
132
- // ❌ 错误:没有解构 Result 包装
133
- const list = await getUserListApi(params); // 这是 Promise<Result<T>>
168
+ // ❌ 错误:按 success / message / code 解构(本项目没有这些字段)
169
+ const { success, message } = await getUserListApi(params);
134
170
 
135
- // ✅ 正确:解构 data 字段
136
- const { data } = await getUserListApi(params);
137
- const list = data.list;
138
- const total = data.total;
171
+ // ✅ 正确:按 status / statusText / data 处理
172
+ const res = await getUserListApi(params);
173
+ if (res.status === 200) {
174
+ const list = res.data?.content ?? [];
175
+ }
139
176
 
140
- // ❌ 错误:没有处理 null 值
141
- <span>{{ user.phone.length }}</span> // phone 为 null 时报错
177
+ // ❌ 错误:当成 { list, total }
178
+ const list = res.data.list;
179
+ const total = res.data.total;
142
180
 
143
- // ✅ 正确:可选链
144
- <span>{{ user.phone?.length ?? "-" }}</span>
181
+ // ✅ 正确:content + totalCount(useTableSearch 已按此约定解析)
182
+ const list = res.data?.content ?? [];
183
+ const total = res.data?.totalCount ?? 0;
145
184
 
146
- // ❌ 错误:日期直接展示原始格式
147
- <span>{{ row.createTime }}</span> // "2024-01-15T10:30:00.000+08:00"
185
+ // ❌ 错误:没有处理 null
186
+ <span>{{ user.phone.length }}</span>
148
187
 
149
- // ✅ 正确:格式化日期
150
- <span>{{ formatDate(row.createTime, "YYYY-MM-DD") }}</span>
188
+ // ✅ 正确:可选链
189
+ <span>{{ user.phone?.length ?? "-" }}</span>
151
190
  ```
152
191
 
153
192
  ## 四、特殊场景检查
@@ -157,16 +196,21 @@ const total = data.total;
157
196
  - [ ] `Content-Type` 设置为 `multipart/form-data`。
158
197
  - [ ] 使用 `FormData` 对象传递文件。
159
198
  - [ ] 文件大小限制与后端配置一致。
160
- - [ ] 上传进度有 UI 反馈。
199
+ - [ ] 上传进度有 UI 反馈(如有)。
161
200
 
162
201
  ```typescript
163
- // ✅ 文件上传标准写法
164
- function uploadFileApi(file: File) {
202
+ // ✅ 参考 src/api/common/index.ts getUploadUrl
203
+ function uploadFileApi(file: File, path = "/documentInfo/uploadFile") {
165
204
  const formData = new FormData();
166
205
  formData.append("file", file);
167
- return http.request<Result<UploadResult>>(
168
- "post", "/api/common/upload",
169
- { data: formData, headers: { "Content-Type": "multipart/form-data" } }
206
+ return http.request<Result<UploadFileResult>>(
207
+ "post",
208
+ `${import.meta.env.VITE_API_BASE_URL}${path}`,
209
+ {
210
+ data: formData,
211
+ headers: { "Content-Type": "multipart/form-data" },
212
+ },
213
+ { repeatRequest: true },
170
214
  );
171
215
  }
172
216
  ```
@@ -174,36 +218,36 @@ function uploadFileApi(file: File) {
174
218
  ### 文件下载/导出
175
219
 
176
220
  - [ ] `responseType` 设置为 `"blob"`。
177
- - [ ] 使用 `blobDown()` 工具函数处理下载。
178
- - [ ] 文件名从响应头 `Content-Disposition` 获取或使用默认名。
221
+ - [ ] 使用 `blobDown(data, name, response)`(`src/utils/utils.ts`)处理下载。
222
+ - [ ] 文件名优先从响应头 `Content-Disposition` 解析;http 封装对 Blob 可能返回 `{ data, name }`。
179
223
  - [ ] 下载过程有 Loading 状态。
180
224
 
181
225
  ```typescript
182
- // ✅ 文件下载标准写法
226
+ import { blobDown } from "@/utils/utils";
227
+
183
228
  async function handleExport() {
184
229
  loading.value = true;
185
230
  try {
186
- const res = await exportApi(queryParams);
187
- blobDown(res, "导出数据.xlsx");
188
- } catch {
189
- ElMessage.error("导出失败");
231
+ const res = await exportApi(queryParams); // responseType: "blob"
232
+ blobDown(res.data, res.name || "导出数据.xlsx", res);
190
233
  } finally {
191
234
  loading.value = false;
192
235
  }
193
236
  }
194
237
  ```
195
238
 
196
- ### 加密接口
239
+ ### 加解密接口
197
240
 
198
- - [ ] 登录、修改密码等敏感接口设置了 `crypto: true`。
199
- - [ ] 加密字段与后端约定一致(哪些字段需要加密)。
200
- - [ ] 加密请求的响应数据也需要解密处理。
241
+ - [ ] 确认当前环境 `VITE_ENCODE_SWITCH`、`VITE_ENCODE_PUBKEY` / `VITE_ENCODE_PRIKEY` 已按对接要求配置。
242
+ - [ ] 开关开启后,非 GET、非 FormData、非白名单接口由拦截器统一加解密;业务 API **不要**写不存在的 `crypto: true`。
243
+ - [ ] 联调时注意:加密开启后控制台可能打印入参/回参明文,正式包需关闭调试输出。
201
244
 
202
245
  ### 分页接口
203
246
 
204
- - [ ] 前端分页参数名与后端一致(`page` vs `pageNum`,`pageSize` vs `size`)。
205
- - [ ] 首页页码从 1 开始(不是从 0)。
206
- - [ ] 空列表时 `total` 返回 0,`list` 返回空数组 `[]`(不是 `null`)。
247
+ - [ ] 入参:`pageNo`(从 **1** 开始)、`pageSize`。
248
+ - [ ] 出参:`content`、`totalCount`、`pageNo`、`pageSize`(可选 `pageCount`)。
249
+ - [ ] 列表页优先用 `useTableSearch`(内部已按上述字段对接)。
250
+ - [ ] 空列表时 `totalCount` 为 0,`content` 为空数组 `[]`(不是 `null`)。
207
251
 
208
252
  ## 五、联调常见问题排查
209
253
 
@@ -211,62 +255,77 @@ async function handleExport() {
211
255
 
212
256
  - 检查参数是否放在了 `data` 中(不是 `params`)。
213
257
  - 检查 `Content-Type` 是否为 `application/json`。
214
- - 检查字段名是否与后端 `@RequestBody` 对象的字段名一致(驼峰 vs 下划线)。
258
+ - 检查字段是否为驼峰,且与后端 `@RequestBody` 字段名一致。
259
+ - 若开启了加解密,确认前后端密钥与开关一致。
215
260
 
216
261
  ### 后端返回数据但前端取不到
217
262
 
218
- - 检查是否解构了 `Result` 包装:`const { data } = await api()`。
219
- - 检查 `data` 的结构是否与类型定义一致。
220
- - 检查数组字段是否直接返回了数组,还是包裹在 `{ list: [] }` 中。
263
+ - 检查是否按 `Result` 处理:`status` / `data` / `statusText`。
264
+ - 检查分页是否用了 `content` / `totalCount`(不是 `list` / `total`)。
265
+ - 检查是否误把 Mock 路径当成了真实地址(或反过来)。
221
266
 
222
267
  ### 跨域问题
223
268
 
224
- - 开发环境:检查 `vite.config.ts` 的 `server.proxy` 配置。
225
- - 生产环境:确认 Nginx 反向代理配置正确。
226
- - 确认后端 CORS 配置允许前端域名。
269
+ - 开发环境:检查 `build/server.ts` / Vite `server.proxy` 配置。
270
+ - 生产环境:确认 Nginx 反向代理与 `VITE_API_BASE_URL` 一致。
271
+ - 确认后端 CORS 允许前端域名。
227
272
 
228
- ### Token 过期
273
+ ### Token 相关
229
274
 
230
- - 检查 http 拦截器是否处理了 `401` 状态码。
231
- - 401 时应自动跳转登录页或刷新 Token。
232
- - 刷新 Token 后重试失败的请求。
275
+ - 请求头字段为 `token`、`userCode`(见 `src/utils/http.ts` 拦截器)。
276
+ - 业务页按项目既有登录态逻辑处理失效场景,勿擅自改成 Bearer 方案。
233
277
 
234
278
  ## 六、接口 Mock 规范
235
279
 
236
- 在后端接口未就绪时,前端可以先 Mock 数据开发:
280
+ 后端未就绪时,使用项目根目录 **`mock/`** + `vite-plugin-fake-server`(`build/plugins/ViteMockServe.ts`),**不要**在 `src/api/mock/` 手写假 Promise 充当标准方案。
237
281
 
238
282
  ```typescript
239
- // src/api/mock/user.ts
240
- import type { Result } from "@/utils/http/types";
241
- import type { UserListResult } from "../types/system";
242
-
243
- export function mockGetUserListApi(params: UserQuery): Promise<Result<UserListResult>> {
244
- return Promise.resolve({
245
- success: true,
246
- data: {
247
- list: [
248
- { id: "1", username: "张三", phone: "13800138000", createTime: "2024-01-15 10:30:00", department: { id: "d1", name: "技术部" }, roles: ["admin"] },
249
- { id: "2", username: "李四", phone: "13900139000", createTime: "2024-02-20 14:00:00", department: { id: "d2", name: "产品部" }, roles: ["editor"] },
250
- ],
251
- total: 2,
283
+ // mock/login.ts(权威写法)
284
+ import { defineFakeRoute } from "vite-plugin-fake-server/client";
285
+
286
+ export default defineFakeRoute([
287
+ {
288
+ url: "/mock/login",
289
+ method: "post",
290
+ response: ({ body }) => {
291
+ // POST:从 body 取入参;GET:从 query 取入参
292
+ return {
293
+ att: [],
294
+ data: {
295
+ accessToken: "demo-token",
296
+ userCode: body.userCode,
297
+ userName: "系统默认管理员", // 驼峰
298
+ },
299
+ exceptionName: null,
300
+ status: 200,
301
+ statusText: "Success",
302
+ };
252
303
  },
253
- message: "success",
254
- code: 200,
255
- });
256
- }
304
+ },
305
+ ]);
306
+ ```
307
+
308
+ 对应 API:
309
+
310
+ ```typescript
311
+ // src/api/login/index.ts
312
+ export const getLogin = (data: LoginParams) => {
313
+ return http.request<Result<UserData>>("post", "/mock/login", { data });
314
+ };
257
315
  ```
258
316
 
259
317
  ### Mock 约定
260
318
 
261
- 1. Mock 数据必须严格符合 `Result<T>` 响应结构。
262
- 2. Mock 数据的字段名、类型必须与后端接口文档一致。
263
- 3. 后端接口就绪后,只需替换 API 函数,组件代码不需要修改。
264
- 4. Mock 文件放在 `src/api/mock/` 目录下,按模块对应。
319
+ 1. Mock 回包必须符合 `Result<T>`:`status` / `statusText` / `data`(不是 `success` / `code` / `message`)。
320
+ 2. 字段名、类型与真实后端契约一致(驼峰;分页用 `content` / `totalCount`)。
321
+ 3. API 函数路径可先指向 Mock;后端就绪后改为 `VITE_API_BASE_URL` + 真实 path,组件调用尽量不变。
322
+ 4. Mock 文件放在项目根 `mock/`,按模块拆分(如 `mock/login.ts`、`mock/table.ts`)。
323
+ 5. 开关与插件:`VITE_USE_MOCK` + `ViteFakeServerPlugin`(`include: 'mock'`)。
265
324
 
266
325
  ## 快速自检流程
267
326
 
268
- 1. **拿到后端接口文档后**:先核对 URL、方法、参数结构、响应结构。
269
- 2. **编写 API 函数时**:声明完整类型,参数放 `data`,返回 `Result<T>`。
270
- 3. **组件中调用时**:解构 `{ data }`,处理 loading/error,做好空值防护。
271
- 4. **联调时**:打开浏览器 Network 面板,对比请求/响应与接口文档是否一致。
272
- 5. **有问题时**:参照「联调常见问题排查」逐项检查。
327
+ 1. **拿到后端接口文档后**:核对真实 path、方法、参数/响应结构;确认不是 Mock 专用路径。
328
+ 2. **编写 API 函数时**:`import { http } from "@/utils/http"`;参数放 `data`;返回 `Result<T>`;URL 用 `VITE_API_BASE_URL`(或明确的 Mock 路径)。
329
+ 3. **字段与分页**:驼峰命名;列表用 `pageNo`/`pageSize` → `content`/`totalCount`。
330
+ 4. **组件中调用时**:判断 `status === 200`,取 `data`,做好空值防护;列表优先 `useTableSearch`。
331
+ 5. **联调时**:打开 Network,对比请求 URL/Body/响应与文档;有问题按第五节排查。
@@ -1,48 +1,49 @@
1
- # 基础代码(字典)
2
-
3
- 规范基础代码(字典)的获取、缓存、映射与使用。在页面需要码表、枚举、下拉数据时参照。
4
-
5
- ## 获取基础代码
6
-
7
- 通过 `useApp().baseCodeGet(codeType)` 获取:
8
-
9
- ```typescript
10
- import { useApp } from "@/hooks/useApp";
11
-
12
- const { baseCodeGet, filterValue } = useApp();
13
- const statusList = baseCodeGet("status");
14
- ```
15
-
16
- ## 特点
17
-
18
- - 首次调用会自动发起请求并缓存到 `BaseCode` Store。
19
- - 后续调用直接返回缓存数据。
20
- - 如需刷新缓存,在 `params` 中传 `refresh: true`。
21
-
22
- ## 映射显示
23
-
24
- ```typescript
25
- const label = filterValue(code, list, "code", "value");
26
- ```
27
-
28
- - 将 `code` 映射为 `value`。
29
- - 默认字段名:`code` / `value`。
30
-
31
- ## 在模板中使用
32
-
33
- ```vue
34
- <template>
35
- <span>{{ filterValue(row.status, statusList) }}</span>
36
- </template>
37
- ```
38
-
39
- ## Store 底层
40
-
41
- - `src/store/modules/baseCode.ts` 维护 `baseCodeCache`。
42
- - 接口:`getBaseCode({ codeType })`。
43
-
44
- ## 关键约定
45
-
46
- 1. 码表数据优先使用 `baseCodeGet`,避免重复请求。
47
- 2. 列表中码表回写统一使用 `filterValue`。
48
- 3. 不同模块相同码表使用相同 `codeType`。
1
+ # 基础代码(字典)
2
+
3
+ > 按本文件示例编写,复用 `useApp().baseCodeGet` / `filterValue` 等已有码表能力,勿另起一套字典请求与缓存。
4
+
5
+ 规范基础代码(字典)的获取、缓存、映射与使用。在页面需要码表、枚举、下拉数据时参照。
6
+
7
+ ## 获取基础代码
8
+
9
+ 通过 `useApp().baseCodeGet(codeType)` 获取:
10
+
11
+ ```typescript
12
+ import { useApp } from "@/hooks/useApp";
13
+
14
+ const { baseCodeGet, filterValue } = useApp();
15
+ const statusList = baseCodeGet("status");
16
+ ```
17
+
18
+ ## 特点
19
+
20
+ - 首次调用会自动发起请求并缓存到 `BaseCode` Store。
21
+ - 后续调用直接返回缓存数据。
22
+ - 如需刷新缓存,在 `params` 中传 `refresh: true`。
23
+
24
+ ## 映射显示
25
+
26
+ ```typescript
27
+ const label = filterValue(code, list, "code", "value");
28
+ ```
29
+
30
+ - 默认字段名:`code` / `value`。
31
+
32
+ ## 在模板中使用
33
+
34
+ ```vue
35
+ <template>
36
+ <span>{{ filterValue(row.status, statusList) }}</span>
37
+ </template>
38
+ ```
39
+
40
+ ## Store 底层
41
+
42
+ - `src/store/modules/baseCode.ts` 维护 `baseCodeCache`。
43
+ - 接口:`getBaseCode({ codeType })`。
44
+
45
+ ## 关键约定
46
+
47
+ 1. 码表数据优先使用 `baseCodeGet`,避免重复请求。
48
+ 2. 列表中码表回写统一使用 `filterValue`。
49
+ 3. 不同模块相同码表使用相同 `codeType`。
@@ -0,0 +1,61 @@
1
+ ---
2
+ skill: chart-echarts
3
+ description: ECharts 图表与 ReEchart 封装。词云等扩展按项目依赖。
4
+ scope: project
5
+ tags: [echarts, ReEchart, chart, wordcloud]
6
+ ---
7
+
8
+ # 图表(ECharts)
9
+
10
+ > **选型**:`echarts` + 项目 `ReEchart`(有则复用)。勿改用 Chart.js / D3 / Plotly 等同类库。
11
+ > 大屏场景叠加 `data-screen`。
12
+
13
+ ## 依赖(缺则先装)
14
+
15
+ | 包 | 版本 | 何时需要 |
16
+ |---|---|---|
17
+ | `echarts` | `6.1.0` | 图表必装 |
18
+ | `echarts-wordcloud` | `2.1.0` | 仅词云 |
19
+
20
+ ```bash
21
+ pnpm add echarts@6.1.0
22
+ # 词云时追加:
23
+ pnpm add echarts-wordcloud@2.1.0
24
+ ```
25
+
26
+ ## 必须复用
27
+
28
+ | 资产 | 说明 |
29
+ |------|------|
30
+ | `ReEchart` | `src/components/ReEchart` |
31
+
32
+
33
+ ## 完整示例(ReEchart)
34
+
35
+ ```vue
36
+ <script setup lang="ts">
37
+ import type { EChartsOption } from "echarts";
38
+ import { ReEchart } from "@/components/ReEchart";
39
+
40
+ defineOptions({ name: "SalesChart" });
41
+
42
+ const option = computed<EChartsOption>(() => ({
43
+ tooltip: { trigger: "axis" },
44
+ xAxis: { type: "category", data: ["1月", "2月", "3月"] },
45
+ yAxis: { type: "value" },
46
+ series: [{ type: "bar", data: [120, 200, 150], name: "销量" }],
47
+ }));
48
+ </script>
49
+
50
+ <template>
51
+ <div class="h-400px w-full">
52
+ <ReEchart :option="option" />
53
+ </div>
54
+ </template>
55
+ ```
56
+
57
+ ## 额外审查
58
+
59
+ - [ ] 使用 echarts 而非其它图表库
60
+ - [ ] 实例已销毁
61
+ - [ ] 颜色优先 CSS 变量 / 主题色,避免大面积硬编码