Commit 47a448b8aea572e54dac97dc4f9fb6c1c005685a
1 parent
5138e447
feat(form): add `Divider` for schema component type
新增Divider用于较长表单的区域分割
Showing
8 changed files
with
94 additions
and
41 deletions
CHANGELOG.zh_CN.md
src/components/Form/src/BasicForm.vue
... | ... | @@ -29,7 +29,7 @@ |
29 | 29 | #[item]="data" |
30 | 30 | v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']" |
31 | 31 | > |
32 | - <slot :name="item" v-bind="data"></slot> | |
32 | + <slot :name="item" v-bind="data || {}"></slot> | |
33 | 33 | </template> |
34 | 34 | </FormAction> |
35 | 35 | <slot name="formFooter"></slot> |
... | ... | @@ -132,7 +132,11 @@ |
132 | 132 | } |
133 | 133 | } |
134 | 134 | } |
135 | - return schemas as FormSchema[]; | |
135 | + if (unref(getProps).showAdvancedButton) { | |
136 | + return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[]; | |
137 | + } else { | |
138 | + return schemas as FormSchema[]; | |
139 | + } | |
136 | 140 | }); |
137 | 141 | |
138 | 142 | const { handleToggleAdvanced } = useAdvanced({ | ... | ... |
src/components/Form/src/componentMap.ts
... | ... | @@ -18,6 +18,7 @@ import { |
18 | 18 | TreeSelect, |
19 | 19 | Slider, |
20 | 20 | Rate, |
21 | + Divider, | |
21 | 22 | } from 'ant-design-vue'; |
22 | 23 | |
23 | 24 | import RadioButtonGroup from './components/RadioButtonGroup.vue'; |
... | ... | @@ -61,6 +62,7 @@ componentMap.set('IconPicker', IconPicker); |
61 | 62 | componentMap.set('InputCountDown', CountdownInput); |
62 | 63 | |
63 | 64 | componentMap.set('Upload', BasicUpload); |
65 | +componentMap.set('Divider', Divider); | |
64 | 66 | |
65 | 67 | export function add(compName: ComponentType, component: Component) { |
66 | 68 | componentMap.set(compName, component); | ... | ... |
src/components/Form/src/components/FormItem.vue
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | import type { ValidationRule } from 'ant-design-vue/lib/form/Form'; |
6 | 6 | import type { TableActionType } from '/@/components/Table'; |
7 | 7 | import { defineComponent, computed, unref, toRefs } from 'vue'; |
8 | - import { Form, Col } from 'ant-design-vue'; | |
8 | + import { Form, Col, Divider } from 'ant-design-vue'; | |
9 | 9 | import { componentMap } from '../componentMap'; |
10 | 10 | import { BasicHelp } from '/@/components/Basic'; |
11 | 11 | import { isBoolean, isFunction, isNull } from '/@/utils/is'; |
... | ... | @@ -73,11 +73,17 @@ |
73 | 73 | |
74 | 74 | const getComponentsProps = computed(() => { |
75 | 75 | const { schema, tableAction, formModel, formActionType } = props; |
76 | - const { componentProps = {} } = schema; | |
77 | - if (!isFunction(componentProps)) { | |
78 | - return componentProps; | |
76 | + let { componentProps = {} } = schema; | |
77 | + if (isFunction(componentProps)) { | |
78 | + componentProps = componentProps({ schema, tableAction, formModel, formActionType }) ?? {}; | |
79 | 79 | } |
80 | - return componentProps({ schema, tableAction, formModel, formActionType }) ?? {}; | |
80 | + if (schema.component === 'Divider') { | |
81 | + componentProps = Object.assign({ type: 'horizontal' }, componentProps, { | |
82 | + orientation: 'left', | |
83 | + plain: true, | |
84 | + }); | |
85 | + } | |
86 | + return componentProps; | |
81 | 87 | }); |
82 | 88 | |
83 | 89 | const getDisable = computed(() => { |
... | ... | @@ -300,38 +306,46 @@ |
300 | 306 | } |
301 | 307 | |
302 | 308 | function renderItem() { |
303 | - const { itemProps, slot, render, field, suffix } = props.schema; | |
309 | + const { itemProps, slot, render, field, suffix, component, label } = props.schema; | |
304 | 310 | const { labelCol, wrapperCol } = unref(itemLabelWidthProp); |
305 | 311 | const { colon } = props.formProps; |
306 | 312 | |
307 | - const getContent = () => { | |
308 | - return slot | |
309 | - ? getSlot(slots, slot, unref(getValues)) | |
310 | - : render | |
311 | - ? render(unref(getValues)) | |
312 | - : renderComponent(); | |
313 | - }; | |
314 | - | |
315 | - const showSuffix = !!suffix; | |
316 | - const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix; | |
317 | - | |
318 | - return ( | |
319 | - <Form.Item | |
320 | - name={field} | |
321 | - colon={colon} | |
322 | - class={{ 'suffix-item': showSuffix }} | |
323 | - {...(itemProps as Recordable)} | |
324 | - label={renderLabelHelpMessage()} | |
325 | - rules={handleRules()} | |
326 | - labelCol={labelCol} | |
327 | - wrapperCol={wrapperCol} | |
328 | - > | |
329 | - <div style="display:flex"> | |
330 | - <div style="flex:1">{getContent()}</div> | |
331 | - {showSuffix && <span class="suffix">{getSuffix}</span>} | |
332 | - </div> | |
333 | - </Form.Item> | |
334 | - ); | |
313 | + if (component === 'Divider') { | |
314 | + return ( | |
315 | + <Col span={24}> | |
316 | + <Divider {...unref(getComponentsProps)}>{label}</Divider> | |
317 | + </Col> | |
318 | + ); | |
319 | + } else { | |
320 | + const getContent = () => { | |
321 | + return slot | |
322 | + ? getSlot(slots, slot, unref(getValues)) | |
323 | + : render | |
324 | + ? render(unref(getValues)) | |
325 | + : renderComponent(); | |
326 | + }; | |
327 | + | |
328 | + const showSuffix = !!suffix; | |
329 | + const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix; | |
330 | + | |
331 | + return ( | |
332 | + <Form.Item | |
333 | + name={field} | |
334 | + colon={colon} | |
335 | + class={{ 'suffix-item': showSuffix }} | |
336 | + {...(itemProps as Recordable)} | |
337 | + label={renderLabelHelpMessage()} | |
338 | + rules={handleRules()} | |
339 | + labelCol={labelCol} | |
340 | + wrapperCol={wrapperCol} | |
341 | + > | |
342 | + <div style="display:flex"> | |
343 | + <div style="flex:1">{getContent()}</div> | |
344 | + {showSuffix && <span class="suffix">{getSuffix}</span>} | |
345 | + </div> | |
346 | + </Form.Item> | |
347 | + ); | |
348 | + } | |
335 | 349 | } |
336 | 350 | |
337 | 351 | return () => { | ... | ... |
src/components/Form/src/hooks/useFormEvents.ts
... | ... | @@ -149,7 +149,9 @@ export function useFormEvents({ |
149 | 149 | updateData = [...data]; |
150 | 150 | } |
151 | 151 | |
152 | - const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field); | |
152 | + const hasField = updateData.every( | |
153 | + (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field) | |
154 | + ); | |
153 | 155 | |
154 | 156 | if (!hasField) { |
155 | 157 | error( |
... | ... | @@ -169,7 +171,9 @@ export function useFormEvents({ |
169 | 171 | updateData = [...data]; |
170 | 172 | } |
171 | 173 | |
172 | - const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field); | |
174 | + const hasField = updateData.every( | |
175 | + (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field) | |
176 | + ); | |
173 | 177 | |
174 | 178 | if (!hasField) { |
175 | 179 | error( | ... | ... |
src/components/Form/src/types/index.ts
src/views/demo/form/AdvancedForm.vue
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 | <script lang="ts"> |
13 | 13 | import { defineComponent } from 'vue'; |
14 | 14 | import { BasicForm, FormSchema, useForm } from '/@/components/Form/index'; |
15 | - import { CollapseContainer } from '/@/components/Container/index'; | |
15 | + import { CollapseContainer } from '/@/components/Container'; | |
16 | 16 | import { PageWrapper } from '/@/components/Page'; |
17 | 17 | |
18 | 18 | const getSchamas = (): FormSchema[] => { |
... | ... | @@ -173,7 +173,12 @@ |
173 | 173 | } |
174 | 174 | const [register1] = useForm({ |
175 | 175 | labelWidth: 120, |
176 | - schemas: [...getSchamas(), ...getAppendSchemas(), ...extraSchemas], | |
176 | + schemas: [ | |
177 | + ...getSchamas(), | |
178 | + ...getAppendSchemas(), | |
179 | + { field: '', component: 'Divider', label: '更多字段' }, | |
180 | + ...extraSchemas, | |
181 | + ], | |
177 | 182 | actionColOptions: { |
178 | 183 | span: 24, |
179 | 184 | }, | ... | ... |
src/views/demo/form/index.vue
... | ... | @@ -101,6 +101,11 @@ |
101 | 101 | |
102 | 102 | const schemas: FormSchema[] = [ |
103 | 103 | { |
104 | + field: '', | |
105 | + component: 'Divider', | |
106 | + label: '基础字段', | |
107 | + }, | |
108 | + { | |
104 | 109 | field: 'field1', |
105 | 110 | component: 'Input', |
106 | 111 | label: '字段1', |
... | ... | @@ -294,6 +299,11 @@ |
294 | 299 | }, |
295 | 300 | }, |
296 | 301 | { |
302 | + field: '', | |
303 | + component: 'Divider', | |
304 | + label: '远程下拉演示', | |
305 | + }, | |
306 | + { | |
297 | 307 | field: 'field30', |
298 | 308 | component: 'ApiSelect', |
299 | 309 | label: '懒加载远程下拉', |
... | ... | @@ -363,6 +373,11 @@ |
363 | 373 | }, |
364 | 374 | }, |
365 | 375 | { |
376 | + field: '', | |
377 | + component: 'Divider', | |
378 | + label: '其它', | |
379 | + }, | |
380 | + { | |
366 | 381 | field: 'field20', |
367 | 382 | component: 'InputNumber', |
368 | 383 | label: '字段20', | ... | ... |