@umbsoft/avue 3.8.3-beta.4 → 3.8.3-beta.41

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
@@ -1,86 +1,2192 @@
1
- <p align="center"><a href="https://avuejs.com" target="_blank" rel="noopener noreferrer"><img width="100" src="https://avuejs.com/images/logo.png" alt="Avue logo"></a></p>
1
+ # Avue.js (@umbsoft/avue)
2
2
 
3
- <p align="center">
4
- <a href="https://gitee.com/smallweigit/avue/stargazers"><img src="https://gitee.com/smallweigit/avue/badge/star.svg?theme=dark" alt="star"></a>
5
- <a href="https://gitee.com/smallweigit/avue/members"><img src="https://gitee.com/smallweigit/avue/badge/fork.svg?theme=dark" alt="fork"></a>
6
- <a href="https://gitee.com/smallweigit/avue"><img src="https://img.shields.io/badge/license-MIT-brightgreen.svg" alt="license"></a>
7
- <a href="https://gitee.com/smallweigit/avue"><img src="https://img.shields.io/badge/version-3.0.0-blue.svg" alt="version"></a>
8
- </p>
3
+ > 基于 Element-Plus 的低代码前端框架,二次开发版本 v3.8.3-beta.4
4
+ > 去掉了 `avue-crud` 组件,新增了 `avue-transfer` 穿梭框组件
9
5
 
10
- # Avue.js
6
+ ## 项目结构
11
7
 
12
- Avue.js 是基于现有的 element-plus 库进行的二次封装,从而简化一些繁琐的操作,核心理念为**数据驱动视图**。主要的组件库针对 table 表格和 form 表单场景,同时衍生出更多企业常用的组件,达到高复用,容易维护和扩展的框架,同时内置了丰富的数据展示组件,让开发变得更加容易。
13
-
14
- ## ✨ 特性
8
+ ```
9
+ avue/
10
+ ├── packages/
11
+ │ ├── core/ # 核心代码
12
+ │ │ ├── components/ # 核心组件(form、dialog-form、icon、image-preview)
13
+ │ │ ├── common/ # 公共混入(props、event、init)
14
+ │ │ └── directive/ # 指令
15
+ │ ├── data/ # 数据展示组件(26个)
16
+ │ └── element-plus/ # 表单及输入组件(44个)
17
+ ├── src/
18
+ │ ├── core/ # 核心模块
19
+ │ ├── global/ # 全局变量(字典属性、HTTP属性、类型列表)
20
+ │ ├── locale/ # 国际化
21
+ │ ├── plugin/ # 插件(ali、clipboard、export、logs、print、qiniu、screenshot、video、watermark)
22
+ │ ├── ui/ # UI 相关
23
+ │ ├── utils/ # 工具函数(bem、identity、mock、util、validate)
24
+ │ ├── icon.js # 图标配置
25
+ │ ├── index.js # 主入口
26
+ │ └── version.js # 版本信息
27
+ ├── examples/ # 示例代码
28
+ ├── build/ # 构建脚本
29
+ └── styles/ # 样式文件
30
+ ```
15
31
 
16
- - 🚀 **高效开发**:基于数据驱动视图的理念,大大减少了代码量
17
- - 📦 **开箱即用**:丰富的表格、表单配置及多种常用组件
18
- - 🛠️ **强大定制**:高度灵活的配置项,满足各种复杂场景需求
19
- - 🔌 **扩展性强**:支持自定义组件和多种交互方式
20
- - 📚 **详尽文档**:完善的文档和示例,快速上手无烦恼
32
+ ---
21
33
 
22
- ## 🔧 安装
34
+ ## 安装
23
35
 
24
36
  ```bash
25
- # 使用 pnpm 安装(推荐)
26
- pnpm add @smallwei/avue
37
+ # 使用 pnpm(推荐)
38
+ pnpm add @umbsoft/avue
27
39
 
28
- # 或使用 npm 安装
29
- npm install @smallwei/avue
40
+ # 或使用 npm
41
+ npm install @umbsoft/avue
30
42
 
31
- # 或使用 yarn 安装
32
- yarn add @smallwei/avue
43
+ # 或使用 yarn
44
+ yarn add @umbsoft/avue
33
45
  ```
34
46
 
35
- ## 📦 使用
47
+ ---
48
+
49
+ ## 快速使用
36
50
 
37
- ```js
38
- // 完整引入
51
+ ### 完整引入
52
+
53
+ ```javascript
39
54
  import { createApp } from 'vue'
40
- import Avue from '@smallwei/avue'
41
- import '@smallwei/avue/dist/avue.css'
42
- import App from './App.vue'
55
+ import ElementPlus from 'element-plus'
56
+ import 'element-plus/dist/index.css'
57
+ import * as ElementPlusIconsVue from '@element-plus/icons-vue'
58
+ import Avue from '@umbsoft/avue'
59
+ import '@umbsoft/avue/lib/index.css'
60
+
61
+ const app = createApp({})
62
+
63
+ // 注册所有图标
64
+ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
65
+ app.component(key, component)
66
+ }
43
67
 
44
- const app = createApp(App)
68
+ app.use(ElementPlus)
45
69
  app.use(Avue)
70
+
46
71
  app.mount('#app')
