@qilitt-mickey/vue3-temp-skill 1.0.8

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 (37) hide show
  1. package/README.md +229 -0
  2. package/SKILL.md +621 -0
  3. package/bin/cli.js +579 -0
  4. package/package.json +46 -0
  5. package/references/advanced-ui.md +302 -0
  6. package/references/api-check.md +272 -0
  7. package/references/base-code-dict.md +48 -0
  8. package/references/build-optim.md +282 -0
  9. package/references/code-quality.md +235 -0
  10. package/references/crud-pages.md +316 -0
  11. package/references/data-compare.md +501 -0
  12. package/references/data-mapping.md +213 -0
  13. package/references/data-screen.md +79 -0
  14. package/references/data-writeback.md +104 -0
  15. package/references/detail-page.md +99 -0
  16. package/references/directives-advanced.md +93 -0
  17. package/references/download-export.md +68 -0
  18. package/references/feedback-loading.md +60 -0
  19. package/references/feedback-ui.md +111 -0
  20. package/references/file-management.md +132 -0
  21. package/references/flowchart-g6.md +244 -0
  22. package/references/form-advanced.md +137 -0
  23. package/references/graph-relation.md +253 -0
  24. package/references/http-api.md +188 -0
  25. package/references/layout-theme.md +540 -0
  26. package/references/mobile-h5.md +271 -0
  27. package/references/permission-auth.md +235 -0
  28. package/references/project-inventory.md +326 -0
  29. package/references/qrcode-barcode.md +92 -0
  30. package/references/rich-text.md +73 -0
  31. package/references/seamless-scroll.md +38 -0
  32. package/references/tree-table.md +111 -0
  33. package/references/ui-components.md +161 -0
  34. package/references/verify-captcha.md +96 -0
  35. package/references/vue-core.md +209 -0
  36. package/references/websocket-realtime.md +176 -0
  37. package/references/workflow-bpmn.md +206 -0
