@agile-team/wl-skills-kit 1.0.0

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 (112) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +328 -0
  3. package/bin/wl-skills.js +104 -0
  4. package/files/.github/copilot-instructions.md +211 -0
  5. package/files/.github/docs/SYS_MENU_INFO.md +247 -0
  6. package/files/.github/docs/menu-sync-design.md +265 -0
  7. package/files/.github/docs/use-skill.md +379 -0
  8. package/files/.github/docs/wl-skills-kit.md +266 -0
  9. package/files/.github/skills/api-contract/SKILL.md +247 -0
  10. package/files/.github/skills/convention-extract/SKILL.md +355 -0
  11. package/files/.github/skills/menu-sync/SKILL.md +255 -0
  12. package/files/.github/skills/menu-sync/env/guide.md +73 -0
  13. package/files/.github/skills/page-codegen/SKILL.md +825 -0
  14. package/files/.github/skills/page-codegen/TPL-CHANGE-HISTORY.md +281 -0
  15. package/files/.github/skills/page-codegen/TPL-DETAIL-TABS.md +1112 -0
  16. package/files/.github/skills/page-codegen/TPL-DRIVEN.md +124 -0
  17. package/files/.github/skills/page-codegen/TPL-FORM-ROUTE.md +441 -0
  18. package/files/.github/skills/page-codegen/TPL-LIST.md +196 -0
  19. package/files/.github/skills/page-codegen/TPL-MASTER-DETAIL.md +153 -0
  20. package/files/.github/skills/page-codegen/TPL-OPERATION-STATION.md +442 -0
  21. package/files/.github/skills/page-codegen/TPL-RECORD-FORM.md +376 -0
  22. package/files/.github/skills/page-codegen/TPL-TREE-LIST.md +191 -0
  23. package/files/.github/skills/prototype-scan/SKILL.md +414 -0
  24. package/files/demo/README.md +44 -0
  25. package/files/demo/produce/aiflow/mmwr-customer-apply-add/api.md +54 -0
  26. package/files/demo/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -0
  27. package/files/demo/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -0
  28. package/files/demo/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -0
  29. package/files/demo/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -0
  30. package/files/demo/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -0
  31. package/files/demo/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -0
  32. package/files/demo/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -0
  33. package/files/demo/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -0
  34. package/files/demo/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -0
  35. package/files/demo/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -0
  36. package/files/demo/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -0
  37. package/files/demo/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -0
  38. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/data.ts +196 -0
  39. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.scss +150 -0
  40. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.vue +79 -0
  41. package/files/demo/produce/aiflow/mmwr-customer-archive/api.md +88 -0
  42. package/files/demo/produce/aiflow/mmwr-customer-archive/data.ts +601 -0
  43. package/files/demo/produce/aiflow/mmwr-customer-archive/index.scss +1 -0
  44. package/files/demo/produce/aiflow/mmwr-customer-archive/index.vue +64 -0
  45. package/files/demo/produce/aiflow/mmwr-customer-detail/api.md +67 -0
  46. package/files/demo/produce/aiflow/mmwr-customer-detail/data.ts +286 -0
  47. package/files/demo/produce/aiflow/mmwr-customer-detail/index.scss +139 -0
  48. package/files/demo/produce/aiflow/mmwr-customer-detail/index.vue +318 -0
  49. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -0
  50. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -0
  51. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -0
  52. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -0
  53. package/files/demo/sale/demo/add-demo/data.ts +518 -0
  54. package/files/demo/sale/demo/add-demo/index.scss +207 -0
  55. package/files/demo/sale/demo/add-demo/index.vue +167 -0
  56. package/files/demo/sale/demo/billet-flame-cut-plan/data.ts +524 -0
  57. package/files/demo/sale/demo/billet-flame-cut-plan/index.scss +155 -0
  58. package/files/demo/sale/demo/billet-flame-cut-plan/index.vue +117 -0
  59. package/files/demo/sale/demo/domestic-trade-order/data.ts +308 -0
  60. package/files/demo/sale/demo/domestic-trade-order/index.scss +99 -0
  61. package/files/demo/sale/demo/domestic-trade-order/index.vue +77 -0
  62. package/files/demo/sale/demo/heat-batch-return/data.ts +367 -0
  63. package/files/demo/sale/demo/heat-batch-return/index.scss +100 -0
  64. package/files/demo/sale/demo/heat-batch-return/index.vue +170 -0
  65. package/files/demo/sale/demo/heat-batch-return/meltDialog.vue +320 -0
  66. package/files/demo/sale/demo/metallurgical-spec/data.ts +825 -0
  67. package/files/demo/sale/demo/metallurgical-spec/index.scss +264 -0
  68. package/files/demo/sale/demo/metallurgical-spec/index.vue +309 -0
  69. package/files/docs/jh-date-range.md +257 -0
  70. package/files/docs/jh-date.md +222 -0
  71. package/files/docs/jh-dept-picker.md +190 -0
  72. package/files/docs/jh-drag-row.md +590 -0
  73. package/files/docs/jh-file-upload.md +216 -0
  74. package/files/docs/jh-pagination.md +505 -0
  75. package/files/docs/jh-picker.md +218 -0
  76. package/files/docs/jh-select.md +148 -0
  77. package/files/docs/jh-text.md +248 -0
  78. package/files/docs/jh-user-picker.md +197 -0
  79. package/files/docs/page-query-hook-best-practices.md +362 -0
  80. package/files/docs/request.md +925 -0
  81. package/files/src/components/global/C_ParentView/index.vue +3 -0
  82. package/files/src/components/global/C_RightToolbar/index.vue +459 -0
  83. package/files/src/components/global/C_Splitter/index.vue +195 -0
  84. package/files/src/components/global/C_SvgIcon/index.vue +61 -0
  85. package/files/src/components/global/C_SvgIcon/svgicon.js +10 -0
  86. package/files/src/components/global/C_TagStatus/README.md +264 -0
  87. package/files/src/components/global/C_TagStatus/config.ts +192 -0
  88. package/files/src/components/global/C_TagStatus/index.vue +127 -0
  89. package/files/src/components/global/C_TagStatus/types.ts +64 -0
  90. package/files/src/components/global/C_Tree/README.md +153 -0
  91. package/files/src/components/global/C_Tree/index.scss +42 -0
  92. package/files/src/components/global/C_Tree/index.vue +119 -0
  93. package/files/src/components/global/C_Tree/types.ts +59 -0
  94. package/files/src/components/local/c_formModal/README.md +235 -0
  95. package/files/src/components/local/c_formModal/data.ts +95 -0
  96. package/files/src/components/local/c_formModal/index.scss +8 -0
  97. package/files/src/components/local/c_formModal/index.vue +107 -0
  98. package/files/src/components/local/c_formSections/README.md +496 -0
  99. package/files/src/components/local/c_formSections/data.ts +175 -0
  100. package/files/src/components/local/c_formSections/index.scss +280 -0
  101. package/files/src/components/local/c_formSections/index.vue +429 -0
  102. package/files/src/components/local/c_listModal/data.ts +41 -0
  103. package/files/src/components/local/c_listModal/index.vue +136 -0
  104. package/files/src/components/local/c_spliterTitle/index.scss +25 -0
  105. package/files/src/components/local/c_spliterTitle/index.vue +21 -0
  106. package/files/src/components/remote/AGGrid/README.md +530 -0
  107. package/files/src/components/remote/BaseForm/README.md +508 -0
  108. package/files/src/components/remote/BaseQuery/README.md +865 -0
  109. package/files/src/components/remote/BaseTable/README.md +941 -0
  110. package/files/src/components/remote/BaseToolbar/README.md +496 -0
  111. package/files/src/types/page.ts +24 -0
  112. package/package.json +31 -0
