xdc-ui-lib 1.0.7 → 2.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.
package/README.md CHANGED
@@ -2,12 +2,38 @@
2
2
 
3
3
  Vue 3 组件库,包含常用的业务组件。
4
4
 
5
- ## 组件列表
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install xdc-ui-lib ant-design-vue
9
+ ```
10
+
11
+ ## 快速开始
12
+
13
+ ```ts
14
+ import { createApp } from 'vue'
15
+ import Antd from 'ant-design-vue'
16
+ import 'ant-design-vue/dist/reset.css'
17
+
18
+ import XdcUiLib from 'xdc-ui-lib'
19
+
20
+ const app = createApp(App)
21
+ app.use(Antd)
22
+ app.use(XdcUiLib)
23
+ app.mount('#app')
24
+ ```
6
25
 
7
- - **CategorySearch**: 分类搜索组件
8
- - **BaseModal**: 模态框组件
9
- - **BaseForm**: 动态表单组件
10
- - **FileUpload**: 文件上传组件
26
+ ## 组件列表(目录)
27
+
28
+ - [CategorySearch 分类搜索组件](#categorysearch-分类搜索组件)
29
+ - [SearchPanel 搜索面板组件](#searchpanel-搜索面板组件)
30
+ - [ColumnSetting 表格列设置组件](#columnsetting-表格列设置组件)
31
+ - [BaseTable 表格增强组件](#basetable-表格增强组件)
32
+ - [BaseForm 动态表单组件](#baseform-动态表单组件)
33
+ - [BaseModal 模态框组件](#basemodal-模态框组件)
34
+ - [FileUpload 文件上传组件](#fileupload-文件上传组件)
35
+
36
+ ---
11
37
 
12
38
  ## CategorySearch 分类搜索组件
13
39
 
@@ -75,7 +101,8 @@ const columns = [
75
101
 
76
102
  ### 高级功能
77
103
 
78
- #### 1. 表单模式 (type="form")
104
+ <details>
105
+ <summary><b>1. 表单模式 (type="form")</b></summary>
79
106
 
80
107
  ```vue
81
108
  <template>