@@ -0,0 +1,302 @@
1
+ ---
2
+ skill: advanced-ui
3
+ description: 规范高级 UI 组件的使用与开发,包括选择器组件(下拉/树/级联)、高级表格(vxe-table)、高级表单、图表(ECharts)、工作流(BPMN)、树形表格等。在开发复杂交互组件时调用。
4
+ scope: project
5
+ tags: [vue3, select, tree, table, vxe-table, echarts, bpmn, cascader, form-advanced]
6
+ ---
7
+
8
+ # 高级 UI 组件规范
9
+
10
+ ## 选择器组件
11
+
12
+ ### ReSelectQuery(下拉查询选择器)
13
+
14
+ 适用于需要搜索、分页、远程加载的下拉选择场景:
15
+
16
+ ```vue
17
+ <script setup lang="ts">
18
+ import { ReSelectQuery } from "@/components/ReSelectQuery";
19
+
20
+ const value = ref("");
21
+
22
+ // 远程搜索
23
+ function remoteMethod(query: string) {
24
+ // 调用 API 获取选项列表
25
+ }
26
+ </script>
27
+
28
+ <template>
29
+ <ReSelectQuery
30
+ v-model="value"
31
+ :api="getUserListApi"
32
+ label-key="name"
33
+ value-key="id"
34
+ placeholder="请选择用户"
35
+ :remote="true"
36
+ :remote-method="remoteMethod"
37
+ />
38
+ </template>
39
+ ```
40
+
41
+ ### el-tree-select(树形下拉选择)
42
+
43
+ 适用于组织架构、分类选择等树形数据场景:
44
+
45
+ ```vue
46
+ <template>
47
+ <el-tree-select
48
+ v-model="value"
49
+ :data="treeData"
50
+ :props="{ label: 'name', value: 'id', children: 'children' }"
51
+ check-strictly
52
+ :render-after-expand="false"
53
+ placeholder="请选择部门"
54
+ />
55
+ </template>
56
+ ```
57
+
58
+ ### ReCascader(级联选择器)
59
+
60
+ 适用于省市区、多级分类等联动选择场景:
61
+
62
+ ```vue
63
+ <template>
64
+ <ReCascader
65
+ v-model="value"
66
+ :api="getAreaListApi"
67
+ :props="{ label: 'name', value: 'code', children: 'children' }"
68
+ placeholder="请选择地区"
69
+ />
70
+ </template>
71
+ ```
72
+
73
+ ### 选择器约定
74
+
75
+ 1. 简单下拉使用 `el-select`,需要搜索+分页用 `ReSelectQuery`。
76
+ 2. 树形数据选择使用 `el-tree-select`,不要用 `el-select` 嵌套 `el-tree`。
77
+ 3. 级联场景使用 `ReCascader`,支持异步加载子节点。
78
+ 4. 移动端选择使用 `RePopupPicker`(基于 Vant)。
79
+ 5. 选择器必须设置 `placeholder`,清除按钮默认开启。
80
+
81
+ ## 高级表格
82
+
83
+ ### ReTableBar(表格工具栏)
84
+
85
+ ```vue
86
+ <ReTableBar>
87
+ <template #left>
88
+ <el-button type="primary" @click="handleAdd">新增</el-button>
89
+ <el-button type="danger" :disabled="!selected.length" @click="handleBatchDelete">
90
+ 批量删除
91
+ </el-button>
92
+ </template>
93
+ <template #right>
94
+ <!-- 右侧默认包含:列配置、密度、全屏按钮 -->
95
+ </template>
96
+ </ReTableBar>
97
+ ```
98
+
99
+ ### ReTableOperate(操作列按钮组)
100
+
101
+ ```vue
102
+ <el-table-column label="操作" width="200" fixed="right">
103
+ <template #default="{ row }">
104
+ <ReTableOperate
105
+ :buttons="[
106
+ { label: '查看', type: 'primary', link: true, onClick: () => handleView(row) },
107
+ { label: '编辑', type: 'primary', link: true, onClick: () => handleEdit(row) },
108
+ {
109
+ label: '删除',
110
+ type: 'danger',
111
+ link: true,
112
+ confirm: { title: '确认删除?', message: `将删除「${row.name}」` },
113
+ onClick: () => handleDelete(row),
114
+ },
115
+ ]"
116
+ :max="3"
117
+ />
118
+ </template>
119
+ </el-table-column>
120
+ ```
121
+
122
+ ### ReGrid(数据表格)
123
+
124
+ ```vue
125
+ <ReGrid
126
+ v-loading="loading"
127
+ :data="content"
128
+ :pagination="pagination"
129
+ @page-change="handlePageChange"
130
+ @size-change="handleSizeChange"
131
+ @selection-change="handleSelectionChange"
132
+ >
133
+ <el-table-column type="selection" width="55" />
134
+ <el-table-column prop="name" label="名称" sortable />
135
+ <el-table-column prop="createTime" label="创建时间" width="180" />
136
+ <el-table-column label="操作" width="200" fixed="right">
137
+ <!-- ... -->
138
+ </el-table-column>
139
+ </ReGrid>
140
+ ```
141
+
142
+ ### vxe-table(高性能表格)
143
+
144
+ 当数据量超过 1000 行或需要复杂编辑(行内编辑、单元格合并)时使用 vxe-table:
145
+
146
+ ```vue
147
+ <script setup lang="ts">
148
+ import { ref } from "vue";
149
+
150
+ const gridRef = ref();
151
+ const tableData = ref([]);
152
+
153
+ const columns = [
154
+ { type: "seq", width: 60 },
155
+ { field: "name", title: "名称", sortable: true },
156
+ { field: "status", title: "状态", formatter: (v) => (v ? "启用" : "禁用") },
157
+ ];
158
+ </script>
159
+
160
+ <template>
161
+ <vxe-grid
162
+ ref="gridRef"
163
+ :data="tableData"
164
+ :columns="columns"
165
+ :pager-config="{ total: 100 }"
166
+ :edit-config="{ trigger: 'click', mode: 'cell' }"
167
+ />
168
+ </template>
169
+ ```
170
+
171
+ ## 树形表格
172
+
173
+ ### 数据转换
174
+
175
+ 使用 `handleTree` 工具函数将平铺数据转为树形结构:
176
+
177
+ ```typescript
178
+ import { handleTree } from "@/utils/tree";
179
+
180
+ const flatData = ref<FlatItem[]>([]);
181
+ const treeData = computed(() =>
182
+ handleTree(flatData.value, "id", "parentId", "children")
183
+ );
184
+ ```
185
+
186
+ ### 树形表格渲染
187
+
188
+ ```vue
189
+ <ReGrid :data="treeData" :tree-props="{ children: 'children' }" row-key="id">
190
+ <el-table-column prop="name" label="名称" />
191
+ <el-table-column prop="code" label="编码" />
192
+ </ReGrid>
193
+ ```
194
+
195
+ ### 树形连线展示
196
+
197
+ 使用 `ReTreeLine` 组件为树形表格添加视觉连线:
198
+
199
+ ```vue
200
+ <template>
201
+ <ReTreeLine :data="treeData">
202
+ <template #default="{ row }">
203
+ <span>{{ row.name }}</span>
204
+ </template>
205
+ </ReTreeLine>
206
+ </template>
207
+ ```
208
+
209
+ ## 高级表单组件
210
+
211
+ ### ReIconPicker(图标选择器)
212
+
213
+ ```vue
214
+ <el-form-item label="菜单图标">
215
+ <ReIconPicker v-model="formData.icon" />
216
+ </el-form-item>
217
+ ```
218
+
219
+ ### ReSegmented(分段控制器)
220
+
221
+ ```vue
222
+ <ReSegmented
223
+ v-model="activeTab"
224
+ :options="[
225
+ { label: '基本信息', value: 'basic' },
226
+ { label: '详细配置', value: 'config' },
227
+ { label: '权限设置', value: 'permission' },
228
+ ]"
229
+ />
230
+ ```
231
+
232
+ ### ReCheckCard(多选卡片)
233
+
234
+ ```vue
235
+ <ReCheckCard
236
+ v-model="selectedRoles"
237
+ :options="roleOptions"
238
+ multiple
239
+ />
240
+ ```
241
+
242
+ ## 图表 (ECharts)
243
+
244
+ ### 基础用法
245
+
246
+ ```vue
247
+ <script setup lang="ts">
248
+ import { ref, onMounted } from "vue";
249
+ import * as echarts from "echarts";
250
+
251
+ const chartRef = ref<HTMLDivElement>();
252
+ let chartInstance: echarts.ECharts;
253
+
254
+ onMounted(() => {
255
+ chartInstance = echarts.init(chartRef.value!);
256
+ chartInstance.setOption({
257
+ title: { text: "数据统计" },
258
+ tooltip: { trigger: "axis" },
259
+ xAxis: { type: "category", data: ["1月", "2月", "3月"] },
260
+ yAxis: { type: "value" },
261
+ series: [{ type: "bar", data: [120, 200, 150] }],
262
+ });
263
+ });
264
+
265
+ // 响应式:监听容器大小变化
266
+ const resizeObserver = new ResizeObserver(() => chartInstance?.resize());
267
+ onMounted(() => resizeObserver.observe(chartRef.value!));
268
+ onUnmounted(() => {
269
+ resizeObserver.disconnect();
270
+ chartInstance?.dispose();
271
+ });
272
+ </script>
273
+
274
+ <template>
275
+ <div ref="chartRef" style="width: 100%; height: 400px;" />
276
+ </template>
277
+ ```
278
+
279
+ ### 图表约定
280
+
281
+ 1. 始终在 `onUnmounted` 中 `dispose()` 图表实例,防止内存泄漏。
282
+ 2. 使用 `ResizeObserver` 监听容器变化自动调整大小。
283
+ 3. 图表配置项抽取为独立变量或函数,不要内联在 `setOption` 中。
284
+ 4. 数据大屏场景使用 `ReFlicker` 组件实现闪烁效果。
285
+
286
+ ## 工作流
287
+
288
+ ### BPMN 流程设计器
289
+
290
+ 项目集成 `bpmn-js` 用于流程设计,使用方式参考 `src/views/workflow/` 下的示例页面。
291
+
292
+ ### jsplumb 关系图
293
+
294
+ 用于可视化连线配置场景(如审批流程配置),参考 `src/components/` 下的封装组件。
295
+
296
+ ## 常见反例
297
+
298
+ - 大数据量表格使用 `el-table` 而不是 `vxe-table`(性能问题)。
299
+ - 树形数据不使用 `handleTree` 转换,手动递归。
300
+ - 图表实例不在组件卸载时销毁,导致内存泄漏。
301
+ - 操作列超过 3 个按钮不使用 `ReTableOperate` 的 `max` 属性折叠。
302
+ - 选择器不设置 `placeholder`。
@@ -0,0 +1,272 @@
1
+ ---
2
+ skill: api-check
3
+ description: 前后端接口对接检查清单。在对接后端 API 或 AI 生成接口调用代码后,必须对照此清单验证接口契约的正确性,确保前后端数据流通畅。适用于接口联调、AI 生成 API 代码自检场景。
4
+ scope: project
5
+ tags: [api, backend, integration, contract, http, request, response, debug, checklist]
6
+ ---
7
+
8
+ # 前后端接口对接检查清单
9
+
10
+ > **使用说明**:在对接后端 API 或 AI 生成接口调用代码后,逐项对照检查。确保前端调用方式与后端接口定义完全匹配,避免联调阶段反复返工。
11
+
12
+ ## 一、接口基本信息核对
13
+
14
+ ### 必须确认
15
+
16
+ - [ ] **请求地址**:URL 路径与后端接口文档一致,注意前缀 `/api`。
17
+ - [ ] **请求方法**:本项目统一使用 POST,确认后端没有要求 GET/PUT/DELETE。
18
+ - [ ] **Content-Type**:默认 `application/json`,文件上传使用 `multipart/form-data`。
19
+ - [ ] **认证方式**:需要 Token 的接口,确认请求头携带了 `Authorization`。
20
+ - [ ] **加密要求**:敏感接口(登录、修改密码等)需要设置 `crypto: true`。
21
+
22
+ ### URL 规范
23
+
24
+ ```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" // 不对
35
+ ```
36
+
37
+ ## 二、请求参数核对
38
+
39
+ ### 必须确认
40
+
41
+ - [ ] **参数位置**:本项目统一通过 `data` 传递(POST body),不是 `params`(query string)。
42
+ - [ ] **字段名称**:与后端接口文档的字段名完全一致,注意大小写。
43
+ - [ ] **字段类型**:字符串/数字/布尔/数组/对象,与后端定义匹配。
44
+ - [ ] **必填字段**:所有后端标记为必填的字段,前端必须传递。
45
+ - [ ] **默认值**:后端有默认值的字段,前端不传时使用后端默认值。
46
+ - [ ] **枚举值**:状态码、类型码等枚举值与后端定义一致。
47
+
48
+ ### 参数格式对照表
49
+
50
+ | 后端 Java 类型 | 前端 TypeScript 类型 | 注意事项 |
51
+ |---------------|---------------------|---------|
52
+ | `String` | `string` | 空字符串 `""` 与 `null` 不同 |
53
+ | `Integer` / `Long` | `number` | 注意 `Long` 精度问题(超过 `Number.MAX_SAFE_INTEGER` 需用 `string`) |
54
+ | `Boolean` | `boolean` | `0/1` 与 `true/false` 需确认后端用哪种 |
55
+ | `BigDecimal` | `string` | 金额类字段必须用 `string` 避免精度丢失 |
56
+ | `Date` / `LocalDateTime` | `string` | 确认格式:`yyyy-MM-dd` 还是 `yyyy-MM-dd HH:mm:ss` |
57
+ | `List<T>` | `T[]` | 确认数组元素的类型 |
58
+ | `Map<String, Object>` | `Record<string, any>` | 尽量避免,要求后端定义明确结构 |
59
+
60
+ ### 常见参数错误
61
+
62
+ ```typescript
63
+ // ❌ 错误:参数放在 params 中(query string)
64
+ http.request("post", "/api/user/list", { params: { page: 1, pageSize: 10 } });
65
+
66
+ // ✅ 正确:参数放在 data 中(request body)
67
+ http.request("post", "/api/user/list", { data: { page: 1, pageSize: 10 } });
68
+
69
+ // ❌ 错误:字段名不匹配
70
+ { userName: "张三" } // 后端期望 username
71
+
72
+ // ✅ 正确:与后端字段名一致
73
+ { username: "张三" }
74
+
75
+ // ❌ 错误:金额使用 number(精度丢失)
76
+ { amount: 99999999.99 } // 可能变成 99999999.989999999
77
+
78
+ // ✅ 正确:金额使用 string
79
+ { amount: "99999999.99" }
80
+ ```
81
+
82
+ ## 三、响应数据核对
83
+
84
+ ### 必须确认
85
+
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`。
91
+ - [ ] **嵌套结构**:复杂对象的嵌套层级与后端返回一致。
92
+ - [ ] **日期格式**:后端返回的日期字符串格式,前端展示时是否需要格式化。
93
+
94
+ ### 响应类型定义
95
+
96
+ ```typescript
97
+ // ✅ 正确:定义完整的响应类型
98
+ interface UserListResult {
99
+ list: UserInfo[];
100
+ total: number;
101
+ }
102
+
103
+ interface UserInfo {
104
+ 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[]; // 角色编码数组
113
+ }
114
+
115
+ // API 调用
116
+ function getUserListApi(params: UserQuery) {
117
+ return http.request<Result<UserListResult>>(
118
+ "post", "/api/system/user/list", { data: params }
119
+ );
120
+ }
121
+
122
+ // 组件中使用
123
+ const { data } = await getUserListApi(query);
124
+ // data.list — 用户列表
125
+ // data.total — 总条数
126
+ // data.list[0].department.name — 部门名称
127
+ ```
128
+
129
+ ### 常见响应处理错误
130
+
131
+ ```typescript
132
+ // ❌ 错误:没有解构 Result 包装
133
+ const list = await getUserListApi(params); // 这是 Promise<Result<T>>
134
+
135
+ // ✅ 正确:解构 data 字段
136
+ const { data } = await getUserListApi(params);
137
+ const list = data.list;
138
+ const total = data.total;
139
+
140
+ // ❌ 错误:没有处理 null 值
141
+ <span>{{ user.phone.length }}</span> // phone 为 null 时报错
142
+
143
+ // ✅ 正确:可选链
144
+ <span>{{ user.phone?.length ?? "-" }}</span>
145
+
146
+ // ❌ 错误:日期直接展示原始格式
147
+ <span>{{ row.createTime }}</span> // "2024-01-15T10:30:00.000+08:00"
148
+
149
+ // ✅ 正确:格式化日期
150
+ <span>{{ formatDate(row.createTime, "YYYY-MM-DD") }}</span>
151
+ ```
152
+
153
+ ## 四、特殊场景检查
154
+
155
+ ### 文件上传
156
+
157
+ - [ ] `Content-Type` 设置为 `multipart/form-data`。
158
+ - [ ] 使用 `FormData` 对象传递文件。
159
+ - [ ] 文件大小限制与后端配置一致。
160
+ - [ ] 上传进度有 UI 反馈。
161
+
162
+ ```typescript
163
+ // ✅ 文件上传标准写法
164
+ function uploadFileApi(file: File) {
165
+ const formData = new FormData();
166
+ formData.append("file", file);
167
+ return http.request<Result<UploadResult>>(
168
+ "post", "/api/common/upload",
169
+ { data: formData, headers: { "Content-Type": "multipart/form-data" } }
170
+ );
171
+ }
172
+ ```
173
+
174
+ ### 文件下载/导出
175
+
176
+ - [ ] `responseType` 设置为 `"blob"`。
177
+ - [ ] 使用 `blobDown()` 工具函数处理下载。
178
+ - [ ] 文件名从响应头 `Content-Disposition` 获取或使用默认名。
179
+ - [ ] 下载过程有 Loading 状态。
180
+
181
+ ```typescript
182
+ // ✅ 文件下载标准写法
183
+ async function handleExport() {
184
+ loading.value = true;
185
+ try {
186
+ const res = await exportApi(queryParams);
187
+ blobDown(res, "导出数据.xlsx");
188
+ } catch {
189
+ ElMessage.error("导出失败");
190
+ } finally {
191
+ loading.value = false;
192
+ }
193
+ }
194
+ ```
195
+
196
+ ### 加密接口
197
+
198
+ - [ ] 登录、修改密码等敏感接口设置了 `crypto: true`。
199
+ - [ ] 加密字段与后端约定一致(哪些字段需要加密)。
200
+ - [ ] 加密请求的响应数据也需要解密处理。
201
+
202
+ ### 分页接口
203
+
204
+ - [ ] 前端分页参数名与后端一致(`page` vs `pageNum`,`pageSize` vs `size`)。
205
+ - [ ] 首页页码从 1 开始(不是从 0)。
206
+ - [ ] 空列表时 `total` 返回 0,`list` 返回空数组 `[]`(不是 `null`)。
207
+
208
+ ## 五、联调常见问题排查
209
+
210
+ ### 请求发出去了但后端收不到参数
211
+
212
+ - 检查参数是否放在了 `data` 中(不是 `params`)。
213
+ - 检查 `Content-Type` 是否为 `application/json`。
214
+ - 检查字段名是否与后端 `@RequestBody` 对象的字段名一致(驼峰 vs 下划线)。
215
+
216
+ ### 后端返回数据但前端取不到
217
+
218
+ - 检查是否解构了 `Result` 包装:`const { data } = await api()`。
219
+ - 检查 `data` 的结构是否与类型定义一致。
220
+ - 检查数组字段是否直接返回了数组,还是包裹在 `{ list: [] }` 中。
221
+
222
+ ### 跨域问题
223
+
224
+ - 开发环境:检查 `vite.config.ts` 的 `server.proxy` 配置。
225
+ - 生产环境:确认 Nginx 反向代理配置正确。
226
+ - 确认后端 CORS 配置允许前端域名。
227
+
228
+ ### Token 过期
229
+
230
+ - 检查 http 拦截器是否处理了 `401` 状态码。
231
+ - 401 时应自动跳转登录页或刷新 Token。
232
+ - 刷新 Token 后重试失败的请求。
233
+
234
+ ## 六、接口 Mock 规范
235
+
236
+ 在后端接口未就绪时,前端可以先 Mock 数据开发:
237
+
238
+ ```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,
252
+ },
253
+ message: "success",
254
+ code: 200,
255
+ });
256
+ }
257
+ ```
258
+
259
+ ### Mock 约定
260
+
261
+ 1. Mock 数据必须严格符合 `Result<T>` 响应结构。
262
+ 2. Mock 数据的字段名、类型必须与后端接口文档一致。
263
+ 3. 后端接口就绪后,只需替换 API 函数,组件代码不需要修改。
264
+ 4. Mock 文件放在 `src/api/mock/` 目录下,按模块对应。
265
+
266
+ ## 快速自检流程
267
+
268
+ 1. **拿到后端接口文档后**:先核对 URL、方法、参数结构、响应结构。
269
+ 2. **编写 API 函数时**:声明完整类型,参数放 `data`,返回 `Result<T>`。
270
+ 3. **组件中调用时**:解构 `{ data }`,处理 loading/error,做好空值防护。
271
+ 4. **联调时**:打开浏览器 Network 面板,对比请求/响应与接口文档是否一致。
272
+ 5. **有问题时**:参照「联调常见问题排查」逐项检查。
@@ -0,0 +1,48 @@
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`。