@agile-team/wl-skills-kit 2.11.1 → 2.11.3

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 (91) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +38 -21
  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/docs/validate-exempt.md +113 -0
  7. package/files/.wl-skills/guides/architecture.md +1 -1
  8. package/files/.wl-skills/skills/_compat/headers/cursor-mdc.txt +1 -1
  9. package/files/.wl-skills/skills/_compat/headers/kiro.txt +1 -1
  10. package/files/.wl-skills/skills/_compat/headers/trae.txt +1 -1
  11. package/files/.wl-skills/skills/core/convention-audit/SKILL.md +3 -3
  12. package/files/.wl-skills/skills/core/spec-doc-parse/SKILL.md +332 -332
  13. package/files/.wl-skills/skills/core/spec-doc-parse/USAGE.md +97 -97
  14. package/files/.wl-skills/skills/sync/permission-sync/USAGE.md +107 -107
  15. package/files/.wl-skills/src/components/global/C_ParentView/index.vue +3 -3
  16. package/files/.wl-skills/src/components/global/C_RightToolbar/index.vue +157 -157
  17. package/files/.wl-skills/src/components/global/C_SvgIcon/index.vue +31 -31
  18. package/files/.wl-skills/src/components/global/C_SvgIcon/svgicon.js +10 -10
  19. package/files/.wl-skills/src/components/global/C_TagStatus/README.md +264 -264
  20. package/files/.wl-skills/src/components/global/C_TagStatus/config.ts +192 -192
  21. package/files/.wl-skills/src/components/global/C_TagStatus/index.vue +106 -106
  22. package/files/.wl-skills/src/components/global/C_TagStatus/types.ts +64 -64
  23. package/files/.wl-skills/src/components/global/C_Tree/README.md +153 -153
  24. package/files/.wl-skills/src/components/global/C_Tree/index.scss +42 -42
  25. package/files/.wl-skills/src/components/global/C_Tree/index.vue +78 -78
  26. package/files/.wl-skills/src/components/global/C_Tree/types.ts +59 -59
  27. package/files/.wl-skills/src/components/local/c_formModal/README.md +235 -235
  28. package/files/.wl-skills/src/components/local/c_formModal/data.ts +95 -95
  29. package/files/.wl-skills/src/components/local/c_formModal/index.scss +8 -8
  30. package/files/.wl-skills/src/components/local/c_formModal/index.vue +107 -107
  31. package/files/.wl-skills/src/components/local/c_formSections/data.ts +175 -175
  32. package/files/.wl-skills/src/components/local/c_formSections/index.scss +280 -280
  33. package/files/.wl-skills/src/components/local/c_formSections/index.vue +429 -429
  34. package/files/.wl-skills/src/components/local/c_listModal/data.ts +41 -41
  35. package/files/.wl-skills/src/components/local/c_listModal/index.vue +136 -136
  36. package/files/.wl-skills/src/components/local/c_spliterTitle/index.scss +25 -25
  37. package/files/.wl-skills/src/components/local/c_spliterTitle/index.vue +21 -21
  38. package/files/.wl-skills/src/components/remote/AGGrid/README.md +530 -530
  39. package/files/.wl-skills/src/components/remote/BaseForm/README.md +508 -508
  40. package/files/.wl-skills/src/components/remote/BaseQuery/README.md +865 -865
  41. package/files/.wl-skills/src/components/remote/BaseTable/README.md +941 -941
  42. package/files/.wl-skills/src/components/remote/BaseToolbar/README.md +496 -496
  43. package/files/.wl-skills/src/types/page.ts +24 -24
  44. package/files/.wl-skills/standards/04-coding-basics.md +39 -1
  45. package/files/.wl-skills/standards/09-typescript.md +26 -3
  46. package/files/.wl-skills/standards/12-base-table.md +56 -4
  47. package/files/.wl-skills/standards/13-platform-components.md +1 -0
  48. package/files/.wl-skills/standards/index.md +2 -2
  49. package/files/.wl-skills/templates/README.md +44 -44
  50. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/api.md +54 -54
  51. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -346
  52. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -1
  53. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -28
  54. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -115
  55. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -44
  56. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -43
  57. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -338
  58. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -1
  59. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -28
  60. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -115
  61. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -44
  62. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -43
  63. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/api.md +88 -88
  64. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/data.ts +601 -601
  65. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.scss +1 -1
  66. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.vue +64 -64
  67. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/api.md +67 -67
  68. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/data.ts +286 -286
  69. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.scss +139 -139
  70. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.vue +318 -318
  71. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -98
  72. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -543
  73. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -1
  74. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -52
  75. package/files/.wl-skills/templates/sale/demo/add-demo/data.ts +518 -518
  76. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/data.ts +524 -524
  77. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.scss +154 -154
  78. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.vue +117 -117
  79. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/data.ts +308 -308
  80. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.scss +99 -99
  81. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.vue +77 -77
  82. package/files/.wl-skills/templates/sale/demo/heat-batch-return/data.ts +367 -367
  83. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.scss +100 -100
  84. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.vue +170 -170
  85. package/files/.wl-skills/templates/sale/demo/heat-batch-return/meltDialog.vue +320 -320
  86. package/files/.wl-skills/templates/sale/demo/metallurgical-spec/data.ts +824 -824
  87. package/lib/ast-rules.js +395 -12
  88. package/mcp/config.js +46 -46
  89. package/mcp/registry.js +6 -1
  90. package/mcp/tools/projectTools.js +9 -1
  91. package/package.json +2 -2
