@agile-team/wl-skills-kit 2.11.1 → 2.11.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 (85) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/bin/wl-skills.js +27 -3
  4. package/files/.wl-skills/docs/jh-pagination.md +505 -505
  5. package/files/.wl-skills/docs/request.md +940 -940
  6. package/files/.wl-skills/guides/architecture.md +1 -1
  7. package/files/.wl-skills/skills/core/convention-audit/SKILL.md +3 -3
  8. package/files/.wl-skills/skills/core/spec-doc-parse/SKILL.md +332 -332
  9. package/files/.wl-skills/skills/core/spec-doc-parse/USAGE.md +97 -97
  10. package/files/.wl-skills/skills/sync/permission-sync/USAGE.md +107 -107
  11. package/files/.wl-skills/src/components/global/C_ParentView/index.vue +3 -3
  12. package/files/.wl-skills/src/components/global/C_RightToolbar/index.vue +157 -157
  13. package/files/.wl-skills/src/components/global/C_SvgIcon/index.vue +31 -31
  14. package/files/.wl-skills/src/components/global/C_SvgIcon/svgicon.js +10 -10
  15. package/files/.wl-skills/src/components/global/C_TagStatus/README.md +264 -264
  16. package/files/.wl-skills/src/components/global/C_TagStatus/config.ts +192 -192
  17. package/files/.wl-skills/src/components/global/C_TagStatus/index.vue +106 -106
  18. package/files/.wl-skills/src/components/global/C_TagStatus/types.ts +64 -64
  19. package/files/.wl-skills/src/components/global/C_Tree/README.md +153 -153
  20. package/files/.wl-skills/src/components/global/C_Tree/index.scss +42 -42
  21. package/files/.wl-skills/src/components/global/C_Tree/index.vue +78 -78
  22. package/files/.wl-skills/src/components/global/C_Tree/types.ts +59 -59
  23. package/files/.wl-skills/src/components/local/c_formModal/README.md +235 -235
  24. package/files/.wl-skills/src/components/local/c_formModal/data.ts +95 -95
  25. package/files/.wl-skills/src/components/local/c_formModal/index.scss +8 -8
  26. package/files/.wl-skills/src/components/local/c_formModal/index.vue +107 -107
  27. package/files/.wl-skills/src/components/local/c_formSections/data.ts +175 -175
  28. package/files/.wl-skills/src/components/local/c_formSections/index.scss +280 -280
  29. package/files/.wl-skills/src/components/local/c_formSections/index.vue +429 -429
  30. package/files/.wl-skills/src/components/local/c_listModal/data.ts +41 -41
  31. package/files/.wl-skills/src/components/local/c_listModal/index.vue +136 -136
  32. package/files/.wl-skills/src/components/local/c_spliterTitle/index.scss +25 -25
  33. package/files/.wl-skills/src/components/local/c_spliterTitle/index.vue +21 -21
  34. package/files/.wl-skills/src/components/remote/AGGrid/README.md +530 -530
  35. package/files/.wl-skills/src/components/remote/BaseForm/README.md +508 -508
  36. package/files/.wl-skills/src/components/remote/BaseQuery/README.md +865 -865
  37. package/files/.wl-skills/src/components/remote/BaseTable/README.md +941 -941
  38. package/files/.wl-skills/src/components/remote/BaseToolbar/README.md +496 -496
  39. package/files/.wl-skills/src/types/page.ts +24 -24
  40. package/files/.wl-skills/standards/04-coding-basics.md +39 -1
  41. package/files/.wl-skills/standards/09-typescript.md +26 -3
  42. package/files/.wl-skills/standards/index.md +2 -2
  43. package/files/.wl-skills/templates/README.md +44 -44
  44. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/api.md +54 -54
  45. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -346
  46. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -1
  47. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -28
  48. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -115
  49. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -44
  50. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -43
  51. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -338
  52. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -1
  53. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -28
  54. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -115
  55. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -44
  56. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -43
  57. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/api.md +88 -88
  58. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/data.ts +601 -601
  59. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.scss +1 -1
  60. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.vue +64 -64
  61. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/api.md +67 -67
  62. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/data.ts +286 -286
  63. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.scss +139 -139
  64. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.vue +318 -318
  65. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -98
  66. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -543
  67. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -1
  68. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -52
  69. package/files/.wl-skills/templates/sale/demo/add-demo/data.ts +518 -518
  70. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/data.ts +524 -524
  71. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.scss +154 -154
  72. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.vue +117 -117
  73. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/data.ts +308 -308
  74. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.scss +99 -99
  75. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.vue +77 -77
  76. package/files/.wl-skills/templates/sale/demo/heat-batch-return/data.ts +367 -367
  77. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.scss +100 -100
  78. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.vue +170 -170
  79. package/files/.wl-skills/templates/sale/demo/heat-batch-return/meltDialog.vue +320 -320
  80. package/files/.wl-skills/templates/sale/demo/metallurgical-spec/data.ts +824 -824
  81. package/lib/ast-rules.js +304 -9
  82. package/mcp/config.js +46 -46
  83. package/mcp/registry.js +6 -1
  84. package/mcp/tools/projectTools.js +9 -1
  85. package/package.json +2 -2