47
72
  ```
48
73
 
49
- ## 📄 文件说明
74
+ ### 引入 axios(用于字典和上传功能)
75
+
76
+ ```javascript
77
+ import axios from 'axios'
78
+
79
+ app.use(Avue, { axios })
80
+ ```
81
+
82
+ ---
83
+
84
+ ## 核心组件
85
+
86
+ ### 1. avue-form(动态表单)
87
+
88
+ 动态表单是 Avue 的核心组件,通过 JSON 配置生成表单页面。
89
+
90
+ #### 基本用法
91
+
92
+ ```vue
93
+ <template>
94
+ <avue-form
95
+ ref="formRef"
96
+ v-model="formData"
97
+ :option="formOption"
98
+ @submit="handleSubmit"
99
+ @reset-change="handleReset"
100
+ />
101
+ </template>
102
+
103
+ <script setup>
104
+ import { ref, reactive } from 'vue'
105
+
106
+ const formRef = ref()
107
+ const formData = reactive({})
108
+
109
+ const formOption = reactive({
110
+ labelWidth: 120,
111
+ column: [
112
+ {
113
+ label: '用户名',
114
+ prop: 'username',
115
+ type: 'input',
116
+ rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }]
117
+ },
118
+ {
119
+ label: '邮箱',
120
+ prop: 'email',
121
+ type: 'input'
122
+ }
123
+ ]
124
+ })
125
+
126
+ const handleSubmit = (form, done) => {
127
+ console.log('提交数据:', form)
128
+ done() // 调用 done() 表示完成,可关闭 loading
129
+ }
130
+
131
+ const handleReset = () => {
132
+ console.log('表单已重置')
133
+ }
134
+ </script>
135
+ ```
136
+
137
+ #### Props 属性
138
+
139
+ | 属性名 | 类型 | 默认值 | 说明 |
140
+ |--------|------|--------|------|
141
+ | `v-model` | `Object` | `{}` | 表单数据对象 |
142
+ | `option` | `Object` | `{}` | 表单配置项 |
143
+ | `status` | `Boolean` | `false` | 提交状态 |
144
+
145
+ #### Option 配置项
146
+
147
+ | 配置项 | 类型 | 默认值 | 说明 |
148
+ |--------|------|--------|------|
149
+ | `column` | `Array` | - | 表单字段配置数组 |
150
+ | `group` | `Array` | - | 分组配置数组 |
151
+ | `footer` | `Array` | - | 底部字段配置 |
152
+ | `labelPosition` | `String` | `'left'` | 标签位置(left/right/top) |
153
+ | `labelWidth` | `Number/String` | `90` | 标签宽度 |
154
+ | `labelSuffix` | `String` | `:` | 标签后缀 |
155
+ | `size` | `String` | - | 组件尺寸(large/default/small) |
156
+ | `span` | `Number` | `12` | 栅格占位(24栏制) |
157
+ | `gutter` | `Number` | `0` | 栅格间距 |
158
+ | `disabled` | `Boolean` | - | 禁用所有表单 |
159
+ | `readonly` | `Boolean` | - | 只读所有表单 |
160
+ | `detail` | `Boolean` | - | 详情展示模式 |
161
+ | `tabs` | `Boolean` | `false` | 开启 Tab 分组模式 |
162
+ | `tabsType` | `String` | - | Tab 类型 |
163
+ | `tabsActive` | `String/Number` | `'1'` | 默认激活的 Tab |
164
+ | `tabsVerifyAll` | `Boolean` | `true` | Tab 内全部验证 |
165
+ | `menuBtn` | `Boolean` | `true` | 显示按钮区域 |
166
+ | `menuSpan` | `Number` | `24` | 按钮区域栅格 |
167
+ | `menuPosition` | `String` | `'center'` | 按钮位置(left/center/right) |
168
+ | `submitBtn` | `Boolean` | `true` | 显示提交按钮 |
169
+ | `submitText` | `String` | `'提交'` | 提交按钮文本 |
170
+ | `submitIcon` | `String` | `'el-icon-check'` | 提交按钮图标 |
171
+ | `emptyBtn` | `Boolean` | `true` | 显示重置按钮 |
172
+ | `emptyText` | `String` | `'清空'` | 重置按钮文本 |
173
+ | `emptyIcon` | `String` | `'el-icon-delete'` | 重置按钮图标 |
174
+ | `printBtn` | `Boolean` | `false` | 显示打印按钮 |
175
+ | `mockBtn` | `Boolean` | `false` | 显示模拟按钮 |
176
+ | `statusIcon` | `Boolean` | - | 显示状态图标 |
177
+ | `scrollToError` | `Boolean` | - | 验证失败时滚动到错误字段 |
178
+ | `hideRequiredAsterisk` | `Boolean` | - | 隐藏必填星号 |
179
+ | `filterNull` | `Boolean` | `false` | 提交时过滤空值 |
180
+ | `filterDic` | `Boolean` | `false` | 提交时过滤字典值 |
181
+ | `filterParams` | `Array` | - | 过滤指定参数 |
182
+ | `enter` | `Boolean` | `false` | 回车提交表单 |
183
+
184
+ #### Column 字段配置
185
+
186
+ | 配置项 | 类型 | 说明 |
187
+ |--------|------|------|
188
+ | `label` | `String` | 字段标签 |
189
+ | `prop` | `String` | 字段名 |
190
+ | `type` | `String` | 字段类型 |
191
+ | `span` | `Number` | 栅格占位 |
192
+ | `offset` | `Number` | 栅格偏移 |
193
+ | `push` | `Number` | 栅格推移 |
194
+ | `pull` | `Number` | 栅格拉取 |
195
+ | `order` | `Number` | 栅格顺序 |
196
+ | `rules` | `Array` | 验证规则 |
197
+ | `disabled` | `Boolean` | 禁用字段 |
198
+ | `readonly` | `Boolean` | 只读字段 |
199
+ | `clearable` | `Boolean` | `true` | 显示清除按钮 |
200
+ | `placeholder` | `String` | 占位符 |
201
+ | `tip` | `String` | 字段提示 |
202
+ | `display` | `Boolean` | 是否显示 |
203
+ | `addDisabled` | `Boolean` | 新增时禁用 |
204
+ | `editDisabled` | `Boolean` | 编辑时禁用 |
205
+ | `addDisplay` | `Boolean` | 新增时显示 |
206
+ | `editDisplay` | `Boolean` | 编辑时显示 |
207
+ | `dicData` | `Array` | 本地字典数据 |
208
+ | `dicUrl` | `String` | 远程字典接口 |
209
+ | `dicMethod` | `String` | 字典请求方法 |
210
+ | `dicQuery` | `Object` | 字典请求参数 |
211
+ | `props` | `Object` | 字典属性映射 |
212
+ | `propsHttp` | `Object` | HTTP 响应属性映射 |
213
+ | `cascader` | `Array` | 级联字段 |
214
+ | `control` | `Function` | 字段联动控制 |
215
+ | `blur` | `Function` | 失焦回调 |
216
+ | `focus` | `Function` | 聚焦回调 |
217
+ | `change` | `Function` | 值变化回调 |
218
+ | `click` | `Function` | 点击回调 |
219
+ | `drag` | `Boolean` | 拖拽排序 |
220
+
221
+ #### 事件
222
+
223
+ | 事件名 | 参数 | 说明 |
224
+ |--------|------|------|
225
+ | `submit` | `(form, hide)` | 表单提交。`hide` 为关闭 loading 的函数,调用 `hide()` 关闭 |
226
+ | `reset-change` | - | 表单重置后触发 |
227
+ | `mock-change` | `(form)` | 模拟数据填充后触发 |
228
+ | `tab-click` | `(activeNames)` | Tab 切换时触发 |
229
+ | `error` | `(msg)` | 表单验证失败时触发 |
230
+ | `change` | `(form)` | 表单数据变化时触发 |
231
+
232
+ #### 方法(通过 ref 调用)
233
+
234
+ | 方法名 | 参数 | 说明 |
235
+ |--------|------|------|
236
+ | `validate()` | `callback` | 验证整个表单 |
237
+ | `validateField()` | `prop, callback` | 验证指定字段 |
238
+ | `resetFields()` | - | 重置所有字段 |
239
+ | `resetForm()` | `reset?` | 重置表单数据 |
240
+ | `clearValidate()` | `props?` | 清除验证状态 |
241
+ | `getField()` | `prop` | 获取指定字段值 |
242
+ | `fields()` | - | 获取所有字段 |
243
+ | `getPropRef()` | `prop` | 获取字段组件的引用 |
244
+ | `submit()` | - | 手动提交表单 |
245
+ | `show()` | - | 显示 loading |
246
+ | `hide()` | - | 隐藏 loading |
247
+ | `scrollToField()` | `prop` | 滚动到指定字段 |
248
+
249
+ #### 插槽
250
+
251
+ | 插槽名 | 作用域数据 | 说明 |
252
+ |--------|-----------|------|
253
+ | `tabs` | `{column}` | Tab 页签自定义 |
254
+ | `header` | `{column}` | 分组头部自定义 |
255
+ | `menu-form-before` | `{disabled, size}` | 按钮区域前 |
256
+ | `menu-form` | `{disabled, size}` | 按钮区域 |
257
+ | `[prop]-form` | `{column, value, readonly, disabled, size, dic}` | 字段自定义组件 |
258
+ | `[prop]-label` | `{column, value, readonly, disabled, size, dic}` | 字段标签自定义 |
259
+ | `[prop]-error` | `{error, column, value, readonly, disabled, size, dic}` | 字段错误提示自定义 |
260
+ | `[prop]-type` | - | 字段类型插槽 |
261
+
262
+ #### 分组表单示例
263
+
264
+ ```javascript
265
+ const option = {
266
+ tabs: true,
267
+ column: [
268
+ {
269
+ label: '基本信息',
270
+ prop: 'base',
271
+ column: [
272
+ { label: '姓名', prop: 'name', type: 'input' },
273
+ { label: '年龄', prop: 'age', type: 'number' }
274
+ ]
275
+ },
276
+ {
277
+ label: '详细信息',
278
+ prop: 'detail',
279
+ column: [
280
+ { label: '地址', prop: 'address', type: 'input' },
281
+ { label: '电话', prop: 'phone', type: 'input' }
282
+ ]
283
+ }
284
+ ]
285
+ }
286
+ ```
287
+
288
+ ---
289
+
290
+ ### 2. avue-transfer(穿梭框)
291
+
292
+ 穿梭框组件,用于在两个列表之间移动数据。
293
+
294
+ #### 基本用法
295
+
296
+ ```vue
297
+ <template>
298
+ <avue-transfer
299
+ v-model="selectedData"
300
+ :dic="allData"
301
+ :option="transferOption"
302
+ @change="handleChange"
303
+ />
304
+ </template>
305
+
306
+ <script setup>
307
+ import { ref, reactive } from 'vue'
308
+
309
+ const selectedData = ref([])
310
+ const allData = ref([
311
+ { label: '选项1111111111111111111', value: 1 },
312
+ { label: '选项2', value: 2 },
313
+ { label: '选项3', value: 3 }
314
+ ])
315
+
316
+ const transferOption = reactive({
317
+ titles: ['可选列表', '已选列表'],
318
+ filterable: true,
319
+ filterPlaceholder: '输入关键字搜索'
320
+ })
321
+
322
+ const handleChange = (value, direction, movedKeys) => {
323
+ console.log('选中值:', value)
324
+ console.log('操作方向:', direction) // 'left' 或 'right'
325
+ console.log('移动的key:', movedKeys)
326
+ }
327
+ </script>
328
+ ```
329
+
330
+ #### Props 属性
331
+
332
+ | 属性名 | 类型 | 默认值 | 说明 |
333
+ |--------|------|--------|------|
334
+ | `v-model` | `Array` | - | 双向绑定值(选中的选项) |
335
+ | `dic` | `Array` | `[]` | 数据源 |
336
+ | `option` | `Object` | `{}` | 配置项 |
337
+ | `titles` | `Array` | `[]` | 左右面板标题 |
338
+ | `filterable` | `Boolean` | `false` | 是否可搜索 |
339
+ | `filterPlaceholder` | `String` | - | 搜索框占位符 |
340
+ | `filterMethod` | `Function` | - | 自定义搜索方法 |
341
+ | `targetOrder` | `String` | `'original'` | 目标面板排序方式 |
342
+ | `format` | `Object` | `{}` | 格式配置 |
343
+ | `leftDefaultChecked` | `Array` | `[]` | 左侧默认选中 |
344
+ | `rightDefaultChecked` | `Array` | `[]` | 右侧默认选中 |
345
+ | `disabled` | `Boolean` | `false` | 禁用状态 |
346
+
347
+ #### Option 配置
348
+
349
+ | 配置项 | 类型 | 说明 |
350
+ |--------|------|------|
351
+ | `titles` | `Array` | 左右面板标题 |
352
+ | `filterable` | `Boolean` | 开启搜索 |
353
+ | `filterPlaceholder` | `String` | 搜索占位符 |
354
+ | `targetOrder` | `String` | `'original'` 或 `'push'` |
355
+ | `props` | `Object` | 数据属性映射 `{label, value}` |
356
+
357
+ #### 事件
358
+
359
+ | 事件名 | 参数 | 说明 |
360
+ |--------|------|------|
361
+ | `change` | `(value, direction, movedKeys)` | 值变化时触发 |
362
+ | `click` | `params` | 点击事件 |
363
+ | `focus` | `params` | 聚焦事件 |
364
+ | `blur` | `params` | 失焦事件 |
365
+
366
+ ---
367
+
368
+ ### 3. avue-tree(树形控件)
369
+
370
+ 树形结构展示和操作组件。
371
+
372
+ #### 基本用法
373
+
374
+ ```vue
375
+ <template>
376
+ <avue-tree
377
+ ref="treeRef"
378
+ :option="treeOption"
379
+ :data="treeData"
380
+ @node-click="handleNodeClick"
381
+ />
382
+ </template>
383
+
384
+ <script setup>
385
+ import { ref, reactive } from 'vue'
386
+
387
+ const treeRef = ref()
388
+ const treeData = ref([
389
+ { label: '一级 1', children: [{ label: '二级 1-1' }] },
390
+ { label: '一级 2', children: [{ label: '二级 2-1' }] }
391
+ ])
392
+
393
+ const treeOption = reactive({
394
+ filter: true,
395
+ addBtn: true,
396
+ editBtn: true,
397
+ delBtn: true,
398
+ props: { label: 'label', children: 'children' }
399
+ })
400
+
401
+ const handleNodeClick = (data, node, nodeComp) => {
402
+ console.log('点击的节点:', data)
403
+ }
404
+ </script>
405
+ ```
406
+
407
+ #### Props 属性
408
+
409
+ | 属性名 | 类型 | 说明 |
410
+ |--------|------|------|
411
+ | `option` | `Object` | 树配置项(必填) |
412
+ | `data` | `Array` | 树数据 |
413
+ | `modelValue` | `Any` | 双向绑定值 |
414
+
415
+ #### Option 配置
416
+
417
+ | 配置项 | 类型 | 默认值 | 说明 |
418
+ |--------|------|--------|------|
419
+ | `filter` | `Boolean` | `true` | 显示搜索框 |
420
+ | `filterText` | `String` | `'输入关键字进行过滤'` | 搜索占位符 |
421
+ | `addBtn` | `Boolean` | `true` | 显示添加按钮 |
422
+ | `editBtn` | `Boolean` | `true` | 显示编辑按钮 |
423
+ | `delBtn` | `Boolean` | `true` | 显示删除按钮 |
424
+ | `menu` | `Boolean` | `true` | 显示右键菜单 |
425
+ | `draggable` | `Boolean` | - | 启用拖拽 |
426
+ | `height` | `Number/String` | - | 固定高度 |
427
+ | `accordion` | `Boolean` | - | 手风琴模式 |
428
+ | `checkStrictly` | `Boolean` | - | 勾选严格模式 |
429
+ | `multiple` | `Boolean` | - | 多选模式 |
430
+ | `lazy` | `Boolean` | - | 懒加载模式 |
431
+ | `treeLoad` | `Function` | - | 懒加载方法 |
432
+ | `props` | `Object` | - | 属性映射 `{label, children, disabled}` |
433
+ | `formOption` | `Object` | - | 表单弹窗配置 |
434
+ | `dialogWidth` | `String` | `'50%'` | 弹窗宽度 |
435
+ | `defaultExpandAll` | `Boolean` | - | 默认全部展开 |
436
+ | `defaultExpandedKeys` | `Array` | - | 默认展开的节点 |
437
+ | `virtualize` | `Boolean` | - | 虚拟滚动 |
438
+
439
+ #### 事件
440
+
441
+ | 事件名 | 参数 | 说明 |
442
+ |--------|------|------|
443
+ | `node-click` | `(data, node, nodeComp)` | 节点点击 |
444
+ | `check-change` | `(data, checked, indeterminate)` | 勾选变化 |
445
+ | `node-expand` | `(data, node, nodeComp)` | 节点展开 |
446
+ | `node-contextmenu` | `(data, node, obj)` | 右键点击 |
447
+ | `node-drag-start` | `(node, ev)` | 拖拽开始 |
448
+ | `node-drag-enter` | `(draggingNode, dropNode, ev)` | 拖拽进入 |
449
+ | `node-drag-leave` | `(draggingNode, dropNode, ev)` | 拖拽离开 |
450
+ | `node-drag-over` | `(draggingNode, dropNode, ev)` | 拖拽经过 |
451
+ | `node-drag-end` | `(draggingNode, dropNode, dropType, ev)` | 拖拽结束 |
452
+ | `node-drop` | `(draggingNode, dropNode, dropType, ev)` | 拖拽放下 |
453
+ | `save` | `(node, data, callback, done)` | 保存节点 |
454
+ | `update` | `(node, data, callback, done)` | 更新节点 |
455
+ | `del` | `(node, callback)` | 删除节点 |
456
+
457
+ #### 方法(通过 ref 调用)
458
+
459
+ | 方法名 | 参数 | 说明 |
460
+ |--------|------|------|
461
+ | `filter(val)` | 搜索值 | 过滤节点 |
462
+ | `updateKeyChildren(key, data)` | key, data | 更新子节点 |
463
+ | `getCheckedNodes(leafOnly)` | - | 获取选中的节点 |
464
+ | `setCheckedNodes(nodes)` | nodes | 设置选中的节点 |
465
+ | `getCheckedKeys(leafOnly)` | - | 获取选中的 key |
466
+ | `setCheckedKeys(keys)` | keys | 设置选中的 key |
467
+ | `setChecked(key, checked)` | key, checked | 设置节点选中状态 |
468
+ | `getHalfCheckedNodes()` | - | 获取半选节点 |
469
+ | `getHalfCheckedKeys()` | - | 获取半选 key |
470
+ | `getCurrentKey()` | - | 获取当前节点 key |
471
+ | `getCurrentNode()` | - | 获取当前节点 |
472
+ | `setCurrentKey(key)` | key | 设置当前节点 |
473
+ | `setCurrentNode(node)` | node | 设置当前节点 |
474
+ | `getNode(key)` | key | 获取节点对象 |
475
+ | `remove(data)` | data | 删除节点 |
476
+ | `append(data, parentNode)` | data, parentNode | 添加子节点 |
477
+ | `insertBefore(data, refNode)` | data, refNode | 在节点前插入 |
478
+ | `insertAfter(data, refNode)` | data, refNode | 在节点后插入 |
479
+
480
+ #### 插槽
481
+
482
+ | 插槽名 | 作用域数据 | 说明 |
483
+ |--------|-----------|------|
484
+ | `default` | `{node, data}` | 节点内容自定义 |
485
+ | `add-btn` | - | 添加按钮插槽 |
486
+ | `menu` | `{node}` | 右键菜单插槽 |
487
+
488
+ ---
489
+
490
+ ## 字段类型
491
+
492
+ ### 输入类
493
+
494
+ #### input(文本输入)
495
+
496
+ ```javascript
497
+ {
498
+ label: '用户名',
499
+ prop: 'username',
500
+ type: 'input',
501
+ // 子类型
502
+ component: 'input',
503
+ // 子类型可选值
504
+ // input | password | textarea | phone | currency | bankCard | idCard | email | code | plate | ip | mac | uscc
505
+ }
506
+ ```
507
+
508
+ #### number(数字输入)
509
+
510
+ ```javascript
511
+ {
512
+ label: '数量',
513
+ prop: 'count',
514
+ type: 'number',
515
+ precision: 2, // 精度
516
+ step: 1, // 步长
517
+ min: 0, // 最小值
518
+ max: 100 // 最大值
519
+ }
520
+ ```
521
+
522
+ #### textarea(多行文本)
523
+
524
+ ```javascript
525
+ {
526
+ label: '描述',
527
+ prop: 'description',
528
+ type: 'input',
529
+ component: 'textarea',
530
+ minRows: 3,
531
+ maxRows: 6
532
+ }
533
+ ```
534
+
535
+ ### 选择类
536
+
537
+ #### select(下拉选择)
538
+
539
+ ```javascript
540
+ {
541
+ label: '状态',
542
+ prop: 'status',
543
+ type: 'select',
544
+ dicData: [
545
+ { label: '启用', value: 1 },
546
+ { label: '禁用', value: 0 }
547
+ ],
548
+ // 或远程字典
549
+ dicUrl: '/api/dict/status',
550
+ multiple: false, // 多选
551
+ filterable: false, // 可搜索
552
+ clearable: true
553
+ }
554
+ ```
555
+
556
+ #### cascader(级联选择)
557
+
558
+ ```javascript
559
+ {
560
+ label: '地区',
561
+ prop: 'region',
562
+ type: 'cascader',
563
+ dicData: [
564
+ { label: '浙江', value: 1, children: [
565
+ { label: '杭州', value: 11 },
566
+ { label: '宁波', value: 12 }
567
+ ]}
568
+ ],
569
+ props: { label: 'label', value: 'value', children: 'children' }
570
+ }
571
+ ```
572
+
573
+ #### tree(树形选择)
574
+
575
+ ```javascript
576
+ {
577
+ label: '部门',
578
+ prop: 'dept',
579
+ type: 'tree',
580
+ dicData: treeData,
581
+ props: { label: 'label', value: 'id' },
582
+ multiple: false,
583
+ clearable: true
584
+ }
585
+ ```
586
+
587
+ #### checkbox(多选框)
588
+
589
+ ```javascript
590
+ {
591
+ label: '爱好',
592
+ prop: 'hobby',
593
+ type: 'checkbox',
594
+ dicData: [
595
+ { label: '足球', value: 'football' },
596
+ { label: '篮球', value: 'basketball' },
597
+ { label: '游泳', value: 'swimming' }
598
+ ]
599
+ }
600
+ ```
601
+
602
+ #### radio(单选框)
603
+
604
+ ```javascript
605
+ {
606
+ label: '性别',
607
+ prop: 'gender',
608
+ type: 'radio',
609
+ dicData: [
610
+ { label: '男', value: 1 },
611
+ { label: '女', value: 0 }
612
+ ]
613
+ }
614
+ ```
615
+
616
+ #### transfer(穿梭框)
617
+
618
+ ```javascript
619
+ {
620
+ label: '权限',
621
+ prop: 'permissions',
622
+ type: 'transfer',
623
+ dicData: allPermissions,
624
+ props: { label: 'label', value: 'id' },
625
+ titles: ['可选权限', '已选权限']
626
+ }
627
+ ```
628
+
629
+ ### 日期时间类
630
+
631
+ #### date(日期)
632
+
633
+ ```javascript
634
+ {
635
+ label: '日期',
636
+ prop: 'date',
637
+ type: 'date',
638
+ format: 'YYYY-MM-DD',
639
+ valueFormat: 'YYYY-MM-DD',
640
+ placeholder: '选择日期'
641
+ }
642
+ ```
643
+
644
+ #### datetime(日期时间)
645
+
646
+ ```javascript
647
+ {
648
+ label: '时间',
649
+ prop: 'datetime',
650
+ type: 'datetime',
651
+ format: 'YYYY-MM-DD HH:mm:ss',
652
+ valueFormat: 'YYYY-MM-DD HH:mm:ss'
653
+ }
654
+ ```
655
+
656
+ #### daterange(日期范围)
657
+
658
+ ```javascript
659
+ {
660
+ label: '日期范围',
661
+ prop: 'daterange',
662
+ type: 'daterange',
663
+ format: 'YYYY-MM-DD',
664
+ valueFormat: 'YYYY-MM-DD',
665
+ startPlaceholder: '开始日期',
666
+ endPlaceholder: '结束日期'
667
+ }
668
+ ```
669
+
670
+ #### datetimerange(日期时间范围)
671
+
672
+ ```javascript
673
+ {
674
+ label: '时间范围',
675
+ prop: 'datetimerange',
676
+ type: 'datetimerange',
677
+ format: 'YYYY-MM-DD HH:mm:ss',
678
+ valueFormat: 'YYYY-MM-DD HH:mm:ss'
679
+ }
680
+ ```
681
+
682
+ #### time(时间)
683
+
684
+ ```javascript
685
+ {
686
+ label: '时间',
687
+ prop: 'time',
688
+ type: 'time',
689
+ format: 'HH:mm:ss'
690
+ }
691
+ ```
692
+
693
+ #### timerange(时间范围)
694
+
695
+ ```javascript
696
+ {
697
+ label: '时间范围',
698
+ prop: 'timerange',
699
+ type: 'timerange',
700
+ format: 'HH:mm:ss'
701
+ }
702
+ ```
703
+
704
+ #### week(周)
705
+
706
+ ```javascript
707
+ {
708
+ label: '周',
709
+ prop: 'week',
710
+ type: 'week',
711
+ format: 'yyyyWW周'
712
+ }
713
+ ```
714
+
715
+ #### month(月)
716
+
717
+ ```javascript
718
+ {
719
+ label: '月份',
720
+ prop: 'month',
721
+ type: 'month',
722
+ format: 'yyyy-MM'
723
+ }
724
+ ```
725
+
726
+ #### year(年)
727
+
728
+ ```javascript
729
+ {
730
+ label: '年份',
731
+ prop: 'year',
732
+ type: 'year'
733
+ }
734
+ ```
735
+
736
+ ### 开关与评分
737
+
738
+ #### switch(开关)
739
+
740
+ ```javascript
741
+ {
742
+ label: '状态',
743
+ prop: 'status',
744
+ type: 'switch',
745
+ dicData: [
746
+ { label: '开启', value: 1 },
747
+ { label: '关闭', value: 0 }
748
+ ],
749
+ value: 1,
750
+ activeText: '开启',
751
+ inactiveText: '关闭'
752
+ }
753
+ ```
754
+
755
+ #### rate(评分)
756
+
757
+ ```javascript
758
+ {
759
+ label: '评分',
760
+ prop: 'rating',
761
+ type: 'rate',
762
+ max: 5,
763
+ allowHalf: false
764
+ }
765
+ ```
766
+
767
+ #### slider(滑块)
768
+
769
+ ```javascript
770
+ {
771
+ label: '进度',
772
+ prop: 'progress',
773
+ type: 'slider',
774
+ min: 0,
775
+ max: 100,
776
+ showInput: true,
777
+ range: false // 范围滑块
778
+ }
779
+ ```
780
+
781
+ ### 文件上传类
782
+
783
+ #### upload(文件上传)
784
+
785
+ ```javascript
786
+ {
787
+ label: '附件',
788
+ prop: 'file',
789
+ type: 'upload',
790
+ limit: 5, // 限制数量
791
+ fileSize: 5, // 文件大小限制(MB)
792
+ accept: '.pdf,.doc,.docx', // 接受的文件类型
793
+ action: '/api/upload', // 上传地址
794
+ headers: {}, // 请求头
795
+ data: {}, // 额外参数
796
+ multiple: true, // 多文件上传
797
+ drag: true, // 拖拽上传
798
+ showFileList: true, // 显示文件列表
799
+ showTip: true, // 显示提示
800
+ // 回调
801
+ uploadBefore: (file, done, loading) => {
802
+ // 上传前,可修改 file 或返回 false 阻止上传
803
+ done()
804
+ },
805
+ uploadAfter: (res, file, done, loading) => {
806
+ // 上传后,可修改 res
807
+ done()
808
+ },
809
+ uploadDelete: (file) => {
810
+ // 删除前回调
811
+ },
812
+ uploadPreview: (file) => {
813
+ // 预览回调
814
+ },
815
+ uploadExceed: (files, file) => {
816
+ // 超出限制回调
817
+ }
818
+ }
819
+ ```
820
+
821
+ #### img(图片上传)
822
+
823
+ ```javascript
824
+ {
825
+ label: '头像',
826
+ prop: 'avatar',
827
+ type: 'upload',
828
+ action: '/api/upload',
829
+ accept: 'image/*',
830
+ imgWidth: 100, // 预览图宽度
831
+ drag: false,
832
+ showFileList: false,
833
+ title: '点击上传头像'
834
+ }
835
+ ```
836
+
837
+ ### 高级输入类
838
+
839
+ #### input-number(数字输入框)
840
+
841
+ ```javascript
842
+ {
843
+ label: '价格',
844
+ prop: 'price',
845
+ type: 'input-number',
846
+ min: 0,
847
+ max: 999999,
848
+ step: 0.01,
849
+ precision: 2,
850
+ controls: true
851
+ }
852
+ ```
853
+
854
+ #### input-color(颜色选择)
855
+
856
+ ```javascript
857
+ {
858
+ label: '颜色',
859
+ prop: 'color',
860
+ type: 'input-color',
861
+ showAlpha: true, // 开启透明度
862
+ colorFormat: 'rgb' // rgba | rgb | hex
863
+ }
864
+ ```
865
+
866
+ #### input-icon(图标选择)
867
+
868
+ ```javascript
869
+ {
870
+ label: '图标',
871
+ prop: 'icon',
872
+ type: 'input-icon',
873
+ placeholder: '选择图标'
874
+ }
875
+ ```
876
+
877
+ #### input-map(地图选址)
878
+
879
+ ```javascript
880
+ {
881
+ label: '位置',
882
+ prop: 'location',
883
+ type: 'input-map',
884
+ mapKey: 'your-amap-key', // 高德地图 key
885
+ sitmap: true // 显示静态地图
886
+ }
887
+ ```
888
+
889
+ #### input-tree(树下拉选择)
890
+
891
+ ```javascript
892
+ {
893
+ label: '选择部门',
894
+ prop: 'dept',
895
+ type: 'input-tree',
896
+ dicData: deptTree,
897
+ props: { label: 'label', value: 'id' }
898
+ }
899
+ ```
900
+
901
+ #### input-table(表格选择)
902
+
903
+ ```javascript
904
+ {
905
+ label: '选择用户',
906
+ prop: 'user',
907
+ type: 'input-table',
908
+ column: [
909
+ { label: '姓名', prop: 'name' },
910
+ { label: '年龄', prop: 'age' }
911
+ ],
912
+ row: {
913
+ disabled: true
914
+ }
915
+ }
916
+ ```
917
+
918
+ #### input-tag(标签输入)
919
+
920
+ ```javascript
921
+ {
922
+ label: '标签',
923
+ prop: 'tags',
924
+ type: 'input-tag',
925
+ max: 10, // 最大标签数
926
+ allowCreate: true, // 允许创建新标签
927
+ filterable: true // 可过滤
928
+ }
929
+ ```
930
+
931
+ #### input-json(JSON 编辑器)
932
+
933
+ JSON 编辑器组件,基于 el-input 封装,支持格式化、语法高亮、错误提示和预览功能。
934
+
935
+ **在 avue-form 中使用:**
936
+
937
+ ```javascript
938
+ {
939
+ label: '配置信息',
940
+ prop: 'config',
941
+ type: 'json',
942
+ showPreview: true, // 显示 JSON 预览面板
943
+ showFormatBtn: true, // 显示格式化按钮
944
+ validateOnBlur: true, // 失焦时验证
945
+ formatOnBlur: false, // 失焦时自动格式化
946
+ rows: 8, // 文本域行数
947
+ minRows: 3, // 最小行数
948
+ maxRows: 20 // 最大行数
949
+ }
950
+ ```
951
+
952
+ **独立组件用法:**
953
+
954
+ ```vue
955
+ <template>
956
+ <avue-input-json
957
+ v-model="jsonData"
958
+ :rows="10"
959
+ :show-preview="true"
960
+ :show-format-btn="true"
961
+ placeholder="请输入 JSON"
962
+ @change="handleChange"
963
+ @error="handleError"
964
+ @format="handleFormat"
965
+ />
966
+ </template>
967
+
968
+ <script setup>
969
+ import { ref } from 'vue'
970
+
971
+ const jsonData = ref('{"name": "test", "value": 123}')
972
+
973
+ const handleChange = (val) => {
974
+ console.log('值变化:', val)
975
+ }
976
+
977
+ const handleError = (errorMsg) => {
978
+ if (errorMsg) {
979
+ console.error('JSON 错误:', errorMsg)
980
+ }
981
+ }
982
+
983
+ const handleFormat = ({ isFormatted, value, parsedValue }) => {
984
+ console.log('格式化状态:', isFormatted)
985
+ console.log('当前值:', value)
986
+ console.log('解析后对象:', parsedValue)
987
+ }
988
+ </script>
989
+ ```
990
+
991
+ **Props 属性:**
992
+
993
+ | 属性名 | 类型 | 默认值 | 说明 |
994
+ |--------|------|--------|------|
995
+ | `v-model` | `String/Object` | - | 绑定值 |
996
+ | `rows` | `Number` | `8` | 文本域行数 |
997
+ | `minRows` | `Number` | `3` | 最小行数 |
998
+ | `maxRows` | `Number` | `20` | 最大行数 |
999
+ | `autosize` | `Boolean/Object` | `{minRows:3, maxRows:20}` | 自动高度 |
1000
+ | `showWordLimit` | `Boolean` | `false` | 显示字数限制 |
1001
+ | `maxlength` | `Number` | - | 最大长度 |
1002
+ | `showFormatBtn` | `Boolean` | `true` | 显示格式化按钮 |
1003
+ | `showPreview` | `Boolean` | `false` | 显示 JSON 预览面板 |
1004
+ | `showError` | `Boolean` | `true` | 显示错误提示 |
1005
+ | `validateOnBlur` | `Boolean` | `true` | 失焦时验证 |
1006
+ | `formatOnBlur` | `Boolean` | `false` | 失焦时自动格式化 |
1007
+ | `width` | `String` | `'100%'` | 组件宽度 |
1008
+
1009
+ **Events 事件:**
1010
+
1011
+ | 事件名 | 参数 | 说明 |
1012
+ |--------|------|------|
1013
+ | `change` | `(value)` | 值变化时触发 |
1014
+ | `format` | `({isFormatted, value, parsedValue})` | 格式化切换时触发 |
1015
+ | `error` | `(errorMsg)` | JSON 错误时触发 |
1016
+ | `click` | `event` | 点击时触发 |
1017
+ | `focus` | `event` | 聚焦时触发 |
1018
+ | `blur` | `event` | 失焦时触发 |
1019
+
1020
+ **Methods 方法(通过 ref 调用):**
1021
+
1022
+ | 方法名 | 说明 |
1023
+ |--------|------|
1024
+ | `getParsedValue()` | 获取解析后的 JSON 对象 |
1025
+ | `isValid()` | 验证 JSON 是否有效 |
1026
+ | `clear()` | 清空内容 |
1027
+ | `setValue(val)` | 设置值 |
1028
+
1029
+ **功能说明:**
1030
+
1031
+ - 点击"格式化"按钮切换到文本域模式,可手动编辑 JSON
1032
+ - 点击"编辑"按钮切换回普通输入模式,组件会自动验证并格式化 JSON
1033
+ - 支持语法高亮预览,显示 JSON 结构
1034
+
1035
+ #### input-cron(Cron 表达式)
1036
+
1037
+ ```javascript
1038
+ {
1039
+ label: '执行周期',
1040
+ prop: 'cron',
1041
+ type: 'input-cron',
1042
+ placeholder: '配置定时任务'
1043
+ }
1044
+ ```
1045
+
1046
+ #### mention(@提及)
1047
+
1048
+ ```javascript
1049
+ {
1050
+ label: '@成员',
1051
+ prop: 'mentions',
1052
+ type: 'mention',
1053
+ data: [
1054
+ { label: '张三', value: 1 },
1055
+ { label: '李四', value: 2 }
1056
+ ]
1057
+ }
1058
+ ```
1059
+
1060
+ ### 其他类型
1061
+
1062
+ #### array(数组输入)
1063
+
1064
+ ```javascript
1065
+ {
1066
+ label: '数组',
1067
+ prop: 'items',
1068
+ type: 'array',
1069
+ minRows: 1,
1070
+ maxRows: 10
1071
+ }
1072
+ ```
1073
+
1074
+ #### dynamic(动态子表单)
1075
+
1076
+ ```javascript
1077
+ {
1078
+ label: '子表单',
1079
+ prop: 'subform',
1080
+ type: 'dynamic',
1081
+ children: {
1082
+ column: [
1083
+ { label: '姓名', prop: 'name', span: 12 },
1084
+ { label: '电话', prop: 'phone', span: 12 }
1085
+ ]
1086
+ }
1087
+ }
1088
+ ```
1089
+
1090
+ #### title(标题)
1091
+
1092
+ ```javascript
1093
+ {
1094
+ label: '分组标题',
1095
+ prop: 'groupTitle',
1096
+ type: 'title',
1097
+ value: '基本信息',
1098
+ labelWidth: 0
1099
+ }
1100
+ ```
1101
+
1102
+ ---
1103
+
1104
+ ## 全局方法
1105
+
1106
+ ### $AVUE 全局配置
1107
+
1108
+ 在 `main.js` 中配置全局默认值:
1109
+
1110
+ ```javascript
1111
+ app.use(Avue, {
1112
+ size: 'default', // 组件尺寸
1113
+ menuType: 'text', // 菜单按钮类型
1114
+ calcHeight: 0, // 计算高度偏移
1115
+ appendToBody: true, // 挂载到 body
1116
+ formOption: {}, // 默认表单配置
1117
+ // 水印配置
1118
+ canvas: {
1119
+ text: 'avuejs.com',
1120
+ fontFamily: 'microsoft yahei',
1121
+ color: '#999',
1122
+ fontSize: 16,
1123
+ opacity: 100,
1124
+ bottom: 10,
1125
+ right: 10
1126
+ }
1127
+ })
1128
+ ```
1129
+
1130
+ ### $DialogForm 弹窗表单
1131
+
1132
+ 创建带表单的弹窗:
1133
+
1134
+ ```javascript
1135
+ this.$DialogForm({
1136
+ title: '编辑信息', // 弹窗标题
1137
+ width: '50%', // 弹窗宽度
1138
+ data: {}, // 表单初始数据
1139
+ menuPosition: 'center', // 按钮位置
1140
+ option: { // avue-form 配置
1141
+ column: [
1142
+ { label: '姓名', prop: 'name', type: 'input' },
1143
+ { label: '年龄', prop: 'age', type: 'number' }
1144
+ ]
1145
+ },
1146
+ callback: (data, close, done) => {
1147
+ // data: 表单提交的数据
1148
+ // close: 关闭弹窗的函数
1149
+ // done: 完成回调(可传 false 表示失败)
1150
+ console.log('提交数据:', data)
1151
+ close() // 关闭弹窗
1152
+ }
1153
+ })
1154
+ ```
1155
+
1156
+ #### DialogForm Option 配置
1157
+
1158
+ | 配置项 | 类型 | 默认值 | 说明 |
1159
+ |--------|------|--------|------|
1160
+ | `title` | `String` | - | 弹窗标题 |
1161
+ | `width` | `String/Number` | `'50%'` | 弹窗宽度 |
1162
+ | `data` | `Object` | `{}` | 表单初始数据 |
1163
+ | `option` | `Object` | - | avue-form 配置 |
1164
+ | `menuPosition` | `String` | `'center'` | 按钮位置 |
1165
+ | `submitText` | `String` | `'提交'` | 提交按钮文本 |
1166
+ | `emptyText` | `String` | `'关闭'` | 关闭按钮文本 |
1167
+ | `submitIcon` | `String` | `'el-icon-check'` | 提交按钮图标 |
1168
+ | `emptyIcon` | `String` | `'el-icon-close'` | 关闭按钮图标 |
1169
+
1170
+ ### $Export 导出功能
1171
+
1172
+ #### 导出 Excel
1173
+
1174
+ ```javascript
1175
+ // 导出数据
1176
+ this.$Export.excel({
1177
+ title: '用户列表',
1178
+ titleStyle: { fontSize: 16 },
1179
+ sheets: [
1180
+ {
1181
+ sheetName: 'sheet1',
1182
+ columns: [
1183
+ { label: '姓名', prop: 'name' },
1184
+ { label: '年龄', prop: 'age' }
1185
+ ],
1186
+ data: [
1187
+ { name: '张三', age: 18 },
1188
+ { name: '李四', age: 20 }
1189
+ ]
1190
+ }
1191
+ ],
1192
+ filename: 'export.xlsx',
1193
+ autoWidth: true
1194
+ })
1195
+
1196
+ // 带表头的导出
1197
+ this.$Export.excel({
1198
+ title: '用户列表',
1199
+ columns: [
1200
+ { label: '姓名', prop: 'name' },
1201
+ { label: '年龄', prop: 'age' }
1202
+ ],
1203
+ data: []
1204
+ })
1205
+ ```
1206
+
1207
+ #### 导出数组数据
1208
+
1209
+ ```javascript
1210
+ this.$Export.excel({
1211
+ columns: [
1212
+ { label: '列1', prop: 'col1' },
1213
+ { label: '列2', prop: 'col2' }
1214
+ ],
1215
+ data: [], // 数据数组
1216
+ filename: 'data.xlsx'
1217
+ })
1218
+ ```
1219
+
1220
+ #### $Export.pdf 导出 PDF
1221
+
1222
+ ```javascript
1223
+ this.$Export.pdf({
1224
+ title: 'PDF标题',
1225
+ data: [],
1226
+ columns: []
1227
+ })
1228
+ ```
1229
+
1230
+ ### $Clipboard 剪贴板
1231
+
1232
+ ```javascript
1233
+ // 复制文本
1234
+ this.$Clipboard('要复制的文本').then(() => {
1235
+ this.$message.success('复制成功')
1236
+ }).catch(() => {
1237
+ this.$message.error('复制失败')
1238
+ })
1239
+
1240
+ // 从元素复制
1241
+ this.$Clipboard({ text: '' }).then(() => {})
1242
+ ```
1243
+
1244
+ ### $Print 打印
1245
+
1246
+ ```javascript
1247
+ // 打印元素
1248
+ this.$Print('#printArea', {
1249
+ printTitle: '打印标题',
1250
+ style: 'body { font-size: 14px }'
1251
+ })
1252
+
1253
+ // 打印指定内容
1254
+ this.$Print({
1255
+ popTitle: '文档标题',
1256
+ extraHead: '<meta charset="utf-8">',
1257
+ extraCss: '<style>body{font-size:12px}</style>'
1258
+ })
1259
+ ```
1260
+
1261
+ ### $Watermark 水印
1262
+
1263
+ ```javascript
1264
+ // 添加水印
1265
+ this.$Watermark.set({
1266
+ watermarkText: 'avuejs.com', // 水印文字
1267
+ fontFamily: '微软雅黑', // 字体
1268
+ fontSize: 16, // 字号
1269
+ color: 'rgba(0, 0, 0, 0.1)', // 颜色
1270
+ opacity: 100, // 透明度
1271
+ bottom: 10, // 距底部
1272
+ right: 10, // 距右侧
1273
+ ratio: window.devicePixelRatio // 清晰度
1274
+ })
1275
+
1276
+ // 清除水印
1277
+ this.$Watermark.del()
1278
+ ```
1279
+
1280
+ ### $Log 日志
1281
+
1282
+ 彩色控制台日志输出:
1283
+
1284
+ ```javascript
1285
+ this.$Log.capsule('标题', '信息', 'primary')
1286
+ this.$Log.success('操作成功')
1287
+ this.$Log.warning('警告信息')
1288
+ this.$Log.danger('危险操作')
1289
+ this.$Log.primary('主要信息')
1290
+ this.$Log.default('默认信息')
1291
+
1292
+ // 彩色日志组
1293
+ this.$Log.colorful([
1294
+ { text: '文本1', type: 'primary' },
1295
+ { text: '文本2', type: 'success' }
1296
+ ])
1297
+ ```
1298
+
1299
+ ### $Screenshot 截图
1300
+
1301
+ ```javascript
1302
+ this.$Screenshot().then(base64 => {
1303
+ console.log('截图base64:', base64)
1304
+ }).catch(err => {
1305
+ console.error('截图失败:', err)
1306
+ })
1307
+ ```
1308
+
1309
+ ### $ImagePreview 图片预览
1310
+
1311
+ ```javascript
1312
+ // 单张图片预览
1313
+ this.$ImagePreview({
1314
+ url: 'https://example.com/image.jpg',
1315
+ title: '图片标题'
1316
+ })
1317
+
1318
+ // 多张图片预览
1319
+ this.$ImagePreview([
1320
+ { url: 'https://example.com/1.jpg', title: '图片1' },
1321
+ { url: 'https://example.com/2.jpg', title: '图片2' }
1322
+ ])
1323
+
1324
+ // 从元素获取图片
1325
+ this.$ImagePreview({
1326
+ list: [], // 图片列表
1327
+ big: true, // 大图预览
1328
+ attr: 'src' // 从元素获取图片的属性
1329
+ })
1330
+ ```
1331
+
1332
+ ### $uploadFun 上传方法工厂
1333
+
1334
+ ```javascript
1335
+ // 创建上传方法
1336
+ const uploadFun = this.$uploadFun({
1337
+ action: '/api/upload', // 上传地址
1338
+ headers: {}, // 请求头
1339
+ data: {} // 额外参数
1340
+ })
1341
+
1342
+ // 使用
1343
+ uploadFun(file).then(res => {
1344
+ console.log('上传成功:', res)
1345
+ })
1346
+ ```
1347
+
1348
+ ---
1349
+
1350
+ ## 工具函数
1351
+
1352
+ 在组件中通过 `this` 访问:
1353
+
1354
+ ```javascript
1355
+ // 深拷贝
1356
+ const copy = this.deepClone(obj)
1357
+
1358
+ // 判断空值
1359
+ this.validatenull(value) // 返回 true 表示为空
1360
+
1361
+ // 数据类型转换
1362
+ this.detailDataType(value, 'number') // 转为数字
1363
+ this.setPx(val, defaultVal) // 设置像素值
1364
+
1365
+ // 查找数据
1366
+ this.findNode(list, props, value) // 查找节点
1367
+ this.findArray(list, value, key) // 查找数组项
1368
+ this.findObject(list, value, prop) // 查找对象
1369
+
1370
+ // 字典处理
1371
+ this.getDicValue(list, value, props) // 根据值获取字典标签
1372
+
1373
+ // 下载文件
1374
+ this.downFile(url, filename)
1375
+
1376
+ // 过滤参数
1377
+ this.filterParams(form, ['', '$'])
1378
+
1379
+ validData(val, defaultVal) // 获取有效数据
1380
+ clearVal(obj, props, excludes) // 清除值
1381
+ blankVal(value) // 置空值
1382
+ arraySort(list, prop, callback) // 数组排序
1383
+ ```
1384
+
1385
+ ---
1386
+
1387
+ ## 数据展示组件
1388
+
1389
+ 使用方式统一:`v-model` 绑定数据,`option` 配置样式。
1390
+
1391
+ ### 基本用法
1392
+
1393
+ ```vue
1394
+ <template>
1395
+ <avue-data-xxx
1396
+ v-model="data"
1397
+ :option="option"
1398
+ />
1399
+ </template>
1400
+ ```
1401
+
1402
+ ### 组件列表
1403
+
1404
+ | 组件名 | 标签 | 说明 |
1405
+ |--------|------|------|
1406
+ | `avue-data-box` | 数据框 | 统计块,含图标、标题、数字 |
1407
+ | `avue-data-card` | 数据卡片 | 大号数值卡片 |
1408
+ | `avue-data-cardText` | 图文卡片 | 含图片和文字描述 |
1409
+ | `avue-data-countdown` | 倒计时 | 活动/任务倒计时 |
1410
+ | `avue-data-dashboard` | 仪表盘 | 进度仪表盘 |
1411
+ | `avue-data-display` | 数据展示 | 带背景的数据块 |
1412
+ | `avue-data-icons` | 图标组 | 图标与数字组合 |
1413
+ | `avue-data-imgText` | 图文组 | 图文并排 |
1414
+ | `avue-data-list` | 列表组 | 排行榜列表 |
1415
+ | `avue-data-notice` | 通知栏 | 滚动通知 |
1416
+ | `avue-data-operaText` | 操作文本 | 带操作按钮的文本 |
1417
+ | `avue-data-panel` | 数据面板 | 通用面板外框 |
1418
+ | `avue-data-pay` | 支付展示 | 价格套餐展示 |
1419
+ | `avue-data-price` | 价格展示 | 定价表 |
1420
+ | `avue-data-product` | 产品展示 | 商品信息块 |
1421
+ | `avue-data-profile` | 个人信息 | 头像与简介 |
1422
+ | `avue-data-progress` | 进度条 | 各项进度条 |
1423
+ | `avue-data-rank` | 排名榜 | Top 排名列表 |
1424
+ | `avue-data-rotate` | 翻转卡片 | 悬停翻转卡片 |
1425
+ | `avue-data-statistic` | 统计数据 | 综合统计块 |
1426
+ | `avue-data-tabs` | 大屏选项卡 | 大屏导航 |
1427
+ | `avue-data-task` | 任务卡片 | 任务进度 |
1428
+ | `avue-data-weather` | 天气展示 | 天气预报 |
1429
+
1430
+ ### 数据框示例
1431
+
1432
+ ```vue
1433
+ <avue-data-box
1434
+ v-model="count"
1435
+ :option="{
1436
+ title: '总用户数',
1437
+ icon: 'el-icon-user',
1438
+ color: '#409EFF',
1439
+ fontSize: 28
1440
+ }"
1441
+ />
1442
+ ```
1443
+
1444
+ ### 数据卡片示例
1445
+
1446
+ ```vue
1447
+ <avue-data-card
1448
+ v-model="data"
1449
+ :option="{
1450
+ borderColor: '#409EFF',
1451
+ headerColor: '#f5f7fa'
1452
+ }"
1453
+ />
1454
+ ```
1455
+
1456
+ ---
1457
+
1458
+ ## 其他交互组件
1459
+
1460
+ ### avue-login(登录组件)
1461
+
1462
+ ```vue
1463
+ <template>
1464
+ <avue-login
1465
+ v-model="loginForm"
1466
+ :option="loginOption"
1467
+ @submit="handleLogin"
1468
+ />
1469
+ </template>
1470
+
1471
+ <script setup>
1472
+ const loginForm = reactive({
1473
+ username: '',
1474
+ password: '',
1475
+ code: ''
1476
+ })
1477
+
1478
+ const loginOption = reactive({
1479
+ username: {
1480
+ label: '用户名',
1481
+ placeholder: '请输入用户名',
1482
+ prefixIcon: 'el-icon-user'
1483
+ },
1484
+ password: {
1485
+ label: '密码',
1486
+ placeholder: '请输入密码',
1487
+ prefixIcon: 'el-icon-lock'
1488
+ },
1489
+ code: {
1490
+ label: '验证码',
1491
+ placeholder: '请输入验证码',
1492
+ prefixIcon: 'el-icon-key'
1493
+ }
1494
+ })
1495
+
1496
+ const handleLogin = (form, done) => {
1497
+ // 登录逻辑
1498
+ done()
1499
+ }
1500
+ </script>
1501
+ ```
1502
+
1503
+ ### avue-verify(滑动验证)
1504
+
1505
+ ```vue
1506
+ <template>
1507
+ <avue-verify
1508
+ v-model="isPass"
1509
+ :width="300"
1510
+ :height="40"
1511
+ @success="handleSuccess"
1512
+ />
1513
+ </template>
1514
+ ```
1515
+
1516
+ ### avue-sign(电子签名)
1517
+
1518
+ ```vue
1519
+ <template>
1520
+ <avue-sign
1521
+ v-model="signData"
1522
+ :width="400"
1523
+ :height="200"
1524
+ :lineWidth="3"
1525
+ :lineColor="'#000'"
1526
+ @save="handleSave"
1527
+ />
1528
+ </template>
1529
+
1530
+ <script setup>
1531
+ const signData = ref('') // base64 格式的签名图片
1532
+
1533
+ const handleSave = (base64) => {
1534
+ console.log('签名数据:', base64)
1535
+ }
1536
+ </script>
1537
+ ```
1538
+
1539
+ ### avue-video(视频播放)
1540
+
1541
+ ```vue
1542
+ <avue-video
1543
+ v-model="videoUrl"
1544
+ :option="{
1545
+ autoplay: false,
1546
+ controls: ['play', 'time', 'volume', 'fullscreen'],
1547
+ muted: false
1548
+ }"
1549
+ />
1550
+ ```
1551
+
1552
+ ### avue-draggable(拖拽)
1553
+
1554
+ ```vue
1555
+ <template>
1556
+ <avue-draggable
1557
+ v-model="list"
1558
+ :option="{
1559
+ disabled: false,
1560
+ ghostClass: 'ghost',
1561
+ animation: 200
1562
+ }"
1563
+ @change="handleChange"
1564
+ >
1565
+ <div v-for="item in list" :key="item.id">
1566
+ {{ item.name }}
1567
+ </div>
1568
+ </avue-draggable>
1569
+ </template>
1570
+ ```
1571
+
1572
+ ### avue-chat(聊天)
1573
+
1574
+ ```vue
1575
+ <avue-chat
1576
+ v-model="messages"
1577
+ :option="{
1578
+ name: 'username',
1579
+ avatar: 'avatar',
1580
+ content: 'content',
1581
+ date: 'date'
1582
+ }"
1583
+ />
1584
+ ```
1585
+
1586
+ ### avue-comment(评论)
1587
+
1588
+ ```vue
1589
+ <avue-comment
1590
+ v-model="comments"
1591
+ :option="{
1592
+ avatar: 'avatar',
1593
+ author: 'author',
1594
+ content: 'content',
1595
+ date: 'date'
1596
+ }"
1597
+ />
1598
+ ```
1599
+
1600
+ ### avue-article(文章)
1601
+
1602
+ ```vue
1603
+ <avue-article
1604
+ v-model="articleContent"
1605
+ :option="{
1606
+ title: '文章标题',
1607
+ author: '作者',
1608
+ date: '2024-01-01',
1609
+ content: '文章内容'
1610
+ }"
1611
+ />
1612
+ ```
1613
+
1614
+ ### avue-tabs(选项卡)
1615
+
1616
+ ```vue
1617
+ <template>
1618
+ <avue-tabs
1619
+ v-model="activeTab"
1620
+ :option="tabsOption"
1621
+ @change="handleChange"
1622
+ />
1623
+ </template>
1624
+
1625
+ <script setup>
1626
+ const activeTab = ref('tab1')
1627
+
1628
+ const tabsOption = {
1629
+ column: [
1630
+ { label: '标签1', prop: 'tab1' },
1631
+ { label: '标签2', prop: 'tab2' }
1632
+ ]
1633
+ }
1634
+
1635
+ const handleChange = (tab) => {
1636
+ console.log('切换到:', tab)
1637
+ }
1638
+ </script>
1639
+ ```
1640
+
1641
+ ### avue-group(分组容器)
50
1642
 
51
- | 文件名 | 用途 | 说明 |
52
- | ----------- | -------- | ---- |
53
- | avue.min.js | 生产环境 | 压缩优化版本,体积更小 |
54
- | avue.js | 开发环境 | 包含完整的调试信息 |
1643
+ ```vue
1644
+ <avue-group
1645
+ :option="{
1646
+ title: '分组标题',
1647
+ collapse: true,
1648
+ border: true
1649
+ }"
1650
+ >
1651
+ <!-- 分组内容 -->
1652
+ <div>分组内容区域</div>
1653
+ </avue-group>
1654
+ ```
55
1655
 
56
- ## 📚 文档与示例
1656
+ ### avue-search(搜索面板)
57
1657
 
58
- 要查看详细文档和在线示例,请访问:[官方文档](https://avuejs.com)
1658
+ ```vue
1659
+ <template>
1660
+ <avue-search
1661
+ v-model="searchForm"
1662
+ :option="searchOption"
1663
+ @search="handleSearch"
1664
+ @reset="handleReset"
1665
+ />
1666
+ </template>
59
1667
 