@@ -1,865 +1,865 @@
1
- # BaseQuery 查询组件
2
-
3
- > 来源:`@jhlc/common-core` 远程组件
4
-
5
- BaseQuery 是一个功能强大的查询条件组件,支持多列布局、条件展开收起、自动查询、批量筛选等功能。适用于列表页的搜索条件区域。
6
-
7
- ## 📦 导入方式
8
-
9
- ```typescript
10
- // 全局注册(已在项目中配置)
11
- // 直接使用 <BaseQuery /> 即可
12
-
13
- // 类型导入
14
- import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
15
- ```
16
-
17
- ## 🚀 基本用法
18
-
19
- ```vue
20
- <template>
21
- <BaseQuery
22
- :form="queryParam"
23
- :items="queryItems"
24
- @select="handleSearch"
25
- @reset="handleReset"
26
- />
27
- </template>
28
-
29
- <script setup lang="ts">
30
- import { reactive, computed } from "vue";
31
-
32
- const queryParam = reactive({
33
- orderNo: "",
34
- customerName: "",
35
- status: "",
36
- startDate: "",
37
- endDate: ""
38
- });
39
-
40
- const queryItems = computed(() => [
41
- {
42
- name: "orderNo",
43
- label: "订单号",
44
- placeholder: "请输入订单号"
45
- },
46
- {
47
- name: "customerName",
48
- label: "客户名称",
49
- placeholder: "请输入客户名称"
50
- },
51
- {
52
- name: "status",
53
- label: "状态",
54
- logicType: "dict",
55
- logicValue: "ORDER_STATUS"
56
- },
57
- {
58
- type: "range",
59
- label: "日期范围",
60
- startName: "startDate",
61
- endName: "endDate",
62
- logicType: "date"
63
- }
64
- ]);
65
-
66
- const handleSearch = () => {
67
- console.log("查询条件:", queryParam);
68
- // 执行查询
69
- };
70
-
71
- const handleReset = () => {
72
- console.log("重置查询");
73
- };
74
- </script>
75
- ```
76
-
77
- ---
78
-
79
- ## 📋 Props 属性
80
-
81
- | 属性名 | 类型 | 默认值 | 说明 |
82
- | ---------------- | -------------------------------- | ------- | ---------------------- |
83
- | `form` | `Object` | - | 查询表单数据对象 |
84
- | `items` | `BaseQueryItemDesc[]` | `[]` | 查询项配置数组 |
85
- | `columns` | `4 \| 5 \| 6 \| 7 \| 8 \| 9` | `4` | 列数 |
86
- | `labelWidth` | `string` | - | 标签宽度 |
87
- | `size` | `'small' \| 'default' \| 'large'`| `''` | 表单尺寸 |
88
- | `spaceX` | `number` | - | 水平间距 |
89
- | `spaceY` | `number` | - | 垂直间距 |
90
- | `suppressExpand` | `boolean` | `false` | 禁止展开收起 |
91
- | `autoSelect` | `boolean` | `true` | 值变化时自动触发查询 |
92
- | `button` | `boolean` | `true` | 是否显示查询/重置按钮 |
93
- | `tools` | `ActionButtonDesc[]` | - | 自定义按钮 |
94
- | `class` | `Array \| String \| Object` | - | 自定义类名 |
95
- | `classnames` | `Array` | - | 自定义类名数组 |
96
-
97
- ---
98
-
99
- ## 📋 Events 事件
100
-
101
- | 事件名 | 参数 | 说明 |
102
- | -------- | ---- | ------------------ |
103
- | `select` | - | 点击查询按钮时触发 |
104
- | `reset` | - | 点击重置按钮时触发 |
105
-
106
- ---
107
-
108
- ## 📋 Expose 方法 (通过 ref 调用)
109
-
110
- | 方法名 | 参数 | 返回值 | 说明 |
111
- | ----------------- | ---- | ------ | ------------ |
112
- | `setDefaultValue` | - | - | 设置默认值 |
113
- | `resetQuery` | - | - | 重置查询条件 |
114
-
115
- ---
116
-
117
- ## 📋 查询项配置 BaseQueryItemDesc
118
-
119
- ### 基础属性
120
-
121
- ```typescript
122
- interface BaseQueryItemDesc<T = any> {
123
- // 字段名
124
- name: string;
125
- // 标签文本
126
- label: string;
127
- // 占位提示
128
- placeholder?: string;
129
- // 是否必填
130
- required?: boolean;
131
- // 是否禁用
132
- disabled?: boolean | ((form: T) => boolean);
133
- // 是否可清空
134
- clearable?: boolean;
135
- // 显示冒号
136
- showColon?: boolean;
137
- // 栅格数
138
- span?: number;
139
- // 宽度百分比
140
- widthScale?: number;
141
- // 是否显示
142
- show?: () => boolean;
143
- }
144
- ```
145
-
146
- ### 逻辑数据类型
147
-
148
- ```typescript
149
- // 字典类型 - 下拉选择
150
- {
151
- name: "status",
152
- label: "状态",
153
- logicType: "dict",
154
- logicValue: "ORDER_STATUS"
155
- }
156
-
157
- // 日期类型
158
- {
159
- name: "createDate",
160
- label: "创建日期",
161
- logicType: "date"
162
- }
163
-
164
- // 月份类型
165
- {
166
- name: "month",
167
- label: "月份",
168
- logicType: "month",
169
- dateFormat: "YYYY-MM"
170
- }
171
-
172
- // 日期时间
173
- {
174
- name: "createTime",
175
- label: "创建时间",
176
- logicType: "datetime"
177
- }
178
-
179
- // 用户选择
180
- {
181
- name: "userId",
182
- label: "负责人",
183
- logicType: "user"
184
- }
185
-
186
- // 部门选择
187
- {
188
- name: "deptId",
189
- label: "部门",
190
- logicType: "dept"
191
- }
192
- ```
193
-
194
- ### 范围查询
195
-
196
- ```typescript
197
- {
198
- type: "range",
199
- label: "日期范围",
200
- startName: "startDate",
201
- endName: "endDate",
202
- logicType: "date",
203
- rangeSeparator: "至",
204
- // 默认最近7天
205
- defaultValue: "recentDay7"
206
- }
207
-
208
- {
209
- type: "range",
210
- label: "金额范围",
211
- startName: "minAmount",
212
- endName: "maxAmount",
213
- logicType: "number",
214
- startFormItem: {
215
- placeholder: "最小金额"
216
- },
217
- endFormItem: {
218
- placeholder: "最大金额"
219
- }
220
- }
221
- ```
222
-
223
- ### 默认值配置
224
-
225
- ```typescript
226
- // 静态默认值
227
- {
228
- name: "status",
229
- label: "状态",
230
- defaultValue: "1"
231
- }
232
-
233
- // 动态默认值
234
- {
235
- name: "createDate",
236
- label: "创建日期",
237
- logicType: "date",
238
- defaultValue: "currentDay" // 当天
239
- }
240
-
241
- // 日期范围默认值
242
- {
243
- type: "range",
244
- label: "日期",
245
- startName: "startDate",
246
- endName: "endDate",
247
- defaultValue: "recentDay7" // 最近7天
248
- }
249
-
250
- // 异步默认值
251
- {
252
- name: "deptId",
253
- label: "部门",
254
- defaultValue: async () => {
255
- // 异步获取默认值
256
- return await getCurrentUserDept();
257
- }
258
- }
259
- ```
260
-
261
- **支持的默认值类型:**
262
-
263
- | 值 | 说明 |
264
- | ------------------------------- | ----------------------- |
265
- | `currentDay` | 当天 |
266
- | `currentMonth` | 当月 |
267
- | `currentYear` | 当年 |
268
- | `currentDept` | 当前部门 |
269
- | `recentDay3` | 最近 3 天 |
270
- | `recentDay7` | 最近 7 天 |
271
- | `recentDay30` | 最近 30 天 |
272
- | `rangeDatetimeToday` | 当天时间范围 |
273
- | `rangeDayCurrentMonth1ToToday` | 当月 1 号到今天 |
274
-
275
- ### 自动查询控制
276
-
277
- ```typescript
278
- // 全局控制:值变化时自动查询
279
- <BaseQuery :autoSelect="true" />
280
-
281
- // 单项控制:该字段值变化时不自动查询
282
- {
283
- name: "keyword",
284
- label: "关键字",
285
- autoSelect: false // 输入完成后手动点击查询
286
- }
287
- ```
288
-
289
- ### 批量筛选
290
-
291
- ```typescript
292
- {
293
- name: "orderNo",
294
- label: "订单号",
295
- multiQuery: true, // 开启批量筛选,支持粘贴多个值
296
- placeholder: "支持批量筛选"
297
- }
298
- ```
299
-
300
- ### 固定查询条件
301
-
302
- ```typescript
303
- {
304
- name: "companyId",
305
- label: "公司",
306
- isFixValue: true, // 重置时不清空此字段
307
- show: () => false // 隐藏但参与查询
308
- }
309
- ```
310
-
311
- ### 自定义组件
312
-
313
- ```typescript
314
- // 方式一:使用 component
315
- {
316
- name: "customField",
317
- label: "自定义",
318
- component: (form) => ({
319
- tag: "el-cascader",
320
- props: {
321
- options: cascaderOptions,
322
- clearable: true
323
- }
324
- })
325
- }
326
-
327
- // 方式二:自定义属性
328
- {
329
- name: "amount",
330
- label: "金额",
331
- logicType: "number",
332
- customProps: (form) => ({
333
- min: 0,
334
- max: 999999,
335
- precision: 2
336
- })
337
- }
338
- ```
339
-
340
- ### 历史记录置顶
341
-
342
- ```typescript
343
- {
344
- name: "productCode",
345
- label: "产品编码",
346
- logicType: "dict",
347
- logicValue: "PRODUCT_CODE",
348
- historyTop: true // 最近选择的选项置顶显示
349
- }
350
- ```
351
-
352
- ---
353
-
354
- ## 💡 完整示例
355
-
356
- ### 标准查询区域
357
-
358
- ```vue
359
- <template>
360
- <BaseQuery
361
- ref="queryRef"
362
- :form="queryParam"
363
- :items="queryItems"
364
- :columns="4"
365
- @select="handleSearch"
366
- @reset="handleReset"
367
- />
368
- </template>
369
-
370
- <script setup lang="ts">
371
- import { ref, reactive, computed, onMounted } from "vue";
372
- import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
373
-
374
- const queryRef = ref();
375
-
376
- const queryParam = reactive({
377
- orderNo: "",
378
- customerName: "",
379
- status: "",
380
- startDate: "",
381
- endDate: "",
382
- productType: ""
383
- });
384
-
385
- const queryItems = computed<BaseQueryItemDesc[]>(() => [
386
- {
387
- name: "orderNo",
388
- label: "订单号",
389
- placeholder: "请输入订单号",
390
- multiQuery: true // 支持批量筛选
391
- },
392
- {
393
- name: "customerName",
394
- label: "客户名称",
395
- placeholder: "请输入客户名称"
396
- },
397
- {
398
- name: "status",
399
- label: "订单状态",
400
- logicType: "dict",
401
- logicValue: "ORDER_STATUS",
402
- clearable: true
403
- },
404
- {
405
- type: "range",
406
- label: "创建日期",
407
- startName: "startDate",
408
- endName: "endDate",
409
- logicType: "date",
410
- defaultValue: "recentDay7"
411
- },
412
- {
413
- name: "productType",
414
- label: "产品类型",
415
- logicType: "dict",
416
- logicValue: "PRODUCT_TYPE"
417
- }
418
- ]);
419
-
420
- const handleSearch = () => {
421
- console.log("查询条件:", queryParam);
422
- // 调用接口查询
423
- };
424
-
425
- const handleReset = () => {
426
- // 重置后自动触发查询
427
- handleSearch();
428
- };
429
-
430
- onMounted(() => {
431
- // 设置默认值后查询
432
- queryRef.value?.setDefaultValue();
433
- handleSearch();
434
- });
435
- </script>
436
- ```
437
-
438
- ### 带自定义按钮
439
-
440
- ```vue
441
- <template>
442
- <BaseQuery
443
- :form="queryParam"
444
- :items="queryItems"
445
- :tools="customTools"
446
- @select="handleSearch"
447
- @reset="handleReset"
448
- />
449
- </template>
450
-
451
- <script setup lang="ts">
452
- import { reactive, computed } from "vue";
453
-
454
- const queryParam = reactive({
455
- keyword: ""
456
- });
457
-
458
- const queryItems = computed(() => [
459
- {
460
- name: "keyword",
461
- label: "关键字",
462
- placeholder: "请输入关键字"
463
- }
464
- ]);
465
-
466
- const customTools = computed(() => [
467
- {
468
- name: "export",
469
- label: "导出",
470
- icon: "Download",
471
- onClick: () => {
472
- console.log("导出");
473
- }
474
- },
475
- {
476
- name: "import",
477
- label: "导入",
478
- icon: "Upload",
479
- onClick: () => {
480
- console.log("导入");
481
- }
482
- }
483
- ]);
484
-
485
- const handleSearch = () => {};
486
- const handleReset = () => {};
487
- </script>
488
- ```
489
-
490
- ---
491
-
492
- ## ⚠️ 注意事项
493
-
494
- 1. **范围类型需要设置 startName 和 endName**
495
-
496
- ```typescript
497
- {
498
- type: "range",
499
- startName: "startDate",
500
- endName: "endDate",
501
- logicType: "date"
502
- }
503
- ```
504
-
505
- 2. **autoSelect 默认为 true**
506
-
507
- - 值变化时会自动触发 select 事件
508
- - 如需手动控制,设置 `autoSelect: false`
509
-
510
- 3. **使用 computed 包装 items**
511
-
512
- ```typescript
513
- const queryItems = computed(() => [...]);
514
- ```
515
-
516
- 4. **默认值需要调用 setDefaultValue**
517
-
518
- ```typescript
519
- onMounted(() => {
520
- queryRef.value?.setDefaultValue();
521
- });
522
- ```
523
-
524
- 5. **isFixValue 字段重置时不清空**
525
-
526
- - 适用于隐藏的固定查询条件
527
-
528
- ---
529
-
530
- ## � 高级用法:联动查询
531
-
532
- ### 三级联动(省市区)示例
533
-
534
- BaseQuery 支持复杂的联动查询场景,通过 `customProps`、`disabled`、`autoSelect` 等配置实现多级联动。
535
-
536
- #### 方案一:使用级联选择器(推荐单字段存储)
537
-
538
- ```vue
539
- <template>
540
- <BaseQuery
541
- :form="queryParam"
542
- :items="queryItems"
543
- @select="handleSearch"
544
- />
545
- </template>
546
-
547
- <script setup lang="ts">
548
- import { reactive, computed } from "vue";
549
- import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
550
-
551
- // 省市区数据
552
- const regionOptions = [
553
- {
554
- value: '110000',
555
- label: '北京市',
556
- children: [
557
- { value: '110100', label: '市辖区', children: [
558
- { value: '110101', label: '东城区' },
559
- { value: '110102', label: '西城区' }
560
- ]}
561
- ]
562
- },
563
- // ... 更多数据
564
- ];
565
-
566
- const queryParam = reactive({
567
- region: [] // 存储 [省code, 市code, 区code]
568
- });
569
-
570
- const queryItems = computed<BaseQueryItemDesc[]>(() => [
571
- {
572
- name: "region",
573
- label: "省市区",
574
- component: (form) => ({
575
- tag: "el-cascader",
576
- props: {
577
- options: regionOptions,
578
- clearable: true,
579
- placeholder: "请选择省市区",
580
- onChange: (value) => {
581
- console.log("选择的省市区:", value);
582
- }
583
- }
584
- })
585
- }
586
- ]);
587
-
588
- const handleSearch = () => {
589
- console.log("查询条件:", queryParam);
590
- };
591
- </script>
592
- ```
593
-
594
- #### 方案二:分成3个独立字段实现联动查询
595
-
596
- 适用于需要分别存储省、市、区的场景,支持通过接口动态加载下级选项。
597
-
598
- ```vue
599
- <template>
600
- <BaseQuery
601
- :form="queryParam"
602
- :items="queryItems"
603
- :auto-select="false"
604
- @select="handleSearch"
605
- />
606
- </template>
607
-
608
- <script setup lang="ts">
609
- import { ref, reactive, computed } from "vue";
610
- import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
611
- import request from "@/utils/request";
612
-
613
- // 动态选项数据
614
- const cityOptions = ref([]);
615
- const districtOptions = ref([]);
616
-
617
- const queryParam = reactive({
618
- province: '',
619
- city: '',
620
- district: ''
621
- });
622
-
623
- const queryItems = computed<BaseQueryItemDesc[]>(() => [
624
- {
625
- name: "province",
626
- label: "省份",
627
- logicType: "dict",
628
- logicValue: "PROVINCE_LIST",
629
- placeholder: "请选择省份",
630
- autoSelect: false, // 不自动触发查询
631
- clearable: true,
632
- customProps: (form) => ({
633
- onChange: async (value: string) => {
634
- // 重置下级选项
635
- form.city = '';
636
- form.district = '';
637
- cityOptions.value = [];
638
- districtOptions.value = [];
639
-
640
- if (value) {
641
- // 调用接口查询城市列表
642
- try {
643
- const res = await request.get('/api/region/cities', {
644
- provinceCode: value
645
- });
646
- cityOptions.value = res.data || [];
647
- } catch (error) {
648
- console.error('查询城市失败:', error);
649
- }
650
- }
651
- }
652
- })
653
- },
654
- {
655
- name: "city",
656
- label: "城市",
657
- logicType: "dict",
658
- logicValue: "CITY_LIST",
659
- placeholder: "请先选择省份",
660
- disabled: (form) => !form.province, // 未选省份时禁用
661
- autoSelect: false,
662
- clearable: true,
663
- customProps: (form) => ({
664
- onChange: async (value: string) => {
665
- // 重置下级选项
666
- form.district = '';
667
- districtOptions.value = [];
668
-
669
- if (value) {
670
- // 调用接口查询区县列表
671
- try {
672
- const res = await request.get('/api/region/districts', {
673
- cityCode: value
674
- });
675
- districtOptions.value = res.data || [];
676
- } catch (error) {
677
- console.error('查询区县失败:', error);
678
- }
679
- }
680
- }
681
- })
682
- },
683
- {
684
- name: "district",
685
- label: "区县",
686
- logicType: "dict",
687
- logicValue: "DISTRICT_LIST",
688
- placeholder: "请先选择城市",
689
- disabled: (form) => !form.city, // 未选城市时禁用
690
- autoSelect: false, // 选完后手动点击查询按钮
691
- clearable: true
692
- }
693
- ]);
694
-
695
- const handleSearch = () => {
696
- console.log("查询条件:", queryParam);
697
- // 执行查询逻辑
698
- };
699
- </script>
700
- ```
701
-
702
- #### 方案三:其他业务联动(产品类别 → 产品型号)
703
-
704
- ```typescript
705
- const productModelOptions = ref([]);
706
-
707
- const queryItems = computed<BaseQueryItemDesc[]>(() => [
708
- {
709
- name: "productCategory",
710
- label: "产品类别",
711
- logicType: "dict",
712
- logicValue: "PRODUCT_CATEGORY",
713
- autoSelect: false,
714
- customProps: (form) => ({
715
- onChange: async (categoryId: string) => {
716
- // 清空产品型号
717
- form.productModel = '';
718
- productModelOptions.value = [];
719
-
720
- if (categoryId) {
721
- // 根据类别查询型号
722
- const res = await request.get('/api/products/models', {
723
- categoryId
724
- });
725
- productModelOptions.value = res.data;
726
- }
727
- }
728
- })
729
- },
730
- {
731
- name: "productModel",
732
- label: "产品型号",
733
- component: (form) => ({
734
- tag: "el-select",
735
- props: {
736
- options: productModelOptions.value,
737
- placeholder: form.productCategory ? "请选择产品型号" : "请先选择产品类别",
738
- disabled: !form.productCategory,
739
- clearable: true
740
- }
741
- })
742
- }
743
- ]);
744
- ```
745
-
746
- ### 联动查询关键配置项
747
-
748
- | 配置项 | 说明 | 示例 |
749
- |--------|------|------|
750
- | `autoSelect` | 控制值变化时是否自动触发查询 | `autoSelect: false` |
751
- | `disabled` | 动态禁用,支持函数 | `disabled: (form) => !form.province` |
752
- | `customProps` | 自定义属性和事件,可访问 form 对象 | `customProps: (form) => ({ onChange: ... })` |
753
- | `component` | 自定义组件 | `component: (form) => ({ tag: "el-cascader" })` |
754
- | `show` | 控制显示/隐藏 | `show: () => someCondition` |
755
- | `clearable` | 是否可清空 | `clearable: true` |
756
-
757
- ### 联动查询最佳实践
758
-
759
- 1. **设置 `autoSelect: false`**:避免每次联动变化都触发查询,让用户选完所有条件后手动点击查询
760
- 2. **使用 `disabled` 函数**:未选择上级时禁用下级,提升用户体验
761
- 3. **重置下级数据**:在上级 `onChange` 中清空下级的值和选项
762
- 4. **错误处理**:接口调用加 try-catch 处理异常
763
- 5. **动态 placeholder**:根据表单状态提示用户操作顺序
764
- 6. **使用 `computed` 包装 `items`**:确保选项数据变化时配置能响应式更新
765
-
766
- ---
767
-
768
- ## 🎯 实用技巧
769
-
770
- ### 隐藏的固定查询条件
771
-
772
- 某些场景下需要固定传递某些查询条件,但不希望在界面上显示:
773
-
774
- ```typescript
775
- {
776
- name: "companyId",
777
- label: "公司ID",
778
- defaultValue: "123456",
779
- isFixValue: true, // 重置时不清空
780
- show: () => false // 隐藏该字段
781
- }
782
- ```
783
-
784
- ### 异步获取默认值
785
-
786
- 从接口获取默认值(如当前用户的部门):
787
-
788
- ```typescript
789
- {
790
- name: "deptId",
791
- label: "部门",
792
- logicType: "dept",
793
- defaultValue: async () => {
794
- const res = await request.get('/api/user/currentDept');
795
- return res.data.deptId;
796
- }
797
- }
798
- ```
799
-
800
- ### 批量输入支持
801
-
802
- 支持粘贴多个值进行批量查询:
803
-
804
- ```typescript
805
- {
806
- name: "orderNos",
807
- label: "订单号",
808
- multiQuery: true,
809
- placeholder: "支持批量输入,多个值用逗号或换行分隔"
810
- }
811
- ```
812
-
813
- ### 动态控制字段显示
814
-
815
- 根据其他条件动态显示/隐藏字段:
816
-
817
- ```typescript
818
- {
819
- name: "detailField",
820
- label: "详细信息",
821
- show: () => queryParam.showDetail === true
822
- }
823
- ```
824
-
825
- ### 自定义查询按钮
826
-
827
- 添加自定义操作按钮:
828
-
829
- ```typescript
830
- const customTools = [
831
- {
832
- name: "export",
833
- label: "导出",
834
- icon: "Download",
835
- onClick: () => {
836
- // 导出逻辑
837
- }
838
- },
839
- {
840
- name: "advanced",
841
- label: "高级查询",
842
- icon: "Setting",
843
- onClick: () => {
844
- // 打开高级查询弹窗
845
- }
846
- }
847
- ];
848
- ```
849
-
850
- ```vue
851
- <BaseQuery
852
- :form="queryParam"
853
- :items="queryItems"
854
- :tools="customTools"
855
- @select="handleSearch"
856
- />
857
- ```
858
-
859
- ---
860
-
861
- ## �📚 相关文档
862
-
863
- - [BaseForm 表单组件](../BaseForm/README.md)
864
- - [BaseToolbar 工具栏组件](../BaseToolbar/README.md)
865
- - [BaseTable 表格组件](../BaseTable/README.md)
1
+ # BaseQuery 查询组件
2
+
3
+ > 来源:`@jhlc/common-core` 远程组件
4
+
5
+ BaseQuery 是一个功能强大的查询条件组件,支持多列布局、条件展开收起、自动查询、批量筛选等功能。适用于列表页的搜索条件区域。
6
+
7
+ ## 📦 导入方式
8
+
9
+ ```typescript
10
+ // 全局注册(已在项目中配置)
11
+ // 直接使用 <BaseQuery /> 即可
12
+
13
+ // 类型导入
14
+ import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
15
+ ```
16
+
17
+ ## 🚀 基本用法
18
+
19
+ ```vue
20
+ <template>
21
+ <BaseQuery
22
+ :form="queryParam"
23
+ :items="queryItems"
24
+ @select="handleSearch"
25
+ @reset="handleReset"
26
+ />
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import { reactive, computed } from "vue";
31
+
32
+ const queryParam = reactive({
33
+ orderNo: "",
34
+ customerName: "",
35
+ status: "",
36
+ startDate: "",
37
+ endDate: ""
38
+ });
39
+
40
+ const queryItems = computed(() => [
41
+ {
42
+ name: "orderNo",
43
+ label: "订单号",
44
+ placeholder: "请输入订单号"
45
+ },
46
+ {
47
+ name: "customerName",
48
+ label: "客户名称",
49
+ placeholder: "请输入客户名称"
50
+ },
51
+ {
52
+ name: "status",
53
+ label: "状态",
54
+ logicType: "dict",
55
+ logicValue: "ORDER_STATUS"
56
+ },
57
+ {
58
+ type: "range",
59
+ label: "日期范围",
60
+ startName: "startDate",
61
+ endName: "endDate",
62
+ logicType: "date"
63
+ }
64
+ ]);
65
+
66
+ const handleSearch = () => {
67
+ console.log("查询条件:", queryParam);
68
+ // 执行查询
69
+ };
70
+
71
+ const handleReset = () => {
72
+ console.log("重置查询");
73
+ };
74
+ </script>
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 📋 Props 属性
80
+
81
+ | 属性名 | 类型 | 默认值 | 说明 |
82
+ | ---------------- | -------------------------------- | ------- | ---------------------- |
83
+ | `form` | `Object` | - | 查询表单数据对象 |
84
+ | `items` | `BaseQueryItemDesc[]` | `[]` | 查询项配置数组 |
85
+ | `columns` | `4 \| 5 \| 6 \| 7 \| 8 \| 9` | `4` | 列数 |
86
+ | `labelWidth` | `string` | - | 标签宽度 |
87
+ | `size` | `'small' \| 'default' \| 'large'`| `''` | 表单尺寸 |
88
+ | `spaceX` | `number` | - | 水平间距 |
89
+ | `spaceY` | `number` | - | 垂直间距 |
90
+ | `suppressExpand` | `boolean` | `false` | 禁止展开收起 |
91
+ | `autoSelect` | `boolean` | `true` | 值变化时自动触发查询 |
92
+ | `button` | `boolean` | `true` | 是否显示查询/重置按钮 |
93
+ | `tools` | `ActionButtonDesc[]` | - | 自定义按钮 |
94
+ | `class` | `Array \| String \| Object` | - | 自定义类名 |
95
+ | `classnames` | `Array` | - | 自定义类名数组 |
96
+
97
+ ---
98
+
99
+ ## 📋 Events 事件
100
+
101
+ | 事件名 | 参数 | 说明 |
102
+ | -------- | ---- | ------------------ |
103
+ | `select` | - | 点击查询按钮时触发 |
104
+ | `reset` | - | 点击重置按钮时触发 |
105
+
106
+ ---
107
+
108
+ ## 📋 Expose 方法 (通过 ref 调用)
109
+
110
+ | 方法名 | 参数 | 返回值 | 说明 |
111
+ | ----------------- | ---- | ------ | ------------ |
112
+ | `setDefaultValue` | - | - | 设置默认值 |
113
+ | `resetQuery` | - | - | 重置查询条件 |
114
+
115
+ ---
116
+
117
+ ## 📋 查询项配置 BaseQueryItemDesc
118
+
119
+ ### 基础属性
120
+
121
+ ```typescript
122
+ interface BaseQueryItemDesc<T = any> {
123
+ // 字段名
124
+ name: string;
125
+ // 标签文本
126
+ label: string;
127
+ // 占位提示
128
+ placeholder?: string;
129
+ // 是否必填
130
+ required?: boolean;
131
+ // 是否禁用
132
+ disabled?: boolean | ((form: T) => boolean);
133
+ // 是否可清空
134
+ clearable?: boolean;
135
+ // 显示冒号
136
+ showColon?: boolean;
137
+ // 栅格数
138
+ span?: number;
139
+ // 宽度百分比
140
+ widthScale?: number;
141
+ // 是否显示
142
+ show?: () => boolean;
143
+ }
144
+ ```
145
+
146
+ ### 逻辑数据类型
147
+
148
+ ```typescript
149
+ // 字典类型 - 下拉选择
150
+ {
151
+ name: "status",
152
+ label: "状态",
153
+ logicType: "dict",
154
+ logicValue: "ORDER_STATUS"
155
+ }
156
+
157
+ // 日期类型
158
+ {
159
+ name: "createDate",
160
+ label: "创建日期",
161
+ logicType: "date"
162
+ }
163
+
164
+ // 月份类型
165
+ {
166
+ name: "month",
167
+ label: "月份",
168
+ logicType: "month",
169
+ dateFormat: "YYYY-MM"
170
+ }
171
+
172
+ // 日期时间
173
+ {
174
+ name: "createTime",
175
+ label: "创建时间",
176
+ logicType: "datetime"
177
+ }
178
+
179
+ // 用户选择
180
+ {
181
+ name: "userId",
182
+ label: "负责人",
183
+ logicType: "user"
184
+ }
185
+
186
+ // 部门选择
187
+ {
188
+ name: "deptId",
189
+ label: "部门",
190
+ logicType: "dept"
191
+ }
192
+ ```
193
+
194
+ ### 范围查询
195
+
196
+ ```typescript
197
+ {
198
+ type: "range",
199
+ label: "日期范围",
200
+ startName: "startDate",
201
+ endName: "endDate",
202
+ logicType: "date",
203
+ rangeSeparator: "至",
204
+ // 默认最近7天
205
+ defaultValue: "recentDay7"
206
+ }
207
+
208
+ {
209
+ type: "range",
210
+ label: "金额范围",
211
+ startName: "minAmount",
212
+ endName: "maxAmount",
213
+ logicType: "number",
214
+ startFormItem: {
215
+ placeholder: "最小金额"
216
+ },
217
+ endFormItem: {
218
+ placeholder: "最大金额"
219
+ }
220
+ }
221
+ ```
222
+
223
+ ### 默认值配置
224
+
225
+ ```typescript
226
+ // 静态默认值
227
+ {
228
+ name: "status",
229
+ label: "状态",
230
+ defaultValue: "1"
231
+ }
232
+
233
+ // 动态默认值
234
+ {
235
+ name: "createDate",
236
+ label: "创建日期",
237
+ logicType: "date",
238
+ defaultValue: "currentDay" // 当天
239
+ }
240
+
241
+ // 日期范围默认值
242
+ {
243
+ type: "range",
244
+ label: "日期",
245
+ startName: "startDate",
246
+ endName: "endDate",
247
+ defaultValue: "recentDay7" // 最近7天
248
+ }
249
+
250
+ // 异步默认值
251
+ {
252
+ name: "deptId",
253
+ label: "部门",
254
+ defaultValue: async () => {
255
+ // 异步获取默认值
256
+ return await getCurrentUserDept();
257
+ }
258
+ }
259
+ ```
260
+
261
+ **支持的默认值类型:**
262
+
263
+ | 值 | 说明 |
264
+ | ------------------------------- | ----------------------- |
265
+ | `currentDay` | 当天 |
266
+ | `currentMonth` | 当月 |
267
+ | `currentYear` | 当年 |
268
+ | `currentDept` | 当前部门 |
269
+ | `recentDay3` | 最近 3 天 |
270
+ | `recentDay7` | 最近 7 天 |
271
+ | `recentDay30` | 最近 30 天 |
272
+ | `rangeDatetimeToday` | 当天时间范围 |
273
+ | `rangeDayCurrentMonth1ToToday` | 当月 1 号到今天 |
274
+
275
+ ### 自动查询控制
276
+
277
+ ```typescript
278
+ // 全局控制:值变化时自动查询
279
+ <BaseQuery :autoSelect="true" />
280
+
281
+ // 单项控制:该字段值变化时不自动查询
282
+ {
283
+ name: "keyword",
284
+ label: "关键字",
285
+ autoSelect: false // 输入完成后手动点击查询
286
+ }
287
+ ```
288
+
289
+ ### 批量筛选
290
+
291
+ ```typescript
292
+ {
293
+ name: "orderNo",
294
+ label: "订单号",
295
+ multiQuery: true, // 开启批量筛选,支持粘贴多个值
296
+ placeholder: "支持批量筛选"
297
+ }
298
+ ```
299
+
300
+ ### 固定查询条件
301
+
302
+ ```typescript
303
+ {
304
+ name: "companyId",
305
+ label: "公司",
306
+ isFixValue: true, // 重置时不清空此字段
307
+ show: () => false // 隐藏但参与查询
308
+ }
309
+ ```
310
+
311
+ ### 自定义组件
312
+
313
+ ```typescript
314
+ // 方式一:使用 component
315
+ {
316
+ name: "customField",
317
+ label: "自定义",
318
+ component: (form) => ({
319
+ tag: "el-cascader",
320
+ props: {
321
+ options: cascaderOptions,
322
+ clearable: true
323
+ }
324
+ })
325
+ }
326
+
327
+ // 方式二:自定义属性
328
+ {
329
+ name: "amount",
330
+ label: "金额",
331
+ logicType: "number",
332
+ customProps: (form) => ({
333
+ min: 0,
334
+ max: 999999,
335
+ precision: 2
336
+ })
337
+ }
338
+ ```
339
+
340
+ ### 历史记录置顶
341
+
342
+ ```typescript
343
+ {
344
+ name: "productCode",
345
+ label: "产品编码",
346
+ logicType: "dict",
347
+ logicValue: "PRODUCT_CODE",
348
+ historyTop: true // 最近选择的选项置顶显示
349
+ }
350
+ ```
351
+
352
+ ---
353
+
354
+ ## 💡 完整示例
355
+
356
+ ### 标准查询区域
357
+
358
+ ```vue
359
+ <template>
360
+ <BaseQuery
361
+ ref="queryRef"
362
+ :form="queryParam"
363
+ :items="queryItems"
364
+ :columns="4"
365
+ @select="handleSearch"
366
+ @reset="handleReset"
367
+ />
368
+ </template>
369
+
370
+ <script setup lang="ts">
371
+ import { ref, reactive, computed, onMounted } from "vue";
372
+ import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
373
+
374
+ const queryRef = ref();
375
+
376
+ const queryParam = reactive({
377
+ orderNo: "",
378
+ customerName: "",
379
+ status: "",
380
+ startDate: "",
381
+ endDate: "",
382
+ productType: ""
383
+ });
384
+
385
+ const queryItems = computed<BaseQueryItemDesc[]>(() => [
386
+ {
387
+ name: "orderNo",
388
+ label: "订单号",
389
+ placeholder: "请输入订单号",
390
+ multiQuery: true // 支持批量筛选
391
+ },
392
+ {
393
+ name: "customerName",
394
+ label: "客户名称",
395
+ placeholder: "请输入客户名称"
396
+ },
397
+ {
398
+ name: "status",
399
+ label: "订单状态",
400
+ logicType: "dict",
401
+ logicValue: "ORDER_STATUS",
402
+ clearable: true
403
+ },
404
+ {
405
+ type: "range",
406
+ label: "创建日期",
407
+ startName: "startDate",
408
+ endName: "endDate",
409
+ logicType: "date",
410
+ defaultValue: "recentDay7"
411
+ },
412
+ {
413
+ name: "productType",
414
+ label: "产品类型",
415
+ logicType: "dict",
416
+ logicValue: "PRODUCT_TYPE"
417
+ }
418
+ ]);
419
+
420
+ const handleSearch = () => {
421
+ console.log("查询条件:", queryParam);
422
+ // 调用接口查询
423
+ };
424
+
425
+ const handleReset = () => {
426
+ // 重置后自动触发查询
427
+ handleSearch();
428
+ };
429
+
430
+ onMounted(() => {
431
+ // 设置默认值后查询
432
+ queryRef.value?.setDefaultValue();
433
+ handleSearch();
434
+ });
435
+ </script>
436
+ ```
437
+
438
+ ### 带自定义按钮
439
+
440
+ ```vue
441
+ <template>
442
+ <BaseQuery
443
+ :form="queryParam"
444
+ :items="queryItems"
445
+ :tools="customTools"
446
+ @select="handleSearch"
447
+ @reset="handleReset"
448
+ />
449
+ </template>
450
+
451
+ <script setup lang="ts">
452
+ import { reactive, computed } from "vue";
453
+
454
+ const queryParam = reactive({
455
+ keyword: ""
456
+ });
457
+
458
+ const queryItems = computed(() => [
459
+ {
460
+ name: "keyword",
461
+ label: "关键字",
462
+ placeholder: "请输入关键字"
463
+ }
464
+ ]);
465
+
466
+ const customTools = computed(() => [
467
+ {
468
+ name: "export",
469
+ label: "导出",
470
+ icon: "Download",
471
+ onClick: () => {
472
+ console.log("导出");
473
+ }
474
+ },
475
+ {
476
+ name: "import",
477
+ label: "导入",
478
+ icon: "Upload",
479
+ onClick: () => {
480
+ console.log("导入");
481
+ }
482
+ }
483
+ ]);
484
+
485
+ const handleSearch = () => {};
486
+ const handleReset = () => {};
487
+ </script>
488
+ ```
489
+
490
+ ---
491
+
492
+ ## ⚠️ 注意事项
493
+
494
+ 1. **范围类型需要设置 startName 和 endName**
495
+
496
+ ```typescript
497
+ {
498
+ type: "range",
499
+ startName: "startDate",
500
+ endName: "endDate",
501
+ logicType: "date"
502
+ }
503
+ ```
504
+
505
+ 2. **autoSelect 默认为 true**
506
+
507
+ - 值变化时会自动触发 select 事件
508
+ - 如需手动控制,设置 `autoSelect: false`
509
+
510
+ 3. **使用 computed 包装 items**
511
+
512
+ ```typescript
513
+ const queryItems = computed(() => [...]);
514
+ ```
515
+
516
+ 4. **默认值需要调用 setDefaultValue**
517
+
518
+ ```typescript
519
+ onMounted(() => {
520
+ queryRef.value?.setDefaultValue();
521
+ });
522
+ ```
523
+
524
+ 5. **isFixValue 字段重置时不清空**
525
+
526
+ - 适用于隐藏的固定查询条件
527
+
528
+ ---
529
+
530
+ ## � 高级用法:联动查询
531
+
532
+ ### 三级联动(省市区)示例
533
+
534
+ BaseQuery 支持复杂的联动查询场景,通过 `customProps`、`disabled`、`autoSelect` 等配置实现多级联动。
535
+
536
+ #### 方案一:使用级联选择器(推荐单字段存储)
537
+
538
+ ```vue
539
+ <template>
540
+ <BaseQuery
541
+ :form="queryParam"
542
+ :items="queryItems"
543
+ @select="handleSearch"
544
+ />
545
+ </template>
546
+
547
+ <script setup lang="ts">
548
+ import { reactive, computed } from "vue";
549
+ import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
550
+
551
+ // 省市区数据
552
+ const regionOptions = [
553
+ {
554
+ value: '110000',
555
+ label: '北京市',
556
+ children: [
557
+ { value: '110100', label: '市辖区', children: [
558
+ { value: '110101', label: '东城区' },
559
+ { value: '110102', label: '西城区' }
560
+ ]}
561
+ ]
562
+ },
563
+ // ... 更多数据
564
+ ];
565
+
566
+ const queryParam = reactive({
567
+ region: [] // 存储 [省code, 市code, 区code]
568
+ });
569
+
570
+ const queryItems = computed<BaseQueryItemDesc[]>(() => [
571
+ {
572
+ name: "region",
573
+ label: "省市区",
574
+ component: (form) => ({
575
+ tag: "el-cascader",
576
+ props: {
577
+ options: regionOptions,
578
+ clearable: true,
579
+ placeholder: "请选择省市区",
580
+ onChange: (value) => {
581
+ console.log("选择的省市区:", value);
582
+ }
583
+ }
584
+ })
585
+ }
586
+ ]);
587
+
588
+ const handleSearch = () => {
589
+ console.log("查询条件:", queryParam);
590
+ };
591
+ </script>
592
+ ```
593
+
594
+ #### 方案二:分成3个独立字段实现联动查询
595
+
596
+ 适用于需要分别存储省、市、区的场景,支持通过接口动态加载下级选项。
597
+
598
+ ```vue
599
+ <template>
600
+ <BaseQuery
601
+ :form="queryParam"
602
+ :items="queryItems"
603
+ :auto-select="false"
604
+ @select="handleSearch"
605
+ />
606
+ </template>
607
+
608
+ <script setup lang="ts">
609
+ import { ref, reactive, computed } from "vue";
610
+ import type { BaseQueryItemDesc } from "@jhlc/common-core/.wl-skills/src/components/form/base-query/type";
611
+ import request from "@/utils/request";
612
+
613
+ // 动态选项数据
614
+ const cityOptions = ref([]);
615
+ const districtOptions = ref([]);
616
+
617
+ const queryParam = reactive({
618
+ province: '',
619
+ city: '',
620
+ district: ''
621
+ });
622
+
623
+ const queryItems = computed<BaseQueryItemDesc[]>(() => [
624
+ {
625
+ name: "province",
626
+ label: "省份",
627
+ logicType: "dict",
628
+ logicValue: "PROVINCE_LIST",
629
+ placeholder: "请选择省份",
630
+ autoSelect: false, // 不自动触发查询
631
+ clearable: true,
632
+ customProps: (form) => ({
633
+ onChange: async (value: string) => {
634
+ // 重置下级选项
635
+ form.city = '';
636
+ form.district = '';
637
+ cityOptions.value = [];
638
+ districtOptions.value = [];
639
+
640
+ if (value) {
641
+ // 调用接口查询城市列表
642
+ try {
643
+ const res = await request.get('/api/region/cities', {
644
+ provinceCode: value
645
+ });
646
+ cityOptions.value = res.data || [];
647
+ } catch (error) {
648
+ console.error('查询城市失败:', error);
649
+ }
650
+ }
651
+ }
652
+ })
653
+ },
654
+ {
655
+ name: "city",
656
+ label: "城市",
657
+ logicType: "dict",
658
+ logicValue: "CITY_LIST",
659
+ placeholder: "请先选择省份",
660
+ disabled: (form) => !form.province, // 未选省份时禁用
661
+ autoSelect: false,
662
+ clearable: true,
663
+ customProps: (form) => ({
664
+ onChange: async (value: string) => {
665
+ // 重置下级选项
666
+ form.district = '';
667
+ districtOptions.value = [];
668
+
669
+ if (value) {
670
+ // 调用接口查询区县列表
671
+ try {
672
+ const res = await request.get('/api/region/districts', {
673
+ cityCode: value
674
+ });
675
+ districtOptions.value = res.data || [];
676
+ } catch (error) {
677
+ console.error('查询区县失败:', error);
678
+ }
679
+ }
680
+ }
681
+ })
682
+ },
683
+ {
684
+ name: "district",
685
+ label: "区县",
686
+ logicType: "dict",
687
+ logicValue: "DISTRICT_LIST",
688
+ placeholder: "请先选择城市",
689
+ disabled: (form) => !form.city, // 未选城市时禁用
690
+ autoSelect: false, // 选完后手动点击查询按钮
691
+ clearable: true
692
+ }
693
+ ]);
694
+
695
+ const handleSearch = () => {
696
+ console.log("查询条件:", queryParam);
697
+ // 执行查询逻辑
698
+ };
699
+ </script>
700
+ ```
701
+
702
+ #### 方案三:其他业务联动(产品类别 → 产品型号)
703
+
704
+ ```typescript
705
+ const productModelOptions = ref([]);
706
+
707
+ const queryItems = computed<BaseQueryItemDesc[]>(() => [
708
+ {
709
+ name: "productCategory",
710
+ label: "产品类别",
711
+ logicType: "dict",
712
+ logicValue: "PRODUCT_CATEGORY",
713
+ autoSelect: false,
714
+ customProps: (form) => ({
715
+ onChange: async (categoryId: string) => {
716
+ // 清空产品型号
717
+ form.productModel = '';
718
+ productModelOptions.value = [];
719
+
720
+ if (categoryId) {
721
+ // 根据类别查询型号
722
+ const res = await request.get('/api/products/models', {
723
+ categoryId
724
+ });
725
+ productModelOptions.value = res.data;
726
+ }
727
+ }
728
+ })
729
+ },
730
+ {
731
+ name: "productModel",
732
+ label: "产品型号",
733
+ component: (form) => ({
734
+ tag: "el-select",
735
+ props: {
736
+ options: productModelOptions.value,
737
+ placeholder: form.productCategory ? "请选择产品型号" : "请先选择产品类别",
738
+ disabled: !form.productCategory,
739
+ clearable: true
740
+ }
741
+ })
742
+ }
743
+ ]);
744
+ ```
745
+
746
+ ### 联动查询关键配置项
747
+
748
+ | 配置项 | 说明 | 示例 |
749
+ |--------|------|------|
750
+ | `autoSelect` | 控制值变化时是否自动触发查询 | `autoSelect: false` |
751
+ | `disabled` | 动态禁用,支持函数 | `disabled: (form) => !form.province` |
752
+ | `customProps` | 自定义属性和事件,可访问 form 对象 | `customProps: (form) => ({ onChange: ... })` |
753
+ | `component` | 自定义组件 | `component: (form) => ({ tag: "el-cascader" })` |
754
+ | `show` | 控制显示/隐藏 | `show: () => someCondition` |
755
+ | `clearable` | 是否可清空 | `clearable: true` |
756
+
757
+ ### 联动查询最佳实践
758
+
759
+ 1. **设置 `autoSelect: false`**:避免每次联动变化都触发查询,让用户选完所有条件后手动点击查询
760
+ 2. **使用 `disabled` 函数**:未选择上级时禁用下级,提升用户体验
761
+ 3. **重置下级数据**:在上级 `onChange` 中清空下级的值和选项
762
+ 4. **错误处理**:接口调用加 try-catch 处理异常
763
+ 5. **动态 placeholder**:根据表单状态提示用户操作顺序
764
+ 6. **使用 `computed` 包装 `items`**:确保选项数据变化时配置能响应式更新
765
+
766
+ ---
767
+
768
+ ## 🎯 实用技巧
769
+
770
+ ### 隐藏的固定查询条件
771
+
772
+ 某些场景下需要固定传递某些查询条件,但不希望在界面上显示:
773
+
774
+ ```typescript
775
+ {
776
+ name: "companyId",
777
+ label: "公司ID",
778
+ defaultValue: "123456",
779
+ isFixValue: true, // 重置时不清空
780
+ show: () => false // 隐藏该字段
781
+ }
782
+ ```
783
+
784
+ ### 异步获取默认值
785
+
786
+ 从接口获取默认值(如当前用户的部门):
787
+
788
+ ```typescript
789
+ {
790
+ name: "deptId",
791
+ label: "部门",
792
+ logicType: "dept",
793
+ defaultValue: async () => {
794
+ const res = await request.get('/api/user/currentDept');
795
+ return res.data.deptId;
796
+ }
797
+ }
798
+ ```
799
+
800
+ ### 批量输入支持
801
+
802
+ 支持粘贴多个值进行批量查询:
803
+
804
+ ```typescript
805
+ {
806
+ name: "orderNos",
807
+ label: "订单号",
808
+ multiQuery: true,
809
+ placeholder: "支持批量输入,多个值用逗号或换行分隔"
810
+ }
811
+ ```
812
+
813
+ ### 动态控制字段显示
814
+
815
+ 根据其他条件动态显示/隐藏字段:
816
+
817
+ ```typescript
818
+ {
819
+ name: "detailField",
820
+ label: "详细信息",
821
+ show: () => queryParam.showDetail === true
822
+ }
823
+ ```
824
+
825
+ ### 自定义查询按钮
826
+
827
+ 添加自定义操作按钮:
828
+
829
+ ```typescript
830
+ const customTools = [
831
+ {
832
+ name: "export",
833
+ label: "导出",
834
+ icon: "Download",
835
+ onClick: () => {
836
+ // 导出逻辑
837
+ }
838
+ },
839
+ {
840
+ name: "advanced",
841
+ label: "高级查询",
842
+ icon: "Setting",
843
+ onClick: () => {
844
+ // 打开高级查询弹窗
845
+ }
846
+ }
847
+ ];
848
+ ```
849
+
850
+ ```vue
851
+ <BaseQuery
852
+ :form="queryParam"
853
+ :items="queryItems"
854
+ :tools="customTools"
855
+ @select="handleSearch"
856
+ />
857
+ ```
858
+
859
+ ---
860
+
861
+ ## �📚 相关文档
862
+
863
+ - [BaseForm 表单组件](../BaseForm/README.md)
864
+ - [BaseToolbar 工具栏组件](../BaseToolbar/README.md)
865
+ - [BaseTable 表格组件](../BaseTable/README.md)