@umbsoft/avue 3.8.3-beta.49 → 3.8.3-beta.50

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 (3) hide show
  1. package/README.md +177 -2192
  2. package/lib/avue.min.js +2 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,2192 +1,177 @@
1
- # Avue.js (@umbsoft/avue)
2
-
3
- > 基于 Element-Plus 的低代码前端框架,二次开发版本 v3.8.3-beta.4
4
- > 去掉了 `avue-crud` 组件,新增了 `avue-transfer` 穿梭框组件
5
-
6
- ## 项目结构
7
-
8
- ```
9
- avue/
10
- ├── packages/
11
- │ ├── core/ # 核心代码
12
- │ │ ├── components/ # 核心组件(formdialog-formiconimage-preview)
13
- │ │ ├── common/ # 公共混入(propseventinit)
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
- ```
31
-
32
- ---
33
-
34
- ## 安装
35
-
36
- ```bash
37
- # 使用 pnpm(推荐)
38
- pnpm add @umbsoft/avue
39
-
40
- # 或使用 npm
41
- npm install @umbsoft/avue
42
-
43
- # 或使用 yarn
44
- yarn add @umbsoft/avue
45
- ```
46
-
47
- ---
48
-
49
- ## 快速使用
50
-
51
- ### 完整引入
52
-
53
- ```javascript
54
- import { createApp } from '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
- }
67
-
68
- app.use(ElementPlus)
69
- app.use(Avue)
70
-
71
- app.mount('#app')
72
- ```
73
-
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(分组容器)
1642
-
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
- ```
1655
-
1656
- ### avue-search(搜索面板)
1657
-
1658
- ```vue
1659
- <template>
1660
- <avue-search
1661
- v-model="searchForm"
1662
- :option="searchOption"
1663
- @search="handleSearch"
1664
- @reset="handleReset"
1665
- />
1666
- </template>
1667
-
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(文本省略)
1683
-
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
- ```
1718
-
1719
- ### avue-input-tree(树下拉选择)
1720
-
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
- ```
1781
-
1782
- ### 上传组件云存储配置
1783
-
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
- ```
2178
-
2179
- ---
2180
-
2181
- ## 版本信息
2182
-
2183
- - 当前版本:v3.8.3-beta.4
2184
- - 依赖:Vue 3.2+, Element-Plus 2.2+
2185
- - 许可证:MIT
2186
-
2187
- ---
2188
-
2189
- ## 文档与支持
2190
-
2191
- - 官方文档:https://avuejs.com
2192
- - 问题反馈:https://gitee.com/umbsoft/avue/issues
1
+ # @umbsoft/avue
2
+
3
+ > 基于 Element-Plus 的低代码前端框架,二次开发版本 v3.8.3-beta.48
4
+ > 去掉 `avue-crud`,新增 `avue-transfer`,重写字典系统支持纯 JSON 联动
5
+
6
+ ## 核心特性
7
+
8
+ - **动态表单**:通过 JSON 配置生成完整表单(`avue-form`)
9
+ - **纯 JSON 联动**:字段联动、反向赋值、显隐控制、禁用控制全部走 JSON 配置,无需手写 `change` / `control` 回调
10
+ - **声明式字典**:`dicUrl` + `dicQuery` + `dicResPath` + `dicMap` 支持任意后端接口协议
11
+ - **44+ 表单组件**:input、select、date、upload、tree、json、map、cron 等
12
+ - **26+ 数据展示组件**:cardstatisticdashboardcountdown 等
13
+ - **插件系统**:exportprintclipboard、watermark、screenshot
14
+
15
+ ---
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ pnpm add @umbsoft/avue
21
+ ```
22
+
23
+ ## 快速使用
24
+
25
+ ```typescript
26
+ import { createApp } from 'vue'
27
+ import ElementPlus from 'element-plus'
28
+ import * as ElementPlusIconsVue from '@element-plus/icons-vue'
29
+ import Avue from '@umbsoft/avue'
30
+ import '@umbsoft/avue/lib/index.css'
31
+
32
+ const app = createApp({})
33
+ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
34
+ app.component(key, component)
35
+ }
36
+ app.use(ElementPlus)
37
+ app.use(Avue, { axios: service }) // 注入业务 axios 实例
38
+ app.mount('#app')
39
+ ```
40
+
41
+ > **重要**:必须注入业务 axios 实例,否则 Avue 内部的字典请求(`dicUrl`)无法携带 token。
42
+
43
+ ---
44
+
45
+ ## 字典系统(v3.8.3-beta.48+ 核心改造)
46
+
47
+ ### 声明式字典加载
48
+
49
+ ```javascript
50
+ {
51
+ label: '平台名称',
52
+ prop: '平台编号',
53
+ type: 'select',
54
+ dicUrl: '/component/pg', // 接口地址
55
+ dicMethod: 'post', // 请求方法(默认 post)
56
+ dicQuery: { // 请求参数
57
+ 来源: '连接器.秘钥_平台表',
58
+ 字段: ['平台名称', '平台编号'],
59
+ 条件: { 平台名称: { $distinct: '平台名称' } },
60
+ 排序: ['平台名称']
61
+ },
62
+ dicResPath: 'data', // 响应提取路径:res.data.data
63
+ dicMap: [ // 数据映射(可选)
64
+ { to: '编码', from: '数据编码' },
65
+ { to: '名称', template: '【${平台名称}】${秘钥名称}' }
66
+ ],
67
+ props: { label: '平台名称', value: '平台编号' }
68
+ }
69
+ ```
70
+
71
+ ### 纯 JSON 联动
72
+
73
+ ```javascript
74
+ {
75
+ prop: '平台编号',
76
+ type: 'select',
77
+ dicUrl: '/component/pg',
78
+ dicQuery: { ... },
79
+ linkage: {
80
+ // ① 反向赋值:选中后自动填充表单其他字段
81
+ assign: { 平台名称: '平台名称' },
82
+ // ② 级联刷新:值变化时触发子字段字典刷新
83
+ cascade: ['秘钥编码']
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### 级联注入 + 前端过滤
89
+
90
+ ```javascript
91
+ // 子字段配置
92
+ {
93
+ prop: '秘钥编码',
94
+ type: 'select',
95
+ dicUrl: '/component/pg',
96
+ dicQuery: {
97
+ 来源: '连接器.秘钥_平台秘钥表',
98
+ 字段: ['数据编码', '平台编号', '平台名称', '秘钥名称'],
99
+ 条件: { 平台编号: { $eq: '{{平台编号}}' } }, // 联动条件注入
100
+ 排序: ['平台名称']
101
+ },
102
+ dicResPath: 'data',
103
+ // cascadeFilter 前端过滤(不重新请求)
104
+ cascadeFilter: { '平台编号': '平台编号' }
105
+ }
106
+ ```
107
+
108
+ ### 显隐/禁用控制(替代 control 函数)
109
+
110
+ ```javascript
111
+ {
112
+ prop: '任务模式',
113
+ type: 'radio',
114
+ dicData: [{ label: '通用', value: '通用' }, { label: '内置', value: '内置' }],
115
+ linkage: {
116
+ display: {
117
+ '任务类型': { ne: '内置', action: 'show' }, // 值 !== '内置' 时显示
118
+ '请求地址': { ne: '内置', action: 'show' },
119
+ '任务标识': { eq: '内置', action: 'show' } // 值 === '内置' 时显示
120
+ },
121
+ disabled: {
122
+ '字段A': { eq: 'xxx' } // 值 === 'xxx' 时禁用
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## 项目结构
131
+
132
+ ```
133
+ avue/
134
+ ├── packages/
135
+ │ ├── core/
136
+ │ │ ├── components/ # form-temp、dialog-form、icon、image-preview
137
+ │ │ ├── common/ # props、event、init 混入
138
+ │ │ └── directive/ # 指令
139
+ │ ├── data/ # 26 个数据展示组件
140
+ │ └── element-plus/ # 44 个表单输入组件
141
+ ├── src/
142
+ │ ├── core/ # 核心模块(dic.js、dataformat.js、detail.js)
143
+ │ ├── global/ # 全局变量
144
+ │ ├── locale/ # 国际化
145
+ │ ├── plugin/ # 插件
146
+ │ ├── ui/ # UI 组件注册入口
147
+ │ ├── utils/ # 工具函数
148
+ │ ├── icon.js # 图标配置
149
+ │ ├── index.js # 主入口
150
+ │ └── version.js # 版本信息
151
+ ├── build/ # 构建脚本(webpack + gulp)
152
+ ├── styles/ # SCSS 样式
153
+ └── types/ # TypeScript 类型定义
154
+ ```
155
+
156
+ ---
157
+
158
+ ## 构建
159
+
160
+ ```bash
161
+ # 开发模式(带 watch)
162
+ pnpm dev
163
+
164
+ # 生产构建
165
+ pnpm build
166
+
167
+ # 发布
168
+ pnpm release
169
+ ```
170
+
171
+ ---
172
+
173
+ ## 开发文档
174
+
175
+ - [CHANGELOG.md](./CHANGELOG.md) 版本变更记录
176
+ - [开发规范.md](./开发规范.md) 编码规范与未来扩展指南
177
+ - [SKILLS.md](./SKILLS.md) AI 调用接口文档