@@ -1,505 +1,505 @@
1
- # jh-pagination - 分页组件
2
-
3
- > 基于 Element Plus Pagination 封装的统一分页组件,提供标准化的分页交互和样式
4
-
5
- ## 📦 组件位置
6
-
7
- ```typescript
8
- // 来自远程 common-core 包
9
- import "@jhlc/common-core";
10
- ```
11
-
12
- 组件已在全局注册,无需手动导入,直接在模板中使用 `<jh-pagination>`。
13
-
14
- ## 基本用法
15
-
16
- ### 标准分页
17
-
18
- ```vue
19
- <template>
20
- <div>
21
- <!-- 表格数据 -->
22
- <BaseTable :data="list" :columns="columns" />
23
-
24
- <!-- 分页组件 -->
25
- <jh-pagination
26
- v-show="page.total && page.total > 0"
27
- :total="page.total || 0"
28
- v-model:currentPage="page.current"
29
- v-model:pageSize="page.size"
30
- @current-change="handlePageChange"
31
- @size-change="handleSizeChange"
32
- />
33
- </div>
34
- </template>
35
-
36
- <script setup lang="ts">
37
- import { ref } from "vue";
38
-
39
- const page = ref({
40
- current: 1,
41
- size: 10,
42
- total: 0
43
- });
44
-
45
- const list = ref([]);
46
-
47
- // 加载数据
48
- const loadData = async () => {
49
- const res = await request({
50
- url: "/api/list",
51
- method: "get",
52
- params: {
53
- page: page.value.current,
54
- size: page.value.size
55
- }
56
- });
57
-
58
- list.value = res.data.records;
59
- page.value.total = res.data.total;
60
- };
61
-
62
- // 页码变化
63
- const handlePageChange = () => {
64
- loadData();
65
- };
66
-
67
- // 页大小变化
68
- const handleSizeChange = () => {
69
- page.value.current = 1; // 重置到第一页
70
- loadData();
71
- };
72
-
73
- // 初始化
74
- onMounted(() => {
75
- loadData();
76
- });
77
- </script>
78
- ```
79
-
80
- ## Props 属性
81
-
82
- | 参数 | 说明 | 类型 | 默认值 |
83
- | --------------------- | ------------------------ | ---------- | ------------------------------------------- |
84
- | total | 总条目数 | `number` | `0` |
85
- | currentPage (v-model) | 当前页码 | `number` | `1` |
86
- | pageSize (v-model) | 每页显示条数 | `number` | `10` |
87
- | pageSizes | 每页显示个数选择器的选项 | `number[]` | `[10, 20, 50, 100]` |
88
- | layout | 组件布局 | `string` | `"total, prev, pager, next, sizes, jumper"` |
89
- | background | 是否为分页按钮添加背景色 | `boolean` | `true` |
90
- | disabled | 是否禁用分页 | `boolean` | `false` |
91
-
92
- ## Events 事件
93
-
94
- | 事件名 | 说明 | 回调参数 |
95
- | ------------------ | --------------------- | ------------------------ |
96
- | current-change | 页码改变时触发 | `(page: number) => void` |
97
- | size-change | 页大小改变时触发 | `(size: number) => void` |
98
- | update:currentPage | 页码变化(v-model) | `(page: number) => void` |
99
- | update:pageSize | 页大小变化(v-model) | `(size: number) => void` |
100
-
101
- ## 常见场景
102
-
103
- ### 场景 1:列表页分页(推荐)
104
-
105
- **适用**: 绝大多数列表页面
106
-
107
- ```vue
108
- <template>
109
- <div class="app-container app-page-container">
110
- <BaseQuery :form="queryParam" :items="queryItems" @select="select" />
111
- <BaseToolbar :items="toolbars" />
112
- <BaseTable :data="list" :columns="columns" />
113
-
114
- <!-- 分页组件 -->
115
- <jh-pagination
116
- v-show="page.total && page.total > 0"
117
- :total="page.total || 0"
118
- v-model:currentPage="page.current"
119
- v-model:pageSize="page.size"
120
- @current-change="select"
121
- @size-change="select"
122
- />
123
- </div>
124
- </template>
125
-
126
- <script setup lang="ts">
127
- import { createPage } from "./data";
128
-
129
- const Page = createPage();
130
- const { page, list, queryParam, queryItems, toolbars, columns, select } = Page;
131
-
132
- onMounted(() => {
133
- select();
134
- });
135
- </script>
136
- ```
137
-
138
- **说明**:
139
-
140
- - ✅ 使用 `v-show` 在无数据时隐藏分页
141
- - ✅ 使用 `v-model` 双向绑定页码和页大小
142
- - ✅ 页码/页大小变化时统一调用 `select()` 刷新数据
143
-
144
- ---
145
-
146
- ### 场景 2:前端分页(本地数据)
147
-
148
- **适用**: 数据量小,一次性加载全部数据后在前端分页
149
-
150
- ```vue
151
- <template>
152
- <div>
153
- <!-- 显示分页后的数据 -->
154
- <BaseTable :data="paginatedData" :columns="columns" />
155
-
156
- <!-- 分页组件 -->
157
- <jh-pagination
158
- v-show="allData.length > 0"
159
- :total="allData.length"
160
- v-model:currentPage="currentPage"
161
- v-model:pageSize="pageSize"
162
- />
163
- </div>
164
- </template>
165
-
166
- <script setup lang="ts">
167
- import { ref, computed } from "vue";
168
-
169
- const allData = ref([]); // 全部数据
170
- const currentPage = ref(1);
171
- const pageSize = ref(10);
172
-
173
- // 计算属性:分页后的数据
174
- const paginatedData = computed(() => {
175
- const start = (currentPage.value - 1) * pageSize.value;
176
- const end = start + pageSize.value;
177
- return allData.value.slice(start, end);
178
- });
179
-
180
- // 加载全部数据
181
- const loadAllData = async () => {
182
- const res = await request({
183
- url: "/api/all-data",
184
- method: "get"
185
- });
186
- allData.value = res.data;
187
- };
188
-
189
- onMounted(() => {
190
- loadAllData();
191
- });
192
- </script>
193
- ```
194
-
195
- **说明**:
196
-
197
- - ✅ `total` 使用全部数据的长度
198
- - ✅ 使用 `computed` 计算当前页的数据
199
- - ✅ 不需要监听事件(响应式自动处理)
200
-
201
- ---
202
-
203
- ### 场景 3:子表格分页
204
-
205
- **适用**: 新增编辑页中的项次信息表格
206
-
207
- ```vue
208
- <template>
209
- <div>
210
- <!-- 主表单区域 -->
211
- <c_formSections :sections="sectionsConfig" :form="form" />
212
-
213
- <!-- 项次信息表格 -->
214
- <el-card shadow="never" class="items-card">
215
- <BaseTable :data="itemData" :columns="itemColumns" />
216
-
217
- <!-- 项次分页 -->
218
- <div class="items-pagination">
219
- <jh-pagination
220
- v-show="itemTotal && itemTotal > 0"
221
- :total="itemTotal || 0"
222
- v-model:currentPage="itemPage"
223
- v-model:pageSize="itemSize"
224
- @current-change="loadItemData"
225
- @size-change="loadItemData"
226
- />
227
- </div>
228
- </el-card>
229
- </div>
230
- </template>
231
-
232
- <script setup lang="ts">
233
- const form = ref({});
234
- const itemData = ref([]);
235
- const itemTotal = ref(0);
236
- const itemPage = ref(1);
237
- const itemSize = ref(10);
238
-
239
- // 加载项次数据
240
- const loadItemData = async () => {
241
- const res = await request({
242
- url: "/api/items/list",
243
- method: "get",
244
- params: {
245
- page: itemPage.value,
246
- size: itemSize.value
247
- }
248
- });
249
- itemData.value = res.data.records;
250
- itemTotal.value = res.data.total;
251
- };
252
-
253
- onMounted(() => {
254
- loadItemData();
255
- });
256
- </script>
257
- ```
258
-
259
- **说明**:
260
-
261
- - ✅ 子表格使用独立的分页状态
262
- - ✅ 与主表单数据解耦
263
- - ✅ 支持独立刷新
264
-
265
- ---
266
-
267
- ### 场景 4:无数据时自动隐藏
268
-
269
- **推荐写法**:
270
-
271
- ```vue
272
- <!-- ✅ 推荐:无数据时不显示 -->
273
- <jh-pagination
274
- v-show="page.total && page.total > 0"
275
- :total="page.total || 0"
276
- v-model:currentPage="page.current"
277
- v-model:pageSize="page.size"
278
- />
279
-
280
- <!-- ❌ 不推荐:始终显示(体验差) -->
281
- <jh-pagination
282
- :total="page.total"
283
- v-model:currentPage="page.current"
284
- v-model:pageSize="page.size"
285
- />
286
- ```
287
-
288
- **说明**:
289
-
290
- - ✅ 使用 `v-show` 在 `total > 0` 时才显示
291
- - ✅ 提升用户体验,避免空状态下显示分页
292
-
293
- ---
294
-
295
- ### 场景 5:自定义页大小选项
296
-
297
- ```vue
298
- <jh-pagination
299
- :total="page.total"
300
- :page-sizes="[5, 10, 20, 50, 200]"
301
- v-model:currentPage="page.current"
302
- v-model:pageSize="page.size"
303
- />
304
- ```
305
-
306
- **说明**:
307
-
308
- - 根据业务需求自定义每页条数选项
309
- - 默认为 `[10, 20, 50, 100]`
310
-
311
- ---
312
-
313
- ## 与 el-pagination 对比
314
-
315
- ### 使用 jh-pagination(推荐)
316
-
317
- ```vue
318
- <jh-pagination
319
- v-show="page.total && page.total > 0"
320
- :total="page.total || 0"
321
- v-model:currentPage="page.current"
322
- v-model:pageSize="page.size"
323
- @current-change="select"
324
- @size-change="select"
325
- />
326
- ```
327
-
328
- **优势**:
329
-
330
- - ✅ **统一规范** - 全局统一的分页样式和交互
331
- - ✅ **简化配置** - 无需配置 layout、background 等(内置默认值)
332
- - ✅ **驼峰命名** - 使用 `currentPage`、`pageSize`(符合 Vue 规范)
333
- - ✅ **自动样式** - 内置统一的边距、居中、背景色
334
-
335
- ### 使用 el-pagination(不推荐)
336
-
337
- ```vue
338
- <el-pagination
339
- v-model:current-page="page.current"
340
- v-model:page-size="page.size"
341
- :page-sizes="[10, 20, 50, 100]"
342
- :total="page.total"
343
- layout="total, prev, pager, next, sizes, jumper"
344
- background
345
- @current-change="select"
346
- @size-change="select"
347
- />
348
- ```
349
-
350
- **劣势**:
351
-
352
- - ❌ **配置繁琐** - 需要手动配置 layout、page-sizes、background
353
- - ❌ **样式不统一** - 每个页面可能配置不同
354
- - ❌ **命名不一致** - 使用 `current-page`(中划线命名)
355
-
356
- ---
357
-
358
- ## 💡 最佳实践
359
-
360
- ### 1. 统一使用 jh-pagination
361
-
362
- **推荐**:
363
-
364
- ```vue
365
- <jh-pagination ... />
366
- ```
367
-
368
- **不推荐**:
369
-
370
- ```vue
371
- <el-pagination ... />
372
- ```
373
-
374
- ### 2. 始终添加 v-show
375
-
376
- ```vue
377
- <!-- ✅ 推荐 -->
378
- <jh-pagination
379
- v-show="page.total && page.total > 0"
380
- :total="page.total || 0"
381
- ...
382
- />
383
- ```
384
-
385
- ### 3. 使用 v-model 双向绑定
386
-
387
- ```vue
388
- <!-- ✅ 推荐:v-model 双向绑定 -->
389
- <jh-pagination
390
- v-model:currentPage="page.current"
391
- v-model:pageSize="page.size"
392
- />
393
-
394
- <!-- ❌ 不推荐:单向绑定 + 事件手动更新 -->
395
- <jh-pagination
396
- :current-page="page.current"
397
- :page-size="page.size"
398
- @update:currentPage="page.current = $event"
399
- @update:pageSize="page.size = $event"
400
- />
401
- ```
402
-
403
- ### 4. 页大小变化时重置页码
404
-
405
- ```typescript
406
- const handleSizeChange = () => {
407
- page.value.current = 1; // 重置到第一页
408
- loadData();
409
- };
410
- ```
411
-
412
- ### 5. 配合 Page Hook 使用
413
-
414
- ```typescript
415
- // data.ts
416
- export function createPage() {
417
- return new (class extends AbstractPageQueryHook {
418
- // ... Hook 内置分页逻辑
419
- })();
420
- }
421
-
422
- // index.vue
423
- const Page = createPage();
424
- const { page, select } = Page;
425
- ```
426
-
427
- **说明**:
428
-
429
- - ✅ Page Hook 内置分页状态管理
430
- - ✅ `select()` 方法自动读取 page 状态
431
- - ✅ 减少手动管理分页的代码
432
-
433
- ---
434
-
435
- ## 🎯 真实项目示例
436
-
437
- ### 示例 1:内贸订单列表页
438
-
439
- **路径**: `src/views/sale/.wl-skills/templates/domestic-trade-order/index.vue`
440
-
441
- ```vue
442
- <jh-pagination
443
- v-show="page.total && page.total > 0"
444
- :total="page.total || 0"
445
- v-model:currentPage="page.current"
446
- v-model:pageSize="page.size"
447
- @current-change="select"
448
- @size-change="select"
449
- />
450
- ```
451
-
452
- ### 示例 2:新增编辑页项次分页
453
-
454
- **路径**: `src/views/sale/.wl-skills/templates/add-.wl-skills/templates/index.vue`
455
-
456
- ```vue
457
- <jh-pagination
458
- v-show="itemTotal && itemTotal > 0"
459
- :total="itemTotal || 0"
460
- v-model:currentPage="currentPage"
461
- v-model:pageSize="pageSize"
462
- @current-change="refreshItemData"
463
- @size-change="refreshItemData"
464
- />
465
- ```
466
-
467
- ---
468
-
469
- ## ⚠️ 注意事项
470
-
471
- 1. **组件来自远程包**
472
-
473
- - 组件由 `@jhlc/common-core` 提供
474
- - 已全局注册,无需手动导入
475
- - 升级远程包时注意版本兼容性
476
-
477
- 2. **页码从 1 开始**
478
-
479
- - `currentPage` 最小值为 1
480
- - 后端接口通常也是从 1 开始
481
-
482
- 3. **total 必须准确**
483
-
484
- - `total` 应该是数据总数,不是当前页数据量
485
- - 后端通常返回 `{ records: [], total: 100 }`
486
-
487
- 4. **事件处理**
488
-
489
- - `current-change` 在页码变化时触发
490
- - `size-change` 在页大小变化时触发
491
- - 两个事件通常调用同一个刷新方法
492
-
493
- 5. **样式定制**
494
- - 如需特殊样式,可通过 CSS 覆盖
495
- - 不要修改远程组件源码
496
-
497
- ---
498
-
499
- ## 🚀 快速开始
500
-
501
- 1. **在列表页使用**:复制"场景 1"代码
502
- 2. **在详情页使用**:复制"场景 3"代码
503
- 3. **前端分页**:复制"场景 2"代码
504
-
505
- **推荐作为项目统一的分页组件使用!**
1
+ # jh-pagination - 分页组件
2
+
3
+ > 基于 Element Plus Pagination 封装的统一分页组件,提供标准化的分页交互和样式
4
+
5
+ ## 📦 组件位置
6
+
7
+ ```typescript
8
+ // 来自远程 common-core 包
9
+ import "@jhlc/common-core";
10
+ ```
11
+
12
+ 组件已在全局注册,无需手动导入,直接在模板中使用 `<jh-pagination>`。
13
+
14
+ ## 基本用法
15
+
16
+ ### 标准分页
17
+
18
+ ```vue
19
+ <template>
20
+ <div>
21
+ <!-- 表格数据 -->
22
+ <BaseTable :data="list" :columns="columns" />
23
+
24
+ <!-- 分页组件 -->
25
+ <jh-pagination
26
+ v-show="page.total && page.total > 0"
27
+ :total="page.total || 0"
28
+ v-model:currentPage="page.current"
29
+ v-model:pageSize="page.size"
30
+ @current-change="handlePageChange"
31
+ @size-change="handleSizeChange"
32
+ />
33
+ </div>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { ref } from "vue";
38
+
39
+ const page = ref({
40
+ current: 1,
41
+ size: 10,
42
+ total: 0
43
+ });
44
+
45
+ const list = ref([]);
46
+
47
+ // 加载数据
48
+ const loadData = async () => {
49
+ const res = await request({
50
+ url: "/api/list",
51
+ method: "get",
52
+ params: {
53
+ page: page.value.current,
54
+ size: page.value.size
55
+ }
56
+ });
57
+
58
+ list.value = res.data.records;
59
+ page.value.total = res.data.total;
60
+ };
61
+
62
+ // 页码变化
63
+ const handlePageChange = () => {
64
+ loadData();
65
+ };
66
+
67
+ // 页大小变化
68
+ const handleSizeChange = () => {
69
+ page.value.current = 1; // 重置到第一页
70
+ loadData();
71
+ };
72
+
73
+ // 初始化
74
+ onMounted(() => {
75
+ loadData();
76
+ });
77
+ </script>
78
+ ```
79
+
80
+ ## Props 属性
81
+
82
+ | 参数 | 说明 | 类型 | 默认值 |
83
+ | --------------------- | ------------------------ | ---------- | ------------------------------------------- |
84
+ | total | 总条目数 | `number` | `0` |
85
+ | currentPage (v-model) | 当前页码 | `number` | `1` |
86
+ | pageSize (v-model) | 每页显示条数 | `number` | `10` |
87
+ | pageSizes | 每页显示个数选择器的选项 | `number[]` | `[10, 20, 50, 100]` |
88
+ | layout | 组件布局 | `string` | `"total, prev, pager, next, sizes, jumper"` |
89
+ | background | 是否为分页按钮添加背景色 | `boolean` | `true` |
90
+ | disabled | 是否禁用分页 | `boolean` | `false` |
91
+
92
+ ## Events 事件
93
+
94
+ | 事件名 | 说明 | 回调参数 |
95
+ | ------------------ | --------------------- | ------------------------ |
96
+ | current-change | 页码改变时触发 | `(page: number) => void` |
97
+ | size-change | 页大小改变时触发 | `(size: number) => void` |
98
+ | update:currentPage | 页码变化(v-model) | `(page: number) => void` |
99
+ | update:pageSize | 页大小变化(v-model) | `(size: number) => void` |
100
+
101
+ ## 常见场景
102
+
103
+ ### 场景 1:列表页分页(推荐)
104
+
105
+ **适用**: 绝大多数列表页面
106
+
107
+ ```vue
108
+ <template>
109
+ <div class="app-container app-page-container">
110
+ <BaseQuery :form="queryParam" :items="queryItems" @select="select" />
111
+ <BaseToolbar :items="toolbars" />
112
+ <BaseTable :data="list" :columns="columns" />
113
+
114
+ <!-- 分页组件 -->
115
+ <jh-pagination
116
+ v-show="page.total && page.total > 0"
117
+ :total="page.total || 0"
118
+ v-model:currentPage="page.current"
119
+ v-model:pageSize="page.size"
120
+ @current-change="select"
121
+ @size-change="select"
122
+ />
123
+ </div>
124
+ </template>
125
+
126
+ <script setup lang="ts">
127
+ import { createPage } from "./data";
128
+
129
+ const Page = createPage();
130
+ const { page, list, queryParam, queryItems, toolbars, columns, select } = Page;
131
+
132
+ onMounted(() => {
133
+ select();
134
+ });
135
+ </script>
136
+ ```
137
+
138
+ **说明**:
139
+
140
+ - ✅ 使用 `v-show` 在无数据时隐藏分页
141
+ - ✅ 使用 `v-model` 双向绑定页码和页大小
142
+ - ✅ 页码/页大小变化时统一调用 `select()` 刷新数据
143
+
144
+ ---
145
+
146
+ ### 场景 2:前端分页(本地数据)
147
+
148
+ **适用**: 数据量小,一次性加载全部数据后在前端分页
149
+
150
+ ```vue
151
+ <template>
152
+ <div>
153
+ <!-- 显示分页后的数据 -->
154
+ <BaseTable :data="paginatedData" :columns="columns" />
155
+
156
+ <!-- 分页组件 -->
157
+ <jh-pagination
158
+ v-show="allData.length > 0"
159
+ :total="allData.length"
160
+ v-model:currentPage="currentPage"
161
+ v-model:pageSize="pageSize"
162
+ />
163
+ </div>
164
+ </template>
165
+
166
+ <script setup lang="ts">
167
+ import { ref, computed } from "vue";
168
+
169
+ const allData = ref([]); // 全部数据
170
+ const currentPage = ref(1);
171
+ const pageSize = ref(10);
172
+
173
+ // 计算属性:分页后的数据
174
+ const paginatedData = computed(() => {
175
+ const start = (currentPage.value - 1) * pageSize.value;
176
+ const end = start + pageSize.value;
177
+ return allData.value.slice(start, end);
178
+ });
179
+
180
+ // 加载全部数据
181
+ const loadAllData = async () => {
182
+ const res = await request({
183
+ url: "/api/all-data",
184
+ method: "get"
185
+ });
186
+ allData.value = res.data;
187
+ };
188
+
189
+ onMounted(() => {
190
+ loadAllData();
191
+ });
192
+ </script>
193
+ ```
194
+
195
+ **说明**:
196
+
197
+ - ✅ `total` 使用全部数据的长度
198
+ - ✅ 使用 `computed` 计算当前页的数据
199
+ - ✅ 不需要监听事件(响应式自动处理)
200
+
201
+ ---
202
+
203
+ ### 场景 3:子表格分页
204
+
205
+ **适用**: 新增编辑页中的项次信息表格
206
+
207
+ ```vue
208
+ <template>
209
+ <div>
210
+ <!-- 主表单区域 -->
211
+ <c_formSections :sections="sectionsConfig" :form="form" />
212
+
213
+ <!-- 项次信息表格 -->
214
+ <el-card shadow="never" class="items-card">
215
+ <BaseTable :data="itemData" :columns="itemColumns" />
216
+
217
+ <!-- 项次分页 -->
218
+ <div class="items-pagination">
219
+ <jh-pagination
220
+ v-show="itemTotal && itemTotal > 0"
221
+ :total="itemTotal || 0"
222
+ v-model:currentPage="itemPage"
223
+ v-model:pageSize="itemSize"
224
+ @current-change="loadItemData"
225
+ @size-change="loadItemData"
226
+ />
227
+ </div>
228
+ </el-card>
229
+ </div>
230
+ </template>
231
+
232
+ <script setup lang="ts">
233
+ const form = ref({});
234
+ const itemData = ref([]);
235
+ const itemTotal = ref(0);
236
+ const itemPage = ref(1);
237
+ const itemSize = ref(10);
238
+
239
+ // 加载项次数据
240
+ const loadItemData = async () => {
241
+ const res = await request({
242
+ url: "/api/items/list",
243
+ method: "get",
244
+ params: {
245
+ page: itemPage.value,
246
+ size: itemSize.value
247
+ }
248
+ });
249
+ itemData.value = res.data.records;
250
+ itemTotal.value = res.data.total;
251
+ };
252
+
253
+ onMounted(() => {
254
+ loadItemData();
255
+ });
256
+ </script>
257
+ ```
258
+
259
+ **说明**:
260
+
261
+ - ✅ 子表格使用独立的分页状态
262
+ - ✅ 与主表单数据解耦
263
+ - ✅ 支持独立刷新
264
+
265
+ ---
266
+
267
+ ### 场景 4:无数据时自动隐藏
268
+
269
+ **推荐写法**:
270
+
271
+ ```vue
272
+ <!-- ✅ 推荐:无数据时不显示 -->
273
+ <jh-pagination
274
+ v-show="page.total && page.total > 0"
275
+ :total="page.total || 0"
276
+ v-model:currentPage="page.current"
277
+ v-model:pageSize="page.size"
278
+ />
279
+
280
+ <!-- ❌ 不推荐:始终显示(体验差) -->
281
+ <jh-pagination
282
+ :total="page.total"
283
+ v-model:currentPage="page.current"
284
+ v-model:pageSize="page.size"
285
+ />
286
+ ```
287
+
288
+ **说明**:
289
+
290
+ - ✅ 使用 `v-show` 在 `total > 0` 时才显示
291
+ - ✅ 提升用户体验,避免空状态下显示分页
292
+
293
+ ---
294
+
295
+ ### 场景 5:自定义页大小选项
296
+
297
+ ```vue
298
+ <jh-pagination
299
+ :total="page.total"
300
+ :page-sizes="[5, 10, 20, 50, 200]"
301
+ v-model:currentPage="page.current"
302
+ v-model:pageSize="page.size"
303
+ />
304
+ ```
305
+
306
+ **说明**:
307
+
308
+ - 根据业务需求自定义每页条数选项
309
+ - 默认为 `[10, 20, 50, 100]`
310
+
311
+ ---
312
+
313
+ ## 与 el-pagination 对比
314
+
315
+ ### 使用 jh-pagination(推荐)
316
+
317
+ ```vue
318
+ <jh-pagination
319
+ v-show="page.total && page.total > 0"
320
+ :total="page.total || 0"
321
+ v-model:currentPage="page.current"
322
+ v-model:pageSize="page.size"
323
+ @current-change="select"
324
+ @size-change="select"
325
+ />
326
+ ```
327
+
328
+ **优势**:
329
+
330
+ - ✅ **统一规范** - 全局统一的分页样式和交互
331
+ - ✅ **简化配置** - 无需配置 layout、background 等(内置默认值)
332
+ - ✅ **驼峰命名** - 使用 `currentPage`、`pageSize`(符合 Vue 规范)
333
+ - ✅ **自动样式** - 内置统一的边距、居中、背景色
334
+
335
+ ### 使用 el-pagination(不推荐)
336
+
337
+ ```vue
338
+ <el-pagination
339
+ v-model:current-page="page.current"
340
+ v-model:page-size="page.size"
341
+ :page-sizes="[10, 20, 50, 100]"
342
+ :total="page.total"
343
+ layout="total, prev, pager, next, sizes, jumper"
344
+ background
345
+ @current-change="select"
346
+ @size-change="select"
347
+ />
348
+ ```
349
+
350
+ **劣势**:
351
+
352
+ - ❌ **配置繁琐** - 需要手动配置 layout、page-sizes、background
353
+ - ❌ **样式不统一** - 每个页面可能配置不同
354
+ - ❌ **命名不一致** - 使用 `current-page`(中划线命名)
355
+
356
+ ---
357
+
358
+ ## 💡 最佳实践
359
+
360
+ ### 1. 统一使用 jh-pagination
361
+
362
+ **推荐**:
363
+
364
+ ```vue
365
+ <jh-pagination ... />
366
+ ```
367
+
368
+ **不推荐**:
369
+
370
+ ```vue
371
+ <el-pagination ... />
372
+ ```
373
+
374
+ ### 2. 始终添加 v-show
375
+
376
+ ```vue
377
+ <!-- ✅ 推荐 -->
378
+ <jh-pagination
379
+ v-show="page.total && page.total > 0"
380
+ :total="page.total || 0"
381
+ ...
382
+ />
383
+ ```
384
+
385
+ ### 3. 使用 v-model 双向绑定
386
+
387
+ ```vue
388
+ <!-- ✅ 推荐:v-model 双向绑定 -->
389
+ <jh-pagination
390
+ v-model:currentPage="page.current"
391
+ v-model:pageSize="page.size"
392
+ />
393
+
394
+ <!-- ❌ 不推荐:单向绑定 + 事件手动更新 -->
395
+ <jh-pagination
396
+ :current-page="page.current"
397
+ :page-size="page.size"
398
+ @update:currentPage="page.current = $event"
399
+ @update:pageSize="page.size = $event"
400
+ />
401
+ ```
402
+
403
+ ### 4. 页大小变化时重置页码
404
+
405
+ ```typescript
406
+ const handleSizeChange = () => {
407
+ page.value.current = 1; // 重置到第一页
408
+ loadData();
409
+ };
410
+ ```
411
+
412
+ ### 5. 配合 Page Hook 使用
413
+
414
+ ```typescript
415
+ // data.ts
416
+ export function createPage() {
417
+ return new (class extends AbstractPageQueryHook {
418
+ // ... Hook 内置分页逻辑
419
+ })();
420
+ }
421
+
422
+ // index.vue
423
+ const Page = createPage();
424
+ const { page, select } = Page;
425
+ ```
426
+
427
+ **说明**:
428
+
429
+ - ✅ Page Hook 内置分页状态管理
430
+ - ✅ `select()` 方法自动读取 page 状态
431
+ - ✅ 减少手动管理分页的代码
432
+
433
+ ---
434
+
435
+ ## 🎯 真实项目示例
436
+
437
+ ### 示例 1:内贸订单列表页
438
+
439
+ **路径**: `src/views/sale/.wl-skills/templates/domestic-trade-order/index.vue`
440
+
441
+ ```vue
442
+ <jh-pagination
443
+ v-show="page.total && page.total > 0"
444
+ :total="page.total || 0"
445
+ v-model:currentPage="page.current"
446
+ v-model:pageSize="page.size"
447
+ @current-change="select"
448
+ @size-change="select"
449
+ />
450
+ ```
451
+
452
+ ### 示例 2:新增编辑页项次分页
453
+
454
+ **路径**: `src/views/sale/.wl-skills/templates/add-.wl-skills/templates/index.vue`
455
+
456
+ ```vue
457
+ <jh-pagination
458
+ v-show="itemTotal && itemTotal > 0"
459
+ :total="itemTotal || 0"
460
+ v-model:currentPage="currentPage"
461
+ v-model:pageSize="pageSize"
462
+ @current-change="refreshItemData"
463
+ @size-change="refreshItemData"
464
+ />
465
+ ```
466
+
467
+ ---
468
+
469
+ ## ⚠️ 注意事项
470
+
471
+ 1. **组件来自远程包**
472
+
473
+ - 组件由 `@jhlc/common-core` 提供
474
+ - 已全局注册,无需手动导入
475
+ - 升级远程包时注意版本兼容性
476
+
477
+ 2. **页码从 1 开始**
478
+
479
+ - `currentPage` 最小值为 1
480
+ - 后端接口通常也是从 1 开始
481
+
482
+ 3. **total 必须准确**
483
+
484
+ - `total` 应该是数据总数,不是当前页数据量
485
+ - 后端通常返回 `{ records: [], total: 100 }`
486
+
487
+ 4. **事件处理**
488
+
489
+ - `current-change` 在页码变化时触发
490
+ - `size-change` 在页大小变化时触发
491
+ - 两个事件通常调用同一个刷新方法
492
+
493
+ 5. **样式定制**
494
+ - 如需特殊样式,可通过 CSS 覆盖
495
+ - 不要修改远程组件源码
496
+
497
+ ---
498
+
499
+ ## 🚀 快速开始
500
+
501
+ 1. **在列表页使用**:复制"场景 1"代码
502
+ 2. **在详情页使用**:复制"场景 3"代码
503
+ 3. **前端分页**:复制"场景 2"代码
504
+
505
+ **推荐作为项目统一的分页组件使用!**