@@ -90,7 +117,10 @@ const columns = [
90
117
  </template>
91
118
  ```
92
119
 
93
- #### 2. 列设置功能
120
+ </details>
121
+
122
+ <details>
123
+ <summary><b>2. 列设置功能</b></summary>
94
124
 
95
125
  ```vue
96
126
  <template>
@@ -103,13 +133,16 @@ const columns = [
103
133
  </template>
104
134
  ```
105
135
 
106
- #### 3. 自定义插槽
136
+ </details>
137
+
138
+ <details>
139
+ <summary><b>3. 自定义插槽</b></summary>
107
140
 
108
141
  ```vue
109
142
  <template>
110
143
  <CategorySearch :filter-types="filterTypes">
111
144
  <template #filter-slots="{ filter, filterTemp, confirm }">
112
- <CustomComponent
145
+ <CustomComponent
113
146
  v-if="filter.id === 'customField'"
114
147
  v-model:value="filterTemp[filter.id]"
115
148
  @change="confirm"
@@ -119,9 +152,12 @@ const columns = [
119
152
  </template>
120
153
  ```
121
154
 
122
- #### 4. 国际化支持
155
+ </details>
156
+
157
+ <details>
158
+ <summary><b>4. 国际化支持</b></summary>
123
159
 
124
- ```javascript
160
+ ```js
125
161
  const filterTypes = [
126
162
  {
127
163
  id: 'status',
@@ -132,6 +168,8 @@ const filterTypes = [
132
168
  ];
133
169
  ```
134
170
 
171
+ </details>
172
+
135
173
  ### Props
136
174
 
137
175
  | 参数 | 说明 | 类型 | 默认值 |
@@ -160,9 +198,11 @@ const filterTypes = [
160
198
  1. **如果提供了 `storageKey`**:直接使用提供的值
161
199
  2. **如果没有提供 `storageKey`**:自动生成基于页面路径和配置的唯一键
162
200
 
163
- #### 自动生成存储键
201
+ <details>
202
+ <summary><b>自动生成存储键</b></summary>
164
203
 
165
204
  当没有提供 `storageKey` 时,组件会自动生成一个基于以下信息的唯一存储键:
205
+
166
206
  - 当前页面路径
167
207
  - 筛选类型配置
168
208
  - 表格列配置
@@ -171,7 +211,10 @@ const filterTypes = [
171
211
 
172
212
  这样可以确保每个页面和配置组合都有唯一的存储键,避免数据冲突。
173
213
 
174
- ### 在 Vue Router 项目中使用
214
+ </details>
215
+
216
+ <details>
217
+ <summary><b>在 Vue Router 项目中使用</b></summary>
175
218
 
176
219
  ```vue
177
220
  <template>
@@ -185,7 +228,10 @@ const filterTypes = [
185
228
  </template>
186
229
  ```
187
230
 
188
- ### 在非路由项目中使用
231
+ </details>
232
+
233
+ <details>
234
+ <summary><b>在非路由项目中使用</b></summary>
189
235
 
190
236
  ```vue
191
237
  <template>
@@ -198,7 +244,10 @@ const filterTypes = [
198
244
  </template>
199
245
  ```
200
246
 
201
- ### 使用自动生成存储键
247
+ </details>
248
+
249
+ <details>
250
+ <summary><b>使用自动生成存储键</b></summary>
202
251
 
203
252
  ```vue
204
253
  <template>
@@ -212,6 +261,8 @@ const filterTypes = [
212
261
  </template>
213
262
  ```
214
263
 
264
+ </details>
265
+
215
266
  ### Events
216
267
 
217
268
  | 事件名 | 说明 | 回调参数 |
@@ -224,6 +275,323 @@ const filterTypes = [
224
275
  | update:columns | 列更新事件 | (columns: array) |
225
276
  | update:filterValue | 筛选值更新事件 | (value: object) |
226
277
 
278
+ ---
279
+
280
+ ## SearchPanel 搜索面板组件
281
+
282
+ SearchPanel 是一个“搜索条件构建器”组件,支持两种模式:
283
+
284
+ - `type="input"`:输入框 + tag 的交互式条件选择(带下拉面板)
285
+ - `type="form"`:表单平铺模式(可折叠),更适合复杂筛选场景
286
+
287
+ 同时内置:
288
+
289
+ - 筛选条件本地缓存(基于 `storageKey`)
290
+ - 条件保存/恢复
291
+ - 筛选项显示/隐藏/排序(“列设置”面板,但作用对象是 filterTypes)
292
+ - 国际化(使用内置 `useI18n` 的 `t('searchPanel.xxx')`)
293
+
294
+ ### 基本用法(Input 模式)
295
+
296
+ ```vue
297
+ <template>
298
+ <SearchPanel
299
+ :loading="loading"
300
+ :filter-types="filterTypes"
301
+ v-model:filter-value="params"
302
+ @search="onSearch"
303
+ />
304
+ </template>
305
+
306
+ <script setup lang="ts">
307
+ import { ref } from 'vue'
308
+ import { SearchPanel } from 'xdc-ui-lib'
309
+
310
+ const loading = ref(false)
311
+ const params = ref<Record<string, any>>({})
312
+
313
+ const filterTypes = [
314
+ { id: 'name', label: '名称', type: 'input', placeholder: '请输入名称' },
315
+ {
316
+ id: 'status',
317
+ label: '状态',
318
+ type: 'select',
319
+ options: [
320
+ { label: '启用', value: 1 },
321
+ { label: '禁用', value: 0 },
322
+ ],
323
+ },
324
+ ]
325
+
326
+ function onSearch(payload: Record<string, any>) {
327
+ console.log('search:', payload)
328
+ }
329
+ </script>
330
+ ```
331
+
332
+ ### 基本用法(Form 模式)
333
+
334
+ ```vue
335
+ <template>
336
+ <SearchPanel
337
+ type="form"
338
+ :loading="loading"
339
+ :filter-types="filterTypes"
340
+ :form-layout="'grid'"
341
+ :form-span="4"
342
+ :collapsed-count="6"
343
+ v-model:filter-value="params"
344
+ @search="onSearch"
345
+ />
346
+ </template>
347
+ ```
348
+
349
+ ### 支持的筛选类型(filterTypes[].type)
350
+
351
+ 与 CategorySearch 基本一致,另外支持更多日期 picker:
352
+
353
+ - `input` / `textarea`
354
+ - `select` / `cascader` / `treeSelect`
355
+ - `checkbox` / `radio`
356
+ - `date` / `datetime` / `month` / `week` / `quarter` / `year`
357
+ - `time`
358
+ - `dateRange` / `datetimeRange`
359
+ - `numberRange`
360
+ - `rate` / `slider` / `switch`
361
+ - `slot`
362
+
363
+ ### Props
364
+
365
+ | 参数 | 说明 | 类型 | 默认值 |
366
+ |------|------|------|--------|
367
+ | type | 模式:`input` / `form` | `'input' \| 'form'` | `'input'` |
368
+ | loading | 加载状态(会阻止 search/refresh) | `boolean` | **必传** |
369
+ | filterTypes | 筛选项配置 | `any[]` | **必传** |
370
+ | filterValue | 当前筛选值(用于回显/受控) | `any` | `{}` |
371
+ | placeholder | Input 模式占位文案 | `string` | `'点击选择搜索条件'` |
372
+ | storageKey | 本地缓存 key;不传时默认使用 `search-panel:${pathname}${search}` | `string` | `''` |
373
+ | hideRefresh | 是否隐藏刷新/搜索按钮 | `boolean` | `false` |
374
+ | showSwitch | 是否显示“切换”按钮 | `boolean` | `false` |
375
+ | showSave | 是否显示“保存”按钮 | `boolean` | `false` |
376
+ | showSettingColumns | 是否显示“筛选项显示设置”按钮 | `boolean` | `true` |
377
+ | disabledFilterTypes | 不允许隐藏的筛选项 id 列表(例如必须展示的条件) | `string[]` | `[]` |
378
+ | isDefaultSearch | 初始化时是否自动触发 search(会读取缓存) | `boolean` | `true` |
379
+ | formLayout | Form 模式布局:`horizontal`/`vertical`/`inline`/`grid` | `'horizontal' \| 'vertical' \| 'inline' \| 'grid'` | `'grid'` |
380
+ | formSpan | Form 模式 grid 布局下列数(CSS 变量) | `number` | `4` |
381
+ | labelCol | Form 模式 labelCol(horizontal/grid 相关) | `any` | `-` |
382
+ | wrapperCol | Form 模式 wrapperCol(horizontal/grid 相关) | `any` | `-` |
383
+ | labelBorder | Form 模式是否显示 label 边框样式(grid-form) | `boolean` | `false` |
384
+ | colon | Form 模式 label 是否显示冒号 | `boolean` | `false` |
385
+ | collapsedCount | Form 模式折叠时展示前 N 个筛选项(传了就启用折叠逻辑,支持 0) | `number` | `undefined` |
386
+ | defaultCollapsed | Form 模式默认是否折叠(仅在启用折叠逻辑时生效) | `boolean` | `true` |
387
+ | columns | 兼容旧入参(已不再使用) | `any[]` | `[]` |
388
+ | disabledColumns | 兼容旧入参(已不再使用) | `string[]` | `[]` |
389
+
390
+ > 说明:组件内部还存在 `collapsible` 默认值,但当前 props 定义里未显式声明(属于历史字段/可忽略)。
391
+
392
+ ### Events
393
+
394
+ | 事件名 | 说明 | 回调参数 |
395
+ |------|------|----------|
396
+ | search | 点击刷新/确认/表单搜索时触发(会扁平化部分日期结构) | `(params: Record<string, any>)` |
397
+ | switch | 点击切换按钮触发 | `(filters: any[])` |
398
+ | clear | 调用 reset/清空时触发 | `()` |
399
+ | reset | (当前代码未 emit reset,仅保留事件名;如需可补) | `()` |
400
+ | columnsChange | (历史事件名:当前主要用于 filterTypes 显示设置,不建议依赖) | `(cols: any[])` |
401
+ | update:columns | (历史 v-model:当前主要用于 filterTypes 显示设置,不建议依赖) | `(cols: any[])` |
402
+ | update:filterValue | v-model 回写,用于回显/受控 | `(value: any)` |
403
+
404
+ ### Slots
405
+
406
+ | 插槽名 | 说明 | 参数 |
407
+ |------|------|------|
408
+ | icon | Input 模式右侧自定义操作按钮区域(点击事件需自行处理) | - |
409
+ | filter-slots | 当 `filterTypes[].type === 'slot'` 时渲染 | `{ filter, filterTemp, confirm }` |
410
+
411
+ ### 方法(Expose)
412
+
413
+ 通过 ref 可调用:
414
+
415
+ - `reset()`:清空条件并触发一次 search
416
+ - `search()`:触发一次 search(内部有 throttle 800ms)
417
+
418
+ ---
419
+
420
+ ## ColumnSetting 表格列设置组件
421
+
422
+ 用于表格列的显示/隐藏、拖拽排序、左右固定,并支持 localStorage 持久化。
423
+
424
+ ### 适用场景
425
+
426
+ - 表格列“显隐/排序/固定(左/右)”需要给用户自定义
427
+ - 需要把列配置持久化到 localStorage(同页面刷新仍保持)
428
+ - 需要禁用某些关键列(不可隐藏/不可拖拽)
429
+
430
+ ### 基本用法
431
+
432
+ ```vue
433
+ <template>
434
+ <ColumnSetting
435
+ v-model:columns="columnSetting"
436
+ storageKey="user-list-columns"
437
+ :disabledColumns="['id']"
438
+ >
439
+ <template #trigger>
440
+ <a-button>列设置</a-button>
441
+ </template>
442
+ </ColumnSetting>
443
+
444
+ <a-table :columns="columnSetting" :data-source="dataSource" />
445
+ </template>
446
+
447
+ <script setup lang="ts">
448
+ import { ref } from 'vue'
449
+ import { ColumnSetting } from 'xdc-ui-lib'
450
+
451
+ const columns = [
452
+ { title: 'ID', dataIndex: 'id', key: 'id' },
453
+ { title: '名称', dataIndex: 'name', key: 'name' },
454
+ { title: '状态', dataIndex: 'status', key: 'status' },
455
+ ]
456
+
457
+ const dataSource = []
458
+
459
+ const columnSetting = ref([])
460
+ </script>
461
+ ```
462
+
463
+ ### 与其他组件的关系
464
+
465
+ ColumnSetting 已解耦,可 **独立使用**(不依赖 CategorySearch / SearchPanel 等组件)。
466
+
467
+ - 只要提供 `v-model:columns` 绑定的列配置,即可完成列的显隐/排序/固定与持久化。
468
+ - 如需在其他组件中集成(例如放在表格工具栏里),直接按本章「基本用法(与 antd Table 配合)」接入即可。
469
+
470
+ ### Props
471
+
472
+ | 参数 | 说明 | 类型 | 默认值 |
473
+ |------|------|------|--------|
474
+ | columns | 原始列配置 | array | [] |
475
+ | modelValue(v-model) | 当前列设置(包含 checked/fixed/顺序) | array | - |
476
+ | disabledColumns | 禁用列(不可隐藏/不可拖拽) | string[] | [] |
477
+ | storageKey | localStorage 存储 key(不传则不持久化) | string | - |
478
+ | placement | Popover 弹出位置 | string | bottomRight |
479
+ | maxHeight | 面板最大高度 | number\|string | 400 |
480
+ | title | 面板标题文案 | string | 列展示 |
481
+ | resetText | 重置文案 | string | 重置 |
482
+ | fixedLeftText | 固定到左侧提示 | string | 固定到左侧 |
483
+ | fixedRightText | 固定到右侧提示 | string | 固定到右侧 |
484
+
485
+ ### Events
486
+
487
+ | 事件名 | 说明 | 回调参数 |
488
+ |------|------|----------|
489
+ | update:modelValue | 列设置变更(全量) | (cols: array) |
490
+ | update:visibleColumns | 可见列变更(过滤 checked=false) | (cols: array) |
491
+ | change | 同 update:modelValue | (cols: array) |
492
+ | reset | 点击重置触发 | - |
493
+
494
+ ---
495
+
496
+ ## BaseTable 表格增强组件
497
+
498
+ BaseTable 是对 `ant-design-vue` 的 `a-table` 做的“增强但不打扰”的封装:
499
+
500
+ - **不重复声明 a-table 的全部 props/emits**:通过 `useAttrs()` 全量透传
501
+ - **动态转发所有 a-table 插槽**:不影响你使用官方的 slots
502
+ - 提供可选工具条(标题/操作区)
503
+ - 内置列设置按钮(复用 `ColumnSetting`),以及刷新/密度(size)切换
504
+ - loading 兼容增强、error 空态兜底
505
+
506
+ ### 基本用法
507
+
508
+ ```vue
509
+ <template>
510
+ <BaseTable
511
+ :columns="columns"
512
+ :data-source="dataSource"
513
+ :pagination="pagination"
514
+ @change="onChange"
515
+ />
516
+ </template>
517
+
518
+ <script setup lang="ts">
519
+ import { BaseTable } from 'xdc-ui-lib'
520
+
521
+ const columns = [
522
+ { title: 'ID', dataIndex: 'id', key: 'id' },
523
+ { title: '名称', dataIndex: 'name', key: 'name' },
524
+ ]
525
+
526
+ const dataSource = []
527
+ const pagination = { current: 1, pageSize: 10, total: 0 }
528
+
529
+ function onChange(...args: any[]) {
530
+ console.log('table change', args)
531
+ }
532
+ </script>
533
+ ```
534
+
535
+ ### 工具条(title + 操作)
536
+
537
+ ```vue
538
+ <BaseTable title="用户列表" :columns="columns" :data-source="dataSource" @refresh="fetchList" />
539
+ ```
540
+
541
+ ### 列设置(ColumnSetting 集成)
542
+
543
+ BaseTable 会在工具条右侧渲染列设置入口(前提:你传入了 `columns`)。
544
+
545
+ 你可以直接把 ColumnSetting 的相关 props 当作 attribute 传给 BaseTable:
546
+
547
+ ```vue
548
+ <BaseTable
549
+ title="用户列表"
550
+ :columns="columns"
551
+ :data-source="dataSource"
552
+ storageKey="user-list-columns"
553
+ :disabledColumns="['id']"
554
+ />
555
+ ```
556
+
557
+ ### Props(BaseTable 自身声明的)
558
+
559
+ > 说明:除下表外,`a-table` 的所有 props/事件都可以直接 `v-bind`/监听传入。
560
+
561
+ | 参数 | 说明 | 类型 | 默认值 |
562
+ |------|------|------|--------|
563
+ | title | 工具条标题(默认展示在左侧) | `string` | `-` |
564
+ | toolbar | 是否展示工具条;不传时按“title/slot/toolbarActions 是否存在”自动判断 | `boolean` | `undefined` |
565
+ | toolbarActions | 是否显示右侧默认操作区(列设置/刷新/密度) | `boolean` | `true` |
566
+ | error | 错误信息(string 或 Error),用于空态兜底 | `string \| Error \| null` | `null` |
567
+ | loading | loading 增强:boolean / {spinning, tip} / AntD 原生 loading 对象 | `boolean \| {spinning?: boolean; tip?: string} \| Record<string, any>` | `undefined` |
568
+ | defaultSize | 默认表格密度(仅当外部未传 `size` 时生效) | `'small' \| 'middle' \| 'large'` | `'middle'` |
569
+
570
+ ### Events(BaseTable 自身声明的)
571
+
572
+ | 事件名 | 说明 | 回调参数 |
573
+ |------|------|----------|
574
+ | refresh | 点击刷新按钮触发 | `()` |
575
+ | update:size | 点击密度切换触发;若外部未受控,会同时更新内部 size | `(size: 'small' \| 'middle' \| 'large')` |
576
+
577
+ ### Slots
578
+
579
+ | 插槽名 | 说明 |
580
+ |------|------|
581
+ | toolbar-left | 覆盖工具条左侧区域(默认显示 title) |
582
+ | toolbar-right | 覆盖工具条右侧区域(默认显示 toolbarActions 区) |
583
+ | toolbar-extra | 在默认 toolbarActions 区后追加内容 |
584
+
585
+ > 除以上 3 个工具条插槽外,**所有 a-table 的插槽都会被动态透传**(例如 `bodyCell`、`headerCell`、`expandedRowRender`、`emptyText` 等)。
586
+
587
+ ### 默认行为(仅在外部未传时生效)
588
+
589
+ - `rowKey` 默认为 `'id'`
590
+ - `scroll` 默认为 `{ x: 'max-content' }`
591
+ - `locale.emptyText` 默认为 `'暂无数据'`(若传入 error 且外部未提供 empty slot/locale.emptyText,则显示 error)
592
+
593
+ ---
594
+
227
595
  ## BaseForm 动态表单组件
228
596
 
229
597
  一个功能强大的动态表单组件,支持多种表单元素类型、布局方式和自定义功能。
@@ -326,7 +694,8 @@ const formItems = [
326
694
 
327
695
  ### 布局方式
328
696
 
329
- #### 1. 水平布局 (默认)
697
+ <details>
698
+ <summary><b>1. 水平布局 (默认)</b></summary>
330
699
 
331
700
  ```vue
332
701
  <BaseForm
@@ -337,62 +706,66 @@ const formItems = [
337
706
  />
338
707
  ```
339
708
 
340
- #### 2. 垂直布局
709
+ </details>
710
+
711
+ <details>
712
+ <summary><b>2. 垂直布局</b></summary>
341
713
 
342
714
  ```vue
343
- <BaseForm
344
- :items="formItems"
345
- layout="vertical"
346
- />
715
+ <BaseForm :items="formItems" layout="vertical" />
347
716
  ```
348
717
 
349
- #### 3. 网格布局
718
+ </details>
719
+
720
+ <details>
721
+ <summary><b>3. 网格布局</b></summary>
350
722
 
351
723
  ```vue
352
- <BaseForm
353
- :items="formItems"
354
- layout="grid"
355
- :columns="3"
356
- />
724
+ <BaseForm :items="formItems" layout="grid" :columns="3" />
357
725
  ```
358
726
 
727
+ </details>
728
+
359
729
  ### 自定义插槽
360
730
 
361
- #### 1. 自定义表单项
731
+ <details>
732
+ <summary><b>1. 自定义表单项</b></summary>
362
733
 
363
734
  ```vue
364
735
  <BaseForm :items="formItems">
365
736
  <template #field-customField="{ item, modelValue, updateValue }">
366
737
  <div class="custom-field">
367
- <a-input
368
- :value="modelValue"
738
+ <a-input
739
+ :value="modelValue"
369
740
  placeholder="自定义字段"
370
- @input="(e) => updateValue(e.target.value)"
741
+ @input="(e) => updateValue(e.target.value)"
371
742
  />
372
743
  </div>
373
744
  </template>
374
745
  </BaseForm>
375
746
  ```
376
747
 
377
- #### 2. 自定义操作按钮
748
+ </details>
749
+
750
+ <details>
751
+ <summary><b>2. 自定义操作按钮</b></summary>
378
752
 
379
753
  ```vue
380
754
  <BaseForm :items="formItems" :show-actions="true">
381
755
  <template #actions="{ submit, reset, validateForm, formData, loading }">
382
756
  <a-space>
383
- <a-button type="primary" :loading="loading" @click="submit">
384
- 确认提交
385
- </a-button>
757
+ <a-button type="primary" :loading="loading" @click="submit">确认提交</a-button>
386
758
  <a-button @click="reset">重置</a-button>
387
- <a-button type="dashed" @click="handlePreview">
388
- 预览数据
389
- </a-button>
759
+ <a-button type="dashed" @click="handlePreview">预览数据</a-button>
390
760
  </a-space>
391
761
  </template>
392
762
  </BaseForm>
393
763
  ```
394
764
 
395
- #### 3. 自定义表单项前缀/后缀
765
+ </details>
766
+
767
+ <details>
768
+ <summary><b>3. 自定义前缀/后缀/after</b></summary>
396
769
 
397
770
  ```vue
398
771
  <BaseForm :items="formItems">
@@ -409,14 +782,21 @@ const formItems = [
409
782
  </BaseForm>
410
783
  ```
411
784
 
412
- #### 4. 自定义整个表单项
785
+ </details>
786
+
787
+ <details>
788
+ <summary><b>4. 自定义整个表单项</b></summary>
413
789
 
414
790
  ```vue
415
791
  <BaseForm :items="formItems">
416
792
  <template #form-item-customField="{ item, modelValue, updateValue }">
417
793
  <a-form-item :label="item.label">
418
794
  <div class="custom-form-item">
419
- <a-input :value="modelValue" placeholder="自定义表单项" @input="(e) => updateValue(e.target.value)" />
795
+ <a-input
796
+ :value="modelValue"
797
+ placeholder="自定义表单项"
798
+ @input="(e) => updateValue(e.target.value)"
799
+ />
420
800
  <small>这是完全自定义的表单项</small>
421
801
  </div>
422
802
  </a-form-item>
@@ -424,11 +804,14 @@ const formItems = [
424
804
  </BaseForm>
425
805
  ```
426
806
 
427
- #### 5. 自定义表单项插槽
807
+ </details>
808
+
809
+ <details>
810
+ <summary><b>5. 自定义 custom-items 插槽</b></summary>
428
811
 
429
812
  ```vue
430
813
  <BaseForm :items="formItems">
431
- <template #custom-items="{ formData, updateField, formRef }">
814
+ <template #custom-items="{ formData }">
432
815
  <a-form-item label="自定义表单项">
433
816
  <a-input v-model:value="formData.customField" placeholder="自定义字段" />
434
817
  </a-form-item>
@@ -436,8 +819,13 @@ const formItems = [
436
819
  </BaseForm>
437
820
  ```
438
821
 
822
+ </details>
823
+
439
824
  ### 复杂表单示例
440
825
 
826
+ <details>
827
+ <summary><b>点击展开</b></summary>
828
+
441
829
  ```vue
442
830
  <template>
443
831
  <BaseForm
@@ -482,6 +870,8 @@ const formItems = [
482
870
  </template>
483
871
  ```
484
872
 
873
+ </details>
874
+
485
875
  ### Props
486
876
 
487
877
  | 参数 | 说明 | 类型 | 默认值 |
@@ -518,411 +908,7 @@ const formItems = [
518
908
  | field-search | 字段搜索事件 | (name: string, value: string, item: object) |
519
909
  | field-press-enter | 字段回车事件 | (name: string, value: any, item: object) |
520
910
 
521
- ### 组件方法
522
-
523
- | 方法名 | 说明 | 参数 |
524
- |--------|------|------|
525
- | validateForm | 验证表单 | (nameList?: string[]) |
526
- | validateFields | 验证指定字段 | (nameList?: string[]) |
527
- | clearValidate | 清除验证状态 | (nameList?: string[]) |
528
- | setFieldsValue | 设置字段值 | (values: object) |
529
- | getFieldsValue | 获取字段值 | (nameList?: string[]) |
530
- | handleSubmit | 手动提交表单 | - |
531
- | handleReset | 重置表单 | - |
532
- | updateFieldValue | 更新字段值 | (name: string, value: any) |
533
- | updateFieldOptions | 更新字段选项 | (fieldName: string, options: array) |
534
- | updateFieldTreeData | 更新树形数据 | (fieldName: string, treeData: array) |
535
- | updateFieldConfig | 更新字段配置 | (fieldName: string, config: object) |
536
- | setFieldsValueWithTrigger | 批量设置字段值(支持联动) | (values: object, triggerChange?: boolean) |
537
- | currentFormItems | 当前表单项配置(响应式) | - |
538
-
539
- ### 表单项配置详解
540
-
541
- #### 基础配置
542
-
543
- ```javascript
544
- {
545
- name: 'fieldName', // 字段名(必填)
546
- label: '字段标签', // 标签文本
547
- type: 'input', // 表单元素类型
548
- placeholder: '请输入', // 占位符
549
- disabled: false, // 是否禁用
550
- required: false, // 是否必填
551
- hidden: false, // 是否隐藏
552
- rules: [], // 验证规则
553
- help: '帮助信息', // 帮助文本
554
- extra: '额外信息' // 额外信息
555
- }
556
- ```
557
-
558
- #### 输入框配置
559
-
560
- ```javascript
561
- {
562
- name: 'username',
563
- type: 'input',
564
- maxLength: 20, // 最大字符长度
565
- showCount: true, // 显示字符计数
566
- prefix: '用户', // 前缀
567
- suffix: '@example.com', // 后缀
568
- addonBefore: 'http://', // 前置标签
569
- addonAfter: '.com' // 后置标签
570
- }
571
- ```
572
-
573
- #### 选择器配置
574
-
575
- ```javascript
576
- {
577
- name: 'category',
578
- type: 'select',
579
- options: [
580
- { label: '选项1', value: 'value1' },
581
- { label: '选项2', value: 'value2' }
582
- ],
583
- showSearch: true, // 显示搜索
584
- mode: 'multiple', // 多选模式
585
- maxTagCount: 3, // 最多显示标签数
586
- loading: false // 加载状态
587
- }
588
- ```
589
-
590
- #### 日期时间配置
591
-
592
- ```javascript
593
- {
594
- name: 'birthday',
595
- type: 'date',
596
- format: 'YYYY-MM-DD', // 显示格式
597
- valueFormat: 'YYYY-MM-DD', // 值格式
598
- picker: 'date', // 选择器类型
599
- showTime: false, // 是否显示时间
600
- disabledDate: (date) => date && date > dayjs().endOf('day') // 禁用日期
601
- }
602
- ```
603
-
604
- #### 验证规则配置
605
-
606
- ```javascript
607
- {
608
- name: 'email',
609
- type: 'input',
610
- rules: [
611
- { required: true, message: '请输入邮箱' },
612
- { type: 'email', message: '请输入正确的邮箱格式' },
613
- { min: 5, max: 50, message: '邮箱长度为5-50个字符' },
614
- { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '邮箱格式不正确' }
615
- ]
616
- }
617
- ```
618
-
619
- #### 树形选择器配置
620
-
621
- ```javascript
622
- {
623
- name: 'department',
624
- type: 'treeSelect',
625
- treeData: [
626
- {
627
- title: '技术部',
628
- value: 'tech',
629
- children: [
630
- { title: '前端组', value: 'frontend' },
631
- { title: '后端组', value: 'backend' }
632
- ]
633
- }
634
- ],
635
- showSearch: true,
636
- multiple: false,
637
- treeCheckable: false,
638
- treeDefaultExpandAll: true
639
- }
640
- ```
641
-
642
- #### 单选框配置
643
-
644
- ```javascript
645
- {
646
- name: 'gender',
647
- type: 'radio',
648
- optionType: 'button', // 'default' | 'button'
649
- buttonStyle: 'outline', // 'outline' | 'solid'
650
- size: 'middle', // 'large' | 'middle' | 'small'
651
- options: [
652
- { label: '男', value: 'male' },
653
- { label: '女', value: 'female' }
654
- ]
655
- }
656
- ```
657
-
658
- #### 开关配置
659
-
660
- ```javascript
661
- {
662
- name: 'enabled',
663
- type: 'switch',
664
- checkedChildren: '开启',
665
- unCheckedChildren: '关闭',
666
- checkedValue: true,
667
- unCheckedValue: false,
668
- size: 'default' // 'default' | 'small'
669
- }
670
- ```
671
-
672
- #### 滑块配置
673
-
674
- ```javascript
675
- {
676
- name: 'quality',
677
- type: 'slider',
678
- min: 0,
679
- max: 100,
680
- step: 1,
681
- range: false, // 是否为范围选择
682
- marks: {
683
- 0: '低',
684
- 50: '中',
685
- 100: '高'
686
- },
687
- dots: false,
688
- included: true,
689
- tooltip: { formatter: (value) => `${value}%` }
690
- }
691
- ```
692
-
693
- #### 评分配置
694
-
695
- ```javascript
696
- {
697
- name: 'rating',
698
- type: 'rate',
699
- count: 5,
700
- allowHalf: true,
701
- allowClear: true,
702
- character: '★',
703
- tooltips: ['很差', '差', '一般', '好', '很好']
704
- }
705
- ```
706
-
707
- #### 自定义组件配置
708
-
709
- ```javascript
710
- {
711
- name: 'customField',
712
- type: 'custom',
713
- component: CustomComponent,
714
- props: {
715
- // 传递给自定义组件的属性
716
- customProp: 'value'
717
- }
718
- }
719
- ```
720
-
721
- ### 动态更新功能
722
-
723
- #### 1. 动态更新字段选项
724
-
725
- ```javascript
726
- const formRef = ref();
727
-
728
- // 更新选择器选项
729
- formRef.value?.updateFieldOptions('category', [
730
- { label: '新选项1', value: 'new1' },
731
- { label: '新选项2', value: 'new2' }
732
- ]);
733
- ```
734
-
735
- #### 2. 动态更新树形数据
736
-
737
- ```javascript
738
- // 更新树形选择器数据
739
- formRef.value?.updateFieldTreeData('department', [
740
- {
741
- title: '技术部',
742
- value: 'tech',
743
- children: [
744
- { title: '前端组', value: 'frontend' },
745
- { title: '后端组', value: 'backend' }
746
- ]
747
- }
748
- ]);
749
- ```
750
-
751
- #### 3. 动态更新字段配置
752
-
753
- ```javascript
754
- // 更新字段的整个配置
755
- formRef.value?.updateFieldConfig('username', {
756
- disabled: true,
757
- placeholder: '用户名已被锁定'
758
- });
759
- ```
760
-
761
- #### 4. 批量设置字段值
762
-
763
- ```javascript
764
- // 批量设置字段值,支持联动
765
- formRef.value?.setFieldsValueWithTrigger({
766
- department: 'tech',
767
- position: 'developer',
768
- skills: ['javascript', 'vue']
769
- }, true); // 第二个参数表示是否触发 change 事件
770
- ```
771
-
772
- #### 5. 动态隐藏/显示表单项
773
-
774
- ```javascript
775
- // 在 handleFieldChange 事件中动态隐藏/显示表单项
776
- const handleFieldChange = (name, value, item) => {
777
- if (name === 'userType') {
778
- // 根据用户类型隐藏/显示相关字段
779
- if (value === 'individual') {
780
- // 隐藏公司相关字段
781
- formRef.value?.updateFieldConfig('companyName', { hidden: true });
782
- formRef.value?.updateFieldConfig('companyAddress', { hidden: true });
783
- // 显示个人相关字段
784
- formRef.value?.updateFieldConfig('idCard', { hidden: false });
785
- } else if (value === 'company') {
786
- // 显示公司相关字段
787
- formRef.value?.updateFieldConfig('companyName', { hidden: false });
788
- formRef.value?.updateFieldConfig('companyAddress', { hidden: false });
789
- // 隐藏个人相关字段
790
- formRef.value?.updateFieldConfig('idCard', { hidden: true });
791
- }
792
- }
793
- };
794
- ```
795
-
796
- #### 6. 条件显示表单项
797
-
798
- ```javascript
799
- // 根据多个字段值组合来控制表单项显示
800
- const handleFieldChange = (name, value, item) => {
801
- if (name === 'country' || name === 'region') {
802
- const country = formData.country;
803
- const region = formData.region;
804
-
805
- // 只有选择特定国家和地区时才显示某些字段
806
- if (country === 'china' && region === 'beijing') {
807
- formRef.value?.updateFieldConfig('specialField', { hidden: false });
808
- } else {
809
- formRef.value?.updateFieldConfig('specialField', { hidden: true });
810
- }
811
- }
812
- };
813
- ```
814
-
815
- #### 7. 动态禁用/启用表单项
816
-
817
- ```javascript
818
- // 动态禁用/启用表单项
819
- const handleFieldChange = (name, value, item) => {
820
- if (name === 'agreeTerms') {
821
- // 根据是否同意条款来启用/禁用提交按钮
822
- formRef.value?.updateFieldConfig('submitButton', {
823
- disabled: !value
824
- });
825
- }
826
- };
827
- ```
828
-
829
- ### 表单验证功能
830
-
831
- #### 1. 验证整个表单
832
-
833
- ```javascript
834
- try {
835
- await formRef.value?.validateForm();
836
- console.log('表单验证通过');
837
- } catch (error) {
838
- console.log('表单验证失败:', error);
839
- }
840
- ```
841
-
842
- #### 2. 验证指定字段
843
-
844
- ```javascript
845
- try {
846
- await formRef.value?.validateFields(['username', 'email']);
847
- console.log('指定字段验证通过');
848
- } catch (error) {
849
- console.log('指定字段验证失败:', error);
850
- }
851
- ```
852
-
853
- #### 3. 清除验证状态
854
-
855
- ```javascript
856
- // 清除所有字段的验证状态
857
- formRef.value?.clearValidate();
858
-
859
- // 清除指定字段的验证状态
860
- formRef.value?.clearValidate(['username', 'email']);
861
- ```
862
-
863
- ### 表单数据操作
864
-
865
- #### 1. 设置字段值
866
-
867
- ```javascript
868
- // 设置单个或多个字段值
869
- formRef.value?.setFieldsValue({
870
- username: 'admin',
871
- email: 'admin@example.com'
872
- });
873
- ```
874
-
875
- #### 2. 获取字段值
876
-
877
- ```javascript
878
- // 获取所有字段值
879
- const allValues = formRef.value?.getFieldsValue();
880
-
881
- // 获取指定字段值
882
- const specificValues = formRef.value?.getFieldsValue(['username', 'email']);
883
- ```
884
-
885
- ### 响应式布局
886
-
887
- #### 1. 网格布局响应式
888
-
889
- ```vue
890
- <BaseForm
891
- :items="formItems"
892
- layout="grid"
893
- :columns="4"
894
- :style="{
895
- '--form-columns-xl': 4,
896
- '--form-columns-lg': 3,
897
- '--form-columns-md': 2,
898
- '--form-columns-sm': 1,
899
- '--form-columns-xs': 1
900
- }"
901
- />
902
- ```
903
-
904
- #### 2. 自定义响应式断点
905
-
906
- ```css
907
- /* 自定义响应式断点 */
908
- .base-form.layout-grid {
909
- @media (max-width: 1600px) {
910
- --form-columns-xl: 4;
911
- }
912
- @media (max-width: 1200px) {
913
- --form-columns-lg: 3;
914
- }
915
- @media (max-width: 992px) {
916
- --form-columns-md: 2;
917
- }
918
- @media (max-width: 768px) {
919
- --form-columns-sm: 1;
920
- }
921
- @media (max-width: 576px) {
922
- --form-columns-xs: 1;
923
- }
924
- }
925
- ```
911
+ ---
926
912
 
927
913
  ## BaseModal 模态框组件
928
914
 
@@ -964,11 +950,7 @@ const handleCancel = () => {
964
950
 
965
951
  ```vue
966
952
  <template>
967
- <BaseModal
968
- v-model="visible"
969
- modal-id="user-modal"
970
- title="用户信息"
971
- >
953
+ <BaseModal v-model="visible" modal-id="user-modal" title="用户信息">
972
954
  <p>用户信息内容</p>
973
955
  </BaseModal>
974
956
  </template>
@@ -978,7 +960,6 @@ import { BaseModal, useModalManager } from 'xdc-ui-lib';
978
960
 
979
961
  const { closeAllModals } = useModalManager();
980
962
 
981
- // 关闭所有模态框
982
963
  const closeAll = () => {
983
964
  closeAllModals();
984
965
  };
@@ -1014,11 +995,10 @@ const closeAll = () => {
1014
995
 
1015
996
  ### 模态框管理 Hook
1016
997
 
1017
- #### useModalManager
1018
-
1019
- 提供模态框管理功能。
998
+ <details>
999
+ <summary><b>useModalManager</b></summary>
1020
1000
 
1021
- ```typescript
1001
+ ```ts
1022
1002
  import { useModalManager } from 'xdc-ui-lib';
1023
1003
 
1024
1004
  const { registerModal, unregisterModal, closeAllModals } = useModalManager();
@@ -1027,29 +1007,26 @@ const { registerModal, unregisterModal, closeAllModals } = useModalManager();
1027
1007
  **方法:**
1028
1008
 
1029
1009
  - `registerModal(id: string, ref: ModalRef)`: 注册模态框
1030
- - `unregisterModal(id: string)`: 注销模态框
1010
+ - `unregisterModal(id: string)`: 注销模态框
1031
1011
  - `closeAllModals()`: 关闭所有模态框
1032
1012
 
1033
1013
  **全局事件:**
1034
1014
 
1035
1015
  - `close-all-modals`: 关闭所有模态框的全局事件
1036
1016
 
1037
- ```javascript
1038
- // 触发全局关闭事件
1017
+ ```js
1039
1018
  window.dispatchEvent(new Event('close-all-modals'));
1040
1019
  ```
1041
1020
 
1042
- ## FileUpload 文件上传组件
1021
+ </details>
1043
1022
 
1044
- 基于 [ant-design-vue](https://www.antdv.com/) 的文件上传组件,支持多选、大小限制、数量限制、删除等功能。
1023
+ ---
1045
1024
 
1046
- ## 安装
1025
+ ## FileUpload 文件上传组件
1047
1026
 
1048
- ```bash
1049
- npm install xdc-ui-lib ant-design-vue
1050
- ```
1027
+ 基于 [ant-design-vue](https://www.antdv.com/) 的文件上传组件,支持多选、大小限制、数量限制、删除等功能。
1051
1028
 
1052
- ## 使用
1029
+ ### 使用
1053
1030
 
1054
1031
  ```vue
1055
1032
  <template>
@@ -1074,27 +1051,28 @@ function onExceed(file) {
1074
1051
  </script>
1075
1052
  ```
1076
1053
 
1077
- ## Props
1054
+ ### Props
1078
1055
 
1079
- | 属性 | 说明 | 类型 | 默认值 |
1080
- | -------------- | ------------------ | --------- | ----------- |
1081
- | accept | 接受的文件类型 | string | '' |
1082
- | btnTxt | 按钮文字 | string | '上传' |
1083
- | btnType | 按钮类型 | string | 'button' |
1084
- | btnProps | 按钮属性 | object | {} |
1085
- | limit | 最大文件数 | number | 1 |
1086
- | multiple | 是否多选 | boolean | 自动由 limit 控制 |
1087
- | disabled | 是否禁用 | boolean | false |
1088
- | icon | 自定义图标 | 组件/函数/null | undefined |
1089
- | fileSizeLimit | 单文件大小限制(字节)| number | 5242880 |
1056
+ | 属性 | 说明 | 类型 | 默认值 |
1057
+ |------|------|------|--------|
1058
+ | accept | 接受的文件类型 | string | '' |
1059
+ | btnTxt | 按钮文字 | string | '上传' |
1060
+ | btnType | 按钮类型 | string | 'button' |
1061
+ | btnProps | 按钮属性 | object | {} |
1062
+ | limit | 最大文件数 | number | 1 |
1063
+ | multiple | 是否多选 | boolean | 自动由 limit 控制 |
1064
+ | disabled | 是否禁用 | boolean | false |
1065
+ | icon | 自定义图标 | 组件/函数/null | undefined |
1066
+ | fileSizeLimit | 单文件大小限制(字节) | number | 5242880 |
1090
1067
 
1091
- ## 事件
1068
+ ### Events
1092
1069
 
1093
- | 事件名 | 说明 | 回调参数 |
1094
- | -------- | ------------------ | --------------- |
1095
- | select | 文件选择后触发 | files/file |
1096
- | exceed | 文件超出大小限制时 | file |
1070
+ | 事件名 | 说明 | 回调参数 |
1071
+ |--------|------|----------|
1072
+ | select | 文件选择后触发 | files/file |
1073
+ | exceed | 文件超出大小限制时 | file |
1097
1074
 
1075
+ ---
1098
1076
 
1099
1077
  ## 开发
1100
1078