@@ -0,0 +1,197 @@
1
+ # jh-user-picker - 用户选择组件
2
+
3
+ > 平台统一的用户挑选组件,用于选择单个或多个用户,内置用户数据加载与回显逻辑
4
+
5
+ ## 📦 组件位置
6
+
7
+ ```ts
8
+ import "@jhlc/common-core";
9
+ ```
10
+
11
+ 组件已全局注册,可直接在模板中使用 `<jh-user-picker />`。
12
+
13
+ ---
14
+
15
+ ## 基本用法
16
+
17
+ ### 1️⃣ 单选用户(最常用)
18
+
19
+ ```vue
20
+ <template>
21
+ <jh-user-picker v-model="form.userId" placeholder="请选择负责人" />
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { ref } from "vue";
26
+
27
+ const form = ref({
28
+ userId: ""
29
+ });
30
+ </script>
31
+ ```
32
+
33
+ ---
34
+
35
+ ### 2️⃣ 多选用户
36
+
37
+ ```vue
38
+ <jh-user-picker v-model="form.userIds" multiple placeholder="请选择相关人员" />
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Props 属性
44
+
45
+ | 参数 | 说明 | 类型 | 默认值 |
46
+ | -------------------- | ---------------------- | --------------------- | ---------------- |
47
+ | modelValue / v-model | 绑定值 | `string \| string[]` | - |
48
+ | multiple | 是否多选 | `boolean` | `false` |
49
+ | placeholder | 占位提示 | `string` | `"请选择用户"` |
50
+ | disabled | 是否禁用 | `boolean` | `false` |
51
+ | clearable | 是否可清空 | `boolean` | `true` |
52
+ | dataType | 返回数据类型(多选时) | `"array" \| "string"` | `"array"` |
53
+ | dialogTitle | 弹窗标题 | `string` | `"选择用户"` |
54
+ | dialogWidth | 弹窗宽度 | `string` | `"800px"` |
55
+ | searchPlaceholder | 搜索框占位文本 | `string` | `"请输入用户名"` |
56
+
57
+ > **重点**: 多选时,`dataType="string"` 会返回逗号分隔的字符串,`dataType="array"` 返回数组。
58
+
59
+ ---
60
+
61
+ ## Events 事件
62
+
63
+ | 事件名 | 说明 | 回调参数 |
64
+ | ----------------- | ------------------------ | ------------------------------------- |
65
+ | update:modelValue | v-model 更新 | `(value: string \| string[]) => void` |
66
+ | confirm | 确认选择时触发 | `() => void` |
67
+ | clear | 清空时触发 | `() => void` |
68
+ | blur | 失去焦点时触发 | `() => void` |
69
+ | closed | 弹窗关闭时触发 | `() => void` |
70
+ | remove | 移除选中项时触发(多选) | `() => void` |
71
+
72
+ ---
73
+
74
+ ## 常见场景
75
+
76
+ ### 场景 1:表单负责人选择
77
+
78
+ ```vue
79
+ <jh-user-picker v-model="form.ownerId" placeholder="请选择负责人" />
80
+ ```
81
+
82
+ ---
83
+
84
+ ### 场景 2:查询条件(多选)
85
+
86
+ ```vue
87
+ <jh-user-picker v-model="query.userIds" multiple placeholder="请选择用户" />
88
+ ```
89
+
90
+ ---
91
+
92
+ ### 场景 3:详情页只读展示(配合 jh-text)
93
+
94
+ ```vue
95
+ <jh-text type="user" :value="detail.userId" />
96
+ ```
97
+
98
+ > ⚠️ `jh-user-picker` 仅用于选择,展示请使用 `jh-text`
99
+
100
+ ---
101
+
102
+ ## 与手动实现对比
103
+
104
+ ### 使用 jh-user-picker(推荐)
105
+
106
+ ```vue
107
+ <jh-user-picker v-model="form.userId" />
108
+ ```
109
+
110
+ ### 手动实现(不推荐)
111
+
112
+ ```vue
113
+ <el-select v-model="form.userId">
114
+ <el-option
115
+ v-for="user in userList"
116
+ :key="user.id"
117
+ :label="user.name"
118
+ :value="user.id"
119
+ />
120
+ </el-select>
121
+ ```
122
+
123
+ ❌ 需要自己加载用户列表
124
+ ❌ 需要处理回显
125
+ ❌ 每个页面重复实现
126
+
127
+ ---
128
+
129
+ ## 最佳实践
130
+
131
+ ### 1️⃣ 编辑 & 展示分离
132
+
133
+ | 场景 | 编辑 | 展示 |
134
+ | ---- | -------------- | ------- |
135
+ | 用户 | jh-user-picker | jh-text |
136
+
137
+ ---
138
+
139
+ ### 2️⃣ 表单中直接使用 v-model
140
+
141
+ ```vue
142
+ <jh-user-picker v-model="form.userId" />
143
+ ```
144
+
145
+ 避免手动监听 `change` 事件
146
+
147
+ ---
148
+
149
+ ### 3️⃣ 多选返回值说明
150
+
151
+ ```ts
152
+ // 单选
153
+ userId: "u001";
154
+
155
+ // 多选
156
+ userIds: ["u001", "u002"];
157
+ ```
158
+
159
+ ---
160
+
161
+ ## 注意事项
162
+
163
+ 1. **组件内部已处理用户数据加载**
164
+ - 不需要手动请求接口
165
+ - 支持自动回显
166
+
167
+ 2. **仅返回用户 ID**
168
+ - 展示用户名称请使用 `jh-text`
169
+
170
+ 3. **多选时注意字段类型**
171
+ - 必须使用数组接收
172
+
173
+ ---
174
+
175
+ ## 🎯 真实项目示例
176
+
177
+ ### 示例 1:新增页面
178
+
179
+ ```vue
180
+ <jh-user-picker v-model="form.createUserId" />
181
+ ```
182
+
183
+ ### 示例 2:查询条件
184
+
185
+ ```vue
186
+ <jh-user-picker v-model="query.userIds" multiple />
187
+ ```
188
+
189
+ ---
190
+
191
+ ## 🚀 快速开始
192
+
193
+ - **单选**:直接使用 v-model
194
+ - **多选**:添加 `multiple`
195
+ - **展示**:统一使用 `jh-text type="user"`
196
+
197
+ **推荐作为平台统一的用户选择组件使用!**
@@ -0,0 +1,362 @@
1
+ # 页面查询 Hook 最佳实践
2
+
3
+ 本文档介绍如何使用 `AbstractPageQueryHook` 基类进行页面配置化开发,无需维护独立的 API 层。
4
+
5
+ ## 核心理念
6
+
7
+ **配置化驱动**:通过在 `data.ts` 中配置 `API_CONFIG` 直接调用基类内置的 HTTP 方法,实现"零 API 层"开发模式。
8
+
9
+ ## 基类概述
10
+
11
+ `AbstractPageQueryHook` 来自 `@jhlc/common-core`,提供完整的 CRUD 操作:
12
+
13
+ ```typescript
14
+ import { AbstractPageQueryHook } from "@jhlc/common-core";
15
+
16
+ class PageQueryHook extends AbstractPageQueryHook {
17
+ // 继承所有内置方法:
18
+ // getAction, postAction, putAction, deleteAction
19
+ // actionBatch, postBatch, putBatch, deleteBatch
20
+ }
21
+ ```
22
+
23
+ ### 内置 HTTP 方法说明
24
+
25
+ 所有内置方法的详细用法、参数说明、实战示例请参考:[request.md - AbstractPageQueryHook 基类内置方法](./request.md#abstractpagequeryhook-基类内置方法)
26
+
27
+ ---
28
+
29
+ ## 快速开始
30
+
31
+ ### 步骤 1:定义 API 配置
32
+
33
+ 在 `data.ts` 中直接配置接口路径:
34
+
35
+ ```typescript
36
+ // data.ts
37
+ import { AbstractPageQueryHook } from "@jhlc/common-core";
38
+
39
+ const API_CONFIG = {
40
+ list: "/mmsm/mmsmRsltLadleUse/list",
41
+ get: "/mmsm/mmsmRsltLadleUse/getById",
42
+ save: "/mmsm/mmsmRsltLadleUse/save",
43
+ update: "/mmsm/mmsmRsltLadleUse/update",
44
+ remove: "/mmsm/mmsmRsltLadleUse/remove"
45
+ };
46
+ ```
47
+
48
+ ### 步骤 2:使用基类方法
49
+
50
+ 直接调用 `this.getAction`、`this.postAction` 等内置方法:
51
+
52
+ ```typescript
53
+ class LadleUseQueryHook extends AbstractPageQueryHook {
54
+ // 新增
55
+ async handleAdd(row: any) {
56
+ await this.postAction(API_CONFIG.save, row);
57
+ this.getTableList(); // 刷新列表
58
+ }
59
+
60
+ // 编辑
61
+ async handleEdit(row: any) {
62
+ await this.putAction(API_CONFIG.update, row);
63
+ this.getTableList();
64
+ }
65
+
66
+ // 删除(单个)
67
+ async handleDelete(row: any) {
68
+ await this.deleteAction(API_CONFIG.remove, {}, { ids: [row.id] });
69
+ this.getTableList();
70
+ }
71
+
72
+ // 批量删除
73
+ async handleBatchDelete(ids: string[]) {
74
+ await this.actionBatch(this.deleteAction, API_CONFIG.remove, "删除", ids);
75
+ this.getTableList();
76
+ }
77
+ }
78
+ ```
79
+
80
+ ---
81
+
82
+ ## 标准页面配置示例
83
+
84
+ 完整的 `data.ts` 配置示例:
85
+
86
+ ```typescript
87
+ import { AbstractPageQueryHook } from "@jhlc/common-core";
88
+ import type { BaseFormItemDesc } from "@/types/jh4j-cloud";
89
+
90
+ const API_CONFIG = {
91
+ list: "/mmsm/mmsmRsltLadleUse/list",
92
+ get: "/mmsm/mmsmRsltLadleUse/getById",
93
+ save: "/mmsm/mmsmRsltLadleUse/save",
94
+ update: "/mmsm/mmsmRsltLadleUse/update",
95
+ remove: "/mmsm/mmsmRsltLadleUse/remove",
96
+ exportExcel: "/mmsm/mmsmRsltLadleUse/export"
97
+ };
98
+
99
+ export class LadleUseQueryHook extends AbstractPageQueryHook {
100
+ constructor() {
101
+ super();
102
+ this.api = API_CONFIG.list;
103
+ }
104
+
105
+ // 查询条件配置
106
+ formSchemas = [
107
+ {
108
+ field: "ladle_num",
109
+ label: "钢包号",
110
+ component: "Input",
111
+ componentProps: { placeholder: "请输入钢包号" }
112
+ },
113
+ {
114
+ field: "use_date",
115
+ label: "使用日期",
116
+ component: "DatePicker",
117
+ componentProps: { type: "daterange", format: "YYYY-MM-DD" }
118
+ }
119
+ ] as BaseFormItemDesc<any>[];
120
+
121
+ // 表单配置(新增/编辑)
122
+ modalSchemas = [
123
+ {
124
+ field: "ladle_num",
125
+ label: "钢包号",
126
+ component: "Input",
127
+ rules: [{ required: true, message: "请输入钢包号" }]
128
+ },
129
+ {
130
+ field: "furnace_id",
131
+ label: "炉号",
132
+ component: "Input",
133
+ rules: [{ required: true, message: "请输入炉号" }]
134
+ },
135
+ {
136
+ field: "use_date",
137
+ label: "使用日期",
138
+ component: "DatePicker",
139
+ componentProps: { type: "date", format: "YYYY-MM-DD" },
140
+ rules: [{ required: true, message: "请选择使用日期" }]
141
+ }
142
+ ] as BaseFormItemDesc<any>[];
143
+
144
+ // 表格列配置
145
+ getColumns = () => [
146
+ { title: "钢包号", dataIndex: "ladle_num", width: 120 },
147
+ { title: "炉号", dataIndex: "furnace_id", width: 100 },
148
+ { title: "使用日期", dataIndex: "use_date", width: 120 },
149
+ {
150
+ title: "操作",
151
+ dataIndex: "action",
152
+ width: 200,
153
+ slots: { customRender: "action" }
154
+ }
155
+ ];
156
+
157
+ // ========== CRUD 操作 ==========
158
+
159
+ // 新增
160
+ async handleAdd(row: any) {
161
+ const res = await this.postAction(API_CONFIG.save, row);
162
+ if (res.success) {
163
+ this.$message.success("新增成功");
164
+ this.getTableList();
165
+ }
166
+ }
167
+
168
+ // 编辑
169
+ async handleEdit(row: any) {
170
+ const res = await this.putAction(API_CONFIG.update, row);
171
+ if (res.success) {
172
+ this.$message.success("更新成功");
173
+ this.getTableList();
174
+ }
175
+ }
176
+
177
+ // 删除
178
+ async handleDelete(row: any) {
179
+ const res = await this.deleteAction(
180
+ API_CONFIG.remove,
181
+ {},
182
+ { ids: [row.id] }
183
+ );
184
+ if (res.success) {
185
+ this.$message.success("删除成功");
186
+ this.getTableList();
187
+ }
188
+ }
189
+
190
+ // 批量删除
191
+ async handleBatchDelete(ids: string[]) {
192
+ await this.actionBatch(
193
+ this.deleteAction,
194
+ API_CONFIG.remove,
195
+ "删除",
196
+ ids,
197
+ true
198
+ );
199
+ this.getTableList();
200
+ }
201
+
202
+ // 导出
203
+ async handleExport() {
204
+ const params = this.getQueryParams();
205
+ await this.getAction(API_CONFIG.exportExcel, params);
206
+ }
207
+
208
+ // 详情查询
209
+ async getDetail(id: string) {
210
+ return await this.getAction(API_CONFIG.get, { id });
211
+ }
212
+ }
213
+
214
+ export default new LadleUseQueryHook();
215
+ ```
216
+
217
+ ---
218
+
219
+ ## 何时需要独立的 API 层?
220
+
221
+ 在以下场景中,建议创建独立的 `api/` 文件:
222
+
223
+ ### ✅ 需要独立 API 层的场景
224
+
225
+ 1. **复杂的数据转换**
226
+
227
+ ```typescript
228
+ // api/complex-data.ts
229
+ export async function fetchComplexData(params: any) {
230
+ const res = await request.post("/api/data", params);
231
+ // 复杂的数据转换逻辑
232
+ return transformData(res.data);
233
+ }
234
+ ```
235
+
236
+ 2. **多个页面共享同一接口**
237
+
238
+ ```typescript
239
+ // api/common.ts
240
+ export const CommonAPI = {
241
+ getDictData: (type: string) => request.get(`/dict/${type}`),
242
+ uploadFile: (file: File) => request.upload("/upload", file)
243
+ };
244
+ ```
245
+
246
+ 3. **需要组合多个接口调用**
247
+
248
+ ```typescript
249
+ // api/batch-operations.ts
250
+ export async function batchProcess(ids: string[]) {
251
+ const details = await Promise.all(
252
+ ids.map((id) => request.get(`/detail/${id}`))
253
+ );
254
+ return await request.post("/batch", { data: details });
255
+ }
256
+ ```
257
+
258
+ 4. **特殊的请求拦截或错误处理**
259
+ ```typescript
260
+ // api/special-request.ts
261
+ export async function sensitiveOperation(data: any) {
262
+ return await request.post("/sensitive", data, {
263
+ headers: { "X-Custom-Token": getSpecialToken() }
264
+ });
265
+ }
266
+ ```
267
+
268
+ ### ⛔ 不需要独立 API 层的场景
269
+
270
+ 1. **标准 CRUD 操作** - 直接使用基类方法
271
+ 2. **简单的列表查询** - 配置 `API_CONFIG.list`
272
+ 3. **单页面独享的接口** - 写在 `data.ts` 的 `API_CONFIG` 中
273
+
274
+ ---
275
+
276
+ ## 完整的方法参考
277
+
278
+ 所有基类方法的详细文档请参考:
279
+
280
+ - [request.md - AbstractPageQueryHook 基类内置方法](./request.md#abstractpagequeryhook-基类内置方法)
281
+ - 方法签名
282
+ - 参数说明
283
+ - 实战示例
284
+ - 常见错误与解决方案
285
+
286
+ ---
287
+
288
+ ## 常见问题
289
+
290
+ ### 1. 删除操作失败?
291
+
292
+ **症状**:删除接口收到空的 `ids` 参数
293
+
294
+ **原因**:`deleteAction` 的第三个参数才是 `data`,不是第二个
295
+
296
+ **解决**:参考 [request.md - 删除操作示例](./request.md#实战示例-4删除操作)
297
+
298
+ ```typescript
299
+ // ❌ 错误
300
+ await this.deleteAction(API_CONFIG.remove, { ids: [row.id] });
301
+
302
+ // ✅ 正确
303
+ await this.deleteAction(API_CONFIG.remove, {}, { ids: [row.id] });
304
+ ```
305
+
306
+ ### 2. `actionBatch` 如何使用?
307
+
308
+ **用法**:批量操作的统一封装,自动处理确认、提示、错误
309
+
310
+ **详细说明**:参考 [request.md - actionBatch 方法](./request.md#4-actionbatch---批量操作统一封装)
311
+
312
+ ```typescript
313
+ // 批量删除
314
+ await this.actionBatch(
315
+ this.deleteAction, // 要执行的方法
316
+ API_CONFIG.remove, // 接口 URL
317
+ "删除", // 操作名称
318
+ ids, // ID 列表
319
+ true // 是否自动成功提示
320
+ );
321
+ ```
322
+
323
+ ### 3. 如何自定义请求头?
324
+
325
+ 所有内置方法都支持 `headers` 参数:
326
+
327
+ ```typescript
328
+ await this.postAction(API_CONFIG.save, row, {}, { "X-Custom-Header": "value" });
329
+ ```
330
+
331
+ ### 4. 如何处理文件上传?
332
+
333
+ 使用 `postAction` 配合 `FormData`:
334
+
335
+ ```typescript
336
+ async handleUpload(file: File) {
337
+ const formData = new FormData()
338
+ formData.append('file', file)
339
+
340
+ const res = await this.postAction('/upload', formData, {}, {
341
+ 'Content-Type': 'multipart/form-data'
342
+ })
343
+
344
+ return res
345
+ }
346
+ ```
347
+
348
+ ---
349
+
350
+ ## 最佳实践总结
351
+
352
+ 1. **简单 CRUD**:直接在 `data.ts` 配置 `API_CONFIG` + 基类方法
353
+ 2. **复杂逻辑**:创建独立 `api/` 文件进行封装
354
+ 3. **查阅方法**:所有 HTTP 方法详细说明见 [request.md](./request.md)
355
+ 4. **参数顺序**:特别注意 `deleteAction(url, params, data, headers)` 的参数位置
356
+
357
+ ---
358
+
359
+ **相关文档**:
360
+
361
+ - [request.md - HTTP 请求方法完整文档](./request.md)
362
+ - [request.md - AbstractPageQueryHook 基类内置方法](./request.md#abstractpagequeryhook-基类内置方法)