From 83513d519d4b6b8fbfd48db266b9bd7b3a998d63 Mon Sep 17 00:00:00 2001
From: kailong321200875 <321200875@qq.com>
Date: Tue, 23 May 2023 15:36:33 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20Radio=E6=94=B9=E9=80=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
package.json | 2 +-
src/components/Form/src/Form.vue | 106 ++++++----
src/components/Form/src/componentMap.ts | 6 +-
.../Form/src/components/useRenderRadio.tsx | 6 +-
.../Form/src/components/useRenderSelect.tsx | 10 +-
src/components/Form/src/helper.ts | 6 +-
src/types/components.d.ts | 66 ++++--
src/types/form.d.ts | 26 ++-
src/utils/index.ts | 7 +
src/views/Components/Form/DefaultForm.vue | 200 ++++++++++--------
10 files changed, 274 insertions(+), 161 deletions(-)
diff --git a/package.json b/package.json
index 48add6b..007d6a1 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,7 @@
"dayjs": "^1.11.7",
"echarts": "^5.4.2",
"echarts-wordcloud": "^2.1.0",
- "element-plus": "2.3.5",
+ "element-plus": "^2.3.5",
"intro.js": "^7.0.1",
"lodash-es": "^4.17.21",
"mitt": "^3.0.0",
diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue
index 6e3b337..04c0adf 100644
--- a/src/components/Form/src/Form.vue
+++ b/src/components/Form/src/Form.vue
@@ -21,7 +21,16 @@ import { set } from 'lodash-es'
import { FormProps } from './types'
import { Icon } from '@/components/Icon'
import { FormSchema, FormSetPropsType } from '@/types/form'
-import { ComponentNameEnum, SelectComponentProps, SelectOption } from '@/types/components.d'
+import {
+ ComponentNameEnum,
+ SelectComponentProps,
+ SelectOption,
+ RadioComponentProps
+} from '@/types/components.d'
+
+const { renderSelectOptions } = useRenderSelect()
+const { renderRadioOptions } = useRenderRadio()
+const { renderCheckboxOptions } = useRenderCheckbox()
const { getPrefixCls } = useDesign()
@@ -181,7 +190,7 @@ export default defineComponent({
// 如果是select组件,并且没有自定义模板,自动渲染options
if (item.component === ComponentNameEnum.SELECT) {
slotsMap.default = !componentSlots.default
- ? () => renderOptions(item)
+ ? () => renderSelectOptions(item)
: () => {
return componentSlots.default(
unref((item?.componentProps as SelectComponentProps)?.options)
@@ -231,24 +240,52 @@ export default defineComponent({
{{
default: () => {
- const Com = componentMap[item.component as string] as ReturnType<
- typeof defineComponent
- >
-
- const { autoSetPlaceholder } = unref(getProps)
-
- return slots[item.field] ? (
- getSlot(slots, item.field, formModel.value)
- ) : (
-
- {{ ...slotsMap }}
-
- )
+
+ const { autoSetPlaceholder } = unref(getProps)
+
+ // 需要特殊处理的组件
+ const specialComponents = [ComponentNameEnum.RADIO]
+
+ if (specialComponents.findIndex((v) => v === item.component) !== -1) {
+ switch (item.component) {
+ case ComponentNameEnum.RADIO:
+ const componentProps = item.componentProps as RadioComponentProps
+ const valueAlias = componentProps?.props?.value || 'value'
+ const labelAlias = componentProps?.props?.label || 'label'
+ const disabledAlias = componentProps?.props?.disabled || 'disabled'
+
+ return componentProps?.options?.map((v) => {
+ return (
+
+ {v[labelAlias]}
+
+ )
+ })
+ }
+ }
+
+ return (
+
+ {{ ...slotsMap }}
+
+ )
+ }
}
}}
@@ -256,23 +293,20 @@ export default defineComponent({
}
// 渲染options
- const renderOptions = (item: FormSchema) => {
- switch (item.component) {
- case ComponentNameEnum.SELECT:
- const { renderSelectOptions } = useRenderSelect()
- return renderSelectOptions(item)
- case 'Radio':
- case 'RadioButton':
- const { renderRadioOptions } = useRenderRadio()
- return renderRadioOptions(item)
- case 'Checkbox':
- case 'CheckboxButton':
- const { renderCheckboxOptions } = useRenderCheckbox()
- return renderCheckboxOptions(item)
- default:
- break
- }
- }
+ // const renderOptions = (item: FormSchema) => {
+ // switch (item.component) {
+ // case ComponentNameEnum.SELECT:
+ // return renderSelectOptions(item)
+ // case ComponentNameEnum.RADIO:
+ // case 'RadioButton':
+ // return renderRadioOptions(item)
+ // case 'Checkbox':
+ // case 'CheckboxButton':
+ // return renderCheckboxOptions(item)
+ // default:
+ // break
+ // }
+ // }
// 过滤传入Form组件的属性
const getFormBindValue = () => {
diff --git a/src/components/Form/src/componentMap.ts b/src/components/Form/src/componentMap.ts
index 9fdb1db..f5d7f17 100644
--- a/src/components/Form/src/componentMap.ts
+++ b/src/components/Form/src/componentMap.ts
@@ -16,14 +16,16 @@ import {
ElTimeSelect,
ElTransfer,
ElAutocomplete,
- ElDivider
+ ElDivider,
+ ElRadio
} from 'element-plus'
import { InputPassword } from '@/components/InputPassword'
import { Editor } from '@/components/Editor'
import { ComponentName } from '@/types/components'
const componentMap: Recordable = {
- Radio: ElRadioGroup,
+ Radio: ElRadio,
+ // RadioGroup: ElRadioGroup,
Checkbox: ElCheckboxGroup,
CheckboxButton: ElCheckboxGroup,
Input: ElInput,
diff --git a/src/components/Form/src/components/useRenderRadio.tsx b/src/components/Form/src/components/useRenderRadio.tsx
index 45b65bf..55fac63 100644
--- a/src/components/Form/src/components/useRenderRadio.tsx
+++ b/src/components/Form/src/components/useRenderRadio.tsx
@@ -1,9 +1,13 @@
import { FormSchema } from '@/types/form'
import { ElRadio, ElRadioButton } from 'element-plus'
import { defineComponent } from 'vue'
+import { ComponentNameEnum } from '@/types/components.d'
export const useRenderRadio = () => {
- const renderRadioOptions = (item: FormSchema) => {
+ const renderRadioOptions = (
+ item: FormSchema,
+ type?: ComponentNameEnum.RADIO | ComponentNameEnum.RADIO_BUTTON = ComponentNameEnum.RADIO
+ ) => {
// 如果有别名,就取别名
const labelAlias = item?.componentProps?.optionsAlias?.labelField
const valueAlias = item?.componentProps?.optionsAlias?.valueField
diff --git a/src/components/Form/src/components/useRenderSelect.tsx b/src/components/Form/src/components/useRenderSelect.tsx
index 4f33f2a..84e327a 100644
--- a/src/components/Form/src/components/useRenderSelect.tsx
+++ b/src/components/Form/src/components/useRenderSelect.tsx
@@ -8,8 +8,8 @@ export const useRenderSelect = () => {
const componentsProps = item.componentProps as SelectComponentProps
const optionGroupDefaultSlot = componentsProps.slots?.optionGroupDefault
// 如果有别名,就取别名
- const labelAlias = componentsProps?.labelAlias
- const keyAlias = componentsProps?.keyAlias
+ const labelAlias = componentsProps?.props?.label
+ const keyAlias = componentsProps?.props?.key
return componentsProps?.options?.map((option) => {
if (option?.options?.length) {
return optionGroupDefaultSlot ? (
@@ -34,9 +34,9 @@ export const useRenderSelect = () => {
const renderSelectOptionItem = (item: FormSchema, option: SelectOption) => {
// 如果有别名,就取别名
const componentsProps = item.componentProps as SelectComponentProps
- const labelAlias = componentsProps?.labelAlias
- const valueAlias = componentsProps?.valueAlias
- const keyAlias = componentsProps?.keyAlias
+ const labelAlias = componentsProps?.props?.label
+ const valueAlias = componentsProps?.props?.value
+ const keyAlias = componentsProps?.props?.key
const optionDefaultSlot = componentsProps.slots?.optionDefault
return (
diff --git a/src/components/Form/src/helper.ts b/src/components/Form/src/helper.ts
index 7f9a6fa..85efd8e 100644
--- a/src/components/Form/src/helper.ts
+++ b/src/components/Form/src/helper.ts
@@ -5,7 +5,7 @@ import { PlaceholderMoel } from './types'
import { FormSchema } from '@/types/form.d'
import { ColProps, ComponentNameEnum } from '@/types/components.d'
import { isFunction } from '@/utils/is'
-import { firstUpperCase } from '@/utils'
+import { firstUpperCase, humpToDash } from '@/utils'
const { t } = useI18n()
@@ -123,11 +123,11 @@ export const setItemComponentSlots = (slotsProps: Recordable = {}): Recordable =
for (const key in slotsProps) {
if (slotsProps[key]) {
if (isFunction(slotsProps[key])) {
- slotObj[key] = (...args: any[]) => {
+ slotObj[humpToDash(key)] = (...args: any[]) => {
return slotsProps[key]?.(...args)
}
} else {
- slotObj[key] = () => {
+ slotObj[humpToDash(key)] = () => {
return slotsProps[key]
}
}
diff --git a/src/types/components.d.ts b/src/types/components.d.ts
index 1c67748..5471e40 100644
--- a/src/types/components.d.ts
+++ b/src/types/components.d.ts
@@ -1,4 +1,4 @@
-import { CSSProperties } from 'vue'
+import { CSSProperties, VNodeProps, VNode } from 'vue'
import {
InputProps,
AutocompleteProps,
@@ -148,7 +148,7 @@ export interface InputNumberComponentProps {
style?: CSSProperties
}
-interface SelectOption {
+export interface SelectOption {
label?: string
disabled?: boolean
value?: any
@@ -208,19 +208,14 @@ export interface SelectComponentProps {
| 'right-end'
maxCollapseTags?: number
/**
- * label别名
+ * 数据源的字段别名
*/
- labelAlias?: string
-
- /**
- * value别名
- */
- valueAlias?: string
-
- /**
- * key别名
- */
- keyAlias?: string
+ props?: {
+ key?: string
+ value?: string
+ label?: string
+ children?: string
+ }
on?: {
change?: (value: string | number | boolean | Object) => void
visibleChange?: (visible: boolean) => void
@@ -390,14 +385,17 @@ export interface ColorPickerComponentProps {
export interface TransferComponentProps {
value?: any[]
- data?: Array<{ key; label; disabled }>
+ data?: any[]
filterable?: boolean
filterPlaceholder?: string
filterMethod?: (query: string, item: any) => boolean
targetOrder?: string
titles?: string[]
buttonTexts?: string[]
- renderContent?: (h: any, option: any) => JSX.Element
+ renderContent?: (
+ h: (type: string, props: VNodeProps | null, children?: string) => VNode,
+ option: any
+ ) => JSX.Element
format?: {
noChecked?: string
hasChecked?: string
@@ -411,7 +409,11 @@ export interface TransferComponentProps {
rightDefaultChecked?: any[]
validateEvent?: boolean
on?: {
- change?: (value: any[]) => void
+ change?: (
+ value: number | string,
+ direction: 'left' | 'right',
+ movedKeys: string[] | number[]
+ ) => void
leftCheckChange?: (value: any[]) => void
rightCheckChange?: (value: any[]) => void
}
@@ -423,6 +425,36 @@ export interface TransferComponentProps {
style?: CSSProperties
}
+export interface RadioOption {
+ label?: string
+ value?: string | number | boolean
+ disabled?: boolean
+ [key: string]: any
+}
+export interface RadioComponentProps {
+ value?: string | number | boolean
+ label?: string | number | boolean
+ disabled?: boolean
+ border?: boolean
+ size?: ElementPlusSize
+ options?: RadioOption[]
+ /**
+ * 数据源的字段别名
+ */
+ props: {
+ label?: string
+ value?: string
+ disabled?: string
+ }
+ name?: string
+ on?: {
+ change?: (value: string | number | boolean) => void
+ }
+ slots?: {
+ default?: (...args: any[]) => JSX.Element | null
+ }
+}
+
export interface ColProps {
span?: number
xs?: number
diff --git a/src/types/form.d.ts b/src/types/form.d.ts
index 2612acb..899a921 100644
--- a/src/types/form.d.ts
+++ b/src/types/form.d.ts
@@ -12,7 +12,8 @@ import {
SwitchComponentProps,
RateComponentProps,
ColorPickerComponentProps,
- TransferComponentProps
+ TransferComponentProps,
+ RadioComponentProps
} from '@/types/components'
import { FormValueType, FormValueType } from '@/types/form'
import type { AxiosPromise } from 'axios'
@@ -36,26 +37,28 @@ export type FormItemProps = {
}
// 定义联合类型和条件类型
-type ComponentPropsForComponent = T extends 'input'
+type ComponentPropsForComponent = T extends 'Input'
? InputComponentProps
- : T extends 'autocomplete'
+ : T extends 'Autocomplete'
? AutocompleteComponentProps
- : T extends 'inputNumber'
+ : T extends 'InputNumber'
? InputNumberComponentProps
- : T extends 'select'
+ : T extends 'Select'
? SelectComponentProps
- : T extends 'selectV2'
+ : T extends 'SelectV2'
? SelectV2ComponentProps
- : T extends 'cascader'
+ : T extends 'Cascader'
? CascaderComponentProps
- : T extends 'switch'
+ : T extends 'Switch'
? SwitchComponentProps
- : T extends 'rate'
+ : T extends 'Rate'
? RateComponentProps
- : T extends 'colorPicker'
+ : T extends 'ColorPicker'
? ColorPickerComponentProps
- : T extends 'transfer'
+ : T extends 'Transfer'
? TransferComponentProps
+ : T extends 'Radio'
+ ? RadioComponentProps
: any
export interface FormSchema {
@@ -93,6 +96,7 @@ export interface FormSchema {
| RateComponentProps
| ColorPickerComponentProps
| TransferComponentProps
+ | RadioComponentProps
/**
* formItem组件属性,具体可以查看element-plus文档
diff --git a/src/utils/index.ts b/src/utils/index.ts
index aa00c95..77aca12 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -36,6 +36,13 @@ export const underlineToHump = (str: string): string => {
})
}
+/**
+ * 驼峰转横杠
+ */
+export const humpToDash = (str: string): string => {
+ return str.replace(/([A-Z])/g, '-$1').toLowerCase()
+}
+
export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
dom.style.setProperty(prop, val)
}
diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue
index 9abdabf..7eb02ce 100644
--- a/src/views/Components/Form/DefaultForm.vue
+++ b/src/views/Components/Form/DefaultForm.vue
@@ -8,7 +8,7 @@ import { useAppStore } from '@/store/modules/app'
import { FormSchema } from '@/types/form'
import { ComponentOptions, SelectOption, SelectComponentProps } from '@/types/components'
import { useForm } from '@/hooks/web/useForm'
-import { ElOption, ElOptionGroup } from 'element-plus'
+import { ElOption, ElOptionGroup, ElButton } from 'element-plus'
const appStore = useAppStore()
@@ -840,92 +840,117 @@ const schema = reactive([
field: 'field34',
label: t('formDemo.transfer'),
component: 'Divider'
+ },
+ {
+ field: 'field35',
+ label: t('formDemo.default'),
+ component: 'Transfer',
+ componentProps: {
+ props: {
+ key: 'value',
+ label: 'desc'
+ },
+ data: generateData()
+ },
+ value: [],
+ colProps: {
+ span: 24
+ }
+ },
+ {
+ field: 'field36',
+ label: t('formDemo.slot'),
+ component: 'Transfer',
+ componentProps: {
+ props: {
+ key: 'value',
+ label: 'desc'
+ },
+ filterable: true,
+ leftDefaultChecked: [2, 3],
+ rightDefaultChecked: [1],
+ titles: ['Source', 'Target'],
+ buttonTexts: ['To Left', 'To Right'],
+ format: {
+ noChecked: '${total}',
+ hasChecked: '${checked}/${total}'
+ },
+ data: generateData(),
+ slots: {
+ default: ({ option }) => {
+ return (
+
+ {option.value} - {option.desc}
+
+ )
+ },
+ leftFooter: () => {
+ return (
+
+ )
+ },
+ rightFooter: () => {
+ return (
+
+ )
+ }
+ }
+ },
+ value: [1],
+ colProps: {
+ span: 24
+ }
+ },
+ {
+ field: 'field37',
+ label: `${t('formDemo.render')}`,
+ component: 'Transfer',
+ componentProps: {
+ props: {
+ key: 'value',
+ label: 'desc',
+ disabled: 'disabled'
+ },
+ leftDefaultChecked: [2, 3],
+ rightDefaultChecked: [1],
+ data: generateData(),
+ renderContent: (h, option) => {
+ return h('span', null, `${option.value} - ${option.desc}`)
+ }
+ },
+ value: [1],
+ colProps: {
+ span: 24
+ }
+ },
+ {
+ field: 'field38',
+ label: t('formDemo.radio'),
+ component: 'Divider'
+ },
+ {
+ field: 'field39',
+ label: t('formDemo.default'),
+ component: 'Radio',
+ componentProps: {
+ options: [
+ {
+ // disabled: true,
+ label: 'option-1',
+ value: '1'
+ },
+ {
+ label: 'option-2',
+ value: '2'
+ }
+ ]
+ }
}
// {
- // field: 'field35',
- // label: t('formDemo.default'),
- // component: 'Transfer',
- // componentProps: {
- // props: {
- // key: 'value',
- // label: 'desc',
- // disabled: 'disabled'
- // },
- // data: generateData()
- // },
- // value: [],
- // colProps: {
- // span: 24
- // }
- // },
- // {
- // field: 'field36',
- // label: t('formDemo.slot'),
- // component: 'Transfer',
- // componentProps: {
- // props: {
- // key: 'value',
- // label: 'desc',
- // disabled: 'disabled'
- // },
- // leftDefaultChecked: [2, 3],
- // rightDefaultChecked: [1],
- // data: generateData(),
- // slots: {
- // default: true
- // }
- // },
- // value: [1],
- // colProps: {
- // span: 24
- // }
- // },
- // {
- // field: 'field37',
- // label: `${t('formDemo.render')}`,
- // component: 'Transfer',
- // componentProps: {
- // props: {
- // key: 'value',
- // label: 'desc',
- // disabled: 'disabled'
- // },
- // leftDefaultChecked: [2, 3],
- // rightDefaultChecked: [1],
- // data: generateData(),
- // renderContent: (h: Fn, option: Recordable) => {
- // return h('span', null, `${option.value} - ${option.desc}`)
- // }
- // },
- // value: [1],
- // colProps: {
- // span: 24
- // }
- // },
- // {
- // field: 'field38',
- // label: t('formDemo.radio'),
- // component: 'Divider'
- // },
- // {
- // field: 'field39',
- // label: t('formDemo.default'),
- // component: 'Radio',
- // componentProps: {
- // options: [
- // {
- // disabled: true,
- // label: 'option-1',
- // value: '1'
- // },
- // {
- // label: 'option-2',
- // value: '2'
- // }
- // ]
- // }
- // },
- // {
// field: 'field40',
// label: t('formDemo.button'),
// component: 'RadioButton',
@@ -1360,4 +1385,9 @@ const changeToggle = () => {
transform: translateX(-50%);
}
}
+
+.transfer-footer {
+ margin-left: 15px;
+ padding: 6px 5px;
+}