@vrojs/element-plus 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/index.ts +5 -0
- package/src/locale/lang/zh-cn.ts +24 -0
- package/src/style/deps.ts +5 -0
- package/src/style/index.scss +5 -0
- package/src/vro-el-config-provider/types.ts +1 -1
- package/src/vro-el-radio-group/README.md +83 -0
- package/src/vro-el-radio-group/index.ts +16 -0
- package/src/vro-el-radio-group/style/css.ts +2 -0
- package/src/vro-el-radio-group/style/deps.ts +2 -0
- package/src/vro-el-radio-group/style/index.scss +1 -0
- package/src/vro-el-radio-group/style/index.ts +2 -0
- package/src/vro-el-radio-group/types.ts +29 -0
- package/src/vro-el-radio-group/vro-el-radio-group.vue +34 -0
- package/src/vro-el-schema-filter/README.md +146 -0
- package/src/vro-el-schema-filter/index.ts +16 -0
- package/src/vro-el-schema-filter/style/css.ts +3 -0
- package/src/vro-el-schema-filter/style/deps.ts +4 -0
- package/src/vro-el-schema-filter/style/index.scss +20 -0
- package/src/vro-el-schema-filter/style/index.ts +2 -0
- package/src/vro-el-schema-filter/types.ts +31 -0
- package/src/vro-el-schema-filter/vro-el-schema-filter.vue +64 -0
- package/src/vro-el-schema-form/README.md +207 -0
- package/src/vro-el-schema-form/defineVroElSchemaFormCreateField.ts +12 -0
- package/src/vro-el-schema-form/defineVroElSchemaFormFieldTrigger.ts +9 -0
- package/src/vro-el-schema-form/index.ts +20 -0
- package/src/vro-el-schema-form/style/css.ts +9 -0
- package/src/vro-el-schema-form/style/deps.ts +20 -0
- package/src/vro-el-schema-form/style/index.scss +4 -0
- package/src/vro-el-schema-form/style/index.ts +2 -0
- package/src/vro-el-schema-form/types.ts +171 -0
- package/src/vro-el-schema-form/useVroElSchemaForm.ts +48 -0
- package/src/vro-el-schema-form/vro-el-schema-form.vue +177 -0
- package/src/vro-el-schema-form/vroElSchemaFormFieldManager.ts +59 -0
- package/src/vro-el-schema-form-dialog/README.md +114 -5
- package/src/vro-el-schema-form-dialog/function-call.ts +11 -3
- package/src/vro-el-schema-form-dialog/index.ts +6 -1
- package/src/vro-el-schema-form-dialog/injection.ts +10 -0
- package/src/vro-el-schema-form-dialog/style/css.ts +2 -0
- package/src/vro-el-schema-form-dialog/style/deps.ts +4 -0
- package/src/vro-el-schema-form-dialog/style/index.scss +4 -1
- package/src/vro-el-schema-form-dialog/types.ts +70 -2
- package/src/vro-el-schema-form-dialog/useVroElSchemaFormDialog.ts +52 -0
- package/src/vro-el-schema-form-dialog/vro-el-schema-form-dialog.vue +119 -9
- package/src/vro-el-tags/README.md +73 -0
- package/src/vro-el-tags/index.ts +16 -0
- package/src/vro-el-tags/style/css.ts +2 -0
- package/src/vro-el-tags/style/deps.ts +3 -0
- package/src/vro-el-tags/style/index.scss +1 -0
- package/src/vro-el-tags/style/index.ts +2 -0
- package/src/vro-el-tags/types.ts +21 -0
- package/src/vro-el-tags/vro-el-tags.vue +69 -0
- package/src/vro-el-tree/README.md +85 -0
- package/src/vro-el-tree/index.ts +16 -0
- package/src/vro-el-tree/style/css.ts +2 -0
- package/src/vro-el-tree/style/deps.ts +1 -0
- package/src/vro-el-tree/style/index.scss +3 -0
- package/src/vro-el-tree/style/index.ts +2 -0
- package/src/vro-el-tree/types.ts +38 -0
- package/src/vro-el-tree/vro-el-tree.vue +78 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# VroElSchemaForm
|
|
2
|
+
|
|
3
|
+
### 介绍
|
|
4
|
+
|
|
5
|
+
基于 `ElForm` 的 schema 表单封装。组件通过 `schema` 描述字段、布局、校验和事件,适合快速搭建中后台表单,同时保留 Element Plus Form、Row、Col、FormItem 的透传能力。
|
|
6
|
+
|
|
7
|
+
## 代码演示
|
|
8
|
+
|
|
9
|
+
### 基础用法
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<template>
|
|
13
|
+
<vro-el-schema-form
|
|
14
|
+
ref="refVroElSchemaForm"
|
|
15
|
+
:schema="schema"
|
|
16
|
+
:form-props="{ labelWidth: '90px' }"
|
|
17
|
+
:col-props="{ span: 12 }"
|
|
18
|
+
/>
|
|
19
|
+
<el-button type="primary" :loading="loading" @click="trigger">提交</el-button>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { ref } from 'vue'
|
|
24
|
+
import { useVroElSchemaForm, type VroElSchemaFormInstance } from '@vrojs/element-plus'
|
|
25
|
+
|
|
26
|
+
const refVroElSchemaForm = ref<VroElSchemaFormInstance>()
|
|
27
|
+
const { schema, loading, trigger } = useVroElSchemaForm(
|
|
28
|
+
{
|
|
29
|
+
username: {
|
|
30
|
+
label: '用户名',
|
|
31
|
+
value: '',
|
|
32
|
+
is: 'ElInput',
|
|
33
|
+
rules: [{ required: true, message: '请填写用户名', trigger: 'blur' }],
|
|
34
|
+
},
|
|
35
|
+
role: {
|
|
36
|
+
label: '角色',
|
|
37
|
+
value: '',
|
|
38
|
+
is: 'VroElSelect',
|
|
39
|
+
options: [
|
|
40
|
+
{ label: '管理员', value: 'admin' },
|
|
41
|
+
{ label: '运营', value: 'operator' },
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
async (data) => {
|
|
46
|
+
console.log(data)
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
instanceRef: refVroElSchemaForm,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
</script>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 动态显示
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const schema = {
|
|
59
|
+
accountType: {
|
|
60
|
+
label: '账号类型',
|
|
61
|
+
value: 'personal',
|
|
62
|
+
is: 'VroElRadioGroup',
|
|
63
|
+
options: [
|
|
64
|
+
{ label: '个人', value: 'personal' },
|
|
65
|
+
{ label: '企业', value: 'company' },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
realName: {
|
|
69
|
+
label: '姓名',
|
|
70
|
+
value: '',
|
|
71
|
+
is: 'ElInput',
|
|
72
|
+
hidden: (_, __, metadata) => metadata.accountType.value !== 'personal',
|
|
73
|
+
},
|
|
74
|
+
companyName: {
|
|
75
|
+
label: '企业名称',
|
|
76
|
+
value: '',
|
|
77
|
+
is: 'ElInput',
|
|
78
|
+
hidden: (_, __, metadata) => metadata.accountType.value !== 'company',
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 字段插槽
|
|
84
|
+
|
|
85
|
+
字段的 `slots` 配置用于把外部同名插槽转发给实际渲染组件。
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<vro-el-schema-form :schema="schema">
|
|
89
|
+
<template #prepend>
|
|
90
|
+
<span>https://</span>
|
|
91
|
+
</template>
|
|
92
|
+
</vro-el-schema-form>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const schema = {
|
|
97
|
+
website: {
|
|
98
|
+
label: '网址',
|
|
99
|
+
value: '',
|
|
100
|
+
is: 'ElInput',
|
|
101
|
+
slots: {
|
|
102
|
+
prepend: 'prepend',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
### 属性 Props
|
|
111
|
+
|
|
112
|
+
<table>
|
|
113
|
+
<tbody>
|
|
114
|
+
<tr>
|
|
115
|
+
<td>名称</td>
|
|
116
|
+
<td>类型</td>
|
|
117
|
+
<td>默认值</td>
|
|
118
|
+
</tr>
|
|
119
|
+
<tr v-for="(item, key) in vroElSchemaFormProps" :key="key">
|
|
120
|
+
<td>{{ key }}</td>
|
|
121
|
+
<td>{{ parseType(item.type || item) }}</td>
|
|
122
|
+
<td>{{ reserve(item.default, '-') }}</td>
|
|
123
|
+
</tr>
|
|
124
|
+
</tbody>
|
|
125
|
+
</table>
|
|
126
|
+
|
|
127
|
+
### 插槽 Slots
|
|
128
|
+
|
|
129
|
+
<table>
|
|
130
|
+
<tbody>
|
|
131
|
+
<tr>
|
|
132
|
+
<td>名称</td>
|
|
133
|
+
<td>说明</td>
|
|
134
|
+
</tr>
|
|
135
|
+
<tr>
|
|
136
|
+
<td>default</td>
|
|
137
|
+
<td>表单尾部内容,会渲染在 ElRow 内部</td>
|
|
138
|
+
</tr>
|
|
139
|
+
<tr>
|
|
140
|
+
<td>schema 字段 slots 配置中的 key</td>
|
|
141
|
+
<td>转发给字段组件的插槽,插槽参数为 { item }</td>
|
|
142
|
+
</tr>
|
|
143
|
+
</tbody>
|
|
144
|
+
</table>
|
|
145
|
+
|
|
146
|
+
### 实例方法
|
|
147
|
+
|
|
148
|
+
<table>
|
|
149
|
+
<tbody>
|
|
150
|
+
<tr>
|
|
151
|
+
<td>名称</td>
|
|
152
|
+
<td>说明</td>
|
|
153
|
+
</tr>
|
|
154
|
+
<tr>
|
|
155
|
+
<td>form</td>
|
|
156
|
+
<td>ElForm 实例</td>
|
|
157
|
+
</tr>
|
|
158
|
+
<tr>
|
|
159
|
+
<td>validate</td>
|
|
160
|
+
<td>校验表单和支持 validate 的字段组件</td>
|
|
161
|
+
</tr>
|
|
162
|
+
<tr>
|
|
163
|
+
<td>validateField</td>
|
|
164
|
+
<td>校验指定字段</td>
|
|
165
|
+
</tr>
|
|
166
|
+
<tr>
|
|
167
|
+
<td>resetFields</td>
|
|
168
|
+
<td>重置表单字段</td>
|
|
169
|
+
</tr>
|
|
170
|
+
<tr>
|
|
171
|
+
<td>extractValues</td>
|
|
172
|
+
<td>提取 schema 字段值和支持 extractValues 的字段组件值</td>
|
|
173
|
+
</tr>
|
|
174
|
+
<tr>
|
|
175
|
+
<td>trigger</td>
|
|
176
|
+
<td>触发支持 trigger 的字段组件</td>
|
|
177
|
+
</tr>
|
|
178
|
+
</tbody>
|
|
179
|
+
</table>
|
|
180
|
+
|
|
181
|
+
### 事件 Events
|
|
182
|
+
|
|
183
|
+
<table>
|
|
184
|
+
<tbody>
|
|
185
|
+
<tr>
|
|
186
|
+
<td>名称</td>
|
|
187
|
+
<td>参数</td>
|
|
188
|
+
<td>说明</td>
|
|
189
|
+
</tr>
|
|
190
|
+
<tr>
|
|
191
|
+
<td>change-field</td>
|
|
192
|
+
<td>{ key, value }</td>
|
|
193
|
+
<td>字段 change 时触发</td>
|
|
194
|
+
</tr>
|
|
195
|
+
<tr>
|
|
196
|
+
<td>input-field</td>
|
|
197
|
+
<td>{ key, value }</td>
|
|
198
|
+
<td>字段 input 时触发</td>
|
|
199
|
+
</tr>
|
|
200
|
+
</tbody>
|
|
201
|
+
</table>
|
|
202
|
+
|
|
203
|
+
<script setup lang="ts">
|
|
204
|
+
import { reserve } from '@daysnap/utils'
|
|
205
|
+
import { VroElSchemaForm, vroElSchemaFormProps } from '.'
|
|
206
|
+
import { parseType } from '../utils'
|
|
207
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { VroElSchemaFormSchemaField } from './types'
|
|
2
|
+
|
|
3
|
+
export function defineVroElSchemaFormCreateField<
|
|
4
|
+
T extends (...args: any[]) => VroElSchemaFormSchemaField,
|
|
5
|
+
>(generator: T) {
|
|
6
|
+
return (options: Partial<VroElSchemaFormSchemaField> = {}, ...args: Parameters<T>) => {
|
|
7
|
+
return {
|
|
8
|
+
...generator(...args),
|
|
9
|
+
...options,
|
|
10
|
+
} as VroElSchemaFormSchemaField
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { withInstall } from '@vrojs/base'
|
|
2
|
+
|
|
3
|
+
import Component from './vro-el-schema-form.vue'
|
|
4
|
+
|
|
5
|
+
export * from './defineVroElSchemaFormCreateField'
|
|
6
|
+
export * from './defineVroElSchemaFormFieldTrigger'
|
|
7
|
+
export * from './types'
|
|
8
|
+
export * from './useVroElSchemaForm'
|
|
9
|
+
export * from './vroElSchemaFormFieldManager'
|
|
10
|
+
|
|
11
|
+
export const VroElSchemaForm = withInstall<typeof Component>(Component)
|
|
12
|
+
export default VroElSchemaForm
|
|
13
|
+
|
|
14
|
+
export type VroElSchemaFormInstance = InstanceType<typeof VroElSchemaForm>
|
|
15
|
+
|
|
16
|
+
declare module 'vue' {
|
|
17
|
+
export interface GlobalComponents {
|
|
18
|
+
VroElSchemaForm: typeof VroElSchemaForm
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import '../../style/base.scss'
|
|
2
|
+
import '../../vro-el-checkbox-group/style/css'
|
|
3
|
+
import '../../vro-el-file-upload/style/css'
|
|
4
|
+
import '../../vro-el-image-upload/style/css'
|
|
5
|
+
import '../../vro-el-radio-group/style/css'
|
|
6
|
+
import '../../vro-el-select/style/css'
|
|
7
|
+
import '../../vro-el-tags/style/css'
|
|
8
|
+
import '../../vro-el-tree/style/css'
|
|
9
|
+
import './index.scss'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import '../../vro-el-checkbox-group/style/deps'
|
|
2
|
+
import '../../vro-el-file-upload/style/deps'
|
|
3
|
+
import '../../vro-el-image-upload/style/deps'
|
|
4
|
+
import '../../vro-el-radio-group/style/deps'
|
|
5
|
+
import '../../vro-el-select/style/deps'
|
|
6
|
+
import '../../vro-el-tags/style/deps'
|
|
7
|
+
import '../../vro-el-tree/style/deps'
|
|
8
|
+
import 'element-plus/es/components/cascader/style/css'
|
|
9
|
+
import 'element-plus/es/components/checkbox-group/style/css'
|
|
10
|
+
import 'element-plus/es/components/col/style/css'
|
|
11
|
+
import 'element-plus/es/components/date-picker/style/css'
|
|
12
|
+
import 'element-plus/es/components/divider/style/css'
|
|
13
|
+
import 'element-plus/es/components/form-item/style/css'
|
|
14
|
+
import 'element-plus/es/components/form/style/css'
|
|
15
|
+
import 'element-plus/es/components/input-number/style/css'
|
|
16
|
+
import 'element-plus/es/components/input/style/css'
|
|
17
|
+
import 'element-plus/es/components/radio-group/style/css'
|
|
18
|
+
import 'element-plus/es/components/row/style/css'
|
|
19
|
+
import 'element-plus/es/components/select/style/css'
|
|
20
|
+
import 'element-plus/es/components/tree-select/style/css'
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { Arrayable } from '@vrojs/base'
|
|
2
|
+
import {
|
|
3
|
+
type ColProps,
|
|
4
|
+
type FormItemProps,
|
|
5
|
+
type FormItemRule,
|
|
6
|
+
type FormProps,
|
|
7
|
+
type RowProps,
|
|
8
|
+
} from 'element-plus'
|
|
9
|
+
import { type ExtractPropTypes, type PropType, type Raw } from 'vue'
|
|
10
|
+
|
|
11
|
+
export interface VroElSchemaFormSchemaField {
|
|
12
|
+
/**
|
|
13
|
+
* 字段渲染组件,支持内置注册名、外部注册名或组件对象。
|
|
14
|
+
*/
|
|
15
|
+
is?:
|
|
16
|
+
| 'ElInput'
|
|
17
|
+
| 'ElSelect'
|
|
18
|
+
| 'ElRadioGroup'
|
|
19
|
+
| 'ElCheckboxGroup'
|
|
20
|
+
| 'ElDatePicker'
|
|
21
|
+
| 'ElInputNumber'
|
|
22
|
+
| 'ElTreeSelect'
|
|
23
|
+
| 'ElCascader'
|
|
24
|
+
| 'ElDivider'
|
|
25
|
+
| 'VroElSelect'
|
|
26
|
+
| 'VroElCheckboxGroup'
|
|
27
|
+
| 'VroElRadioGroup'
|
|
28
|
+
| 'VroElImageUpload'
|
|
29
|
+
| 'VroElFileUpload'
|
|
30
|
+
| 'VroElTags'
|
|
31
|
+
| 'VroElTree'
|
|
32
|
+
| Raw<object>
|
|
33
|
+
| (string & {})
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 表单项标签文本。
|
|
37
|
+
*/
|
|
38
|
+
label?: string
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 字段当前值。
|
|
42
|
+
*/
|
|
43
|
+
value?: any
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 字段默认值,供外部工具生成初始值时使用。
|
|
47
|
+
*/
|
|
48
|
+
defaultValue?: any
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 字段重置值,重置的时候使用。
|
|
52
|
+
*/
|
|
53
|
+
resetValue?: any
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 透传给字段组件的属性。
|
|
57
|
+
*/
|
|
58
|
+
props?: Record<string, any>
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 字段选项列表,常用于选择器、单选、多选等组件。
|
|
62
|
+
*/
|
|
63
|
+
options?: any
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 选项展示文本字段名。
|
|
67
|
+
*/
|
|
68
|
+
labelKey?: string
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 选项绑定值字段名。
|
|
72
|
+
*/
|
|
73
|
+
valueKey?: string
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 当前字段栅格配置,会与组件级 colProps 合并。
|
|
77
|
+
*/
|
|
78
|
+
colProps?: Partial<ColProps>
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 当前字段表单项配置,会与组件级 formItemProps 合并。
|
|
82
|
+
*/
|
|
83
|
+
formItemProps?: Partial<FormItemProps>
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 从字段值转换提交值。
|
|
87
|
+
*/
|
|
88
|
+
get?: (value: any, filed: VroElSchemaFormSchemaField, metadata: VroElSchemaFormSchema) => any
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 将外部数据写入字段。
|
|
92
|
+
*/
|
|
93
|
+
set?: (source: any, field: VroElSchemaFormSchemaField, metadata: VroElSchemaFormSchema) => void
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 是否隐藏字段,支持根据当前字段和完整 schema 动态判断。
|
|
97
|
+
*/
|
|
98
|
+
hidden?:
|
|
99
|
+
| boolean
|
|
100
|
+
| ((value: any, filed: VroElSchemaFormSchemaField, metadata: VroElSchemaFormSchema) => boolean)
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 字段校验规则,透传给 ElForm rules。
|
|
104
|
+
*/
|
|
105
|
+
rules?:
|
|
106
|
+
| Arrayable<FormItemRule>
|
|
107
|
+
| ((
|
|
108
|
+
value: any,
|
|
109
|
+
field: VroElSchemaFormSchemaField,
|
|
110
|
+
metadata: VroElSchemaFormSchema,
|
|
111
|
+
) => Arrayable<FormItemRule>)
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 字段 change 事件回调。
|
|
115
|
+
*/
|
|
116
|
+
onChange?: (value: any, field: VroElSchemaFormSchemaField, metadata: VroElSchemaFormSchema) => any
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 字段 input 事件回调。
|
|
120
|
+
*/
|
|
121
|
+
onInput?: (value: any, field: VroElSchemaFormSchemaField, metadata: VroElSchemaFormSchema) => any
|
|
122
|
+
|
|
123
|
+
[key: string]: any
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export type VroElSchemaFormSchema = Record<string, VroElSchemaFormSchemaField>
|
|
127
|
+
export type VroElSchemaFormFormProps = Partial<Omit<FormProps, 'model' | 'rules'>>
|
|
128
|
+
|
|
129
|
+
export const vroElSchemaFormProps = {
|
|
130
|
+
/**
|
|
131
|
+
* 透传给 ElForm 的属性,不包含 model 和 rules。
|
|
132
|
+
*/
|
|
133
|
+
formProps: {
|
|
134
|
+
type: Object as PropType<VroElSchemaFormFormProps>,
|
|
135
|
+
default: () => ({}),
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 透传给 ElRow 的属性。
|
|
140
|
+
*/
|
|
141
|
+
rowProps: {
|
|
142
|
+
type: Object as PropType<Partial<RowProps>>,
|
|
143
|
+
default: () => ({}),
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 透传给 ElCol 的默认属性,字段级 colProps 优先级更高。
|
|
148
|
+
*/
|
|
149
|
+
colProps: {
|
|
150
|
+
type: Object as PropType<Partial<ColProps>>,
|
|
151
|
+
default: () => ({}),
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 透传给 ElFormItem 的默认属性,字段级 formItemProps 优先级更高。
|
|
156
|
+
*/
|
|
157
|
+
formItemProps: {
|
|
158
|
+
type: Object as PropType<Partial<FormItemProps>>,
|
|
159
|
+
default: () => ({}),
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 表单字段 schema 配置。
|
|
164
|
+
*/
|
|
165
|
+
schema: {
|
|
166
|
+
type: Object as PropType<VroElSchemaFormSchema>,
|
|
167
|
+
default: () => ({}),
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export type VroElSchemaFormProps = ExtractPropTypes<typeof vroElSchemaFormProps>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import banana from '@daysnap/banana'
|
|
2
|
+
import { isFunction } from '@daysnap/utils'
|
|
3
|
+
import { useAsyncTask } from '@vrojs/use'
|
|
4
|
+
import { reactive, type Ref, ref } from 'vue'
|
|
5
|
+
|
|
6
|
+
import type { VroElSchemaFormInstance } from '.'
|
|
7
|
+
import type { VroElSchemaFormSchema } from './types'
|
|
8
|
+
|
|
9
|
+
export function useVroElSchemaForm<T extends (data: any) => Promise<any>>(
|
|
10
|
+
rawSchema: (() => VroElSchemaFormSchema) | VroElSchemaFormSchema,
|
|
11
|
+
task?: T,
|
|
12
|
+
options: {
|
|
13
|
+
initialValue?: Record<string, any>
|
|
14
|
+
instanceRef?: Ref<VroElSchemaFormInstance | undefined>
|
|
15
|
+
} = {},
|
|
16
|
+
) {
|
|
17
|
+
const { instanceRef, initialValue } = options
|
|
18
|
+
const schema = reactive(isFunction(rawSchema) ? rawSchema() : rawSchema)
|
|
19
|
+
|
|
20
|
+
const refVroElSchemaForm = instanceRef ?? ref<VroElSchemaFormInstance>()
|
|
21
|
+
|
|
22
|
+
const { loading, trigger } = useAsyncTask(
|
|
23
|
+
async () => {
|
|
24
|
+
if (!refVroElSchemaForm.value) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
await refVroElSchemaForm.value.validate()
|
|
29
|
+
} catch {
|
|
30
|
+
throw ''
|
|
31
|
+
}
|
|
32
|
+
const data = await refVroElSchemaForm.value.extractValues()
|
|
33
|
+
await task?.(data)
|
|
34
|
+
},
|
|
35
|
+
{ throwError: true },
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if (initialValue) {
|
|
39
|
+
banana.assignment(initialValue, schema as any)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
schema,
|
|
44
|
+
refVroElSchemaForm,
|
|
45
|
+
loading,
|
|
46
|
+
trigger,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-form
|
|
3
|
+
v-bind="elFormProps"
|
|
4
|
+
ref="refForm"
|
|
5
|
+
class="vro-el-schema-form"
|
|
6
|
+
:model="model"
|
|
7
|
+
:rules="rules"
|
|
8
|
+
>
|
|
9
|
+
<el-row :gutter="16" v-bind="rowProps">
|
|
10
|
+
<el-col v-for="(item, key) in metadata" :key="key" v-bind="{ ...colProps, ...item.colProps }">
|
|
11
|
+
<el-form-item
|
|
12
|
+
:label="item.label"
|
|
13
|
+
:prop="key"
|
|
14
|
+
v-bind="{ ...formItemProps, ...item.formItemProps }"
|
|
15
|
+
>
|
|
16
|
+
<component
|
|
17
|
+
v-model="item.value"
|
|
18
|
+
v-bind="mapping?.[key]?.props"
|
|
19
|
+
:is="mapping?.[key]?.is"
|
|
20
|
+
ref="refComponents"
|
|
21
|
+
@change="handleChange(key, $event)"
|
|
22
|
+
@input="handleInput(key, $event)"
|
|
23
|
+
>
|
|
24
|
+
<template v-for="(slot, key) in item.slots" #[slot] :key="slot">
|
|
25
|
+
<slot :name="key" :item="item" />
|
|
26
|
+
</template>
|
|
27
|
+
</component>
|
|
28
|
+
</el-form-item>
|
|
29
|
+
</el-col>
|
|
30
|
+
<slot></slot>
|
|
31
|
+
</el-row>
|
|
32
|
+
</el-form>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup lang="ts">
|
|
36
|
+
import banana from '@daysnap/banana'
|
|
37
|
+
import { filterEmptyValue, isFunction, isString } from '@daysnap/utils'
|
|
38
|
+
import { ElCol, ElForm, ElFormItem, ElRow } from 'element-plus'
|
|
39
|
+
import { computed, ref, useTemplateRef, watchEffect } from 'vue'
|
|
40
|
+
|
|
41
|
+
import { useLocale } from '../locale'
|
|
42
|
+
import { datePickerValueFormat } from '../utils'
|
|
43
|
+
import { defineVroElSchemaFormFieldTrigger } from './defineVroElSchemaFormFieldTrigger'
|
|
44
|
+
import { vroElSchemaFormProps, type VroElSchemaFormSchema } from './types'
|
|
45
|
+
import { vroElSchemaFormFieldManager } from './vroElSchemaFormFieldManager'
|
|
46
|
+
|
|
47
|
+
defineOptions({ name: 'VroElSchemaForm' })
|
|
48
|
+
|
|
49
|
+
const emit = defineEmits(['change-field', 'input-field'])
|
|
50
|
+
const props = defineProps(vroElSchemaFormProps)
|
|
51
|
+
|
|
52
|
+
const elFormProps = computed(() => {
|
|
53
|
+
return {
|
|
54
|
+
validateOnRuleChange: false,
|
|
55
|
+
...props.formProps,
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const { locale } = useLocale()
|
|
60
|
+
|
|
61
|
+
// 规则
|
|
62
|
+
const rules = ref<Record<string, any>>({})
|
|
63
|
+
const model = ref<Record<string, any>>({})
|
|
64
|
+
const metadata = ref<VroElSchemaFormSchema>({})
|
|
65
|
+
|
|
66
|
+
watchEffect(() => {
|
|
67
|
+
const { schema } = props
|
|
68
|
+
metadata.value = {}
|
|
69
|
+
Object.entries(schema).forEach(([key, item]) => {
|
|
70
|
+
// eslint-disable-next-line prefer-const
|
|
71
|
+
let { hidden, value, rules: itemRules, is } = item
|
|
72
|
+
|
|
73
|
+
if (isFunction(hidden)) {
|
|
74
|
+
hidden = hidden(value, item, schema)
|
|
75
|
+
}
|
|
76
|
+
if (!is) {
|
|
77
|
+
hidden = true
|
|
78
|
+
}
|
|
79
|
+
if (!hidden) {
|
|
80
|
+
model.value[key] = value
|
|
81
|
+
metadata.value[key] = item
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isFunction(rules)) {
|
|
85
|
+
rules.value = rules(value, item, schema)
|
|
86
|
+
}
|
|
87
|
+
rules.value[key] = itemRules
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const mapping = computed(() => {
|
|
92
|
+
return Object.entries(metadata.value).reduce<Record<string, any>>((res, [key, item]) => {
|
|
93
|
+
// eslint-disable-next-line prefer-const
|
|
94
|
+
let { props = {}, is, options, labelKey, valueKey } = item
|
|
95
|
+
if (isString(is)) {
|
|
96
|
+
const data = vroElSchemaFormFieldManager.get(is)
|
|
97
|
+
if (data) {
|
|
98
|
+
let loc: Record<string, any> = {}
|
|
99
|
+
if (isString(is)) {
|
|
100
|
+
loc = (locale.value.el['schemaForm'] as any)[is]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (is === 'ElDatePicker') {
|
|
104
|
+
props.valueFormat = datePickerValueFormat[props?.type ?? 'date']
|
|
105
|
+
}
|
|
106
|
+
is = data.is
|
|
107
|
+
props = Object.assign(
|
|
108
|
+
{},
|
|
109
|
+
data.props,
|
|
110
|
+
loc,
|
|
111
|
+
filterEmptyValue({ options, labelKey, valueKey }),
|
|
112
|
+
props,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if (props.disabled) {
|
|
116
|
+
props.placeholder = '-'
|
|
117
|
+
if (is === 'ElDatePicker') {
|
|
118
|
+
props.startPlaceholder = '-'
|
|
119
|
+
props.endPlaceholder = '-'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
res[key] = { is, props }
|
|
125
|
+
return res
|
|
126
|
+
}, {})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// 事件
|
|
130
|
+
const handleChange = async (key: string, value: any) => {
|
|
131
|
+
emit('change-field', { key, value })
|
|
132
|
+
await props.schema[key]?.onChange?.(value, props.schema[key], props.schema)
|
|
133
|
+
}
|
|
134
|
+
const handleInput = async (key: string, value: any) => {
|
|
135
|
+
emit('input-field', { key, value })
|
|
136
|
+
await props.schema[key]?.onInput?.(value, props.schema[key], props.schema)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 校验
|
|
140
|
+
const refComponents = useTemplateRef<any[]>('refComponents')
|
|
141
|
+
const refForm = useTemplateRef('refForm')
|
|
142
|
+
const validate = async () => {
|
|
143
|
+
const instances = refComponents.value?.filter((item) => isFunction(item.validate)) ?? []
|
|
144
|
+
await Promise.all([refForm.value, ...instances].map((item) => item?.validate()))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 获取值 这里返回异步函数 为以后可能会做校验做准备
|
|
148
|
+
const extractValues = async () => {
|
|
149
|
+
const instances = refComponents.value?.filter((item) => isFunction(item.extractValues)) ?? []
|
|
150
|
+
const results = await Promise.all<Record<string, any>[]>(
|
|
151
|
+
instances.map((item) => item.extractValues()),
|
|
152
|
+
)
|
|
153
|
+
results.push(banana.extract(props.schema as any))
|
|
154
|
+
return results.filter(Boolean).reduce<Record<string, any>>((res, item) => {
|
|
155
|
+
return { ...res, ...item }
|
|
156
|
+
}, {})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 触发执行子组件的 trigger 事件
|
|
160
|
+
const trigger = defineVroElSchemaFormFieldTrigger(async (ctx) => {
|
|
161
|
+
const instances = refComponents.value?.filter((item) => isFunction(item.trigger)) ?? []
|
|
162
|
+
await Promise.all(instances.map((item) => item.trigger(ctx)))
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
defineExpose({
|
|
166
|
+
get form() {
|
|
167
|
+
return refForm.value!
|
|
168
|
+
},
|
|
169
|
+
validate,
|
|
170
|
+
resetFields: () => refForm.value?.resetFields(),
|
|
171
|
+
trigger,
|
|
172
|
+
extractValues,
|
|
173
|
+
validateField: async (key: string) => {
|
|
174
|
+
return refForm.value?.validateField(key)
|
|
175
|
+
},
|
|
176
|
+
})
|
|
177
|
+
</script>
|