60
- ## 🌈 相关产品
1668
+ <script setup>
1669
+ const searchForm = reactive({})
1670
+ const searchOption = {
1671
+ column: [
1672
+ { label: '姓名', prop: 'name', type: 'input' },
1673
+ { label: '状态', prop: 'status', type: 'select', dicData: [] }
1674
+ ],
1675
+ menuPosition: 'left',
1676
+ submitBtn: true,
1677
+ emptyBtn: true
1678
+ }
1679
+ </script>
1680
+ ```
1681
+
1682
+ ### avue-text-ellipsis(文本省略)
61
1683
 
62
- 除了核心框架外,我们还提供以下解决方案:
1684
+ ```vue
1685
+ <avue-text-ellipsis
1686
+ text="这是一段很长的文本内容..."
1687
+ :height="60"
1688
+ :moreText="'展开'"
1689
+ :lessText="'收起'"
1690
+ />
1691
+ ```
1692
+
1693
+ ### avue-count-up(数字滚动)
1694
+
1695
+ ```vue
1696
+ <avue-count-up
1697
+ v-model="count"
1698
+ :option="{
1699
+ startVal: 0,
1700
+ endVal: 1000,
1701
+ duration: 2000,
1702
+ separator: ','
1703
+ }"
1704
+ />
1705
+ ```
1706
+
1707
+ ### avue-license(授权证书)
1708
+
1709
+ ```vue
1710
+ <avue-license
1711
+ v-model="licenseInfo"
1712
+ :option="{
1713
+ company: '公司名称',
1714
+ license: '许可证号'
1715
+ }"
1716
+ />
1717
+ ```
63
1718
 
64
- - **[数据大屏](https://data.avuejs.com)** - 专业的可视化数据大屏解决方案
65
- - **[数据组态](http://iot.avuejs.com)** - 工业物联网数据组态平台
66
- - **[AI大模型](http://ai.avuejs.com)** - 智能AI应用解决方案
1719
+ ### avue-input-tree(树下拉选择)
67
1720
 
68
- ## 🤝 参与贡献
1721
+ ```vue
1722
+ <avue-input-tree
1723
+ v-model="selectedDept"
1724
+ :dic="deptTree"
1725
+ :option="{
1726
+ props: { label: 'label', value: 'id' },
1727
+ clearable: true
1728
+ }"
1729
+ />
1730
+ ```
1731
+
1732
+ ### avue-input-table(表格选择)
1733
+
1734
+ ```vue
1735
+ <avue-input-table
1736
+ v-model="selectedUser"
1737
+ :option="{
1738
+ column: [
1739
+ { label: '姓名', prop: 'name' },
1740
+ { label: '部门', prop: 'dept' }
1741
+ ],
1742
+ row: { disabled: true }
1743
+ }"
1744
+ :tableData="userList"
1745
+ />
1746
+ ```
1747
+
1748
+ ---
1749
+
1750
+ ## 云存储配置
1751
+
1752
+ ### 七牛云
1753
+
1754
+ ```javascript
1755
+ app.use(Avue, {
1756
+ qiniu: {
1757
+ AK: 'your-access-key',
1758
+ SK: 'your-secret-key',
1759
+ scope: 'your-bucket',
1760
+ url: 'https://your-domain.com',
1761
+ bucket: 'https://upload.qiniup.com',
1762
+ deadline: 3600
1763
+ }
1764
+ })
1765
+ ```
1766
+
1767
+ ### 阿里云 OSS
1768
+
1769
+ ```javascript
1770
+ app.use(Avue, {
1771
+ ali: {
1772
+ region: 'oss-cn-hangzhou',
1773
+ endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
1774
+ stsToken: 'your-sts-token',
1775
+ accessKeyId: 'your-key-id',
1776
+ accessKeySecret: 'your-key-secret',
1777
+ bucket: 'your-bucket'
1778
+ }
1779
+ })
1780
+ ```
69
1781
 
70
- 1. Fork 本仓库
71
- 2. 新建 Feature 分支
72
- 3. 提交代码
73
- 4. 创建 Pull Request
1782
+ ### 上传组件云存储配置
74
1783
 
75
- ## ❓ 问答与支持
1784
+ ```javascript
1785
+ {
1786
+ type: 'upload',
1787
+ action: 'qiniu', // 或 'ali'
1788
+ token: '/api/qiniu/token' // 获取 token 的接口
1789
+ }
1790
+ ```
1791
+
1792
+ ---
1793
+
1794
+ ## 国际化
1795
+
1796
+ ```javascript
1797
+ import locale from '@umbsoft/avue/lib/locale/lang/zh-CN'
1798
+
1799
+ app.use(Avue, { locale })
1800
+ ```
1801
+
1802
+ ---
1803
+
1804
+ ## 完整示例
1805
+
1806
+ ### 用户管理表单页面
1807
+
1808
+ ```vue
1809
+ <template>
1810
+ <avue-form
1811
+ ref="userForm"
1812
+ v-model="userForm"
1813
+ :option="formOption"
1814
+ @submit="handleSubmit"
1815
+ @reset-change="handleReset"
1816
+ >
1817
+ <template #menu-form>
1818
+ <el-button type="primary" @click="handleCustom">自定义操作</el-button>
1819
+ </template>
1820
+ </avue-form>
1821
+ </template>
1822
+
1823
+ <script setup>
1824
+ import { ref, reactive, computed } from 'vue'
1825
+ import { ElMessage } from 'element-plus'
1826
+
1827
+ const userForm = ref({
1828
+ username: '',
1829
+ email: '',
1830
+ phone: '',
1831
+ gender: 1,
1832
+ status: true,
1833
+ birthday: '',
1834
+ dept: null,
1835
+ avatar: '',
1836
+ remark: ''
1837
+ })
1838
+
1839
+ const formOption = reactive({
1840
+ labelWidth: 120,
1841
+ span: 12,
1842
+ menuPosition: 'right',
1843
+ submitBtn: true,
1844
+ emptyBtn: true,
1845
+ column: [
1846
+ {
1847
+ label: '用户名',
1848
+ prop: 'username',
1849
+ type: 'input',
1850
+ rules: [
1851
+ { required: true, message: '请输入用户名', trigger: 'blur' },
1852
+ { min: 3, max: 20, message: '用户名长度 3-20 个字符', trigger: 'blur' }
1853
+ ],
1854
+ prepend: 'el-icon-user'
1855
+ },
1856
+ {
1857
+ label: '邮箱',
1858
+ prop: 'email',
1859
+ type: 'input',
1860
+ component: 'email',
1861
+ rules: [
1862
+ { required: true, message: '请输入邮箱', trigger: 'blur' },
1863
+ { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
1864
+ ]
1865
+ },
1866
+ {
1867
+ label: '手机号',
1868
+ prop: 'phone',
1869
+ type: 'input',
1870
+ component: 'phone',
1871
+ rules: [
1872
+ { required: true, message: '请输入手机号', trigger: 'blur' }
1873
+ ]
1874
+ },
1875
+ {
1876
+ label: '性别',
1877
+ prop: 'gender',
1878
+ type: 'radio',
1879
+ dicData: [
1880
+ { label: '男', value: 1 },
1881
+ { label: '女', value: 0 }
1882
+ ],
1883
+ value: 1
1884
+ },
1885
+ {
1886
+ label: '状态',
1887
+ prop: 'status',
1888
+ type: 'switch',
1889
+ dicData: [
1890
+ { label: '启用', value: true },
1891
+ { label: '禁用', value: false }
1892
+ ],
1893
+ value: true,
1894
+ activeText: '启用',
1895
+ inactiveText: '禁用'
1896
+ },
1897
+ {
1898
+ label: '生日',
1899
+ prop: 'birthday',
1900
+ type: 'date',
1901
+ format: 'YYYY-MM-DD',
1902
+ valueFormat: 'YYYY-MM-DD'
1903
+ },
1904
+ {
1905
+ label: '部门',
1906
+ prop: 'dept',
1907
+ type: 'tree',
1908
+ dicData: [
1909
+ { label: '技术部', children: [
1910
+ { label: '前端组', value: 'fe' },
1911
+ { label: '后端组', value: 'be' }
1912
+ ]},
1913
+ { label: '运营部', value: 'op' }
1914
+ ],
1915
+ props: { label: 'label', value: 'value' }
1916
+ },
1917
+ {
1918
+ label: '头像',
1919
+ prop: 'avatar',
1920
+ type: 'upload',
1921
+ action: '/api/upload',
1922
+ accept: 'image/*',
1923
+ showFileList: false,
1924
+ imgWidth: 80
1925
+ },
1926
+ {
1927
+ label: '备注',
1928
+ prop: 'remark',
1929
+ type: 'input',
1930
+ component: 'textarea',
1931
+ span: 24,
1932
+ minRows: 3,
1933
+ maxRows: 5
1934
+ }
1935
+ ]
1936
+ })
1937
+
1938
+ const handleSubmit = (form, done) => {
1939
+ console.log('提交数据:', form)
1940
+ // 模拟请求
1941
+ setTimeout(() => {
1942
+ ElMessage.success('提交成功')
1943
+ done()
1944
+ }, 1000)
1945
+ }
1946
+
1947
+ const handleReset = () => {
1948
+ ElMessage.info('表单已重置')
1949
+ }
1950
+
1951
+ const handleCustom = () => {
1952
+ // 自定义操作
1953
+ console.log('自定义操作')
1954
+ }
1955
+ </script>
1956
+ ```
1957
+
1958
+ ---
1959
+
1960
+ ## 字段联动
1961
+
1962
+ ### 使用 control 属性
1963
+
1964
+ ```javascript
1965
+ {
1966
+ label: '类型',
1967
+ prop: 'type',
1968
+ type: 'select',
1969
+ dicData: [
1970
+ { label: '文本', value: 'text' },
1971
+ { label: '数字', value: 'number' },
1972
+ { label: '日期', value: 'date' }
1973
+ ],
1974
+ value: 'text'
1975
+ },
1976
+ {
1977
+ label: '文本值',
1978
+ prop: 'textValue',
1979
+ type: 'input',
1980
+ display: true,
1981
+ control: (val, form) => {
1982
+ if (val === 'text') {
1983
+ return { textValue: { display: true, type: 'input' } }
1984
+ } else if (val === 'number') {
1985
+ return { textValue: { display: true, type: 'number' } }
1986
+ } else {
1987
+ return { textValue: { display: false } }
1988
+ }
1989
+ }
1990
+ }
1991
+ ```
1992
+
1993
+ ### 使用 change 事件
1994
+
1995
+ ```javascript
1996
+ {
1997
+ label: '国家',
1998
+ prop: 'country',
1999
+ type: 'select',
2000
+ dicData: [
2001
+ { label: '中国', value: 'china' },
2002
+ { label: '美国', value: 'usa' }
2003
+ ],
2004
+ change: ({ column, value }) => {
2005
+ // 根据选择更新城市字典
2006
+ if (value === 'china') {
2007
+ column[1].dicData = [
2008
+ { label: '北京', value: 'beijing' },
2009
+ { label: '上海', value: 'shanghai' }
2010
+ ]
2011
+ } else {
2012
+ column[1].dicData = [
2013
+ { label: '纽约', value: 'ny' },
2014
+ { label: '洛杉矶', value: 'la' }
2015
+ ]
2016
+ }
2017
+ }
2018
+ },
2019
+ {
2020
+ label: '城市',
2021
+ prop: 'city',
2022
+ type: 'select'
2023
+ }
2024
+ ```
2025
+
2026
+ ---
2027
+
2028
+ ## 字典配置
2029
+
2030
+ ### 本地字典
2031
+
2032
+ ```javascript
2033
+ {
2034
+ label: '状态',
2035
+ prop: 'status',
2036
+ type: 'select',
2037
+ dicData: [
2038
+ { label: '启用', value: 1 },
2039
+ { label: '禁用', value: 0 }
2040
+ ]
2041
+ }
2042
+ ```
2043
+
2044
+ ### 远程字典
2045
+
2046
+ ```javascript
2047
+ {
2048
+ label: '角色',
2049
+ prop: 'role',
2050
+ type: 'select',
2051
+ dicUrl: '/api/dict/role',
2052
+ dicMethod: 'get',
2053
+ dicQuery: { type: 'role' },
2054
+ props: {
2055
+ label: 'name', // 字典显示字段
2056
+ value: 'id' // 字典值字段
2057
+ },
2058
+ dicFormatter: (res) => {
2059
+ return res.data.list
2060
+ }
2061
+ }
2062
+ ```
2063
+
2064
+ ### HTTP 响应映射
2065
+
2066
+ ```javascript
2067
+ {
2068
+ label: '分类',
2069
+ prop: 'category',
2070
+ type: 'select',
2071
+ dicUrl: '/api/category',
2072
+ propsHttp: {
2073
+ name: 'name', // 字典名称字段
2074
+ url: 'url', // 字典链接字段
2075
+ res: 'data.list' // 数据路径
2076
+ }
2077
+ }
2078
+ ```
2079
+
2080
+ ### 级联字典
2081
+
2082
+ ```javascript
2083
+ {
2084
+ label: '省份',
2085
+ prop: 'province',
2086
+ type: 'select',
2087
+ dicUrl: '/api/province',
2088
+ cascader: ['city'] // 指定级联字段
2089
+ },
2090
+ {
2091
+ label: '城市',
2092
+ prop: 'city',
2093
+ type: 'select'
2094
+ }
2095
+ ```
2096
+
2097
+ ---
2098
+
2099
+ ## 验证规则
2100
+
2101
+ ```javascript
2102
+ {
2103
+ label: '邮箱',
2104
+ prop: 'email',
2105
+ type: 'input',
2106
+ rules: [
2107
+ { required: true, message: '请输入邮箱', trigger: 'blur' },
2108
+ { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
2109
+ ]
2110
+ },
2111
+ {
2112
+ label: '年龄',
2113
+ prop: 'age',
2114
+ type: 'number',
2115
+ rules: [
2116
+ { required: true, message: '请输入年龄', trigger: 'blur' },
2117
+ { type: 'number', min: 0, max: 150, message: '年龄范围 0-150', trigger: 'blur' }
2118
+ ]
2119
+ },
2120
+ {
2121
+ label: '手机号',
2122
+ prop: 'phone',
2123
+ type: 'input',
2124
+ rules: [
2125
+ { required: true, message: '请输入手机号', trigger: 'blur' },
2126
+ { pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
2127
+ ]
2128
+ },
2129
+ {
2130
+ label: '自定义验证',
2131
+ prop: 'custom',
2132
+ type: 'input',
2133
+ rules: [
2134
+ {
2135
+ validator: (rule, value, callback) => {
2136
+ if (value === 'forbidden') {
2137
+ callback(new Error('该值被禁止使用'))
2138
+ } else {
2139
+ callback()
2140
+ }
2141
+ },
2142
+ trigger: 'blur'
2143
+ }
2144
+ ]
2145
+ }
2146
+ ```
2147
+
2148
+ ---
2149
+
2150
+ ## 远程字典完整示例
2151
+
2152
+ ```javascript
2153
+ // main.js 配置 axios
2154
+ import axios from 'axios'
2155
+
2156
+ app.use(Avue, { axios })
2157
+
2158
+ // 组件中使用
2159
+ {
2160
+ label: '用户',
2161
+ prop: 'userId',
2162
+ type: 'select',
2163
+ dicUrl: '/api/users',
2164
+ dicQuery: { status: 1 },
2165
+ props: {
2166
+ label: 'nickname',
2167
+ value: 'id'
2168
+ },
2169
+ dicFormatter: (res) => {
2170
+ // 自定义处理响应数据
2171
+ return res.data.filter(item => item.deleted === 0)
2172
+ },
2173
+ filterable: true,
2174
+ clearable: true,
2175
+ placeholder: '请选择用户'
2176
+ }
2177
+ ```
76
2178
 
77
- 有关问题和支持,请使用[issues](https://gitee.com/smallweigit/avue/issues)。我们会尽快为您解答。
2179
+ ---
78
2180
 
79
- > **注意**:提交问题前,请务必提供详细的问题过程和截图,不符合准则的问题将会被拒绝。
2181
+ ## 版本信息
80
2182
 
2183
+ - 当前版本:v3.8.3-beta.4
2184
+ - 依赖:Vue 3.2+, Element-Plus 2.2+
2185
+ - 许可证:MIT
81
2186
 
82
- ## 📄 开源协议
2187
+ ---
83
2188
 
84
- [MIT](http://opensource.org/licenses/MIT)
2189
+ ## 文档与支持
85
2190
 
86
- Copyright (c) 2017-present, Smallwei
2191
+ - 官方文档:https://avuejs.com
2192
+ - 问题反馈:https://gitee.com/umbsoft/avue/issues