diff --git a/plugin-render-antd/README.md b/plugin-render-antd/README.md index 96ad1bb..648677a 100644 --- a/plugin-render-antd/README.md +++ b/plugin-render-antd/README.md @@ -39,7 +39,6 @@ VxeUI.use(VxeUIPluginRenderAntd) | optionGroups | 只对 name=ASelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ASelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | ### edit-render 可编辑渲染器配置项说明 @@ -52,7 +51,6 @@ VxeUI.use(VxeUIPluginRenderAntd) | optionGroups | 只对 name=ASelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ASelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | ### filter-render 筛选渲染器配置项说明 @@ -65,7 +63,6 @@ VxeUI.use(VxeUIPluginRenderAntd) | optionGroups | 只对 name=ASelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ASelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | ### item-render 表单-项选渲染器配置项说明 @@ -78,7 +75,12 @@ VxeUI.use(VxeUIPluginRenderAntd) | optionGroups | 只对 name=ASelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ASelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | + +### 表单设计器配置项 + +| 描述 | +|------| +| 'AInputWidget', 'ATextareaWidget', 'ANumberInputWidget', 'ADatePickerWidget', 'ASelectWidget', 'ARadioWidget', 'ACheckboxWidget', 'ASwitchWidget' | ## Cell demo diff --git a/plugin-render-antd/package.json b/plugin-render-antd/package.json index 28ef26d..8b9dd6c 100644 --- a/plugin-render-antd/package.json +++ b/plugin-render-antd/package.json @@ -1,6 +1,6 @@ { "name": "@vxe-ui/plugin-render-antd", - "version": "4.0.3", + "version": "4.0.4", "description": "Vxe UI plug-in for compatibility with the ant-design-vue component.", "scripts": { "lib": "gulp build" @@ -51,8 +51,8 @@ "typescript": "^4.6.4", "vinyl-source-stream": "^2.0.0", "vue": "^3.4.27", - "vxe-pc-ui": "^4.0.24", - "vxe-table": "^4.7.25" + "vxe-pc-ui": "^4.0.30", + "vxe-table": "^4.7.32" }, "repository": { "type": "git", diff --git a/plugin-render-antd/src/form-design/checkbox-widget.ts b/plugin-render-antd/src/form-design/checkbox-widget.ts new file mode 100644 index 0000000..d96d7cf --- /dev/null +++ b/plugin-render-antd/src/form-design/checkbox-widget.ts @@ -0,0 +1,164 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions, computed } from 'vue' +import { useWidgetPropDataSource, WidgetDataSourceOptionObjVO } from './use' +import XEUtils from 'xe-utils' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' + +interface WidgetACheckboxFormObjVO { + options: WidgetDataSourceOptionObjVO[] +} + +export function createWidgetACheckbox (VxeUI: VxeUIExport) { + const getWidgetACheckboxConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '复选框', + icon: 'vxe-icon-checkbox-checked', + options: { + options: XEUtils.range(0, 3).map((v, i) => { + return { + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [i + 1]) + } + }) + } + } + } + + const WidgetACheckboxFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') + + const { renderDataSourceFormItem } = useWidgetPropDataSource(VxeUI, props, false) + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(VxeUIInputComponent, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }), + renderDataSourceFormItem() + ] + } + }) + } + } + }) + + const WidgetACheckboxViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const checkboxOptions = computed(() => { + const { renderParams } = props + const { widget } = renderParams + const { options } = widget + return options.options.map(item => { + return { + label: item.value, + value: item.value + } + }) + }) + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('a-checkbox-group') as ComponentOptions, { + value: $formView ? $formView.getItemValue(widget) : null, + options: checkboxOptions.value, + onChange: changeEvent, + 'onUpdate:value' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetACheckboxConfig, + WidgetACheckboxFormComponent, + WidgetACheckboxViewComponent + } +} diff --git a/plugin-render-antd/src/form-design/a-date-picker.ts b/plugin-render-antd/src/form-design/date-picker-widget.ts similarity index 93% rename from plugin-render-antd/src/form-design/a-date-picker.ts rename to plugin-render-antd/src/form-design/date-picker-widget.ts index 89e0e8e..86240c1 100644 --- a/plugin-render-antd/src/form-design/a-date-picker.ts +++ b/plugin-render-antd/src/form-design/date-picker-widget.ts @@ -1,6 +1,6 @@ import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' -import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' interface WidgetADatePickerFormObjVO { placeholder: string @@ -33,6 +33,7 @@ export function createWidgetADatePicker (VxeUI: VxeUIExport) { const VxeUIFormComponent = VxeUI.getComponent('VxeForm') const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') return () => { const { renderParams } = props @@ -52,7 +53,7 @@ export function createWidgetADatePicker (VxeUI: VxeUIExport) { title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') }, { default () { - return h(resolveComponent('a-date-picker') as ComponentOptions, { + return h(VxeUIInputComponent, { modelValue: widget.title, 'onUpdate:modelValue' (val: any) { widget.title = val @@ -120,10 +121,10 @@ export function createWidgetADatePicker (VxeUI: VxeUIExport) { }, { default () { return h(resolveComponent('a-date-picker') as ComponentOptions, { - modelValue: $formView ? $formView.getItemValue(widget) : null, + value: $formView ? $formView.getItemValue(widget) : null, placeholder: options.placeholder, onChange: changeEvent, - 'onUpdate:modelValue' (val: any) { + 'onUpdate:value' (val: any) { if ($formView) { $formView.setItemValue(widget, val) } diff --git a/plugin-render-antd/src/form-design/index.ts b/plugin-render-antd/src/form-design/index.ts index 33b1e31..a3996af 100644 --- a/plugin-render-antd/src/form-design/index.ts +++ b/plugin-render-antd/src/form-design/index.ts @@ -1,6 +1,12 @@ import { h } from 'vue' -import { createWidgetAInput } from './a-input' -import { createWidgetADatePicker } from './a-date-picker' +import { createWidgetAInput } from './input-widget' +import { createWidgetATextarea } from './textarea-widget' +import { createWidgetAInputNumber } from './number-input-widget' +import { createWidgetADatePicker } from './date-picker-widget' +import { createWidgetASelect } from './select-widget' +import { createWidgetARadio } from './radio-widget' +import { createWidgetACheckbox } from './checkbox-widget' +import { createWidgetASwitch } from './switch-widget' import type { VxeUIExport } from 'vxe-pc-ui' @@ -9,10 +15,16 @@ import type { VxeUIExport } from 'vxe-pc-ui' */ export function defineFormDesignRender (VxeUI: VxeUIExport) { const { getWidgetAInputConfig, WidgetAInputViewComponent, WidgetAInputFormComponent } = createWidgetAInput(VxeUI) + const { getWidgetATextareaConfig, WidgetATextareaViewComponent, WidgetATextareaFormComponent } = createWidgetATextarea(VxeUI) + const { getWidgetAInputNumberConfig, WidgetAInputNumberViewComponent, WidgetAInputNumberFormComponent } = createWidgetAInputNumber(VxeUI) const { getWidgetADatePickerConfig, WidgetADatePickerViewComponent, WidgetADatePickerFormComponent } = createWidgetADatePicker(VxeUI) + const { getWidgetASelectConfig, WidgetASelectViewComponent, WidgetASelectFormComponent } = createWidgetASelect(VxeUI) + const { getWidgetARadioConfig, WidgetARadioViewComponent, WidgetARadioFormComponent } = createWidgetARadio(VxeUI) + const { getWidgetACheckboxConfig, WidgetACheckboxViewComponent, WidgetACheckboxFormComponent } = createWidgetACheckbox(VxeUI) + const { getWidgetASwitchConfig, WidgetASwitchViewComponent, WidgetASwitchFormComponent } = createWidgetASwitch(VxeUI) VxeUI.renderer.mixin({ - AInput: { + AInputWidget: { createFormDesignWidgetConfig: getWidgetAInputConfig, renderFormDesignWidgetView (renderOpts, renderParams) { return h(WidgetAInputViewComponent, { renderOpts, renderParams }) @@ -21,7 +33,25 @@ export function defineFormDesignRender (VxeUI: VxeUIExport) { return h(WidgetAInputFormComponent, { renderOpts, renderParams }) } }, - ADatePicker: { + ATextareaWidget: { + createFormDesignWidgetConfig: getWidgetATextareaConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetATextareaViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetATextareaFormComponent, { renderOpts, renderParams }) + } + }, + ANumberInputWidget: { + createFormDesignWidgetConfig: getWidgetAInputNumberConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetAInputNumberViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetAInputNumberFormComponent, { renderOpts, renderParams }) + } + }, + ADatePickerWidget: { createFormDesignWidgetConfig: getWidgetADatePickerConfig, renderFormDesignWidgetView (renderOpts, renderParams) { return h(WidgetADatePickerViewComponent, { renderOpts, renderParams }) @@ -29,6 +59,43 @@ export function defineFormDesignRender (VxeUI: VxeUIExport) { renderFormDesignWidgetFormView (renderOpts, renderParams) { return h(WidgetADatePickerFormComponent, { renderOpts, renderParams }) } + }, + ASelectWidget: { + createFormDesignWidgetConfig: getWidgetASelectConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetASelectViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetASelectFormComponent, { renderOpts, renderParams }) + } + }, + ARadioWidget: { + createFormDesignWidgetConfig: getWidgetARadioConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetARadioViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetARadioFormComponent, { renderOpts, renderParams }) + } + }, + ACheckboxWidget: { + createFormDesignWidgetConfig: getWidgetACheckboxConfig, + createFormDesignWidgetFieldValue: () => [], + renderFormDesignWidgetView (renderOpts: any, renderParams: any) { + return h(WidgetACheckboxViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts: any, renderParams: any) { + return h(WidgetACheckboxFormComponent, { renderOpts, renderParams }) + } + }, + ASwitchWidget: { + createFormDesignWidgetConfig: getWidgetASwitchConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetASwitchViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetASwitchFormComponent, { renderOpts, renderParams }) + } } }) } diff --git a/plugin-render-antd/src/form-design/a-input.ts b/plugin-render-antd/src/form-design/input-widget.ts similarity index 92% rename from plugin-render-antd/src/form-design/a-input.ts rename to plugin-render-antd/src/form-design/input-widget.ts index 3c97f68..1a3b197 100644 --- a/plugin-render-antd/src/form-design/a-input.ts +++ b/plugin-render-antd/src/form-design/input-widget.ts @@ -1,6 +1,6 @@ import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' -import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' interface WidgetAInputFormObjVO { placeholder: string @@ -33,6 +33,7 @@ export function createWidgetAInput (VxeUI: VxeUIExport) { const VxeUIFormComponent = VxeUI.getComponent('VxeForm') const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') return () => { const { renderParams } = props @@ -53,7 +54,7 @@ export function createWidgetAInput (VxeUI: VxeUIExport) { title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') }, { default () { - return h(resolveComponent('a-input') as ComponentOptions, { + return h(VxeUIInputComponent, { modelValue: widget.title, placeholder: options.placeholder, 'onUpdate:modelValue' (val: any) { @@ -121,9 +122,9 @@ export function createWidgetAInput (VxeUI: VxeUIExport) { }, { default () { return h(resolveComponent('a-input') as ComponentOptions, { - modelValue: $formView ? $formView.getItemValue(widget) : null, + value: $formView ? $formView.getItemValue(widget) : null, onChange: changeEvent, - 'onUpdate:modelValue' (val: any) { + 'onUpdate:value' (val: any) { if ($formView) { $formView.setItemValue(widget, val) } diff --git a/plugin-render-antd/src/form-design/number-input-widget.ts b/plugin-render-antd/src/form-design/number-input-widget.ts new file mode 100644 index 0000000..1ae9446 --- /dev/null +++ b/plugin-render-antd/src/form-design/number-input-widget.ts @@ -0,0 +1,144 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' + +interface WidgetAInputNumberFormObjVO { + placeholder: string +} + +export function createWidgetAInputNumber (VxeUI: VxeUIExport) { + const getWidgetAInputNumberConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '数字', + icon: 'vxe-icon-number', + options: { + placeholder: '请输入' + } + } + } + + const WidgetAInputNumberFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(VxeUIInputComponent, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }) + ] + } + }) + } + } + }) + + const WidgetAInputNumberViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('a-input-number') as ComponentOptions, { + value: $formView ? $formView.getItemValue(widget) : null, + placeholder: options.placeholder, + onChange: changeEvent, + 'onUpdate:value' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetAInputNumberConfig, + WidgetAInputNumberFormComponent, + WidgetAInputNumberViewComponent + } +} diff --git a/plugin-render-antd/src/form-design/radio-widget.ts b/plugin-render-antd/src/form-design/radio-widget.ts new file mode 100644 index 0000000..7578f8e --- /dev/null +++ b/plugin-render-antd/src/form-design/radio-widget.ts @@ -0,0 +1,164 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions, computed } from 'vue' +import { useWidgetPropDataSource, WidgetDataSourceOptionObjVO } from './use' +import XEUtils from 'xe-utils' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' + +interface WidgetARadioFormObjVO { + options: WidgetDataSourceOptionObjVO[] +} + +export function createWidgetARadio (VxeUI: VxeUIExport) { + const getWidgetARadioConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '单选框', + icon: 'vxe-icon-radio-checked', + options: { + options: XEUtils.range(0, 3).map((v, i) => { + return { + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [i + 1]) + } + }) + } + } + } + + const WidgetARadioFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') + + const { renderDataSourceFormItem } = useWidgetPropDataSource(VxeUI, props, false) + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(VxeUIInputComponent, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }), + renderDataSourceFormItem() + ] + } + }) + } + } + }) + + const WidgetARadioViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const radioOptions = computed(() => { + const { renderParams } = props + const { widget } = renderParams + const { options } = widget + return options.options.map(item => { + return { + label: item.value, + value: item.value + } + }) + }) + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('a-radio-group') as ComponentOptions, { + value: $formView ? $formView.getItemValue(widget) : null, + options: radioOptions.value, + onChange: changeEvent, + 'onUpdate:value' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetARadioConfig, + WidgetARadioFormComponent, + WidgetARadioViewComponent + } +} diff --git a/plugin-render-antd/src/form-design/select-widget.ts b/plugin-render-antd/src/form-design/select-widget.ts new file mode 100644 index 0000000..eba0a0b --- /dev/null +++ b/plugin-render-antd/src/form-design/select-widget.ts @@ -0,0 +1,156 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' +import { useWidgetPropDataSource, WidgetDataSourceOptionObjVO } from './use' +import XEUtils from 'xe-utils' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' + +interface WidgetASelectFormObjVO { + placeholder: string + options: WidgetDataSourceOptionObjVO[] +} + +export function createWidgetASelect (VxeUI: VxeUIExport) { + const getWidgetASelectConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '下拉框', + icon: 'vxe-icon-select', + options: { + placeholder: '请选择', + options: XEUtils.range(0, 3).map((v, i) => { + return { + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [i + 1]) + } + }) + } + } + } + + const WidgetASelectFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') + + const { renderDataSourceFormItem } = useWidgetPropDataSource(VxeUI, props, false) + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(VxeUIInputComponent, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }), + renderDataSourceFormItem() + ] + } + }) + } + } + }) + + const WidgetASelectViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('a-select') as ComponentOptions, { + value: $formView ? $formView.getItemValue(widget) : null, + options: options.options, + placeholder: options.placeholder, + onChange: changeEvent, + 'onUpdate:value' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetASelectConfig, + WidgetASelectFormComponent, + WidgetASelectViewComponent + } +} diff --git a/plugin-render-antd/src/form-design/switch-widget.ts b/plugin-render-antd/src/form-design/switch-widget.ts new file mode 100644 index 0000000..477e168 --- /dev/null +++ b/plugin-render-antd/src/form-design/switch-widget.ts @@ -0,0 +1,140 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' + +interface WidgetASwitchFormObjVO { +} + +export function createWidgetASwitch (VxeUI: VxeUIExport) { + const getWidgetASwitchConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '是/否', + icon: 'vxe-icon-switch', + options: { + } + } + } + + const WidgetASwitchFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(VxeUIInputComponent, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }) + ] + } + }) + } + } + }) + + const WidgetASwitchViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('a-switch') as ComponentOptions, { + checked: $formView ? $formView.getItemValue(widget) : null, + onChange: changeEvent, + 'onUpdate:checked' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetASwitchConfig, + WidgetASwitchFormComponent, + WidgetASwitchViewComponent + } +} diff --git a/plugin-render-antd/src/form-design/textarea-widget.ts b/plugin-render-antd/src/form-design/textarea-widget.ts new file mode 100644 index 0000000..35c2625 --- /dev/null +++ b/plugin-render-antd/src/form-design/textarea-widget.ts @@ -0,0 +1,148 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent, VxeInputComponent } from 'vxe-pc-ui' + +interface WidgetATextareaFormObjVO { + placeholder: string +} + +export function createWidgetATextarea (VxeUI: VxeUIExport) { + const getWidgetATextareaConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '文本域', + icon: 'vxe-icon-textarea', + options: { + placeholder: '请输入' + } + } + } + + const WidgetATextareaFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + const VxeUIInputComponent = VxeUI.getComponent('VxeInput') + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(VxeUIInputComponent, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }) + ] + } + }) + } + } + }) + + const WidgetATextareaViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('a-textarea') as ComponentOptions, { + value: $formView ? $formView.getItemValue(widget) : null, + placeholder: options.placeholder, + autoSize: { + minRows: 2, + maxRows: 4 + }, + onChange: changeEvent, + 'onUpdate:value' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetATextareaConfig, + WidgetATextareaFormComponent, + WidgetATextareaViewComponent + } +} diff --git a/plugin-render-antd/src/form-design/use.ts b/plugin-render-antd/src/form-design/use.ts new file mode 100644 index 0000000..4c27540 --- /dev/null +++ b/plugin-render-antd/src/form-design/use.ts @@ -0,0 +1,255 @@ +import { VNode, h, onMounted, ref, watch } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormItemComponent, VxeButtonComponent, VxeTextareaComponent, VxeTipComponent } from 'vxe-pc-ui' + +export interface WidgetDataSourceOptionSubObjVO { + value: string, +} + +export interface WidgetDataSourceOptionObjVO { + value: string, + options?: WidgetDataSourceOptionSubObjVO[] +} + +export function useWidgetPropDataSource (VxeUI: VxeUIExport, props: { + readonly renderOpts: VxeGlobalRendererHandles.RenderFormDesignWidgetFormViewOptions; + readonly renderParams: VxeGlobalRendererHandles.RenderFormDesignWidgetFormViewParams<{ + options: WidgetDataSourceOptionObjVO[] + }>; +}, isSubOption: boolean) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUIButtonComponent = VxeUI.getComponent('VxeButton') + const VxeUITextareaComponent = VxeUI.getComponent('VxeTextarea') + const VxeUITipComponent = VxeUI.getComponent('VxeTip') + + const optionsContent = ref('') + const expandIndexList = ref([]) + + const addOptionEvent = () => { + const { renderParams } = props + const { widget } = renderParams + const options = widget.options.options || [] + options.push({ + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [options.length + 1]) + }) + widget.options.options = [...options] + } + + const subRE = /^(\s|\t)+/ + + const hasSubOption = (str: string) => { + return subRE.test(str) + } + + const expandAllOption = () => { + const { renderParams } = props + const { widget } = renderParams + const options = widget.options.options || [] + const indexList: number[] = [] + options.forEach((group, gIndex) => { + const { options } = group + if (options && options.length) { + indexList.push(gIndex) + } + }) + expandIndexList.value = indexList + } + + const toggleExpandOption = (item: WidgetDataSourceOptionSubObjVO, gIndex: number) => { + if (expandIndexList.value.includes(gIndex)) { + expandIndexList.value = expandIndexList.value.filter(num => num !== gIndex) + } else { + expandIndexList.value.push(gIndex) + } + } + + const confirmBatchAddOptionEvent = () => { + const { renderParams } = props + const { widget } = renderParams + const optList: WidgetDataSourceOptionSubObjVO[] = [] + const rowList = optionsContent.value.split('\n') + let prevGroup: Required | null = null + if (isSubOption) { + rowList.forEach((str, index) => { + const nextStr = rowList[index + 1] + const value = str.trim() + if (!value) { + return + } + const item: WidgetDataSourceOptionSubObjVO = { + value + } + if (prevGroup) { + if (hasSubOption(str)) { + prevGroup.options.push(item) + return + } + prevGroup = null + optList.push(item) + } else { + optList.push(item) + } + if (nextStr) { + if (hasSubOption(nextStr)) { + prevGroup = Object.assign(item, { options: [] }) + } + } + }) + } else { + rowList.forEach((str) => { + optList.push({ + value: str.trim() + }) + }) + } + widget.options.options = optList + expandAllOption() + } + + const openPopupEditEvent = () => { + const { renderParams } = props + const { widget } = renderParams + + const contList: string[] = [] + widget.options.options?.forEach(group => { + contList.push(group.value) + group.options?.forEach(item => { + contList.push(`\t${item.value}`) + }) + }) + + optionsContent.value = contList.join('\n') + + VxeUI.modal.open({ + title: `${widget.title} - ${VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.batchEditOption')}`, + width: 500, + height: '50vh ', + resize: true, + showFooter: true, + showCancelButton: true, + showConfirmButton: true, + confirmButtonText: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.buildOption'), + onConfirm: confirmBatchAddOptionEvent, + slots: { + default () { + return h('div', { + class: 'vxe-form-design--widget-form-item-data-source-popup' + }, [ + h(VxeUITipComponent, { + status: 'primary', + title: '', + content: VxeUI.getI18n(`vxe.formDesign.widgetProp.dataSource.${isSubOption ? 'batchEditSubTip' : 'batchEditTip'}`) + }), + h(VxeUITextareaComponent, { + resize: 'none', + modelValue: optionsContent.value, + 'onUpdate:modelValue' (val: any) { + optionsContent.value = val + } + }) + ]) + } + } + }) + } + + const renderOption = (item: WidgetDataSourceOptionSubObjVO, hasFirstLevel: boolean, isExpand: boolean, gIndex: number, hasSub: boolean, isFirst: boolean, isLast: boolean) => { + return h('div', { + class: ['vxe-form-design--widget-form-item-data-source-option', { + 'is--first': isFirst, + 'is--last': isLast + }] + }, [ + h('div', { + class: 'vxe-form-design--widget-expand-btn' + }, hasFirstLevel && hasSub + ? [ + h('i', { + class: isExpand ? VxeUI.getIcon().FORM_DESIGN_WIDGET_OPTION_EXPAND_CLOSE : VxeUI.getIcon().FORM_DESIGN_WIDGET_OPTION_EXPAND_OPEN, + onClick () { + toggleExpandOption(item, gIndex) + } + }) + ] + : []), + h('input', { + class: 'vxe-default-input', + value: item.value, + onInput (evnt: InputEvent & { target: HTMLInputElement }) { + item.value = evnt.target.value + } + }), + h(VxeUIButtonComponent, { + status: 'danger', + mode: 'text', + icon: VxeUI.getIcon().FORM_DESIGN_WIDGET_DELETE + }) + ]) + } + + const renderOptions = () => { + const { renderParams } = props + const { widget } = renderParams + const { options } = widget + const groups = options.options + const optVNs: VNode[] = [] + if (groups) { + groups.forEach((group, gIndex) => { + const { options } = group + const isExpand = expandIndexList.value.includes(gIndex) + if (options && options.length) { + optVNs.push(renderOption(group, true, isExpand, gIndex, true, gIndex === 0, gIndex === groups.length - 1)) + if (isExpand) { + optVNs.push( + h('div', { + class: 'vxe-form-design--widget-form-item-data-source-sub-option' + }, options.map(item => renderOption(item, false, isExpand, 0, false, false, false))) + ) + } + } else { + optVNs.push(renderOption(group, true, isExpand, gIndex, false, gIndex === 0, gIndex === groups.length - 1)) + } + }) + } + return optVNs + } + + watch(() => props.renderParams.widget, () => { + expandAllOption() + }) + + onMounted(() => { + expandAllOption() + }) + + return { + renderDataSourceFormItem () { + return h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.name'), + field: 'options' + }, { + default () { + return [ + h('div', {}, [ + h(VxeUIButtonComponent, { + status: 'primary', + mode: 'text', + content: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.addOption'), + onClick: addOptionEvent + }), + h(VxeUIButtonComponent, { + status: 'primary', + mode: 'text', + content: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.batchEditOption'), + onClick: openPopupEditEvent + }) + ]), + h('div', { + class: 'vxe-form-design--widget-form-item-data-source' + }, renderOptions()) + ] + } + }) + } + } +} diff --git a/plugin-render-antd/style.scss b/plugin-render-antd/style.scss index 3e35896..959d268 100644 --- a/plugin-render-antd/style.scss +++ b/plugin-render-antd/style.scss @@ -11,7 +11,8 @@ $vxe-table-validate-error-color: #f56c6c; & > .ant-select, & > .ant-cascader-picker, & > .ant-calendar-picker, - & > .ant-time-picker { + & > .ant-time-picker, + & > .ant-picker { width: 100%; } } diff --git a/plugin-render-element/README.md b/plugin-render-element/README.md index c82077d..bcbb932 100644 --- a/plugin-render-element/README.md +++ b/plugin-render-element/README.md @@ -39,7 +39,6 @@ VxeUI.use(VxeUIPluginRenderElement) | optionGroups | 只对 name=ElSelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ElSelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | ### edit-render 可编辑渲染器配置项说明 @@ -53,7 +52,6 @@ VxeUI.use(VxeUIPluginRenderElement) | optionGroups | 只对 name=ElSelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ElSelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {row,rowIndex,column,columnIndex}, ...Component arguments ) | Object | — | — | ### filter-render 筛选渲染器配置项说明 @@ -67,7 +65,6 @@ VxeUI.use(VxeUIPluginRenderElement) | optionGroups | 只对 name=ElSelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ElSelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | ### item-render 表单-项渲染器配置项说明 @@ -81,7 +78,12 @@ VxeUI.use(VxeUIPluginRenderElement) | optionGroups | 只对 name=ElSelect 有效,下拉组件分组选项列表 | Array | — | [] | | optionGroupProps | 只对 name=ElSelect 有效,下拉组件分组选项属性参数配置 | Object | — | { options: 'options', label: 'label' } | | events | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | -| nativeEvents | 渲染组件附加事件,参数为 ( {}, ...Component arguments ) | Object | — | — | + +### 表单设计器配置项 + +| 描述 | +|------| +| 'ElInputWidget', 'ElTextareaWidget', 'ElNumberInputWidget', 'ElDatePickerWidget', 'ElSelectWidget', 'ElRadioWidget', 'ElCheckboxWidget', 'ElSwitchWidget' | ## Cell demo diff --git a/plugin-render-element/package.json b/plugin-render-element/package.json index e4c9cfa..dfb5f61 100644 --- a/plugin-render-element/package.json +++ b/plugin-render-element/package.json @@ -1,6 +1,6 @@ { "name": "@vxe-ui/plugin-render-element", - "version": "4.0.2", + "version": "4.0.3", "description": "Vxe UI plug-in for compatibility with the element-plus component.", "scripts": { "lib": "gulp build" @@ -52,8 +52,8 @@ "typescript": "^4.6.4", "vinyl-source-stream": "^2.0.0", "vue": "^3.4.27", - "vxe-pc-ui": "^4.0.24", - "vxe-table": "^4.7.25" + "vxe-pc-ui": "^4.0.30", + "vxe-table": "^4.7.32" }, "repository": { "type": "git", diff --git a/plugin-render-element/src/form-design/checkbox-widget.ts b/plugin-render-element/src/form-design/checkbox-widget.ts new file mode 100644 index 0000000..b3e69a1 --- /dev/null +++ b/plugin-render-element/src/form-design/checkbox-widget.ts @@ -0,0 +1,166 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' +import { useWidgetPropDataSource, WidgetDataSourceOptionObjVO } from './use' +import XEUtils from 'xe-utils' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' + +interface WidgetElCheckboxFormObjVO { + options: WidgetDataSourceOptionObjVO[] +} + +export function createWidgetElCheckbox (VxeUI: VxeUIExport) { + const getWidgetElCheckboxConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '复选框', + icon: 'vxe-icon-checkbox-checked', + options: { + options: XEUtils.range(0, 3).map((v, i) => { + return { + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [i + 1]) + } + }) + } + } + } + + const WidgetElCheckboxFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + + const { renderDataSourceFormItem } = useWidgetPropDataSource(VxeUI, props, false) + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }), + renderDataSourceFormItem() + ] + } + }) + } + } + }) + + const WidgetElCheckboxViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('el-checkbox-group') as ComponentOptions, { + modelValue: $formView ? $formView.getItemValue(widget) : null, + onChange: changeEvent, + 'onUpdate:modelValue' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }, { + default: () => { + return options.options + ? options.options.map((item, index) => { + return h(resolveComponent('el-checkbox') as ComponentOptions, { + key: index, + value: item.value + }, { + default () { + return `${item.value}` + } + }) + }) + : [] + } + }) + } + }) + } + } + }) + + return { + getWidgetElCheckboxConfig, + WidgetElCheckboxFormComponent, + WidgetElCheckboxViewComponent + } +} diff --git a/plugin-render-element/src/form-design/el-date-picker.ts b/plugin-render-element/src/form-design/date-picker-widget.ts similarity index 97% rename from plugin-render-element/src/form-design/el-date-picker.ts rename to plugin-render-element/src/form-design/date-picker-widget.ts index fbb06d4..008564a 100644 --- a/plugin-render-element/src/form-design/el-date-picker.ts +++ b/plugin-render-element/src/form-design/date-picker-widget.ts @@ -12,7 +12,7 @@ export function createWidgetElDatePicker (VxeUI: VxeUIExport) { title: '日期', icon: 'vxe-icon-input', options: { - placeholder: '' + placeholder: '请选择' } } } @@ -52,7 +52,7 @@ export function createWidgetElDatePicker (VxeUI: VxeUIExport) { title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') }, { default () { - return h(resolveComponent('el-date-picker') as ComponentOptions, { + return h(resolveComponent('el-input') as ComponentOptions, { modelValue: widget.title, 'onUpdate:modelValue' (val: any) { widget.title = val diff --git a/plugin-render-element/src/form-design/index.ts b/plugin-render-element/src/form-design/index.ts index 2637a33..4a68298 100644 --- a/plugin-render-element/src/form-design/index.ts +++ b/plugin-render-element/src/form-design/index.ts @@ -1,6 +1,12 @@ import { h } from 'vue' -import { createWidgetElInput } from './el-input' -import { createWidgetElDatePicker } from './el-date-picker' +import { createWidgetElInput } from './input-widget' +import { createWidgetElTextarea } from './textarea-widget' +import { createWidgetElInputNumber } from './number-input-widget' +import { createWidgetElDatePicker } from './date-picker-widget' +import { createWidgetElSelect } from './select-widget' +import { createWidgetElRadio } from './radio-widget' +import { createWidgetElCheckbox } from './checkbox-widget' +import { createWidgetElSwitch } from './switch-widget' import type { VxeUIExport } from 'vxe-pc-ui' @@ -9,10 +15,16 @@ import type { VxeUIExport } from 'vxe-pc-ui' */ export function defineFormDesignRender (VxeUI: VxeUIExport) { const { getWidgetElInputConfig, WidgetElInputViewComponent, WidgetElInputFormComponent } = createWidgetElInput(VxeUI) + const { getWidgetElTextareaConfig, WidgetElTextareaViewComponent, WidgetElTextareaFormComponent } = createWidgetElTextarea(VxeUI) + const { getWidgetElInputNumberConfig, WidgetElInputNumberViewComponent, WidgetElInputNumberFormComponent } = createWidgetElInputNumber(VxeUI) const { getWidgetElDatePickerConfig, WidgetElDatePickerViewComponent, WidgetElDatePickerFormComponent } = createWidgetElDatePicker(VxeUI) + const { getWidgetElSelectConfig, WidgetElSelectViewComponent, WidgetElSelectFormComponent } = createWidgetElSelect(VxeUI) + const { getWidgetElRadioConfig, WidgetElRadioViewComponent, WidgetElRadioFormComponent } = createWidgetElRadio(VxeUI) + const { getWidgetElCheckboxConfig, WidgetElCheckboxViewComponent, WidgetElCheckboxFormComponent } = createWidgetElCheckbox(VxeUI) + const { getWidgetElSwitchConfig, WidgetElSwitchViewComponent, WidgetElSwitchFormComponent } = createWidgetElSwitch(VxeUI) VxeUI.renderer.mixin({ - ElInput: { + ElInputWidget: { createFormDesignWidgetConfig: getWidgetElInputConfig, renderFormDesignWidgetView (renderOpts, renderParams) { return h(WidgetElInputViewComponent, { renderOpts, renderParams }) @@ -21,7 +33,25 @@ export function defineFormDesignRender (VxeUI: VxeUIExport) { return h(WidgetElInputFormComponent, { renderOpts, renderParams }) } }, - ElDatePicker: { + ElTextareaWidget: { + createFormDesignWidgetConfig: getWidgetElTextareaConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetElTextareaViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetElTextareaFormComponent, { renderOpts, renderParams }) + } + }, + ElNumberInputWidget: { + createFormDesignWidgetConfig: getWidgetElInputNumberConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetElInputNumberViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetElInputNumberFormComponent, { renderOpts, renderParams }) + } + }, + ElDatePickerWidget: { createFormDesignWidgetConfig: getWidgetElDatePickerConfig, renderFormDesignWidgetView (renderOpts, renderParams) { return h(WidgetElDatePickerViewComponent, { renderOpts, renderParams }) @@ -29,6 +59,43 @@ export function defineFormDesignRender (VxeUI: VxeUIExport) { renderFormDesignWidgetFormView (renderOpts, renderParams) { return h(WidgetElDatePickerFormComponent, { renderOpts, renderParams }) } + }, + ElSelectWidget: { + createFormDesignWidgetConfig: getWidgetElSelectConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetElSelectViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetElSelectFormComponent, { renderOpts, renderParams }) + } + }, + ElRadioWidget: { + createFormDesignWidgetConfig: getWidgetElRadioConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetElRadioViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetElRadioFormComponent, { renderOpts, renderParams }) + } + }, + ElCheckboxWidget: { + createFormDesignWidgetConfig: getWidgetElCheckboxConfig, + createFormDesignWidgetFieldValue: () => [], + renderFormDesignWidgetView (renderOpts: any, renderParams: any) { + return h(WidgetElCheckboxViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts: any, renderParams: any) { + return h(WidgetElCheckboxFormComponent, { renderOpts, renderParams }) + } + }, + ElSwitchWidget: { + createFormDesignWidgetConfig: getWidgetElSwitchConfig, + renderFormDesignWidgetView (renderOpts, renderParams) { + return h(WidgetElSwitchViewComponent, { renderOpts, renderParams }) + }, + renderFormDesignWidgetFormView (renderOpts, renderParams) { + return h(WidgetElSwitchFormComponent, { renderOpts, renderParams }) + } } }) } diff --git a/plugin-render-element/src/form-design/el-input.ts b/plugin-render-element/src/form-design/input-widget.ts similarity index 97% rename from plugin-render-element/src/form-design/el-input.ts rename to plugin-render-element/src/form-design/input-widget.ts index 212111f..7056a35 100644 --- a/plugin-render-element/src/form-design/el-input.ts +++ b/plugin-render-element/src/form-design/input-widget.ts @@ -12,7 +12,7 @@ export function createWidgetElInput (VxeUI: VxeUIExport) { title: '输入框', icon: 'vxe-icon-input', options: { - placeholder: '' + placeholder: '请输入' } } } @@ -55,7 +55,6 @@ export function createWidgetElInput (VxeUI: VxeUIExport) { default () { return h(resolveComponent('el-input') as ComponentOptions, { modelValue: widget.title, - placeholder: options.placeholder, 'onUpdate:modelValue' (val: any) { widget.title = val } @@ -113,6 +112,7 @@ export function createWidgetElInput (VxeUI: VxeUIExport) { return () => { const { renderParams } = props const { widget, $formView } = renderParams + const { options } = widget return h(VxeUIFormItemComponent, { class: ['vxe-form-design--widget-render-form-item'], @@ -122,6 +122,7 @@ export function createWidgetElInput (VxeUI: VxeUIExport) { default () { return h(resolveComponent('el-input') as ComponentOptions, { modelValue: $formView ? $formView.getItemValue(widget) : null, + placeholder: options.placeholder, onChange: changeEvent, 'onUpdate:modelValue' (val: any) { if ($formView) { diff --git a/plugin-render-element/src/form-design/number-input-widget.ts b/plugin-render-element/src/form-design/number-input-widget.ts new file mode 100644 index 0000000..7be1ccf --- /dev/null +++ b/plugin-render-element/src/form-design/number-input-widget.ts @@ -0,0 +1,143 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' + +interface WidgetElInputNumberFormObjVO { + placeholder: string +} + +export function createWidgetElInputNumber (VxeUI: VxeUIExport) { + const getWidgetElInputNumberConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '数字', + icon: 'vxe-icon-number', + options: { + placeholder: '请输入' + } + } + } + + const WidgetElInputNumberFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }) + ] + } + }) + } + } + }) + + const WidgetElInputNumberViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('el-input-number') as ComponentOptions, { + modelValue: $formView ? $formView.getItemValue(widget) : null, + placeholder: options.placeholder, + onChange: changeEvent, + 'onUpdate:modelValue' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetElInputNumberConfig, + WidgetElInputNumberFormComponent, + WidgetElInputNumberViewComponent + } +} diff --git a/plugin-render-element/src/form-design/radio-widget.ts b/plugin-render-element/src/form-design/radio-widget.ts new file mode 100644 index 0000000..3e04ac7 --- /dev/null +++ b/plugin-render-element/src/form-design/radio-widget.ts @@ -0,0 +1,166 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' +import { useWidgetPropDataSource, WidgetDataSourceOptionObjVO } from './use' +import XEUtils from 'xe-utils' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' + +interface WidgetElRadioFormObjVO { + options: WidgetDataSourceOptionObjVO[] +} + +export function createWidgetElRadio (VxeUI: VxeUIExport) { + const getWidgetElRadioConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '单选框', + icon: 'vxe-icon-radio-checked', + options: { + options: XEUtils.range(0, 3).map((v, i) => { + return { + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [i + 1]) + } + }) + } + } + } + + const WidgetElRadioFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + + const { renderDataSourceFormItem } = useWidgetPropDataSource(VxeUI, props, false) + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }), + renderDataSourceFormItem() + ] + } + }) + } + } + }) + + const WidgetElRadioViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('el-radio-group') as ComponentOptions, { + modelValue: $formView ? $formView.getItemValue(widget) : null, + onChange: changeEvent, + 'onUpdate:modelValue' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }, { + default: () => { + return options.options + ? options.options.map((item, index) => { + return h(resolveComponent('el-radio') as ComponentOptions, { + key: index, + value: item.value + }, { + default () { + return `${item.value || ''}` + } + }) + }) + : [] + } + }) + } + }) + } + } + }) + + return { + getWidgetElRadioConfig, + WidgetElRadioFormComponent, + WidgetElRadioViewComponent + } +} diff --git a/plugin-render-element/src/form-design/select-widget.ts b/plugin-render-element/src/form-design/select-widget.ts new file mode 100644 index 0000000..75732df --- /dev/null +++ b/plugin-render-element/src/form-design/select-widget.ts @@ -0,0 +1,165 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' +import { useWidgetPropDataSource, WidgetDataSourceOptionObjVO } from './use' +import XEUtils from 'xe-utils' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' + +interface WidgetElSelectFormObjVO { + placeholder: string + options: WidgetDataSourceOptionObjVO[] +} + +export function createWidgetElSelect (VxeUI: VxeUIExport) { + const getWidgetElSelectConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '下拉框', + icon: 'vxe-icon-select', + options: { + placeholder: '请选择', + options: XEUtils.range(0, 3).map((v, i) => { + return { + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [i + 1]) + } + }) + } + } + } + + const WidgetElSelectFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + + const { renderDataSourceFormItem } = useWidgetPropDataSource(VxeUI, props, false) + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }), + renderDataSourceFormItem() + ] + } + }) + } + } + }) + + const WidgetElSelectViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('el-select') as ComponentOptions, { + modelValue: $formView ? $formView.getItemValue(widget) : null, + placeholder: options.placeholder, + onChange: changeEvent, + 'onUpdate:modelValue' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }, { + default: () => { + return options.options + ? options.options.map(item => { + return h(resolveComponent('el-option') as ComponentOptions, { + label: item.value, + value: item.value + }) + }) + : [] + } + }) + } + }) + } + } + }) + + return { + getWidgetElSelectConfig, + WidgetElSelectFormComponent, + WidgetElSelectViewComponent + } +} diff --git a/plugin-render-element/src/form-design/switch-widget.ts b/plugin-render-element/src/form-design/switch-widget.ts new file mode 100644 index 0000000..bee7086 --- /dev/null +++ b/plugin-render-element/src/form-design/switch-widget.ts @@ -0,0 +1,139 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' + +interface WidgetElSwitchFormObjVO { +} + +export function createWidgetElSwitch (VxeUI: VxeUIExport) { + const getWidgetElSwitchConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '是/否', + icon: 'vxe-icon-switch', + options: { + } + } + } + + const WidgetElSwitchFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }) + ] + } + }) + } + } + }) + + const WidgetElSwitchViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('el-switch') as ComponentOptions, { + modelValue: $formView ? $formView.getItemValue(widget) : null, + onChange: changeEvent, + 'onUpdate:modelValue' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetElSwitchConfig, + WidgetElSwitchFormComponent, + WidgetElSwitchViewComponent + } +} diff --git a/plugin-render-element/src/form-design/textarea-widget.ts b/plugin-render-element/src/form-design/textarea-widget.ts new file mode 100644 index 0000000..02c0688 --- /dev/null +++ b/plugin-render-element/src/form-design/textarea-widget.ts @@ -0,0 +1,148 @@ +import { defineComponent, h, PropType, resolveComponent, ComponentOptions } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormComponent, VxeFormItemComponent, VxeSwitchComponent } from 'vxe-pc-ui' + +interface WidgetElTextareaFormObjVO { + placeholder: string +} + +export function createWidgetElTextarea (VxeUI: VxeUIExport) { + const getWidgetElTextareaConfig = (params: VxeGlobalRendererHandles.CreateFormDesignWidgetConfigParams): VxeGlobalRendererHandles.CreateFormDesignWidgetConfigObj => { + return { + title: '文本域', + icon: 'vxe-icon-textarea', + options: { + placeholder: '请输入' + } + } + } + + const WidgetElTextareaFormComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormComponent = VxeUI.getComponent('VxeForm') + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUISwitchComponent = VxeUI.getComponent('VxeSwitch') + + return () => { + const { renderParams } = props + const { widget } = renderParams + + return h(VxeUIFormComponent, { + class: 'vxe-form-design--widget-render-form-wrapper', + vertical: true, + span: 24, + titleBold: true, + titleOverflow: true, + data: widget.options + }, { + default () { + return [ + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.name') + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: widget.title, + 'onUpdate:modelValue' (val: any) { + widget.title = val + } + }) + } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.placeholder'), + field: 'placeholder', + itemRender: { name: 'ElInput' } + }), + h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.required') + }, { + default () { + return h(VxeUISwitchComponent, { + modelValue: widget.required, + 'onUpdate:modelValue' (val: any) { + widget.required = val + } + }) + } + }) + ] + } + }) + } + } + }) + + const WidgetElTextareaViewComponent = defineComponent({ + props: { + renderOpts: { + type: Object as PropType, + default: () => ({}) + }, + renderParams: { + type: Object as PropType>, + default: () => ({}) + } + }, + emits: [], + setup (props) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + + const changeEvent = () => { + const { renderParams } = props + const { widget, $formView } = renderParams + if ($formView) { + const itemValue = $formView ? $formView.getItemValue(widget) : null + $formView.updateItemStatus(widget, itemValue) + } + } + + return () => { + const { renderParams } = props + const { widget, $formView } = renderParams + const { options } = widget + + return h(VxeUIFormItemComponent, { + class: ['vxe-form-design--widget-render-form-item'], + field: widget.field, + title: widget.title + }, { + default () { + return h(resolveComponent('el-input') as ComponentOptions, { + modelValue: $formView ? $formView.getItemValue(widget) : null, + placeholder: options.placeholder, + type: 'textarea', + autosize: { + minRows: 2, + maxRows: 4 + }, + onChange: changeEvent, + 'onUpdate:modelValue' (val: any) { + if ($formView) { + $formView.setItemValue(widget, val) + } + } + }) + } + }) + } + } + }) + + return { + getWidgetElTextareaConfig, + WidgetElTextareaFormComponent, + WidgetElTextareaViewComponent + } +} diff --git a/plugin-render-element/src/form-design/use.ts b/plugin-render-element/src/form-design/use.ts new file mode 100644 index 0000000..4c27540 --- /dev/null +++ b/plugin-render-element/src/form-design/use.ts @@ -0,0 +1,255 @@ +import { VNode, h, onMounted, ref, watch } from 'vue' + +import type { VxeUIExport, VxeGlobalRendererHandles, VxeFormItemComponent, VxeButtonComponent, VxeTextareaComponent, VxeTipComponent } from 'vxe-pc-ui' + +export interface WidgetDataSourceOptionSubObjVO { + value: string, +} + +export interface WidgetDataSourceOptionObjVO { + value: string, + options?: WidgetDataSourceOptionSubObjVO[] +} + +export function useWidgetPropDataSource (VxeUI: VxeUIExport, props: { + readonly renderOpts: VxeGlobalRendererHandles.RenderFormDesignWidgetFormViewOptions; + readonly renderParams: VxeGlobalRendererHandles.RenderFormDesignWidgetFormViewParams<{ + options: WidgetDataSourceOptionObjVO[] + }>; +}, isSubOption: boolean) { + const VxeUIFormItemComponent = VxeUI.getComponent('VxeFormItem') + const VxeUIButtonComponent = VxeUI.getComponent('VxeButton') + const VxeUITextareaComponent = VxeUI.getComponent('VxeTextarea') + const VxeUITipComponent = VxeUI.getComponent('VxeTip') + + const optionsContent = ref('') + const expandIndexList = ref([]) + + const addOptionEvent = () => { + const { renderParams } = props + const { widget } = renderParams + const options = widget.options.options || [] + options.push({ + value: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.defValue', [options.length + 1]) + }) + widget.options.options = [...options] + } + + const subRE = /^(\s|\t)+/ + + const hasSubOption = (str: string) => { + return subRE.test(str) + } + + const expandAllOption = () => { + const { renderParams } = props + const { widget } = renderParams + const options = widget.options.options || [] + const indexList: number[] = [] + options.forEach((group, gIndex) => { + const { options } = group + if (options && options.length) { + indexList.push(gIndex) + } + }) + expandIndexList.value = indexList + } + + const toggleExpandOption = (item: WidgetDataSourceOptionSubObjVO, gIndex: number) => { + if (expandIndexList.value.includes(gIndex)) { + expandIndexList.value = expandIndexList.value.filter(num => num !== gIndex) + } else { + expandIndexList.value.push(gIndex) + } + } + + const confirmBatchAddOptionEvent = () => { + const { renderParams } = props + const { widget } = renderParams + const optList: WidgetDataSourceOptionSubObjVO[] = [] + const rowList = optionsContent.value.split('\n') + let prevGroup: Required | null = null + if (isSubOption) { + rowList.forEach((str, index) => { + const nextStr = rowList[index + 1] + const value = str.trim() + if (!value) { + return + } + const item: WidgetDataSourceOptionSubObjVO = { + value + } + if (prevGroup) { + if (hasSubOption(str)) { + prevGroup.options.push(item) + return + } + prevGroup = null + optList.push(item) + } else { + optList.push(item) + } + if (nextStr) { + if (hasSubOption(nextStr)) { + prevGroup = Object.assign(item, { options: [] }) + } + } + }) + } else { + rowList.forEach((str) => { + optList.push({ + value: str.trim() + }) + }) + } + widget.options.options = optList + expandAllOption() + } + + const openPopupEditEvent = () => { + const { renderParams } = props + const { widget } = renderParams + + const contList: string[] = [] + widget.options.options?.forEach(group => { + contList.push(group.value) + group.options?.forEach(item => { + contList.push(`\t${item.value}`) + }) + }) + + optionsContent.value = contList.join('\n') + + VxeUI.modal.open({ + title: `${widget.title} - ${VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.batchEditOption')}`, + width: 500, + height: '50vh ', + resize: true, + showFooter: true, + showCancelButton: true, + showConfirmButton: true, + confirmButtonText: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.buildOption'), + onConfirm: confirmBatchAddOptionEvent, + slots: { + default () { + return h('div', { + class: 'vxe-form-design--widget-form-item-data-source-popup' + }, [ + h(VxeUITipComponent, { + status: 'primary', + title: '', + content: VxeUI.getI18n(`vxe.formDesign.widgetProp.dataSource.${isSubOption ? 'batchEditSubTip' : 'batchEditTip'}`) + }), + h(VxeUITextareaComponent, { + resize: 'none', + modelValue: optionsContent.value, + 'onUpdate:modelValue' (val: any) { + optionsContent.value = val + } + }) + ]) + } + } + }) + } + + const renderOption = (item: WidgetDataSourceOptionSubObjVO, hasFirstLevel: boolean, isExpand: boolean, gIndex: number, hasSub: boolean, isFirst: boolean, isLast: boolean) => { + return h('div', { + class: ['vxe-form-design--widget-form-item-data-source-option', { + 'is--first': isFirst, + 'is--last': isLast + }] + }, [ + h('div', { + class: 'vxe-form-design--widget-expand-btn' + }, hasFirstLevel && hasSub + ? [ + h('i', { + class: isExpand ? VxeUI.getIcon().FORM_DESIGN_WIDGET_OPTION_EXPAND_CLOSE : VxeUI.getIcon().FORM_DESIGN_WIDGET_OPTION_EXPAND_OPEN, + onClick () { + toggleExpandOption(item, gIndex) + } + }) + ] + : []), + h('input', { + class: 'vxe-default-input', + value: item.value, + onInput (evnt: InputEvent & { target: HTMLInputElement }) { + item.value = evnt.target.value + } + }), + h(VxeUIButtonComponent, { + status: 'danger', + mode: 'text', + icon: VxeUI.getIcon().FORM_DESIGN_WIDGET_DELETE + }) + ]) + } + + const renderOptions = () => { + const { renderParams } = props + const { widget } = renderParams + const { options } = widget + const groups = options.options + const optVNs: VNode[] = [] + if (groups) { + groups.forEach((group, gIndex) => { + const { options } = group + const isExpand = expandIndexList.value.includes(gIndex) + if (options && options.length) { + optVNs.push(renderOption(group, true, isExpand, gIndex, true, gIndex === 0, gIndex === groups.length - 1)) + if (isExpand) { + optVNs.push( + h('div', { + class: 'vxe-form-design--widget-form-item-data-source-sub-option' + }, options.map(item => renderOption(item, false, isExpand, 0, false, false, false))) + ) + } + } else { + optVNs.push(renderOption(group, true, isExpand, gIndex, false, gIndex === 0, gIndex === groups.length - 1)) + } + }) + } + return optVNs + } + + watch(() => props.renderParams.widget, () => { + expandAllOption() + }) + + onMounted(() => { + expandAllOption() + }) + + return { + renderDataSourceFormItem () { + return h(VxeUIFormItemComponent, { + title: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.name'), + field: 'options' + }, { + default () { + return [ + h('div', {}, [ + h(VxeUIButtonComponent, { + status: 'primary', + mode: 'text', + content: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.addOption'), + onClick: addOptionEvent + }), + h(VxeUIButtonComponent, { + status: 'primary', + mode: 'text', + content: VxeUI.getI18n('vxe.formDesign.widgetProp.dataSource.batchEditOption'), + onClick: openPopupEditEvent + }) + ]), + h('div', { + class: 'vxe-form-design--widget-form-item-data-source' + }, renderOptions()) + ] + } + }) + } + } +}