From 4d04734e13f6926c16aeee421feecb0d339534f0 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Thu, 11 May 2023 15:52:04 +0800 Subject: [PATCH 01/78] =?UTF-8?q?feat:=20SelectV2=E6=94=B9=E9=80=A0?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Form/src/Form.vue | 11 +- .../Form/src/components/useRenderSelect.tsx | 17 ++- src/components/Form/src/helper.ts | 48 +++++-- src/types/components.d.ts | 50 +++++++- src/types/form.d.ts | 4 +- src/utils/index.ts | 7 + src/views/Components/Form/DefaultForm.vue | 121 ++++++++++-------- 7 files changed, 183 insertions(+), 75 deletions(-) diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 88657bc..453696f 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -21,7 +21,7 @@ import { set } from 'lodash-es' import { FormProps } from './types' import { Icon } from '@/components/Icon' import { FormSchema, FormSetPropsType } from '@/types/form' -import { ComponentNameEnum, SelectComponentProps } from '@/types/components.d' +import { ComponentNameEnum, SelectComponentProps, SelectOption } from '@/types/components.d' const { getPrefixCls } = useDesign() @@ -188,6 +188,13 @@ export default defineComponent({ ) } } + + // 虚拟列表 + if (item.component === ComponentNameEnum.SELECT_V2 && componentSlots.default) { + slotsMap.default = ({ item }: any) => { + return componentSlots.default(item) + } + } // if ( // item?.component !== 'SelectV2' && // item?.component !== 'Cascader' && @@ -252,7 +259,7 @@ export default defineComponent({ const renderOptions = (item: FormSchema) => { switch (item.component) { case ComponentNameEnum.SELECT: - const { renderSelectOptions } = useRenderSelect(slots) + const { renderSelectOptions } = useRenderSelect() return renderSelectOptions(item) case 'Radio': case 'RadioButton': diff --git a/src/components/Form/src/components/useRenderSelect.tsx b/src/components/Form/src/components/useRenderSelect.tsx index 213ab9d..4f33f2a 100644 --- a/src/components/Form/src/components/useRenderSelect.tsx +++ b/src/components/Form/src/components/useRenderSelect.tsx @@ -1,22 +1,21 @@ import { ElOption, ElOptionGroup } from 'element-plus' -import { getSlot } from '@/utils/tsxHelper' -import { Slots } from 'vue' import { FormSchema } from '@/types/form' import { SelectComponentProps, SelectOption } from '@/types/components' -export const useRenderSelect = (slots: Slots) => { +export const useRenderSelect = () => { // 渲染 select options const renderSelectOptions = (item: FormSchema) => { const componentsProps = item.componentProps as SelectComponentProps const optionGroupDefaultSlot = componentsProps.slots?.optionGroupDefault // 如果有别名,就取别名 const labelAlias = componentsProps?.labelAlias + const keyAlias = componentsProps?.keyAlias return componentsProps?.options?.map((option) => { if (option?.options?.length) { return optionGroupDefaultSlot ? ( optionGroupDefaultSlot(option) ) : ( - + {{ default: () => option?.options?.map((v) => { @@ -37,15 +36,15 @@ export const useRenderSelect = (slots: Slots) => { const componentsProps = item.componentProps as SelectComponentProps const labelAlias = componentsProps?.labelAlias const valueAlias = componentsProps?.valueAlias + const keyAlias = componentsProps?.keyAlias const optionDefaultSlot = componentsProps.slots?.optionDefault - const { label, value, ...other } = option - return ( {{ default: () => (optionDefaultSlot ? optionDefaultSlot(option) : undefined) diff --git a/src/components/Form/src/helper.ts b/src/components/Form/src/helper.ts index aaf4d03..8cbc98c 100644 --- a/src/components/Form/src/helper.ts +++ b/src/components/Form/src/helper.ts @@ -2,9 +2,10 @@ import { useI18n } from '@/hooks/web/useI18n' import { unref, type Slots } from 'vue' import { getSlot } from '@/utils/tsxHelper' import { PlaceholderMoel } from './types' -import { FormSchema } from '@/types/form' -import { ColProps } from '@/types/components' +import { FormSchema } from '@/types/form.d' +import { ColProps, ComponentNameEnum } from '@/types/components.d' import { isFunction } from '@/utils/is' +import { firstUpperCase } from '@/utils' const { t } = useI18n() @@ -15,14 +16,25 @@ const { t } = useI18n() * @description 用于自动设置placeholder */ export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => { - const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword'] - const selectMap = ['Select', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect'] - if (textMap.includes(schema?.component as string)) { + const textMap = [ + ComponentNameEnum.INPUT, + ComponentNameEnum.AUTOCOMPLETE, + ComponentNameEnum.INPUT_NUMBER, + ComponentNameEnum.INPUT_PASSWORD + ] + const selectMap = [ + ComponentNameEnum.SELECT, + ComponentNameEnum.TIME_PICKER, + ComponentNameEnum.DATE_PICKER, + ComponentNameEnum.TIME_SELECT, + ComponentNameEnum.SELECT_V2 + ] + if (textMap.includes(schema?.component as ComponentNameEnum)) { return { placeholder: t('common.inputText') } } - if (selectMap.includes(schema?.component as string)) { + if (selectMap.includes(schema?.component as ComponentNameEnum)) { // 一些范围选择器 const twoTextMap = ['datetimerange', 'daterange', 'monthrange', 'datetimerange', 'daterange'] if ( @@ -74,14 +86,30 @@ export const setGridProp = (col: ColProps = {}): ColProps => { */ export const setComponentProps = (item: FormSchema): Recordable => { // const notNeedClearable = ['ColorPicker'] + // 拆分事件并组合 + const onEvents = item?.componentProps?.on || {} + const newOnEvents: Recordable = {} + + for (const key in onEvents) { + if (onEvents[key]) { + newOnEvents[`on${firstUpperCase(key)}`] = (...args: any[]) => { + onEvents[key](...args) + } + } + } + const componentProps: Recordable = { clearable: true, - ...item.componentProps + ...item.componentProps, + ...newOnEvents } // 需要删除额外的属性 if (componentProps.slots) { delete componentProps.slots } + if (componentProps.on) { + delete componentProps.on + } return componentProps } @@ -95,8 +123,8 @@ export const setItemComponentSlots = (formModel: any, slotsProps: Recordable = { for (const key in slotsProps) { if (slotsProps[key]) { if (isFunction(slotsProps[key])) { - slotObj[key] = () => { - return slotsProps[key]?.(formModel) + slotObj[key] = (...args: any[]) => { + return slotsProps[key]?.(formModel, ...args) } } else { slotObj[key] = () => { @@ -124,7 +152,7 @@ export const initModel = (schema: FormSchema[], formModel: Recordable) => { } else if (v.component && v.component !== 'Divider') { const hasField = Reflect.has(model, v.field) // 如果先前已经有值存在,则不进行重新赋值,而是采用现有的值 - model[v.field] = hasField ? model[v.field] : v.value !== void 0 ? v.value : '' + model[v.field] = hasField ? model[v.field] : v.value !== void 0 ? v.value : undefined } }) return model diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 7c93506..00994bf 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -105,7 +105,7 @@ export interface AutocompleteComponentProps { change?: (value: string | number) => void } slots?: { - default?: JSX.Element | null | ((formData: any) => JSX.Element | null) + default?: JSX.Element | null | ((formData: any, ...args: any[]) => JSX.Element | null) prefix?: JSX.Element | null | ((formData: any) => JSX.Element | null) suffix?: JSX.Element | null | ((formData: any) => JSX.Element | null) prepend?: JSX.Element | null | ((formData: any) => JSX.Element | null) @@ -150,7 +150,7 @@ interface SelectOption { } export interface SelectComponentProps { - value?: Array | string | number | boolean | Object + value?: string | number | boolean | Object multiple?: boolean disabled?: boolean valueKey?: string @@ -230,6 +230,52 @@ export interface SelectComponentProps { } options?: SelectOption[] style?: CSSProperties + style?: CSSProperties +} + +export interface SelectV2ComponentProps { + value?: string | number | boolean | Object + multiple?: boolean + disabled?: boolean + valueKey?: string + size?: InputNumberProps['size'] + clearable?: boolean + clearIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) + collapseTags?: boolean + multipleLimit?: number + name?: string + effect?: string + autocomplete?: string + placeholder?: string + filterable?: boolean + allowCreate?: boolean + reserveKeyword?: boolean + noDataText?: string + popperClass?: string + teleported?: boolean + persistent?: boolean + popperOptions?: any + automaticDropdown?: boolean + height?: number + scrollbarAlwaysOn?: boolean + remote?: boolean + remoteMethod?: (query: string) => void + validateEvent?: boolean + placement?: AutocompleteProps['placement'] + collapseTagsTooltip?: boolean + on?: { + change?: (value: string | number | boolean | Object) => void + visibleChange?: (visible: boolean) => void + removeTag?: (tag: any) => void + clear?: () => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + } + options?: SelectOption[] + slots?: { + default?: (option: SelectOption) => JSX.Element | null + } + style?: CSSProperties } export interface ColProps { diff --git a/src/types/form.d.ts b/src/types/form.d.ts index 5530c99..ca09bde 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -6,7 +6,8 @@ import { InputComponentProps, AutocompleteComponentProps, InputNumberComponentProps, - SelectComponentProps + SelectComponentProps, + SelectV2ComponentProps } from '@/types/components' import { FormValueType, FormValueType } from '@/types/form' import type { AxiosPromise } from 'axios' @@ -58,6 +59,7 @@ export interface FormSchema { | AutocompleteComponentProps | InputNumberComponentProps | SelectComponentProps + | SelectV2ComponentProps /** * formItem组件属性,具体可以查看element-plus文档 diff --git a/src/utils/index.ts b/src/utils/index.ts index 246de69..aa00c95 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -108,3 +108,10 @@ export function toAnyString() { }) return str } + +/** + * 首字母大写 + */ +export function firstUpperCase(str: string) { + return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase()) +} diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index 503400d..a559040 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -459,11 +459,11 @@ const schema = reactive([ select: handleSelect }, slots: { - default: (item: any) => { + default: (_, { item }) => { return ( <> -
{item.value}
- {item.link} +
{item?.value}
+ {item?.link} ) } @@ -689,56 +689,75 @@ const schema = reactive([ } } } + }, + { + field: 'field18', + label: `${t('formDemo.selectV2')}`, + component: 'Divider' + }, + { + field: 'field19', + label: t('formDemo.default'), + component: 'SelectV2', + componentProps: { + value: undefined, + options: options.value + } + }, + { + field: 'field20', + label: t('formDemo.slot'), + component: 'SelectV2', + componentProps: { + options: options.value, + slots: { + default: (option: SelectOption) => { + return ( + <> + {option?.label} + + {option?.value} + + + ) + } + } + } + }, + { + field: 'field21', + label: t('formDemo.selectGroup'), + component: 'SelectV2', + componentProps: { + options: options2.value + } + }, + { + field: 'field22', + label: `${t('formDemo.selectGroup')}${t('formDemo.slot')}`, + component: 'SelectV2', + componentProps: { + options: options2.value, + slots: { + default: (option: SelectOption) => { + return ( + <> + {option?.label} + + {option?.value} + + + ) + } + } + } + }, + { + field: 'field23', + label: t('formDemo.cascader'), + component: 'Divider' } // { - // field: 'field18', - // label: `${t('formDemo.selectV2')}`, - // component: 'Divider' - // }, - // { - // field: 'field19', - // label: t('formDemo.default'), - // component: 'SelectV2', - // componentProps: { - // options: options.value - // } - // }, - // { - // field: 'field20', - // label: t('formDemo.slot'), - // component: 'SelectV2', - // componentProps: { - // options: options.value, - // slots: { - // default: true - // } - // } - // }, - // { - // field: 'field21', - // label: t('formDemo.selectGroup'), - // component: 'SelectV2', - // componentProps: { - // options: options2.value - // } - // }, - // { - // field: 'field22', - // label: `${t('formDemo.selectGroup')}${t('formDemo.slot')}`, - // component: 'SelectV2', - // componentProps: { - // options: options2.value, - // slots: { - // default: true - // } - // } - // }, - // { - // field: 'field23', - // label: t('formDemo.cascader'), - // component: 'Divider' - // }, - // { // field: 'field24', // label: t('formDemo.default'), // component: 'Cascader', From c5b545d2c78ffa351d2cf882c8cf86eb40860bb1 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Wed, 17 May 2023 14:53:53 +0800 Subject: [PATCH 02/78] =?UTF-8?q?wip:=20Form=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/components.d.ts | 157 ++++++++++++++++++- src/types/form.d.ts | 12 +- src/views/Components/Form/DefaultForm.vue | 176 ++++++++++++---------- 3 files changed, 255 insertions(+), 90 deletions(-) diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 00994bf..56effac 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -1,5 +1,13 @@ import { CSSProperties } from 'vue' -import { InputProps, AutocompleteProps, InputNumberProps } from 'element-plus' +import { + InputProps, + AutocompleteProps, + InputNumberProps, + CascaderProps, + CascaderNode, + CascaderValue +} from 'element-plus' +import { ElementPlusSize, ElementPlusInfoType } from './elementPlus.d' export enum ComponentNameEnum { RADIO = 'Radio', @@ -46,7 +54,7 @@ export interface InputComponentProps { parser?: (value: string) => string showPassword?: boolean disabled?: boolean - size?: InputProps['size'] + size?: ElementPlusSize prefixIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) suffixIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) type?: InputProps['type'] @@ -121,7 +129,7 @@ export interface InputNumberComponentProps { step?: number stepStrictly?: boolean precision?: number - size?: InputNumberProps['size'] + size?: ElementPlusSize readonly?: boolean disabled?: boolean controls?: boolean @@ -154,7 +162,7 @@ export interface SelectComponentProps { multiple?: boolean disabled?: boolean valueKey?: string - size?: InputNumberProps['size'] + size?: ElementPlusSize clearable?: boolean collapseTags?: boolean collapseTagsTooltip?: number @@ -230,7 +238,6 @@ export interface SelectComponentProps { } options?: SelectOption[] style?: CSSProperties - style?: CSSProperties } export interface SelectV2ComponentProps { @@ -238,7 +245,7 @@ export interface SelectV2ComponentProps { multiple?: boolean disabled?: boolean valueKey?: string - size?: InputNumberProps['size'] + size?: ElementPlusSize clearable?: boolean clearIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) collapseTags?: boolean @@ -278,6 +285,144 @@ export interface SelectV2ComponentProps { style?: CSSProperties } +export interface CascaderComponentProps { + value?: string | number | string[] | number[] | any + options?: Record[] + props?: CascaderProps + size?: ElementPlusSize + placeholder?: string + disabled?: boolean + clearable?: boolean + showAllLevels?: boolean + collapseTags?: boolean + collapseTagsTooltip?: boolean + separator?: string + filterable?: boolean + filterMethod?: (node: CascaderNode, keyword: string) => boolean + debounce?: number + beforeFilter?: (value: string) => boolean + popperClass?: string + teleported?: boolean + tagType?: ElementPlusInfoType + validateEvent?: boolean + on?: { + change?: (value: CascaderValue) => void + expandChange?: (value: CascaderValue) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + visibleChange?: (value: boolean) => void + removeTag?: (value: CascaderNode['valueByOption']) => void + } + slots?: { + default?: (formData: any, { node: any, data: any }) => JSX.Element | null + empty?: JSX.Element | null | ((formData: any) => JSX.Element | null) + } + style?: CSSProperties +} + +export interface SwitchComponentProps { + value?: boolean | string | number + disabled?: boolean + loading?: boolean + size?: ElementPlusSize + width?: number | string + inlinePrompt?: boolean + activeIcon?: string | JSX.Element | null | ((formData: any) => string | JSX.Element | null) + inactiveIcon?: string | JSX.Element | null | ((formData: any) => string | JSX.Element | null) + activeText?: string + inactiveText?: string + activeValue?: boolean | string | number + inactiveValue?: boolean | string | number + name?: string + validateEvent?: boolean + beforeChange?: (value: boolean) => boolean | Promise + on?: { + change?: (value: boolean | string | number) => void + } + style?: CSSProperties +} + +export interface RateComponentProps { + value?: number + max?: number + size?: ElementPlusSize + disabled?: boolean + allowHalf?: boolean + lowThreshold?: number + highThreshold?: number + colors?: string[] | Record + voidColor?: string + disabledVoidColor?: string + icons?: string[] | JSX.Element[] | Record + voidIcon?: string | JSX.Element + disabledVoidIcon?: string | JSX.Element + showText?: boolean + showScore?: boolean + textColor?: string + texts?: string[] + scoreTemplate?: string + clearable?: boolean + id?: string + label?: string + on?: { + change?: (value: number) => void + } + style?: CSSProperties +} + +export interface ColorPickerComponentProps { + value?: string + disabled?: boolean + size?: ElementPlusSize + showAlpha?: boolean + colorFormat?: 'hsl' | 'hsv' | 'hex' | 'rgb' | 'hex' | 'rgb' + predefine?: string[] + validateEvent?: boolean + tabindex?: number | string + label?: string + id?: string + on?: { + change?: (value: string) => void + activeChange?: (value: string) => void + } + style?: CSSProperties +} + +export interface TransferComponentProps { + value?: any[] + data?: Array<{ key; label; disabled }> + filterable?: boolean + filterPlaceholder?: string + filterMethod?: (query: string, item: any) => boolean + targetOrder?: string + titles?: string[] + buttonTexts?: string[] + renderContent?: (h: any, option: any) => JSX.Element + format?: { + noChecked?: string + hasChecked?: string + } + props?: { + label?: string + key?: string + disabled?: string + } + leftDefaultChecked?: any[] + rightDefaultChecked?: any[] + validateEvent?: boolean + on?: { + change?: (value: any[]) => void + leftCheckChange?: (value: any[]) => void + rightCheckChange?: (value: any[]) => void + } + slots?: { + default?: (formData: any, data: { option: any }) => JSX.Element | null + leftFooter?: (formData: any) => JSX.Element | null + rightFooter?: (formData: any) => JSX.Element | null + } + style?: CSSProperties +} + export interface ColProps { span?: number xs?: number diff --git a/src/types/form.d.ts b/src/types/form.d.ts index ca09bde..1c1c26b 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -7,7 +7,12 @@ import { AutocompleteComponentProps, InputNumberComponentProps, SelectComponentProps, - SelectV2ComponentProps + SelectV2ComponentProps, + CascaderComponentProps, + SwitchComponentProps, + RateComponentProps, + ColorPickerComponentProps, + TransferComponentProps } from '@/types/components' import { FormValueType, FormValueType } from '@/types/form' import type { AxiosPromise } from 'axios' @@ -60,6 +65,11 @@ export interface FormSchema { | InputNumberComponentProps | SelectComponentProps | SelectV2ComponentProps + | CascaderComponentProps + | SwitchComponentProps + | RateComponentProps + | ColorPickerComponentProps + | TransferComponentProps /** * formItem组件属性,具体可以查看element-plus文档 diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index a559040..9a6af1f 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -61,13 +61,13 @@ onMounted(() => { }) const initials = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] -const options = ref( +const options = ref( Array.from({ length: 1000 }).map((_, idx) => ({ value: `Option ${idx + 1}`, label: `${initials[idx % 10]}${idx}` })) ) -const options2 = ref( +const options2 = ref( Array.from({ length: 10 }).map((_, idx) => { const label = idx + 1 return { @@ -81,7 +81,7 @@ const options2 = ref( }) ) -const options3: ComponentOptions[] = [ +const options3 = [ { value: 'guide', label: 'Guide', @@ -756,88 +756,98 @@ const schema = reactive([ field: 'field23', label: t('formDemo.cascader'), component: 'Divider' + }, + { + field: 'field24', + label: t('formDemo.default'), + component: 'Cascader', + componentProps: { + options: options3, + props: { + multiple: true + } + } + }, + { + field: 'field25', + label: t('formDemo.slot'), + component: 'Cascader', + componentProps: { + options: options3, + slots: { + default: (_, { data, node }) => { + return ( + <> + {data.label} + {!node.isLeaf ? ({data.children.length}) : null} + + ) + } + } + } + }, + { + field: 'field26', + label: t('formDemo.switch'), + component: 'Divider' + }, + { + field: 'field27', + label: t('formDemo.default'), + component: 'Switch', + value: false + }, + { + field: 'field28', + label: t('formDemo.icon'), + component: 'Switch', + value: false, + componentProps: { + activeIcon: useIcon({ icon: 'ep:check' }), + inactiveIcon: useIcon({ icon: 'ep:close' }) + } + }, + { + field: 'field29', + label: t('formDemo.rate'), + component: 'Divider' + }, + { + field: 'field30', + label: t('formDemo.default'), + component: 'Rate', + value: 0 + }, + { + field: 'field31', + label: t('formDemo.icon'), + component: 'Rate', + value: null, + componentProps: { + voidIcon: useIcon({ icon: 'ep:chat-round' }), + icons: [ + useIcon({ icon: 'ep:chat-round' }), + useIcon({ icon: 'ep:chat-line-round' }), + useIcon({ icon: 'ep:chat-dot-round' }) + ] + } + }, + { + field: 'field32', + label: t('formDemo.colorPicker'), + component: 'Divider' + }, + { + field: 'field33', + label: t('formDemo.default'), + component: 'ColorPicker' + }, + { + field: 'field34', + label: t('formDemo.transfer'), + component: 'Divider' } // { - // field: 'field24', - // label: t('formDemo.default'), - // component: 'Cascader', - // componentProps: { - // options: options3 - // } - // }, - // { - // field: 'field25', - // label: t('formDemo.slot'), - // component: 'Cascader', - // componentProps: { - // options: options3, - // slots: { - // default: true - // } - // } - // }, - // { - // field: 'field26', - // label: t('formDemo.switch'), - // component: 'Divider' - // }, - // { - // field: 'field27', - // label: t('formDemo.default'), - // component: 'Switch', - // value: false - // }, - // { - // field: 'field28', - // label: t('formDemo.icon'), - // component: 'Switch', - // value: false, - // componentProps: { - // activeIcon: useIcon({ icon: 'ep:check' }), - // inactiveIcon: useIcon({ icon: 'ep:close' }) - // } - // }, - // { - // field: 'field29', - // label: t('formDemo.rate'), - // component: 'Divider' - // }, - // { - // field: 'field30', - // label: t('formDemo.default'), - // component: 'Rate', - // value: null - // }, - // { - // field: 'field31', - // label: t('formDemo.icon'), - // component: 'Rate', - // value: null, - // componentProps: { - // voidIcon: useIcon({ icon: 'ep:chat-round' }), - // icons: [ - // useIcon({ icon: 'ep:chat-round' }), - // useIcon({ icon: 'ep:chat-line-round' }), - // useIcon({ icon: 'ep:chat-dot-round' }) - // ] - // } - // }, - // { - // field: 'field32', - // label: t('formDemo.colorPicker'), - // component: 'Divider' - // }, - // { - // field: 'field33', - // label: t('formDemo.default'), - // component: 'ColorPicker' - // }, - // { - // field: 'field34', - // label: t('formDemo.transfer'), - // component: 'Divider' - // }, - // { // field: 'field35', // label: t('formDemo.default'), // component: 'Transfer', From 7d0476f47c5858019db871cff2bdd19f0210f0d4 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Mon, 22 May 2023 17:26:43 +0800 Subject: [PATCH 03/78] =?UTF-8?q?types:=20=E4=BF=AE=E6=94=B9=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Form/src/Form.vue | 2 +- src/components/Form/src/helper.ts | 4 +- src/types/components.d.ts | 46 +++++++++++------------ src/types/form.d.ts | 35 +++++++++++------ src/views/Components/Form/DefaultForm.vue | 28 ++++++-------- 5 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 453696f..6e3b337 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -176,7 +176,7 @@ export default defineComponent({ // const notRenderOptions = ['SelectV2', 'Cascader', 'Transfer'] const componentSlots = (item?.componentProps as any)?.slots || {} const slotsMap: Recordable = { - ...setItemComponentSlots(unref(formModel), componentSlots) + ...setItemComponentSlots(componentSlots) } // 如果是select组件,并且没有自定义模板,自动渲染options if (item.component === ComponentNameEnum.SELECT) { diff --git a/src/components/Form/src/helper.ts b/src/components/Form/src/helper.ts index 8cbc98c..7f9a6fa 100644 --- a/src/components/Form/src/helper.ts +++ b/src/components/Form/src/helper.ts @@ -118,13 +118,13 @@ export const setComponentProps = (item: FormSchema): Recordable => { * @param formModel 表单数据 * @param slotsProps 插槽属性 */ -export const setItemComponentSlots = (formModel: any, slotsProps: Recordable = {}): Recordable => { +export const setItemComponentSlots = (slotsProps: Recordable = {}): Recordable => { const slotObj: Recordable = {} for (const key in slotsProps) { if (slotsProps[key]) { if (isFunction(slotsProps[key])) { slotObj[key] = (...args: any[]) => { - return slotsProps[key]?.(formModel, ...args) + return slotsProps[key]?.(...args) } } else { slotObj[key] = () => { diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 56effac..1c67748 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -55,8 +55,8 @@ export interface InputComponentProps { showPassword?: boolean disabled?: boolean size?: ElementPlusSize - prefixIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) - suffixIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) + prefixIcon?: string | JSX.Element + suffixIcon?: string | JSX.Element type?: InputProps['type'] rows?: number autosize?: boolean | { Pows?: numer; maxRows?: number } @@ -81,10 +81,10 @@ export interface InputComponentProps { input?: (value: string | number) => void } slots?: { - prefix?: JSX.Element | null | ((formData: any) => JSX.Element | null) - suffix?: JSX.Element | null | ((formData: any) => JSX.Element | null) - prepend?: JSX.Element | null | ((formData: any) => JSX.Element | null) - append?: JSX.Element | null | ((formData: any) => JSX.Element | null) + prefix?: (...args: any[]) => JSX.Element | null + suffix?: (...args: any[]) => JSX.Element | null + prepend?: (...args: any[]) => JSX.Element | null + append?: (...args: any[]) => JSX.Element | null } style?: CSSProperties } @@ -113,11 +113,11 @@ export interface AutocompleteComponentProps { change?: (value: string | number) => void } slots?: { - default?: JSX.Element | null | ((formData: any, ...args: any[]) => JSX.Element | null) - prefix?: JSX.Element | null | ((formData: any) => JSX.Element | null) - suffix?: JSX.Element | null | ((formData: any) => JSX.Element | null) - prepend?: JSX.Element | null | ((formData: any) => JSX.Element | null) - append?: JSX.Element | null | ((formData: any) => JSX.Element | null) + default?: (...args: any[]) => JSX.Element | null + prefix?: (...args: any[]) => JSX.Element | null + suffix?: (...args: any[]) => JSX.Element | null + prepend?: (...args: any[]) => JSX.Element | null + append?: (...args: any[]) => JSX.Element | null } style?: CSSProperties } @@ -188,9 +188,9 @@ export interface SelectComponentProps { teleported?: boolean persistent?: boolean automaticDropdown?: boolean - clearIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) + clearIcon?: string | JSX.Element | null fitInputWidth?: boolean - suffixIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) + suffixIcon?: string | JSX.Element | null tagType?: 'success' | 'info' | 'warning' | 'danger' validateEvent?: boolean placement?: @@ -233,8 +233,8 @@ export interface SelectComponentProps { default?: (options: SelectOption[]) => JSX.Element[] | null optionGroupDefault?: (item: SelectOption) => JSX.Element optionDefault?: (option: SelectOption) => JSX.Element | null - prefix?: JSX.Element | null | ((formData: any) => JSX.Element | null) - empty?: JSX.Element | null | ((formData: any) => JSX.Element | null) + prefix?: (...args: any[]) => JSX.Element | null + empty?: (...args: any[]) => JSX.Element | null } options?: SelectOption[] style?: CSSProperties @@ -247,7 +247,7 @@ export interface SelectV2ComponentProps { valueKey?: string size?: ElementPlusSize clearable?: boolean - clearIcon?: string | JSX.Element | ((formData: any) => string | JSX.Element) + clearIcon?: string | JSX.Element | null collapseTags?: boolean multipleLimit?: number name?: string @@ -314,8 +314,8 @@ export interface CascaderComponentProps { removeTag?: (value: CascaderNode['valueByOption']) => void } slots?: { - default?: (formData: any, { node: any, data: any }) => JSX.Element | null - empty?: JSX.Element | null | ((formData: any) => JSX.Element | null) + default?: (...args: any[]) => JSX.Element | null + empty?: (...args: any[]) => JSX.Element | null } style?: CSSProperties } @@ -327,8 +327,8 @@ export interface SwitchComponentProps { size?: ElementPlusSize width?: number | string inlinePrompt?: boolean - activeIcon?: string | JSX.Element | null | ((formData: any) => string | JSX.Element | null) - inactiveIcon?: string | JSX.Element | null | ((formData: any) => string | JSX.Element | null) + activeIcon?: string | JSX.Element | null + inactiveIcon?: string | JSX.Element | null activeText?: string inactiveText?: string activeValue?: boolean | string | number @@ -416,9 +416,9 @@ export interface TransferComponentProps { rightCheckChange?: (value: any[]) => void } slots?: { - default?: (formData: any, data: { option: any }) => JSX.Element | null - leftFooter?: (formData: any) => JSX.Element | null - rightFooter?: (formData: any) => JSX.Element | null + default?: (...args: any[]) => JSX.Element | null + leftFooter?: (...args: any[]) => JSX.Element | null + rightFooter?: (...args: any[]) => JSX.Element | null } style?: CSSProperties } diff --git a/src/types/form.d.ts b/src/types/form.d.ts index 1c1c26b..b31924d 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -35,6 +35,29 @@ export type FormItemProps = { style?: CSSProperties } +// 定义联合类型和条件类型 +type ComponentPropsForComponent = T extends 'input' + ? InputComponentProps + : T extends 'autocomplete' + ? AutocompleteComponentProps + : T extends 'inputNumber' + ? InputNumberComponentProps + : T extends 'select' + ? SelectComponentProps + : T extends 'selectV2' + ? SelectV2ComponentProps + : T extends 'cascader' + ? CascaderComponentProps + : T extends 'switch' + ? SwitchComponentProps + : T extends 'rate' + ? RateComponentProps + : T extends 'colorPicker' + ? ColorPickerComponentProps + : T extends 'transfer' + ? TransferComponentProps + : any + export interface FormSchema { /** * 唯一标识 @@ -59,17 +82,7 @@ export interface FormSchema { /** * 表单组件属性,具体可以查看element-plus文档 */ - componentProps?: - | InputComponentProps - | AutocompleteComponentProps - | InputNumberComponentProps - | SelectComponentProps - | SelectV2ComponentProps - | CascaderComponentProps - | SwitchComponentProps - | RateComponentProps - | ColorPickerComponentProps - | TransferComponentProps + componentProps?: ComponentPropsForComponent /** * formItem组件属性,具体可以查看element-plus文档 diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index 9a6af1f..9abdabf 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -383,9 +383,7 @@ const schema = reactive([ component: 'Input', componentProps: { suffixIcon: useIcon({ icon: 'ep:calendar' }), - prefixIcon: () => { - return unref(toggle) ? useIcon({ icon: 'ep:calendar' }) : useIcon({ icon: 'ep:share' }) - } + prefixIcon: useIcon({ icon: 'ep:share' }) } }, { @@ -394,12 +392,10 @@ const schema = reactive([ component: 'Input', componentProps: { slots: { - suffix: (data: any) => { - return unref(toggle) && data.field4 - ? useIcon({ icon: 'ep:calendar' }) - : useIcon({ icon: 'ep:share' }) + suffix: () => { + return useIcon({ icon: 'ep:share' }) }, - prefix: useIcon({ icon: 'ep:calendar' }) + prefix: () => useIcon({ icon: 'ep:calendar' }) } } }, @@ -409,10 +405,8 @@ const schema = reactive([ component: 'Input', componentProps: { slots: { - prepend: useIcon({ icon: 'ep:calendar' }), - append: (data: any) => { - return data.field5 ? useIcon({ icon: 'ep:calendar' }) : useIcon({ icon: 'ep:share' }) - } + prepend: () => useIcon({ icon: 'ep:calendar' }), + append: () => useIcon({ icon: 'ep:share' }) } } }, @@ -459,7 +453,7 @@ const schema = reactive([ select: handleSelect }, slots: { - default: (_, { item }) => { + default: ({ item }) => { return ( <>
{item?.value}
@@ -549,9 +543,9 @@ const schema = reactive([ return null } }, - prefix: useIcon({ icon: 'ep:calendar' }), - empty: (data: any) => { - return data.field5 ? useIcon({ icon: 'ep:calendar' }) : useIcon({ icon: 'ep:share' }) + prefix: () => useIcon({ icon: 'ep:calendar' }), + empty: () => { + return useIcon({ icon: 'ep:share' }) } } } @@ -775,7 +769,7 @@ const schema = reactive([ componentProps: { options: options3, slots: { - default: (_, { data, node }) => { + default: ({ data, node }) => { return ( <> {data.label} From c3ac1915045d4d59bca09ec6d19151bc5da342f1 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Mon, 22 May 2023 17:44:29 +0800 Subject: [PATCH 04/78] =?UTF-8?q?types:=20=E4=BF=AE=E6=94=B9=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/form.d.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/types/form.d.ts b/src/types/form.d.ts index b31924d..2612acb 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -82,7 +82,17 @@ export interface FormSchema { /** * 表单组件属性,具体可以查看element-plus文档 */ - componentProps?: ComponentPropsForComponent + componentProps?: + | InputComponentProps + | AutocompleteComponentProps + | InputNumberComponentProps + | SelectComponentProps + | SelectV2ComponentProps + | CascaderComponentProps + | SwitchComponentProps + | RateComponentProps + | ColorPickerComponentProps + | TransferComponentProps /** * formItem组件属性,具体可以查看element-plus文档 From 64d436bf84a7120e81a384ebb4dbe4912d49a78a Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Tue, 23 May 2023 10:32:16 +0800 Subject: [PATCH 05/78] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 23f74c8..48add6b 100644 --- a/package.json +++ b/package.json @@ -30,55 +30,55 @@ "@vueuse/core": "^10.1.2", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.10", - "@zxcvbn-ts/core": "^3.0.0", + "@zxcvbn-ts/core": "^3.0.1", "animate.css": "^4.1.1", "axios": "^1.4.0", "dayjs": "^1.11.7", "echarts": "^5.4.2", "echarts-wordcloud": "^2.1.0", - "element-plus": "2.3.4", + "element-plus": "2.3.5", "intro.js": "^7.0.1", "lodash-es": "^4.17.21", "mitt": "^3.0.0", "mockjs": "^1.1.0", "nprogress": "^0.2.0", - "pinia": "^2.0.36", + "pinia": "^2.1.3", "pinia-plugin-persist": "^1.0.0", "qrcode": "^1.5.3", - "qs": "^6.11.1", + "qs": "^6.11.2", "url": "^0.11.0", - "vue": "3.2.47", + "vue": "3.3.4", "vue-i18n": "9.2.2", - "vue-router": "^4.1.6", - "vue-types": "^5.0.2", + "vue-router": "^4.2.1", + "vue-types": "^5.0.3", "web-storage-cache": "^1.1.1" }, "devDependencies": { "@commitlint/cli": "^17.6.3", "@commitlint/config-conventional": "^17.6.3", - "@iconify/json": "^2.2.62", + "@iconify/json": "^2.2.68", "@intlify/unplugin-vue-i18n": "^0.10.0", "@purge-icons/generated": "^0.9.0", "@types/intro.js": "^5.1.1", "@types/lodash-es": "^4.17.7", - "@types/node": "^20.1.1", + "@types/node": "^20.2.3", "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.5.0", "@types/qs": "^6.9.7", - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", - "@unocss/transformer-variant-group": "^0.51.12", + "@typescript-eslint/eslint-plugin": "^5.59.7", + "@typescript-eslint/parser": "^5.59.7", + "@unocss/transformer-variant-group": "^0.52.1", "@vitejs/plugin-legacy": "^4.0.3", - "@vitejs/plugin-vue": "^4.2.1", + "@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue-jsx": "^3.0.1", "@vue-macros/volar": "^0.9.8", "autoprefixer": "^10.4.14", "consola": "^3.1.0", - "eslint": "^8.40.0", + "eslint": "^8.41.0", "eslint-config-prettier": "^8.8.0", "eslint-define-config": "^1.20.0", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-vue": "^9.11.1", + "eslint-plugin-vue": "^9.14.0", "husky": "^8.0.3", "less": "^4.1.3", "lint-staged": "^13.2.2", @@ -87,27 +87,27 @@ "postcss-html": "^1.5.0", "postcss-less": "^6.0.0", "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "rollup": "^3.21.5", - "stylelint": "^15.6.1", + "rimraf": "^5.0.1", + "rollup": "^3.23.0", + "stylelint": "^15.6.2", "stylelint-config-html": "^1.1.0", "stylelint-config-prettier": "^9.0.5", "stylelint-config-recommended": "^12.0.0", "stylelint-config-standard": "^33.0.0", "stylelint-order": "^6.0.3", - "terser": "^5.17.2", + "terser": "^5.17.5", "typescript": "5.0.4", - "unocss": "^0.51.12", + "unocss": "^0.52.1", "unplugin-vue-define-options": "^1.3.5", - "vite": "4.3.5", + "vite": "4.3.8", "vite-plugin-ejs": "^1.6.4", "vite-plugin-eslint": "^1.8.1", - "vite-plugin-mock": "^3.0.0", + "vite-plugin-mock": "2.9.6", "vite-plugin-progress": "^0.0.7", "vite-plugin-purge-icons": "^0.9.2", "vite-plugin-style-import": "2.0.0", "vite-plugin-svg-icons": "^2.0.1", - "vue-tsc": "^1.6.4" + "vue-tsc": "^1.6.5" }, "engines": { "node": ">= 14.18.0" 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 06/78] =?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 ( + + Operation + + ) + }, + rightFooter: () => { + return ( + + Operation + + ) + } + } + }, + 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; +} From 6f1a94809ec2d27de239404c8c75a4849ac87c2a Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Wed, 24 May 2023 18:14:36 +0800 Subject: [PATCH 07/78] =?UTF-8?q?wip:=20Form=E6=94=B9=E9=80=A0=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Form/src/Form.vue | 61 +++++++++----- src/components/Form/src/componentMap.ts | 2 +- .../Form/src/components/useRenderRadio.tsx | 27 +++--- src/locales/en.ts | 1 + src/locales/zh-CN.ts | 1 + src/types/components.d.ts | 30 +++++++ src/types/form.d.ts | 29 +------ src/views/Components/Form/DefaultForm.vue | 84 ++++++++++++++++++- 8 files changed, 172 insertions(+), 63 deletions(-) diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 04c0adf..547f699 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -183,27 +183,7 @@ export default defineComponent({ const renderFormItem = (item: FormSchema) => { // 单独给只有options属性的组件做判断 // const notRenderOptions = ['SelectV2', 'Cascader', 'Transfer'] - const componentSlots = (item?.componentProps as any)?.slots || {} - const slotsMap: Recordable = { - ...setItemComponentSlots(componentSlots) - } - // 如果是select组件,并且没有自定义模板,自动渲染options - if (item.component === ComponentNameEnum.SELECT) { - slotsMap.default = !componentSlots.default - ? () => renderSelectOptions(item) - : () => { - return componentSlots.default( - unref((item?.componentProps as SelectComponentProps)?.options) - ) - } - } - // 虚拟列表 - if (item.component === ComponentNameEnum.SELECT_V2 && componentSlots.default) { - slotsMap.default = ({ item }: any) => { - return componentSlots.default(item) - } - } // if ( // item?.component !== 'SelectV2' && // item?.component !== 'Cascader' && @@ -268,19 +248,56 @@ export default defineComponent({ label={v[valueAlias]} disabled={v[disabledAlias]} > - {v[labelAlias]} + {() => + componentProps?.slots?.default + ? componentProps?.slots?.default({ option: v }) + : v[labelAlias] + } ) }) } } + const componentSlots = (item?.componentProps as any)?.slots || {} + const slotsMap: Recordable = { + ...setItemComponentSlots(componentSlots) + } + // 如果是select组件,并且没有自定义模板,自动渲染options + if (item.component === ComponentNameEnum.SELECT) { + slotsMap.default = !componentSlots.default + ? () => renderSelectOptions(item) + : () => { + return componentSlots.default( + unref((item?.componentProps as SelectComponentProps)?.options) + ) + } + } + + // 虚拟列表 + if (item.component === ComponentNameEnum.SELECT_V2 && componentSlots.default) { + slotsMap.default = ({ item }) => { + return componentSlots.default(item) + } + } + + // 单选框组 + if (item.component === ComponentNameEnum.RADIO_GROUP) { + slotsMap.default = !componentSlots.default + ? () => renderRadioOptions(item) + : () => { + return componentSlots.default( + unref((item?.componentProps as RadioComponentProps)?.options) + ) + } + } + return ( {{ ...slotsMap }} diff --git a/src/components/Form/src/componentMap.ts b/src/components/Form/src/componentMap.ts index f5d7f17..afd3d12 100644 --- a/src/components/Form/src/componentMap.ts +++ b/src/components/Form/src/componentMap.ts @@ -25,7 +25,7 @@ import { ComponentName } from '@/types/components' const componentMap: Recordable = { Radio: ElRadio, - // RadioGroup: ElRadioGroup, + 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 55fac63..0d2a098 100644 --- a/src/components/Form/src/components/useRenderRadio.tsx +++ b/src/components/Form/src/components/useRenderRadio.tsx @@ -1,23 +1,26 @@ import { FormSchema } from '@/types/form' import { ElRadio, ElRadioButton } from 'element-plus' import { defineComponent } from 'vue' -import { ComponentNameEnum } from '@/types/components.d' +import { ComponentNameEnum, RadioGroupComponentProps } from '@/types/components.d' export const useRenderRadio = () => { - const renderRadioOptions = ( - item: FormSchema, - type?: ComponentNameEnum.RADIO | ComponentNameEnum.RADIO_BUTTON = ComponentNameEnum.RADIO - ) => { + const renderRadioOptions = (item: FormSchema) => { // 如果有别名,就取别名 - const labelAlias = item?.componentProps?.optionsAlias?.labelField - const valueAlias = item?.componentProps?.optionsAlias?.valueField - const Com = (item.component === 'Radio' ? ElRadio : ElRadioButton) as ReturnType< - typeof defineComponent - > - return item?.componentProps?.options?.map((option) => { + const componentProps = item.componentProps as RadioGroupComponentProps + const valueAlias = componentProps?.props?.value || 'value' + const labelAlias = componentProps?.props?.label || 'label' + const disabledAlias = componentProps?.props?.disabled || 'disabled' + const Com = ( + item.component === ComponentNameEnum.RADIO_GROUP ? ElRadio : ElRadioButton + ) as ReturnType + return componentProps?.options?.map((option) => { const { value, ...other } = option return ( - + {option[labelAlias || 'label']} ) diff --git a/src/locales/en.ts b/src/locales/en.ts index 4646233..575e810 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -241,6 +241,7 @@ export default { transfer: 'Transfer', render: 'Render', radio: 'Radio', + radioGroup: 'Radio Group', button: 'Button', checkbox: 'Checkbox', slider: 'Slider', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 4a162c3..c6cd808 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -241,6 +241,7 @@ export default { transfer: '穿梭框', render: '渲染器', radio: '单选框', + radioGroup: '单选框组', button: '按钮', checkbox: '多选框', slider: '滑块', diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 5471e40..28a05a9 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -11,6 +11,7 @@ import { ElementPlusSize, ElementPlusInfoType } from './elementPlus.d' export enum ComponentNameEnum { RADIO = 'Radio', + RADIO_GROUP = 'RadioGroup', RADIO_BUTTON = 'RadioButton', CHECKBOX = 'Checkbox', CHECKBOX_BUTTON = 'CheckboxButton', @@ -453,6 +454,35 @@ export interface RadioComponentProps { slots?: { default?: (...args: any[]) => JSX.Element | null } + style?: CSSProperties +} + +export interface RadioGroupComponentProps { + value?: string | number | boolean + size?: ElementPlusSize + disabled?: boolean + textColor?: string + fill?: string + validateEvent?: boolean + label?: string + name?: string + id?: string + options?: RadioOption[] + /** + * 数据源的字段别名 + */ + props: { + label?: string + value?: string + disabled?: string + } + on?: { + change?: (value: string | number | boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties } export interface ColProps { diff --git a/src/types/form.d.ts b/src/types/form.d.ts index 899a921..6cec366 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -13,7 +13,8 @@ import { RateComponentProps, ColorPickerComponentProps, TransferComponentProps, - RadioComponentProps + RadioComponentProps, + RadioGroupComponentProps } from '@/types/components' import { FormValueType, FormValueType } from '@/types/form' import type { AxiosPromise } from 'axios' @@ -36,31 +37,6 @@ export type FormItemProps = { style?: CSSProperties } -// 定义联合类型和条件类型 -type ComponentPropsForComponent = T extends 'Input' - ? InputComponentProps - : T extends 'Autocomplete' - ? AutocompleteComponentProps - : T extends 'InputNumber' - ? InputNumberComponentProps - : T extends 'Select' - ? SelectComponentProps - : T extends 'SelectV2' - ? SelectV2ComponentProps - : T extends 'Cascader' - ? CascaderComponentProps - : T extends 'Switch' - ? SwitchComponentProps - : T extends 'Rate' - ? RateComponentProps - : T extends 'ColorPicker' - ? ColorPickerComponentProps - : T extends 'Transfer' - ? TransferComponentProps - : T extends 'Radio' - ? RadioComponentProps - : any - export interface FormSchema { /** * 唯一标识 @@ -97,6 +73,7 @@ export interface FormSchema { | ColorPickerComponentProps | TransferComponentProps | RadioComponentProps + | RadioGroupComponentProps /** * formItem组件属性,具体可以查看element-plus文档 diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index 7eb02ce..aef5790 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -6,9 +6,14 @@ import { useIcon } from '@/hooks/web/useIcon' import { ContentWrap } from '@/components/ContentWrap' import { useAppStore } from '@/store/modules/app' import { FormSchema } from '@/types/form' -import { ComponentOptions, SelectOption, SelectComponentProps } from '@/types/components' +import { + ComponentOptions, + SelectOption, + SelectComponentProps, + RadioOption +} from '@/types/components' import { useForm } from '@/hooks/web/useForm' -import { ElOption, ElOptionGroup, ElButton } from 'element-plus' +import { ElOption, ElOptionGroup, ElButton, ElRadio } from 'element-plus' const appStore = useAppStore() @@ -949,6 +954,81 @@ const schema = reactive([ } ] } + }, + { + field: 'field39-1', + label: t('formDemo.slot'), + component: 'Radio', + componentProps: { + options: [ + { + // disabled: true, + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + } + ], + slots: { + default: ({ option }) => { + return ( + <> + {option.label} + ({option.value}) + + ) + } + } + } + }, + { + field: 'field39-2', + label: t('formDemo.radioGroup'), + component: 'RadioGroup', + componentProps: { + options: [ + { + // disabled: true, + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + } + ] + } + }, + { + field: 'field39-3', + label: `${t('formDemo.radioGroup')}${t('formDemo.slot')}`, + component: 'RadioGroup', + componentProps: { + options: [ + { + // disabled: true, + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + } + ], + slots: { + default: (options: RadioOption[]) => { + return options?.map((v) => { + return ( + + {v.label}({v.value}) + + ) + }) + } + } + } } // { // field: 'field40', From deeee73bcb3ad912844fddee62b1155d95d4b42b Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Thu, 25 May 2023 09:29:49 +0800 Subject: [PATCH 08/78] =?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 --- src/components/Form/src/Form.vue | 7 ++- src/components/Form/src/componentMap.ts | 2 +- src/types/components.d.ts | 28 +++++++++ src/types/form.d.ts | 4 +- src/views/Components/Form/DefaultForm.vue | 75 +++++++++++++++-------- 5 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 547f699..9e47bfb 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -281,8 +281,11 @@ export default defineComponent({ } } - // 单选框组 - if (item.component === ComponentNameEnum.RADIO_GROUP) { + // 单选框组和按钮样式 + if ( + item.component === ComponentNameEnum.RADIO_GROUP || + item.component === ComponentNameEnum.RADIO_BUTTON + ) { slotsMap.default = !componentSlots.default ? () => renderRadioOptions(item) : () => { diff --git a/src/components/Form/src/componentMap.ts b/src/components/Form/src/componentMap.ts index afd3d12..e8e3731 100644 --- a/src/components/Form/src/componentMap.ts +++ b/src/components/Form/src/componentMap.ts @@ -26,6 +26,7 @@ import { ComponentName } from '@/types/components' const componentMap: Recordable = { Radio: ElRadio, RadioGroup: ElRadioGroup, + RadioButton: ElRadioGroup, Checkbox: ElCheckboxGroup, CheckboxButton: ElCheckboxGroup, Input: ElInput, @@ -43,7 +44,6 @@ const componentMap: Recordable = { Divider: ElDivider, TimeSelect: ElTimeSelect, SelectV2: ElSelectV2, - RadioButton: ElRadioGroup, InputPassword: InputPassword, Editor: Editor } diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 28a05a9..9cb0727 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -485,6 +485,34 @@ export interface RadioGroupComponentProps { style?: CSSProperties } +export interface RadioButtonComponentProps { + value?: string | number | boolean + size?: ElementPlusSize + disabled?: boolean + textColor?: string + fill?: string + validateEvent?: boolean + label?: string + name?: string + id?: string + options?: RadioOption[] + /** + * 数据源的字段别名 + */ + props: { + label?: string + value?: string + disabled?: string + } + on?: { + change?: (value: string | number | boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + export interface ColProps { span?: number xs?: number diff --git a/src/types/form.d.ts b/src/types/form.d.ts index 6cec366..e8a564d 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -14,7 +14,8 @@ import { ColorPickerComponentProps, TransferComponentProps, RadioComponentProps, - RadioGroupComponentProps + RadioGroupComponentProps, + RadioButtonComponentProps } from '@/types/components' import { FormValueType, FormValueType } from '@/types/form' import type { AxiosPromise } from 'axios' @@ -74,6 +75,7 @@ export interface FormSchema { | TransferComponentProps | RadioComponentProps | RadioGroupComponentProps + | RadioButtonComponentProps /** * formItem组件属性,具体可以查看element-plus文档 diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index aef5790..109c56e 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -13,7 +13,7 @@ import { RadioOption } from '@/types/components' import { useForm } from '@/hooks/web/useForm' -import { ElOption, ElOptionGroup, ElButton, ElRadio } from 'element-plus' +import { ElOption, ElOptionGroup, ElButton, ElRadio, ElRadioButton } from 'element-plus' const appStore = useAppStore() @@ -1029,31 +1029,58 @@ const schema = reactive([ } } } + }, + { + field: 'field40', + label: t('formDemo.button'), + component: 'RadioButton', + componentProps: { + options: [ + { + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + } + ] + } + }, + { + field: 'field40', + label: `${t('formDemo.button')}${t('formDemo.slot')}`, + component: 'RadioButton', + componentProps: { + options: [ + { + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + } + ], + slots: { + default: (options: RadioOption[]) => { + return options?.map((v) => { + return ( + + {v.label}({v.value}) + + ) + }) + } + } + } + }, + { + field: 'field41', + label: t('formDemo.checkbox'), + component: 'Divider' } // { - // field: 'field40', - // label: t('formDemo.button'), - // component: 'RadioButton', - // componentProps: { - // options: [ - // { - // disabled: true, - // label: 'option-1', - // value: '1' - // }, - // { - // label: 'option-2', - // value: '2' - // } - // ] - // } - // }, - // { - // field: 'field41', - // label: t('formDemo.checkbox'), - // component: 'Divider' - // }, - // { // field: 'field42', // label: t('formDemo.default'), // component: 'Checkbox', From e34b5cb6132a2afd1446da598d2b0805afc65105 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Thu, 25 May 2023 11:33:37 +0800 Subject: [PATCH 09/78] =?UTF-8?q?wip:=20Form=E6=94=B9=E9=80=A0=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Form/src/Form.vue | 51 +++++++++-------- src/components/Form/src/componentMap.ts | 6 +- src/locales/en.ts | 2 + src/locales/zh-CN.ts | 2 + src/types/components.d.ts | 46 +++++++++++++++ src/types/form.d.ts | 4 +- src/views/Components/Form/DefaultForm.vue | 70 ++++++++++++++++++++--- 7 files changed, 144 insertions(+), 37 deletions(-) diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 9e47bfb..0aeb8e2 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -25,7 +25,8 @@ import { ComponentNameEnum, SelectComponentProps, SelectOption, - RadioComponentProps + RadioComponentProps, + CheckboxComponentProps } from '@/types/components.d' const { renderSelectOptions } = useRenderSelect() @@ -230,33 +231,33 @@ export default defineComponent({ const { autoSetPlaceholder } = unref(getProps) // 需要特殊处理的组件 - const specialComponents = [ComponentNameEnum.RADIO] + const specialComponents = [ComponentNameEnum.RADIO, ComponentNameEnum.CHECKBOX] 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' + const componentProps = + item.component === ComponentNameEnum.RADIO + ? (item.componentProps as RadioComponentProps) + : (item.componentProps as CheckboxComponentProps) - return componentProps?.options?.map((v) => { - return ( - - {() => - componentProps?.slots?.default - ? componentProps?.slots?.default({ option: v }) - : v[labelAlias] - } - - ) - }) - } + const valueAlias = componentProps?.props?.value || 'value' + const labelAlias = componentProps?.props?.label || 'label' + const disabledAlias = componentProps?.props?.disabled || 'disabled' + return componentProps?.options?.map((v) => { + return ( + + {() => + componentProps?.slots?.default + ? componentProps?.slots?.default({ option: v }) + : v[labelAlias] + } + + ) + }) } const componentSlots = (item?.componentProps as any)?.slots || {} diff --git a/src/components/Form/src/componentMap.ts b/src/components/Form/src/componentMap.ts index e8e3731..2c48f60 100644 --- a/src/components/Form/src/componentMap.ts +++ b/src/components/Form/src/componentMap.ts @@ -17,7 +17,8 @@ import { ElTransfer, ElAutocomplete, ElDivider, - ElRadio + ElRadio, + ElCheckbox } from 'element-plus' import { InputPassword } from '@/components/InputPassword' import { Editor } from '@/components/Editor' @@ -27,7 +28,8 @@ const componentMap: Recordable = { Radio: ElRadio, RadioGroup: ElRadioGroup, RadioButton: ElRadioGroup, - Checkbox: ElCheckboxGroup, + Checkbox: ElCheckbox, + CheckboxGroup: ElCheckboxGroup, CheckboxButton: ElCheckboxGroup, Input: ElInput, Autocomplete: ElAutocomplete, diff --git a/src/locales/en.ts b/src/locales/en.ts index 575e810..9527e3d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -244,6 +244,8 @@ export default { radioGroup: 'Radio Group', button: 'Button', checkbox: 'Checkbox', + checkboxButton: 'Checkbox Button', + checkboxGroup: 'Checkbox Group', slider: 'Slider', datePicker: 'Date Picker', shortcuts: 'Shortcuts', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index c6cd808..619c4ba 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -244,6 +244,8 @@ export default { radioGroup: '单选框组', button: '按钮', checkbox: '多选框', + checkboxButton: '多选框按钮', + checkboxGroup: '多选框组', slider: '滑块', datePicker: '日期选择器', shortcuts: '快捷选项', diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 9cb0727..1354f65 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -14,6 +14,7 @@ export enum ComponentNameEnum { RADIO_GROUP = 'RadioGroup', RADIO_BUTTON = 'RadioButton', CHECKBOX = 'Checkbox', + CHECKBOX_GROUP = 'CheckboxGroup', CHECKBOX_BUTTON = 'CheckboxButton', INPUT = 'Input', AUTOCOMPLETE = 'Autocomplete', @@ -432,6 +433,7 @@ export interface RadioOption { disabled?: boolean [key: string]: any } + export interface RadioComponentProps { value?: string | number | boolean label?: string | number | boolean @@ -513,6 +515,50 @@ export interface RadioButtonComponentProps { style?: CSSProperties } +export interface CheckboxOption { + label?: string + value?: string | number | boolean + disabled?: boolean + [key: string]: any +} + +export interface CheckboxComponentProps { + value?: string | number | boolean + label?: string | number | boolean | any + trueLabel?: string | number + falseLabel?: string | number + disabled?: boolean + border?: boolean + size?: ElementPlusSize + name?: string + checked?: boolean + indeterminate?: boolean + validateEvent?: boolean + tabindex?: number | string + id?: string + controls?: boolean + on?: { + change?: (value: string | number | boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + } + options: CheckboxOption[] + /** + * 数据源的字段别名 + */ + props: { + label?: string + value?: string + disabled?: string + } + style?: CSSProperties +} + +export interface CheckboxGroupComponentProps { + value?: string[] | number[] +} + export interface ColProps { span?: number xs?: number diff --git a/src/types/form.d.ts b/src/types/form.d.ts index e8a564d..37ea21a 100644 --- a/src/types/form.d.ts +++ b/src/types/form.d.ts @@ -15,7 +15,8 @@ import { TransferComponentProps, RadioComponentProps, RadioGroupComponentProps, - RadioButtonComponentProps + RadioButtonComponentProps, + CheckboxComponentProps } from '@/types/components' import { FormValueType, FormValueType } from '@/types/form' import type { AxiosPromise } from 'axios' @@ -76,6 +77,7 @@ export interface FormSchema { | RadioComponentProps | RadioGroupComponentProps | RadioButtonComponentProps + | CheckboxComponentProps /** * formItem组件属性,具体可以查看element-plus文档 diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index 109c56e..fdaabe8 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -1003,7 +1003,7 @@ const schema = reactive([ }, { field: 'field39-3', - label: `${t('formDemo.radioGroup')}${t('formDemo.slot')}`, + label: `${t('formDemo.radioGroup')} ${t('formDemo.slot')}`, component: 'RadioGroup', componentProps: { options: [ @@ -1048,8 +1048,8 @@ const schema = reactive([ } }, { - field: 'field40', - label: `${t('formDemo.button')}${t('formDemo.slot')}`, + field: 'field40-1', + label: `${t('formDemo.button')} ${t('formDemo.slot')}`, component: 'RadioButton', componentProps: { options: [ @@ -1079,16 +1079,68 @@ const schema = reactive([ field: 'field41', label: t('formDemo.checkbox'), component: 'Divider' + }, + { + field: 'field42', + label: t('formDemo.default'), + component: 'Checkbox', + componentProps: { + options: [ + { + disabled: true, + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + }, + { + label: 'option-3', + value: '3' + } + ] + } + }, + { + field: 'field42-1', + label: t('formDemo.slot'), + component: 'Checkbox', + componentProps: { + options: [ + { + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + }, + { + label: 'option-3', + value: '3' + } + ], + slots: { + default: ({ option }) => { + return ( + <> + {option.label} + ({option.value}) + + ) + } + } + } } // { - // field: 'field42', - // label: t('formDemo.default'), - // component: 'Checkbox', + // field: 'field42-2', + // label: t('formDemo.checkboxGroup'), + // component: 'CheckboxGroup', // value: [], // componentProps: { // options: [ // { - // disabled: true, // label: 'option-1', // value: '1' // }, @@ -1098,11 +1150,11 @@ const schema = reactive([ // }, // { // label: 'option-3', - // value: '23' + // value: '3' // } // ] // } - // }, + // } // { // field: 'field43', // label: t('formDemo.button'), From 46b35e48b3e7876c74159625b5149ef663396f5c Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Wed, 31 May 2023 16:24:28 +0800 Subject: [PATCH 10/78] =?UTF-8?q?types:=20=E8=BF=81=E7=A7=BBtypes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConfigGlobal/src/ConfigGlobal.vue | 1 - .../ConfigGlobal/src/types.ts} | 1 - .../ContextMenu/src/ContextMenu.vue | 2 +- .../ContextMenu/src/types.ts} | 0 .../Descriptions/src/Descriptions.vue | 2 +- .../Descriptions/src/types.ts} | 0 src/components/Form/index.ts | 2 +- src/components/Form/src/Form copy.vue | 302 ----- src/components/Form/src/Form.vue | 56 +- src/components/Form/src/componentMap.ts | 8 +- .../Form/src/components/useRenderCheckbox.tsx | 22 +- .../Form/src/components/useRenderRadio.tsx | 3 +- .../Form/src/components/useRenderSelect.tsx | 3 +- src/components/Form/src/helper.ts | 7 +- src/components/Form/src/types.ts | 822 ++++++++++++ src/hooks/web/useConfigGlobal.ts | 2 +- src/types/components.d.ts | 590 --------- src/types/elementPlus.d.ts | 3 - src/types/form.d.ts | 106 -- src/types/{icon.d.ts => icon.ts} | 0 src/types/{infoTip.d.ts => infoTip.ts} | 0 src/types/layout.d.ts | 1 - ...{localeDropdown.d.ts => localeDropdown.ts} | 0 src/types/{qrcode.d.ts => qrcode.ts} | 0 src/types/{table.d.ts => table.ts} | 0 src/types/theme.d.ts | 16 - src/types/theme.ts | 16 + .../Components/Form/DefaultForm copy.vue | 1136 ----------------- src/views/Components/Form/DefaultForm.vue | 657 +++++----- types/global.d.ts | 6 + 30 files changed, 1176 insertions(+), 2588 deletions(-) rename src/{types/configGlobal.d.ts => components/ConfigGlobal/src/types.ts} (57%) rename src/{types/contextMenu.d.ts => components/ContextMenu/src/types.ts} (100%) rename src/{types/descriptions.d.ts => components/Descriptions/src/types.ts} (100%) delete mode 100644 src/components/Form/src/Form copy.vue delete mode 100644 src/types/components.d.ts delete mode 100644 src/types/elementPlus.d.ts delete mode 100644 src/types/form.d.ts rename src/types/{icon.d.ts => icon.ts} (100%) rename src/types/{infoTip.d.ts => infoTip.ts} (100%) delete mode 100644 src/types/layout.d.ts rename src/types/{localeDropdown.d.ts => localeDropdown.ts} (100%) rename src/types/{qrcode.d.ts => qrcode.ts} (100%) rename src/types/{table.d.ts => table.ts} (100%) delete mode 100644 src/types/theme.d.ts create mode 100644 src/types/theme.ts delete mode 100644 src/views/Components/Form/DefaultForm copy.vue diff --git a/src/components/ConfigGlobal/src/ConfigGlobal.vue b/src/components/ConfigGlobal/src/ConfigGlobal.vue index 0a55f15..4594ebd 100644 --- a/src/components/ConfigGlobal/src/ConfigGlobal.vue +++ b/src/components/ConfigGlobal/src/ConfigGlobal.vue @@ -7,7 +7,6 @@ import { useWindowSize } from '@vueuse/core' import { useAppStore } from '@/store/modules/app' import { setCssVar } from '@/utils' import { useDesign } from '@/hooks/web/useDesign' -import { ElementPlusSize } from '@/types/elementPlus' const { variables } = useDesign() diff --git a/src/types/configGlobal.d.ts b/src/components/ConfigGlobal/src/types.ts similarity index 57% rename from src/types/configGlobal.d.ts rename to src/components/ConfigGlobal/src/types.ts index f6d7b3c..a77893a 100644 --- a/src/types/configGlobal.d.ts +++ b/src/components/ConfigGlobal/src/types.ts @@ -1,4 +1,3 @@ -import { ElementPlusSize } from './elementPlus' export interface ConfigGlobalTypes { size?: ElementPlusSize } diff --git a/src/components/ContextMenu/src/ContextMenu.vue b/src/components/ContextMenu/src/ContextMenu.vue index 5e77307..ddba8be 100644 --- a/src/components/ContextMenu/src/ContextMenu.vue +++ b/src/components/ContextMenu/src/ContextMenu.vue @@ -4,7 +4,7 @@ import { PropType, ref } from 'vue' import { useI18n } from '@/hooks/web/useI18n' import { useDesign } from '@/hooks/web/useDesign' import type { RouteLocationNormalizedLoaded } from 'vue-router' -import { contextMenuSchema } from '../../../types/contextMenu' +import { contextMenuSchema } from './types' const { getPrefixCls } = useDesign() const prefixCls = getPrefixCls('context-menu') diff --git a/src/types/contextMenu.d.ts b/src/components/ContextMenu/src/types.ts similarity index 100% rename from src/types/contextMenu.d.ts rename to src/components/ContextMenu/src/types.ts diff --git a/src/components/Descriptions/src/Descriptions.vue b/src/components/Descriptions/src/Descriptions.vue index d0fbf5d..a9948d1 100644 --- a/src/components/Descriptions/src/Descriptions.vue +++ b/src/components/Descriptions/src/Descriptions.vue @@ -4,7 +4,7 @@ import { useDesign } from '@/hooks/web/useDesign' import { propTypes } from '@/utils/propTypes' import { ref, unref, PropType, computed, useAttrs, useSlots } from 'vue' import { useAppStore } from '@/store/modules/app' -import { DescriptionsSchema } from '@/types/descriptions' +import { DescriptionsSchema } from './types' const appStore = useAppStore() diff --git a/src/types/descriptions.d.ts b/src/components/Descriptions/src/types.ts similarity index 100% rename from src/types/descriptions.d.ts rename to src/components/Descriptions/src/types.ts diff --git a/src/components/Form/index.ts b/src/components/Form/index.ts index 484c7a2..82c59ef 100644 --- a/src/components/Form/index.ts +++ b/src/components/Form/index.ts @@ -1,6 +1,6 @@ import Form from './src/Form.vue' import { ElForm } from 'element-plus' -import { FormSchema, FormSetPropsType } from '@/types/form' +import { FormSchema, FormSetPropsType } from './src/types' export interface FormExpose { setValues: (data: Recordable) => void diff --git a/src/components/Form/src/Form copy.vue b/src/components/Form/src/Form copy.vue deleted file mode 100644 index 94fe848..0000000 --- a/src/components/Form/src/Form copy.vue +++ /dev/null @@ -1,302 +0,0 @@ - - - diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 0aeb8e2..15d9c8f 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -20,14 +20,14 @@ import { findIndex } from '@/utils' import { set } from 'lodash-es' import { FormProps } from './types' import { Icon } from '@/components/Icon' -import { FormSchema, FormSetPropsType } from '@/types/form' import { + FormSchema, + FormSetPropsType, ComponentNameEnum, SelectComponentProps, - SelectOption, - RadioComponentProps, - CheckboxComponentProps -} from '@/types/components.d' + RadioGroupComponentProps, + CheckboxGroupComponentProps +} from './types' const { renderSelectOptions } = useRenderSelect() const { renderRadioOptions } = useRenderRadio() @@ -230,36 +230,6 @@ export default defineComponent({ const { autoSetPlaceholder } = unref(getProps) - // 需要特殊处理的组件 - const specialComponents = [ComponentNameEnum.RADIO, ComponentNameEnum.CHECKBOX] - - if (specialComponents.findIndex((v) => v === item.component) !== -1) { - const componentProps = - item.component === ComponentNameEnum.RADIO - ? (item.componentProps as RadioComponentProps) - : (item.componentProps as CheckboxComponentProps) - - const valueAlias = componentProps?.props?.value || 'value' - const labelAlias = componentProps?.props?.label || 'label' - const disabledAlias = componentProps?.props?.disabled || 'disabled' - return componentProps?.options?.map((v) => { - return ( - - {() => - componentProps?.slots?.default - ? componentProps?.slots?.default({ option: v }) - : v[labelAlias] - } - - ) - }) - } - const componentSlots = (item?.componentProps as any)?.slots || {} const slotsMap: Recordable = { ...setItemComponentSlots(componentSlots) @@ -291,7 +261,21 @@ export default defineComponent({ ? () => renderRadioOptions(item) : () => { return componentSlots.default( - unref((item?.componentProps as RadioComponentProps)?.options) + unref((item?.componentProps as CheckboxGroupComponentProps)?.options) + ) + } + } + + // 多选框组和按钮样式 + if ( + item.component === ComponentNameEnum.CHECKBOX_GROUP || + item.component === ComponentNameEnum.CHECKBOX_BUTTON + ) { + slotsMap.default = !componentSlots.default + ? () => renderCheckboxOptions(item) + : () => { + return componentSlots.default( + unref((item?.componentProps as RadioGroupComponentProps)?.options) ) } } diff --git a/src/components/Form/src/componentMap.ts b/src/components/Form/src/componentMap.ts index 2c48f60..772019e 100644 --- a/src/components/Form/src/componentMap.ts +++ b/src/components/Form/src/componentMap.ts @@ -16,19 +16,15 @@ import { ElTimeSelect, ElTransfer, ElAutocomplete, - ElDivider, - ElRadio, - ElCheckbox + ElDivider } from 'element-plus' import { InputPassword } from '@/components/InputPassword' import { Editor } from '@/components/Editor' -import { ComponentName } from '@/types/components' +import { ComponentName } from './types' const componentMap: Recordable = { - Radio: ElRadio, RadioGroup: ElRadioGroup, RadioButton: ElRadioGroup, - Checkbox: ElCheckbox, CheckboxGroup: ElCheckboxGroup, CheckboxButton: ElCheckboxGroup, Input: ElInput, diff --git a/src/components/Form/src/components/useRenderCheckbox.tsx b/src/components/Form/src/components/useRenderCheckbox.tsx index 16adecf..adbc0a7 100644 --- a/src/components/Form/src/components/useRenderCheckbox.tsx +++ b/src/components/Form/src/components/useRenderCheckbox.tsx @@ -1,19 +1,25 @@ -import { FormSchema } from '@/types/form' +import { FormSchema, ComponentNameEnum, CheckboxGroupComponentProps } from '../types' import { ElCheckbox, ElCheckboxButton } from 'element-plus' import { defineComponent } from 'vue' export const useRenderCheckbox = () => { const renderCheckboxOptions = (item: FormSchema) => { // 如果有别名,就取别名 - const labelAlias = item?.componentProps?.optionsAlias?.labelField - const valueAlias = item?.componentProps?.optionsAlias?.valueField - const Com = (item.component === 'Checkbox' ? ElCheckbox : ElCheckboxButton) as ReturnType< - typeof defineComponent - > - return item?.componentProps?.options?.map((option) => { + const componentProps = item.componentProps as CheckboxGroupComponentProps + const valueAlias = componentProps?.props?.value || 'value' + const labelAlias = componentProps?.props?.label || 'label' + const disabledAlias = componentProps?.props?.disabled || 'disabled' + const Com = ( + item.component === ComponentNameEnum.CHECKBOX_GROUP ? ElCheckbox : ElCheckboxButton + ) as ReturnType + return componentProps?.options?.map((option) => { const { value, ...other } = option return ( - + {option[labelAlias || 'label']} ) diff --git a/src/components/Form/src/components/useRenderRadio.tsx b/src/components/Form/src/components/useRenderRadio.tsx index 0d2a098..67879f5 100644 --- a/src/components/Form/src/components/useRenderRadio.tsx +++ b/src/components/Form/src/components/useRenderRadio.tsx @@ -1,7 +1,6 @@ -import { FormSchema } from '@/types/form' +import { FormSchema, ComponentNameEnum, RadioGroupComponentProps } from '../types' import { ElRadio, ElRadioButton } from 'element-plus' import { defineComponent } from 'vue' -import { ComponentNameEnum, RadioGroupComponentProps } from '@/types/components.d' export const useRenderRadio = () => { const renderRadioOptions = (item: FormSchema) => { diff --git a/src/components/Form/src/components/useRenderSelect.tsx b/src/components/Form/src/components/useRenderSelect.tsx index 84e327a..63a0dc7 100644 --- a/src/components/Form/src/components/useRenderSelect.tsx +++ b/src/components/Form/src/components/useRenderSelect.tsx @@ -1,6 +1,5 @@ import { ElOption, ElOptionGroup } from 'element-plus' -import { FormSchema } from '@/types/form' -import { SelectComponentProps, SelectOption } from '@/types/components' +import { FormSchema, SelectComponentProps, SelectOption } from '../types' export const useRenderSelect = () => { // 渲染 select options diff --git a/src/components/Form/src/helper.ts b/src/components/Form/src/helper.ts index 85efd8e..4200da2 100644 --- a/src/components/Form/src/helper.ts +++ b/src/components/Form/src/helper.ts @@ -1,9 +1,7 @@ import { useI18n } from '@/hooks/web/useI18n' import { unref, type Slots } from 'vue' import { getSlot } from '@/utils/tsxHelper' -import { PlaceholderMoel } from './types' -import { FormSchema } from '@/types/form.d' -import { ColProps, ComponentNameEnum } from '@/types/components.d' +import { PlaceholderMoel, FormSchema, ComponentNameEnum, ColProps } from './types' import { isFunction } from '@/utils/is' import { firstUpperCase, humpToDash } from '@/utils' @@ -39,7 +37,8 @@ export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => { const twoTextMap = ['datetimerange', 'daterange', 'monthrange', 'datetimerange', 'daterange'] if ( twoTextMap.includes( - (schema?.componentProps?.type || schema?.componentProps?.isRange) as string + ((schema?.componentProps as any)?.type || + (schema?.componentProps as any)?.isRange) as string ) ) { return { diff --git a/src/components/Form/src/types.ts b/src/components/Form/src/types.ts index 92a49d8..4ed0c3d 100644 --- a/src/components/Form/src/types.ts +++ b/src/components/Form/src/types.ts @@ -1,4 +1,13 @@ import { FormSchema } from '@/types/form' +import { CSSProperties, VNodeProps, VNode } from 'vue' +import { + InputProps, + AutocompleteProps, + InputNumberProps, + CascaderProps, + CascaderNode, + CascaderValue +} from 'element-plus' export interface PlaceholderMoel { placeholder?: string @@ -15,3 +24,816 @@ export type FormProps = { isCustom?: boolean labelWidth?: string | number } & Recordable + +export enum ComponentNameEnum { + RADIO_GROUP = 'RadioGroup', + RADIO_BUTTON = 'RadioButton', + CHECKBOX_GROUP = 'CheckboxGroup', + CHECKBOX_BUTTON = 'CheckboxButton', + INPUT = 'Input', + AUTOCOMPLETE = 'Autocomplete', + INPUT_NUMBER = 'InputNumber', + SELECT = 'Select', + CASCADER = 'Cascader', + SWITCH = 'Switch', + SLIDER = 'Slider', + TIME_PICKER = 'TimePicker', + DATE_PICKER = 'DatePicker', + RATE = 'Rate', + COLOR_PICKER = 'ColorPicker', + TRANSFER = 'Transfer', + DIVIDER = 'Divider', + TIME_SELECT = 'TimeSelect', + SELECT_V2 = 'SelectV2', + INPUT_PASSWORD = 'InputPassword', + EDITOR = 'Editor' +} + +type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K + ? K extends string + ? K extends `${infer A}_${infer B}` + ? `${Capitalize>}${Capitalize>}` + : Capitalize> + : never + : never + +export type ComponentName = CamelCaseComponentName + +export interface InputComponentProps { + value?: string | number + maxlength?: number | string + minlength?: number | string + showWordLimit?: boolean + placeholder?: string + clearable?: boolean + formatter?: (value: string | number) => string + parser?: (value: string) => string + showPassword?: boolean + disabled?: boolean + size?: ElementPlusSize + prefixIcon?: string | JSX.Element + suffixIcon?: string | JSX.Element + type?: InputProps['type'] + rows?: number + autosize?: boolean | { Pows?: numer; maxRows?: number } + autocomplete?: string + name?: string + readonly?: boolean + max?: number | string + min?: number | string + step?: number | string + resize?: InputProps['resize'] + autofocus?: boolean + form?: string + label?: string + tabindex?: string | number + validateEvent?: boolean + inputStyle?: string | CSSProperties | CSSProperties[] | string[] + on?: { + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + change?: (value: string | number) => void + clear?: () => void + input?: (value: string | number) => void + } + slots?: { + prefix?: (...args: any[]) => JSX.Element | null + suffix?: (...args: any[]) => JSX.Element | null + prepend?: (...args: any[]) => JSX.Element | null + append?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface AutocompleteComponentProps { + value?: string + placeholder?: string + clearable?: boolean + disabled?: boolean + valueKey?: string + debounce?: number + placement?: AutocompleteProps['placement'] + fetchSuggestions?: (queryString: string, callback: (data: string[]) => void) => void + triggerOnFocus?: boolean + selectWhenUnmatched?: boolean + name?: string + label?: string + hideLoading?: boolean + popperClass?: string + popperAppendToBody?: boolean + teleported?: boolean + highlightFirstItem?: boolean + fitInputWidth?: boolean + on?: { + select?: (item: any) => void + change?: (value: string | number) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + prefix?: (...args: any[]) => JSX.Element | null + suffix?: (...args: any[]) => JSX.Element | null + prepend?: (...args: any[]) => JSX.Element | null + append?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface InputNumberComponentProps { + value?: number + min?: number + max?: number + step?: number + stepStrictly?: boolean + precision?: number + size?: ElementPlusSize + readonly?: boolean + disabled?: boolean + controls?: boolean + controlsPosition?: InputNumberProps['controlsPosition'] + name?: string + label?: string + placeholder?: string + id?: string + valueOnClear?: number | null | 'min' | 'max' + validateEvent?: boolean + on?: { + change?: (currentValue: number | undefined, oldValue: number | undefined) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + } + style?: CSSProperties +} + +export interface SelectOption { + label?: string + disabled?: boolean + value?: any + key?: string | number + options?: SelectOption[] + [key: string]: any +} + +export interface SelectComponentProps { + value?: string | number | boolean | Object + multiple?: boolean + disabled?: boolean + valueKey?: string + size?: ElementPlusSize + clearable?: boolean + collapseTags?: boolean + collapseTagsTooltip?: number + multipleLimit?: number + name?: string + effect?: string + autocomplete?: string + placeholder?: string + filterable?: boolean + allowCreate?: boolean + filterMethod?: (query: string, item: any) => boolean + remote?: boolean + remoteMethod?: (query: string) => void + remoteShowSuffix?: boolean + loading?: boolean + loadingText?: string + noMatchText?: string + noDataText?: string + popperClass?: string + reserveKeyword?: boolean + defaultFirstOption?: boolean + popperAppendToBody?: boolean + teleported?: boolean + persistent?: boolean + automaticDropdown?: boolean + clearIcon?: string | JSX.Element | null + fitInputWidth?: boolean + suffixIcon?: string | JSX.Element | null + tagType?: 'success' | 'info' | 'warning' | 'danger' + validateEvent?: boolean + placement?: + | 'top' + | 'top-start' + | 'top-end' + | 'bottom' + | 'bottom-start' + | 'bottom-end' + | 'left' + | 'left-start' + | 'left-end' + | 'right' + | 'right-start' + | 'right-end' + maxCollapseTags?: number + /** + * 数据源的字段别名 + */ + props?: { + key?: string + value?: string + label?: string + children?: string + } + on?: { + change?: (value: string | number | boolean | Object) => void + visibleChange?: (visible: boolean) => void + removeTag?: (tag: any) => void + clear?: () => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + } + slots?: { + default?: (options: SelectOption[]) => JSX.Element[] | null + optionGroupDefault?: (item: SelectOption) => JSX.Element + optionDefault?: (option: SelectOption) => JSX.Element | null + prefix?: (...args: any[]) => JSX.Element | null + empty?: (...args: any[]) => JSX.Element | null + } + options?: SelectOption[] + style?: CSSProperties +} + +export interface SelectV2ComponentProps { + value?: string | number | boolean | Object + multiple?: boolean + disabled?: boolean + valueKey?: string + size?: ElementPlusSize + clearable?: boolean + clearIcon?: string | JSX.Element | null + collapseTags?: boolean + multipleLimit?: number + name?: string + effect?: string + autocomplete?: string + placeholder?: string + filterable?: boolean + allowCreate?: boolean + reserveKeyword?: boolean + noDataText?: string + popperClass?: string + teleported?: boolean + persistent?: boolean + popperOptions?: any + automaticDropdown?: boolean + height?: number + scrollbarAlwaysOn?: boolean + remote?: boolean + remoteMethod?: (query: string) => void + validateEvent?: boolean + placement?: AutocompleteProps['placement'] + collapseTagsTooltip?: boolean + on?: { + change?: (value: string | number | boolean | Object) => void + visibleChange?: (visible: boolean) => void + removeTag?: (tag: any) => void + clear?: () => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + } + options?: SelectOption[] + slots?: { + default?: (option: SelectOption) => JSX.Element | null + } + style?: CSSProperties +} + +export interface CascaderComponentProps { + value?: string | number | string[] | number[] | any + options?: Record[] + props?: CascaderProps + size?: ElementPlusSize + placeholder?: string + disabled?: boolean + clearable?: boolean + showAllLevels?: boolean + collapseTags?: boolean + collapseTagsTooltip?: boolean + separator?: string + filterable?: boolean + filterMethod?: (node: CascaderNode, keyword: string) => boolean + debounce?: number + beforeFilter?: (value: string) => boolean + popperClass?: string + teleported?: boolean + tagType?: ElementPlusInfoType + validateEvent?: boolean + on?: { + change?: (value: CascaderValue) => void + expandChange?: (value: CascaderValue) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + visibleChange?: (value: boolean) => void + removeTag?: (value: CascaderNode['valueByOption']) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + empty?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface SwitchComponentProps { + value?: boolean | string | number + disabled?: boolean + loading?: boolean + size?: ElementPlusSize + width?: number | string + inlinePrompt?: boolean + activeIcon?: string | JSX.Element | null + inactiveIcon?: string | JSX.Element | null + activeText?: string + inactiveText?: string + activeValue?: boolean | string | number + inactiveValue?: boolean | string | number + name?: string + validateEvent?: boolean + beforeChange?: (value: boolean) => boolean | Promise + on?: { + change?: (value: boolean | string | number) => void + } + style?: CSSProperties +} + +export interface RateComponentProps { + value?: number + max?: number + size?: ElementPlusSize + disabled?: boolean + allowHalf?: boolean + lowThreshold?: number + highThreshold?: number + colors?: string[] | Record + voidColor?: string + disabledVoidColor?: string + icons?: string[] | JSX.Element[] | Record + voidIcon?: string | JSX.Element + disabledVoidIcon?: string | JSX.Element + showText?: boolean + showScore?: boolean + textColor?: string + texts?: string[] + scoreTemplate?: string + clearable?: boolean + id?: string + label?: string + on?: { + change?: (value: number) => void + } + style?: CSSProperties +} + +export interface ColorPickerComponentProps { + value?: string + disabled?: boolean + size?: ElementPlusSize + showAlpha?: boolean + colorFormat?: 'hsl' | 'hsv' | 'hex' | 'rgb' | 'hex' | 'rgb' + predefine?: string[] + validateEvent?: boolean + tabindex?: number | string + label?: string + id?: string + on?: { + change?: (value: string) => void + activeChange?: (value: string) => void + } + style?: CSSProperties +} + +export interface TransferComponentProps { + value?: any[] + data?: any[] + filterable?: boolean + filterPlaceholder?: string + filterMethod?: (query: string, item: any) => boolean + targetOrder?: string + titles?: string[] + buttonTexts?: string[] + renderContent?: ( + h: (type: string, props: VNodeProps | null, children?: string) => VNode, + option: any + ) => JSX.Element + format?: { + noChecked?: string + hasChecked?: string + } + props?: { + label?: string + key?: string + disabled?: string + } + leftDefaultChecked?: any[] + rightDefaultChecked?: any[] + validateEvent?: boolean + on?: { + change?: ( + value: number | string, + direction: 'left' | 'right', + movedKeys: string[] | number[] + ) => void + leftCheckChange?: (value: any[]) => void + rightCheckChange?: (value: any[]) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + leftFooter?: (...args: any[]) => JSX.Element | null + rightFooter?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface RadioOption { + label?: string + value?: string | number | boolean + disabled?: boolean + border?: boolean + size?: ElementPlusSize + name?: string + [key: string]: any +} +export interface RadioGroupComponentProps { + value?: string | number | boolean + size?: ElementPlusSize + disabled?: boolean + textColor?: string + fill?: string + validateEvent?: boolean + label?: string + name?: string + id?: string + options?: RadioOption[] + /** + * 数据源的字段别名 + */ + props: { + label?: string + value?: string + disabled?: string + } + on?: { + change?: (value: string | number | boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface RadioButtonComponentProps { + value?: string | number | boolean + size?: ElementPlusSize + disabled?: boolean + textColor?: string + fill?: string + validateEvent?: boolean + label?: string + name?: string + id?: string + options?: RadioOption[] + /** + * 数据源的字段别名 + */ + props: { + label?: string + value?: string + disabled?: string + } + on?: { + change?: (value: string | number | boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface CheckboxOption { + label?: string + value?: string | number | boolean + disabled?: boolean + trueLabel?: string | number + falseLabel?: string | number + border?: boolean + size?: ElementPlusSize + name?: string + checked?: boolean + indeterminate?: boolean + validateEvent?: boolean + tabindex?: number | string + id?: string + controls?: boolean + [key: string]: any +} + +export interface CheckboxGroupComponentProps { + value?: string[] | number[] + size?: ElementPlusSize + disabled?: boolean + min?: number + max?: number + label?: string + textColor?: string + fill?: string + tag?: string + validateEvent?: boolean + options?: CheckboxOption[] + /** + * 数据源的字段别名 + */ + props: { + label?: string + value?: string + disabled?: string + } + on?: { + change?: (value: string | number | boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface DividerComponentProps { + value?: number | Array + min?: number + max?: number + disabled?: boolean + step?: number + showInput?: boolean + showInputControls?: boolean + size?: ElementPlusSize + inputSize?: ElementPlusSize + showStops?: boolean + showTooltip?: boolean + formatTooltip?: (value: number) => string + range?: boolean + vertical?: boolean + height?: string + label?: string + rangeStartLabel?: string + rangeEndLabel?: string + formatValueText?: (value: number) => string + debounce?: number + tooltipClass?: string + placement?: string + marks?: Record + validateEvent?: boolean + on?: { + change?: (value: number) => void + input?: (value: number) => void + } + style?: CSSProperties +} + +export interface DatePickerComponentProps { + value?: string | Date | number | string[] + readonly?: boolean + disabled?: boolean + size?: ElementPlusSize + editable?: boolean + clearable?: boolean + placeholder?: string + startPlaceholder?: string + endPlaceholder?: string + type?: + | 'year' + | 'month' + | 'date' + | 'dates' + | 'week' + | 'datetime' + | 'datetimerange' + | 'daterange' + | 'monthrange' + format?: string + popperClass?: string + popperOptions?: Record + rangeSeparator?: string + defaultValue?: Date | [Date, Date] + defaultTime?: Date | [Date, Date] + valueFormat?: string + id?: string + name?: string + unlinkPanels?: boolean + prefixIcon?: string | JSX.Element + clearIcon?: string | JSX.Element + validateEvent?: boolean + disabledDate?: (date: Date) => boolean + shortcuts?: Array<{ text: string; value: Date | Function }> + cellClassName?: string | ((date: Date) => string | undefined) + teleported?: boolean + on?: { + change?: (value: string | Date | number | string[]) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + calendarChange?: (val: [Date, Date]) => void + panelChange?: (date, mode, view) => void + visibleChange?: (visibility: boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + rangeSeparator?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface DateTimePickerComponentProps { + value?: string | Date | number | string[] + readonly?: boolean + disabled?: boolean + editable?: boolean + clearable?: boolean + size?: ElementPlusSize + placeholder?: string + startPlaceholder?: string + endPlaceholder?: string + timeArrowControl?: boolean + type?: 'year' | 'month' | 'date' | 'datetime' | 'datetimerange' | 'daterange' | 'week' + format?: string + popperClass?: string + rangeSeparator?: string + defaultValue?: Date | [Date, Date] + defaultTime?: Date | [Date, Date] + valueFormat?: string + id?: string + name?: string + unlinkPanels?: boolean + prefixIcon?: string | JSX.Element + clearIcon?: string | JSX.Element + shortcuts?: Array<{ text: string; value: Date | Function }> + disabledDate?: (date: Date) => boolean + cellClassName?: string | ((date: Date) => string | undefined) + teleported?: boolean + on?: { + change?: (value: string | Date | number | string[]) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + calendarChange?: (val: [Date, Date]) => void + visibleChange?: (visibility: boolean) => void + } + slots?: { + default?: (...args: any[]) => JSX.Element | null + rangeSeparator?: (...args: any[]) => JSX.Element | null + } + style?: CSSProperties +} + +export interface TimePickerComponentProps { + value?: string | Date | number | [Date, Date] | [number, number] | [string, string] + readonly?: boolean + disabled?: boolean + editable?: boolean + clearable?: boolean + size?: ElementPlusSize + placeholder?: string + startPlaceholder?: string + endPlaceholder?: string + isRange?: boolean + arrowControl?: boolean + popperClass?: string + rangeSeparator?: string + format?: string + defaultValue?: Date | [Date, Date] + id?: string + name?: string + label?: string + prefixIcon?: string | JSX.Element + clearIcon?: string | JSX.Element + disabledHours?: (role: string, comparingDate?: any) => number[] + disabledMinutes?: (hour: number, role: string, comparingDate?: any) => number[] + disabledSeconds?: (hour: number, minute: number, role: string, comparingDate?: any) => number[] + teleported?: boolean + tabindex?: number | string + on?: { + change: ( + val: number | string | Date | [number, number] | [string, string] | [Date, Date] + ) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + visibleChange?: (visibility: boolean) => void + } + style?: CSSProperties +} + +export interface TimeSelectComponentProps { + value?: string + disabled?: boolean + editable?: boolean + clearable?: boolean + size?: ElementPlusSize + placeholder?: string + name?: string + effect?: string + prefixIcon?: string | JSX.Element + clearIcon?: string | JSX.Element + start?: string + end?: string + step?: string + minTime?: string + maxTime?: string + format?: string + on?: { + change?: (val: string) => void + blur?: (event: FocusEvent) => void + focus?: (event: FocusEvent) => void + } + style?: CSSProperties +} + +export interface ColProps { + span?: number + xs?: number + sm?: number + md?: number + lg?: number + xl?: number + tag?: string +} + +import type { AxiosPromise } from 'axios' + +export type FormSetPropsType = { + field: string + path: string + value: any +} + +export type FormValueType = string | number | string[] | number[] | boolean | undefined | null + +export type FormItemProps = { + labelWidth?: string | number + required?: boolean + rules?: Recordable + error?: string + showMessage?: boolean + inlineMessage?: boolean + style?: CSSProperties +} + +export interface FormSchema { + /** + * 唯一标识 + */ + field: string + + /** + * 标题 + */ + label?: string + + /** + * 提示信息 + */ + labelMessage?: string + + /** + * col组件属性 + */ + colProps?: ColProps + + /** + * 表单组件属性,具体可以查看element-plus文档 + */ + componentProps?: + | InputComponentProps + | AutocompleteComponentProps + | InputNumberComponentProps + | SelectComponentProps + | SelectV2ComponentProps + | CascaderComponentProps + | SwitchComponentProps + | RateComponentProps + | ColorPickerComponentProps + | TransferComponentProps + | RadioGroupComponentProps + | RadioButtonComponentProps + | DividerComponentProps + | DatePickerComponentProps + | DateTimePickerComponentProps + | TimePickerComponentProps + + /** + * formItem组件属性,具体可以查看element-plus文档 + */ + formItemProps?: FormItemProps + + /** + * 渲染的组件名称 + */ + component?: ComponentName + + /** + * 初始值 + */ + value?: FormValueType + + /** + * 是否隐藏 + */ + hidden?: boolean + + /** + * @returns 远程加载下拉项 + */ + api?: () => AxiosPromise +} diff --git a/src/hooks/web/useConfigGlobal.ts b/src/hooks/web/useConfigGlobal.ts index bde9d78..9357b10 100644 --- a/src/hooks/web/useConfigGlobal.ts +++ b/src/hooks/web/useConfigGlobal.ts @@ -1,4 +1,4 @@ -import { ConfigGlobalTypes } from '@/types/configGlobal' +import { ConfigGlobalTypes } from '@/components/ConfigGlobal/src/types' import { inject } from 'vue' export const useConfigGlobal = () => { diff --git a/src/types/components.d.ts b/src/types/components.d.ts deleted file mode 100644 index 1354f65..0000000 --- a/src/types/components.d.ts +++ /dev/null @@ -1,590 +0,0 @@ -import { CSSProperties, VNodeProps, VNode } from 'vue' -import { - InputProps, - AutocompleteProps, - InputNumberProps, - CascaderProps, - CascaderNode, - CascaderValue -} from 'element-plus' -import { ElementPlusSize, ElementPlusInfoType } from './elementPlus.d' - -export enum ComponentNameEnum { - RADIO = 'Radio', - RADIO_GROUP = 'RadioGroup', - RADIO_BUTTON = 'RadioButton', - CHECKBOX = 'Checkbox', - CHECKBOX_GROUP = 'CheckboxGroup', - CHECKBOX_BUTTON = 'CheckboxButton', - INPUT = 'Input', - AUTOCOMPLETE = 'Autocomplete', - INPUT_NUMBER = 'InputNumber', - SELECT = 'Select', - CASCADER = 'Cascader', - SWITCH = 'Switch', - SLIDER = 'Slider', - TIME_PICKER = 'TimePicker', - DATE_PICKER = 'DatePicker', - RATE = 'Rate', - COLOR_PICKER = 'ColorPicker', - TRANSFER = 'Transfer', - DIVIDER = 'Divider', - TIME_SELECT = 'TimeSelect', - SELECT_V2 = 'SelectV2', - INPUT_PASSWORD = 'InputPassword', - EDITOR = 'Editor' -} - -type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K - ? K extends string - ? K extends `${infer A}_${infer B}` - ? `${Capitalize>}${Capitalize>}` - : Capitalize> - : never - : never - -export type ComponentName = CamelCaseComponentName - -export interface InputComponentProps { - value?: string | number - maxlength?: number | string - minlength?: number | string - showWordLimit?: boolean - placeholder?: string - clearable?: boolean - formatter?: (value: string | number) => string - parser?: (value: string) => string - showPassword?: boolean - disabled?: boolean - size?: ElementPlusSize - prefixIcon?: string | JSX.Element - suffixIcon?: string | JSX.Element - type?: InputProps['type'] - rows?: number - autosize?: boolean | { Pows?: numer; maxRows?: number } - autocomplete?: string - name?: string - readonly?: boolean - max?: number | string - min?: number | string - step?: number | string - resize?: InputProps['resize'] - autofocus?: boolean - form?: string - label?: string - tabindex?: string | number - validateEvent?: boolean - inputStyle?: string | CSSProperties | CSSProperties[] | string[] - on?: { - blur?: (event: FocusEvent) => void - focus?: (event: FocusEvent) => void - change?: (value: string | number) => void - clear?: () => void - input?: (value: string | number) => void - } - slots?: { - prefix?: (...args: any[]) => JSX.Element | null - suffix?: (...args: any[]) => JSX.Element | null - prepend?: (...args: any[]) => JSX.Element | null - append?: (...args: any[]) => JSX.Element | null - } - style?: CSSProperties -} - -export interface AutocompleteComponentProps { - value?: string - placeholder?: string - clearable?: boolean - disabled?: boolean - valueKey?: string - debounce?: number - placement?: AutocompleteProps['placement'] - fetchSuggestions?: (queryString: string, callback: (data: string[]) => void) => void - triggerOnFocus?: boolean - selectWhenUnmatched?: boolean - name?: string - label?: string - hideLoading?: boolean - popperClass?: string - popperAppendToBody?: boolean - teleported?: boolean - highlightFirstItem?: boolean - fitInputWidth?: boolean - on?: { - select?: (item: any) => void - change?: (value: string | number) => void - } - slots?: { - default?: (...args: any[]) => JSX.Element | null - prefix?: (...args: any[]) => JSX.Element | null - suffix?: (...args: any[]) => JSX.Element | null - prepend?: (...args: any[]) => JSX.Element | null - append?: (...args: any[]) => JSX.Element | null - } - style?: CSSProperties -} - -export interface InputNumberComponentProps { - value?: number - min?: number - max?: number - step?: number - stepStrictly?: boolean - precision?: number - size?: ElementPlusSize - readonly?: boolean - disabled?: boolean - controls?: boolean - controlsPosition?: InputNumberProps['controlsPosition'] - name?: string - label?: string - placeholder?: string - id?: string - valueOnClear?: number | null | 'min' | 'max' - validateEvent?: boolean - on?: { - change?: (currentValue: number | undefined, oldValue: number | undefined) => void - blur?: (event: FocusEvent) => void - focus?: (event: FocusEvent) => void - } - style?: CSSProperties -} - -export interface SelectOption { - label?: string - disabled?: boolean - value?: any - key?: string | number - options?: SelectOption[] - [key: string]: any -} - -export interface SelectComponentProps { - value?: string | number | boolean | Object - multiple?: boolean - disabled?: boolean - valueKey?: string - size?: ElementPlusSize - clearable?: boolean - collapseTags?: boolean - collapseTagsTooltip?: number - multipleLimit?: number - name?: string - effect?: string - autocomplete?: string - placeholder?: string - filterable?: boolean - allowCreate?: boolean - filterMethod?: (query: string, item: any) => boolean - remote?: boolean - remoteMethod?: (query: string) => void - remoteShowSuffix?: boolean - loading?: boolean - loadingText?: string - noMatchText?: string - noDataText?: string - popperClass?: string - reserveKeyword?: boolean - defaultFirstOption?: boolean - popperAppendToBody?: boolean - teleported?: boolean - persistent?: boolean - automaticDropdown?: boolean - clearIcon?: string | JSX.Element | null - fitInputWidth?: boolean - suffixIcon?: string | JSX.Element | null - tagType?: 'success' | 'info' | 'warning' | 'danger' - validateEvent?: boolean - placement?: - | 'top' - | 'top-start' - | 'top-end' - | 'bottom' - | 'bottom-start' - | 'bottom-end' - | 'left' - | 'left-start' - | 'left-end' - | 'right' - | 'right-start' - | 'right-end' - maxCollapseTags?: number - /** - * 数据源的字段别名 - */ - props?: { - key?: string - value?: string - label?: string - children?: string - } - on?: { - change?: (value: string | number | boolean | Object) => void - visibleChange?: (visible: boolean) => void - removeTag?: (tag: any) => void - clear?: () => void - blur?: (event: FocusEvent) => void - focus?: (event: FocusEvent) => void - } - slots?: { - default?: (options: SelectOption[]) => JSX.Element[] | null - optionGroupDefault?: (item: SelectOption) => JSX.Element - optionDefault?: (option: SelectOption) => JSX.Element | null - prefix?: (...args: any[]) => JSX.Element | null - empty?: (...args: any[]) => JSX.Element | null - } - options?: SelectOption[] - style?: CSSProperties -} - -export interface SelectV2ComponentProps { - value?: string | number | boolean | Object - multiple?: boolean - disabled?: boolean - valueKey?: string - size?: ElementPlusSize - clearable?: boolean - clearIcon?: string | JSX.Element | null - collapseTags?: boolean - multipleLimit?: number - name?: string - effect?: string - autocomplete?: string - placeholder?: string - filterable?: boolean - allowCreate?: boolean - reserveKeyword?: boolean - noDataText?: string - popperClass?: string - teleported?: boolean - persistent?: boolean - popperOptions?: any - automaticDropdown?: boolean - height?: number - scrollbarAlwaysOn?: boolean - remote?: boolean - remoteMethod?: (query: string) => void - validateEvent?: boolean - placement?: AutocompleteProps['placement'] - collapseTagsTooltip?: boolean - on?: { - change?: (value: string | number | boolean | Object) => void - visibleChange?: (visible: boolean) => void - removeTag?: (tag: any) => void - clear?: () => void - blur?: (event: FocusEvent) => void - focus?: (event: FocusEvent) => void - } - options?: SelectOption[] - slots?: { - default?: (option: SelectOption) => JSX.Element | null - } - style?: CSSProperties -} - -export interface CascaderComponentProps { - value?: string | number | string[] | number[] | any - options?: Record[] - props?: CascaderProps - size?: ElementPlusSize - placeholder?: string - disabled?: boolean - clearable?: boolean - showAllLevels?: boolean - collapseTags?: boolean - collapseTagsTooltip?: boolean - separator?: string - filterable?: boolean - filterMethod?: (node: CascaderNode, keyword: string) => boolean - debounce?: number - beforeFilter?: (value: string) => boolean - popperClass?: string - teleported?: boolean - tagType?: ElementPlusInfoType - validateEvent?: boolean - on?: { - change?: (value: CascaderValue) => void - expandChange?: (value: CascaderValue) => void - blur?: (event: FocusEvent) => void - focus?: (event: FocusEvent) => void - visibleChange?: (value: boolean) => void - removeTag?: (value: CascaderNode['valueByOption']) => void - } - slots?: { - default?: (...args: any[]) => JSX.Element | null - empty?: (...args: any[]) => JSX.Element | null - } - style?: CSSProperties -} - -export interface SwitchComponentProps { - value?: boolean | string | number - disabled?: boolean - loading?: boolean - size?: ElementPlusSize - width?: number | string - inlinePrompt?: boolean - activeIcon?: string | JSX.Element | null - inactiveIcon?: string | JSX.Element | null - activeText?: string - inactiveText?: string - activeValue?: boolean | string | number - inactiveValue?: boolean | string | number - name?: string - validateEvent?: boolean - beforeChange?: (value: boolean) => boolean | Promise - on?: { - change?: (value: boolean | string | number) => void - } - style?: CSSProperties -} - -export interface RateComponentProps { - value?: number - max?: number - size?: ElementPlusSize - disabled?: boolean - allowHalf?: boolean - lowThreshold?: number - highThreshold?: number - colors?: string[] | Record - voidColor?: string - disabledVoidColor?: string - icons?: string[] | JSX.Element[] | Record - voidIcon?: string | JSX.Element - disabledVoidIcon?: string | JSX.Element - showText?: boolean - showScore?: boolean - textColor?: string - texts?: string[] - scoreTemplate?: string - clearable?: boolean - id?: string - label?: string - on?: { - change?: (value: number) => void - } - style?: CSSProperties -} - -export interface ColorPickerComponentProps { - value?: string - disabled?: boolean - size?: ElementPlusSize - showAlpha?: boolean - colorFormat?: 'hsl' | 'hsv' | 'hex' | 'rgb' | 'hex' | 'rgb' - predefine?: string[] - validateEvent?: boolean - tabindex?: number | string - label?: string - id?: string - on?: { - change?: (value: string) => void - activeChange?: (value: string) => void - } - style?: CSSProperties -} - -export interface TransferComponentProps { - value?: any[] - data?: any[] - filterable?: boolean - filterPlaceholder?: string - filterMethod?: (query: string, item: any) => boolean - targetOrder?: string - titles?: string[] - buttonTexts?: string[] - renderContent?: ( - h: (type: string, props: VNodeProps | null, children?: string) => VNode, - option: any - ) => JSX.Element - format?: { - noChecked?: string - hasChecked?: string - } - props?: { - label?: string - key?: string - disabled?: string - } - leftDefaultChecked?: any[] - rightDefaultChecked?: any[] - validateEvent?: boolean - on?: { - change?: ( - value: number | string, - direction: 'left' | 'right', - movedKeys: string[] | number[] - ) => void - leftCheckChange?: (value: any[]) => void - rightCheckChange?: (value: any[]) => void - } - slots?: { - default?: (...args: any[]) => JSX.Element | null - leftFooter?: (...args: any[]) => JSX.Element | null - rightFooter?: (...args: any[]) => JSX.Element | null - } - 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 - } - style?: CSSProperties -} - -export interface RadioGroupComponentProps { - value?: string | number | boolean - size?: ElementPlusSize - disabled?: boolean - textColor?: string - fill?: string - validateEvent?: boolean - label?: string - name?: string - id?: string - options?: RadioOption[] - /** - * 数据源的字段别名 - */ - props: { - label?: string - value?: string - disabled?: string - } - on?: { - change?: (value: string | number | boolean) => void - } - slots?: { - default?: (...args: any[]) => JSX.Element | null - } - style?: CSSProperties -} - -export interface RadioButtonComponentProps { - value?: string | number | boolean - size?: ElementPlusSize - disabled?: boolean - textColor?: string - fill?: string - validateEvent?: boolean - label?: string - name?: string - id?: string - options?: RadioOption[] - /** - * 数据源的字段别名 - */ - props: { - label?: string - value?: string - disabled?: string - } - on?: { - change?: (value: string | number | boolean) => void - } - slots?: { - default?: (...args: any[]) => JSX.Element | null - } - style?: CSSProperties -} - -export interface CheckboxOption { - label?: string - value?: string | number | boolean - disabled?: boolean - [key: string]: any -} - -export interface CheckboxComponentProps { - value?: string | number | boolean - label?: string | number | boolean | any - trueLabel?: string | number - falseLabel?: string | number - disabled?: boolean - border?: boolean - size?: ElementPlusSize - name?: string - checked?: boolean - indeterminate?: boolean - validateEvent?: boolean - tabindex?: number | string - id?: string - controls?: boolean - on?: { - change?: (value: string | number | boolean) => void - } - slots?: { - default?: (...args: any[]) => JSX.Element | null - } - options: CheckboxOption[] - /** - * 数据源的字段别名 - */ - props: { - label?: string - value?: string - disabled?: string - } - style?: CSSProperties -} - -export interface CheckboxGroupComponentProps { - value?: string[] | number[] -} - -export interface ColProps { - span?: number - xs?: number - sm?: number - md?: number - lg?: number - xl?: number - tag?: string -} - -export interface ComponentOptions extends Recordable { - label?: string - value?: any - disabled?: boolean - key?: string | number - children?: ComponentOptions[] - options?: ComponentOptions[] -} - -export interface ComponentOptionsAlias { - labelField?: string - valueField?: string -} - -export interface ComponentProps extends Recordable { - optionsAlias?: ComponentOptionsAlias - options?: ComponentOptions[] - optionsSlot?: boolean -} diff --git a/src/types/elementPlus.d.ts b/src/types/elementPlus.d.ts deleted file mode 100644 index 2c6b76e..0000000 --- a/src/types/elementPlus.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type ElementPlusSize = 'default' | 'small' | 'large' - -export type ElementPlusInfoType = 'success' | 'info' | 'warning' | 'danger' diff --git a/src/types/form.d.ts b/src/types/form.d.ts deleted file mode 100644 index 37ea21a..0000000 --- a/src/types/form.d.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { CSSProperties } from 'vue' -import { - ColProps, - ComponentProps, - ComponentName, - InputComponentProps, - AutocompleteComponentProps, - InputNumberComponentProps, - SelectComponentProps, - SelectV2ComponentProps, - CascaderComponentProps, - SwitchComponentProps, - RateComponentProps, - ColorPickerComponentProps, - TransferComponentProps, - RadioComponentProps, - RadioGroupComponentProps, - RadioButtonComponentProps, - CheckboxComponentProps -} from '@/types/components' -import { FormValueType, FormValueType } from '@/types/form' -import type { AxiosPromise } from 'axios' - -export type FormSetPropsType = { - field: string - path: string - value: any -} - -export type FormValueType = string | number | string[] | number[] | boolean | undefined | null - -export type FormItemProps = { - labelWidth?: string | number - required?: boolean - rules?: Recordable - error?: string - showMessage?: boolean - inlineMessage?: boolean - style?: CSSProperties -} - -export interface FormSchema { - /** - * 唯一标识 - */ - field: string - - /** - * 标题 - */ - label?: string - - /** - * 提示信息 - */ - labelMessage?: string - - /** - * col组件属性 - */ - colProps?: ColProps - - /** - * 表单组件属性,具体可以查看element-plus文档 - */ - componentProps?: - | InputComponentProps - | AutocompleteComponentProps - | InputNumberComponentProps - | SelectComponentProps - | SelectV2ComponentProps - | CascaderComponentProps - | SwitchComponentProps - | RateComponentProps - | ColorPickerComponentProps - | TransferComponentProps - | RadioComponentProps - | RadioGroupComponentProps - | RadioButtonComponentProps - | CheckboxComponentProps - - /** - * formItem组件属性,具体可以查看element-plus文档 - */ - formItemProps?: FormItemProps - - /** - * 渲染的组件名称 - */ - component?: ComponentName - - /** - * 初始值 - */ - value?: FormValueType - - /** - * 是否隐藏 - */ - hidden?: boolean - - /** - * @returns 远程加载下拉项 - */ - api?: () => AxiosPromise -} diff --git a/src/types/icon.d.ts b/src/types/icon.ts similarity index 100% rename from src/types/icon.d.ts rename to src/types/icon.ts diff --git a/src/types/infoTip.d.ts b/src/types/infoTip.ts similarity index 100% rename from src/types/infoTip.d.ts rename to src/types/infoTip.ts diff --git a/src/types/layout.d.ts b/src/types/layout.d.ts deleted file mode 100644 index c7ac4c2..0000000 --- a/src/types/layout.d.ts +++ /dev/null @@ -1 +0,0 @@ -export type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu' \ No newline at end of file diff --git a/src/types/localeDropdown.d.ts b/src/types/localeDropdown.ts similarity index 100% rename from src/types/localeDropdown.d.ts rename to src/types/localeDropdown.ts diff --git a/src/types/qrcode.d.ts b/src/types/qrcode.ts similarity index 100% rename from src/types/qrcode.d.ts rename to src/types/qrcode.ts diff --git a/src/types/table.d.ts b/src/types/table.ts similarity index 100% rename from src/types/table.d.ts rename to src/types/table.ts diff --git a/src/types/theme.d.ts b/src/types/theme.d.ts deleted file mode 100644 index 879b895..0000000 --- a/src/types/theme.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -export type ThemeTypes = { - elColorPrimary?: string - leftMenuBorderColor?: string - leftMenuBgColor?: string - leftMenuBgLightColor?: string - leftMenuBgActiveColor?: string - leftMenuCollapseBgActiveColor?: string - leftMenuTextColor?: string - leftMenuTextActiveColor?: string - logoTitleTextColor?: string - logoBorderColor?: string - topHeaderBgColor?: string - topHeaderTextColor?: string - topHeaderHoverColor?: string - topToolBorderColor?: string - } \ No newline at end of file diff --git a/src/types/theme.ts b/src/types/theme.ts new file mode 100644 index 0000000..ad649b0 --- /dev/null +++ b/src/types/theme.ts @@ -0,0 +1,16 @@ +export type ThemeTypes = { + elColorPrimary?: string + leftMenuBorderColor?: string + leftMenuBgColor?: string + leftMenuBgLightColor?: string + leftMenuBgActiveColor?: string + leftMenuCollapseBgActiveColor?: string + leftMenuTextColor?: string + leftMenuTextActiveColor?: string + logoTitleTextColor?: string + logoBorderColor?: string + topHeaderBgColor?: string + topHeaderTextColor?: string + topHeaderHoverColor?: string + topToolBorderColor?: string +} diff --git a/src/views/Components/Form/DefaultForm copy.vue b/src/views/Components/Form/DefaultForm copy.vue deleted file mode 100644 index ea93e52..0000000 --- a/src/views/Components/Form/DefaultForm copy.vue +++ /dev/null @@ -1,1136 +0,0 @@ - - - - - diff --git a/src/views/Components/Form/DefaultForm.vue b/src/views/Components/Form/DefaultForm.vue index fdaabe8..fc576ef 100644 --- a/src/views/Components/Form/DefaultForm.vue +++ b/src/views/Components/Form/DefaultForm.vue @@ -5,15 +5,17 @@ import { useI18n } from '@/hooks/web/useI18n' import { useIcon } from '@/hooks/web/useIcon' import { ContentWrap } from '@/components/ContentWrap' import { useAppStore } from '@/store/modules/app' -import { FormSchema } from '@/types/form' -import { - ComponentOptions, - SelectOption, - SelectComponentProps, - RadioOption -} from '@/types/components' +import { SelectOption, RadioOption, CheckboxOption, FormSchema } from '@/components/Form/src/types' import { useForm } from '@/hooks/web/useForm' -import { ElOption, ElOptionGroup, ElButton, ElRadio, ElRadioButton } from 'element-plus' +import { + ElOption, + ElOptionGroup, + ElButton, + ElRadio, + ElRadioButton, + ElCheckbox, + ElCheckboxButton +} from 'element-plus' const appStore = useAppStore() @@ -937,52 +939,6 @@ const schema = reactive([ 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: 'field39-1', - label: t('formDemo.slot'), - component: 'Radio', - componentProps: { - options: [ - { - // disabled: true, - label: 'option-1', - value: '1' - }, - { - label: 'option-2', - value: '2' - } - ], - slots: { - default: ({ option }) => { - return ( - <> - {option.label} - ({option.value}) - - ) - } - } - } - }, { field: 'field39-2', label: t('formDemo.radioGroup'), @@ -1081,13 +1037,13 @@ const schema = reactive([ component: 'Divider' }, { - field: 'field42', - label: t('formDemo.default'), - component: 'Checkbox', + field: 'field42-2', + label: t('formDemo.checkboxGroup'), + component: 'CheckboxGroup', + value: [], componentProps: { options: [ { - disabled: true, label: 'option-1', value: '1' }, @@ -1103,9 +1059,10 @@ const schema = reactive([ } }, { - field: 'field42-1', - label: t('formDemo.slot'), - component: 'Checkbox', + field: 'field42-3', + label: `${t('formDemo.checkboxGroup')} ${t('formDemo.slot')}`, + component: 'CheckboxGroup', + value: [], componentProps: { options: [ { @@ -1122,252 +1079,271 @@ const schema = reactive([ } ], slots: { - default: ({ option }) => { + default: (options: CheckboxOption[]) => { + return options?.map((v) => { + return ( + + {v.label}({v.value}) + + ) + }) + } + } + } + }, + { + field: 'field43', + label: t('formDemo.button'), + component: 'CheckboxButton', + value: [], + componentProps: { + options: [ + { + disabled: true, + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + }, + { + label: 'option-3', + value: '23' + } + ] + } + }, + { + field: 'field43-1', + label: `${t('formDemo.button')} ${t('formDemo.slot')}`, + component: 'CheckboxButton', + value: [], + componentProps: { + options: [ + { + disabled: true, + label: 'option-1', + value: '1' + }, + { + label: 'option-2', + value: '2' + }, + { + label: 'option-3', + value: '23' + } + ], + slots: { + default: (options: CheckboxOption[]) => { + return options?.map((v) => { + return ( + + {v.label}({v.value}) + + ) + }) + } + } + } + }, + { + field: 'field44', + component: 'Divider', + label: t('formDemo.slider') + }, + { + field: 'field45', + component: 'Slider', + label: t('formDemo.default'), + value: 0 + }, + { + field: 'field46', + component: 'Divider', + label: t('formDemo.datePicker') + }, + { + field: 'field47', + component: 'DatePicker', + label: t('formDemo.default'), + componentProps: { + type: 'date' + } + }, + { + field: 'field48', + component: 'DatePicker', + label: t('formDemo.shortcuts'), + componentProps: { + type: 'date', + disabledDate: (time: Date) => { + return time.getTime() > Date.now() + }, + shortcuts: [ + { + text: t('formDemo.today'), + value: new Date() + }, + { + text: t('formDemo.yesterday'), + value: () => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24) + return date + } + }, + { + text: t('formDemo.aWeekAgo'), + value: () => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) + return date + } + } + ] + } + }, + { + field: 'field47-1', + component: 'DatePicker', + label: t('formDemo.slot'), + value: '2021-10-29', + componentProps: { + type: 'date', + slots: { + default: (cell: any) => { return ( - <> - {option.label} - ({option.value}) - +
+ {cell.text} + {isHoliday(cell) ? : null} +
) } } } + }, + { + field: 'field49', + component: 'DatePicker', + label: t('formDemo.week'), + componentProps: { + type: 'week', + format: `[${t('formDemo.week')}]` + } + }, + { + field: 'field50', + component: 'DatePicker', + label: t('formDemo.year'), + componentProps: { + type: 'year' + } + }, + { + field: 'field51', + component: 'DatePicker', + label: t('formDemo.month'), + componentProps: { + type: 'month' + } + }, + { + field: 'field52', + component: 'DatePicker', + label: t('formDemo.dates'), + componentProps: { + type: 'dates' + } + }, + { + field: 'field53', + component: 'DatePicker', + label: t('formDemo.daterange'), + componentProps: { + type: 'daterange' + } + }, + { + field: 'field54', + component: 'DatePicker', + label: t('formDemo.monthrange'), + componentProps: { + type: 'monthrange' + } + }, + { + field: 'field56', + component: 'Divider', + label: t('formDemo.dateTimePicker') + }, + { + field: 'field57', + component: 'DatePicker', + label: t('formDemo.default'), + componentProps: { + type: 'datetime' + } + }, + { + field: 'field58', + component: 'DatePicker', + label: t('formDemo.shortcuts'), + componentProps: { + type: 'datetime', + shortcuts: [ + { + text: t('formDemo.today'), + value: new Date() + }, + { + text: t('formDemo.yesterday'), + value: () => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24) + return date + } + }, + { + text: t('formDemo.aWeekAgo'), + value: () => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) + return date + } + } + ] + } + }, + { + field: 'field59', + component: 'DatePicker', + label: t('formDemo.dateTimerange'), + componentProps: { + type: 'datetimerange' + } + }, + { + field: 'field60', + component: 'Divider', + label: t('formDemo.timePicker') + }, + { + field: 'field61', + component: 'TimePicker', + label: t('formDemo.default') + }, + { + field: 'field62', + component: 'Divider', + label: t('formDemo.timeSelect') + }, + { + field: 'field63', + component: 'TimeSelect', + label: t('formDemo.default') } - // { - // field: 'field42-2', - // label: t('formDemo.checkboxGroup'), - // component: 'CheckboxGroup', - // value: [], - // componentProps: { - // options: [ - // { - // label: 'option-1', - // value: '1' - // }, - // { - // label: 'option-2', - // value: '2' - // }, - // { - // label: 'option-3', - // value: '3' - // } - // ] - // } - // } - // { - // field: 'field43', - // label: t('formDemo.button'), - // component: 'CheckboxButton', - // value: [], - // componentProps: { - // options: [ - // { - // disabled: true, - // label: 'option-1', - // value: '1' - // }, - // { - // label: 'option-2', - // value: '2' - // }, - // { - // label: 'option-3', - // value: '23' - // } - // ] - // } - // }, - // { - // field: 'field44', - // component: 'Divider', - // label: t('formDemo.slider') - // }, - // { - // field: 'field45', - // component: 'Slider', - // label: t('formDemo.default'), - // value: 0 - // }, - // { - // field: 'field46', - // component: 'Divider', - // label: t('formDemo.datePicker') - // }, - // { - // field: 'field47', - // component: 'DatePicker', - // label: t('formDemo.default'), - // componentProps: { - // type: 'date' - // } - // }, - // { - // field: 'field48', - // component: 'DatePicker', - // label: t('formDemo.shortcuts'), - // componentProps: { - // type: 'date', - // disabledDate: (time: Date) => { - // return time.getTime() > Date.now() - // }, - // shortcuts: [ - // { - // text: t('formDemo.today'), - // value: new Date() - // }, - // { - // text: t('formDemo.yesterday'), - // value: () => { - // const date = new Date() - // date.setTime(date.getTime() - 3600 * 1000 * 24) - // return date - // } - // }, - // { - // text: t('formDemo.aWeekAgo'), - // value: () => { - // const date = new Date() - // date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) - // return date - // } - // } - // ] - // } - // }, - // { - // field: 'field49', - // component: 'DatePicker', - // label: t('formDemo.week'), - // componentProps: { - // type: 'week', - // format: `[${t('formDemo.week')}] ww` - // } - // }, - // { - // field: 'field50', - // component: 'DatePicker', - // label: t('formDemo.year'), - // componentProps: { - // type: 'year' - // } - // }, - // { - // field: 'field51', - // component: 'DatePicker', - // label: t('formDemo.month'), - // componentProps: { - // type: 'month' - // } - // }, - // { - // field: 'field52', - // component: 'DatePicker', - // label: t('formDemo.dates'), - // componentProps: { - // type: 'dates' - // } - // }, - // { - // field: 'field53', - // component: 'DatePicker', - // label: t('formDemo.daterange'), - // componentProps: { - // type: 'daterange' - // } - // }, - // { - // field: 'field54', - // component: 'DatePicker', - // label: t('formDemo.monthrange'), - // componentProps: { - // type: 'monthrange' - // } - // }, - // { - // field: 'field55', - // component: 'DatePicker', - // label: t('formDemo.slot'), - // componentProps: { - // type: 'date', - // format: 'YYYY/MM/DD', - // valueFormat: 'YYYY-MM-DD', - // slots: { - // default: true - // } - // } - // }, - // { - // field: 'field56', - // component: 'Divider', - // label: t('formDemo.dateTimePicker') - // }, - // { - // field: 'field57', - // component: 'DatePicker', - // label: t('formDemo.default'), - // componentProps: { - // type: 'datetime' - // } - // }, - // { - // field: 'field58', - // component: 'DatePicker', - // label: t('formDemo.shortcuts'), - // componentProps: { - // type: 'datetime', - // shortcuts: [ - // { - // text: t('formDemo.today'), - // value: new Date() - // }, - // { - // text: t('formDemo.yesterday'), - // value: () => { - // const date = new Date() - // date.setTime(date.getTime() - 3600 * 1000 * 24) - // return date - // } - // }, - // { - // text: t('formDemo.aWeekAgo'), - // value: () => { - // const date = new Date() - // date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) - // return date - // } - // } - // ] - // } - // }, - // { - // field: 'field59', - // component: 'DatePicker', - // label: t('formDemo.dateTimerange'), - // componentProps: { - // type: 'datetimerange' - // } - // }, - // { - // field: 'field60', - // component: 'Divider', - // label: t('formDemo.timePicker') - // }, - // { - // field: 'field61', - // component: 'TimePicker', - // label: t('formDemo.default') - // }, - // { - // field: 'field62', - // component: 'Divider', - // label: t('formDemo.timeSelect') - // }, - // { - // field: 'field63', - // component: 'TimeSelect', - // label: t('formDemo.default') - // } ]) const { register, formRef, methods } = useForm({ @@ -1445,102 +1421,43 @@ const changeToggle = () => { --> -
- -
+
- From 3e4e27c21fd59c944229856bee929f005d2ee140 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Wed, 21 Jun 2023 11:28:03 +0800 Subject: [PATCH 19/78] =?UTF-8?q?feat:=20Form=20useForm=20=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Editor/src/Editor.vue | 2 +- src/components/Form/index.ts | 2 + src/components/Form/src/Form.vue | 55 ++++++++++++++++++--- src/components/Form/src/types/index.ts | 1 + src/hooks/web/useForm.ts | 18 ++++++- src/locales/en.ts | 4 +- src/locales/zh-CN.ts | 4 +- src/views/Components/Form/DefaultForm.vue | 54 ++++++++++++++++++++- src/views/Components/Form/UseFormDemo.vue | 59 +++++++++++++++++------ 9 files changed, 173 insertions(+), 26 deletions(-) diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue index 0d6872b..3c40436 100644 --- a/src/components/Editor/src/Editor.vue +++ b/src/components/Editor/src/Editor.vue @@ -115,7 +115,7 @@ defineExpose({ diff --git a/src/views/Components/Search.vue b/src/views/Components/Search.vue index 2c3db31..bc3e860 100644 --- a/src/views/Components/Search.vue +++ b/src/views/Components/Search.vue @@ -11,7 +11,7 @@ import { useSearch } from '@/hooks/web/useSearch' const { t } = useI18n() const { searchRegister, searchMethods } = useSearch() -const { setSchema, setProps } = searchMethods +const { setSchema, setProps, setValues } = searchMethods const schema = reactive([ { @@ -166,6 +166,48 @@ const getDictOne = async () => { const handleSearch = (data: any) => { console.log(data) } + +const delRadio = () => { + setSchema([ + { + field: 'field3', + path: 'remove', + value: true + } + ]) +} + +const restoreRadio = () => { + setSchema([ + { + field: 'field3', + path: 'remove', + value: false + } + ]) +} + +const setValue = () => { + setValues({ + field1: 'Joy' + }) +} + +const searchLoading = ref(false) +const changeSearchLoading = () => { + searchLoading.value = true + setTimeout(() => { + searchLoading.value = false + }, 2000) +} + +const resetLoading = ref(false) +const changeResetLoading = () => { + resetLoading.value = true + setTimeout(() => { + resetLoading.value = false + }, 2000) +} + + From 4f8330a4faf6cc98a9bac17bd3e1719ae1b30c81 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 25 Jun 2023 14:20:51 +0800 Subject: [PATCH 25/78] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=94=81?= =?UTF-8?q?=E5=B1=8F=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/{types.ts => types/index.ts} | 0 .../src/{types.ts => types/index.ts} | 0 .../src/{types.ts => types/index.ts} | 0 .../src/{types.ts => types/index.ts} | 0 .../UserInfo/src/components/LockDialog.vue | 17 ++++++++--------- .../UserInfo/src/components/LockPage.vue | 2 +- .../src/components => hooks/web}/useNow.ts | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) rename src/components/ConfigGlobal/src/{types.ts => types/index.ts} (100%) rename src/components/ContextMenu/src/{types.ts => types/index.ts} (100%) rename src/components/Descriptions/src/{types.ts => types/index.ts} (100%) rename src/components/ImageViewer/src/{types.ts => types/index.ts} (100%) rename src/{components/UserInfo/src/components => hooks/web}/useNow.ts (95%) diff --git a/src/components/ConfigGlobal/src/types.ts b/src/components/ConfigGlobal/src/types/index.ts similarity index 100% rename from src/components/ConfigGlobal/src/types.ts rename to src/components/ConfigGlobal/src/types/index.ts diff --git a/src/components/ContextMenu/src/types.ts b/src/components/ContextMenu/src/types/index.ts similarity index 100% rename from src/components/ContextMenu/src/types.ts rename to src/components/ContextMenu/src/types/index.ts diff --git a/src/components/Descriptions/src/types.ts b/src/components/Descriptions/src/types/index.ts similarity index 100% rename from src/components/Descriptions/src/types.ts rename to src/components/Descriptions/src/types/index.ts diff --git a/src/components/ImageViewer/src/types.ts b/src/components/ImageViewer/src/types/index.ts similarity index 100% rename from src/components/ImageViewer/src/types.ts rename to src/components/ImageViewer/src/types/index.ts diff --git a/src/components/UserInfo/src/components/LockDialog.vue b/src/components/UserInfo/src/components/LockDialog.vue index e7355a7..f8bc0b4 100644 --- a/src/components/UserInfo/src/components/LockDialog.vue +++ b/src/components/UserInfo/src/components/LockDialog.vue @@ -1,12 +1,12 @@ + const toggleClick = () => { + if (props.collapse) { + show.value = !unref(show) + } + } - + +
+ + {{ + extra: () => (slots['extra'] ? slots['extra']() : props.extra), + default: () => { + return props.schema.map((item) => { + return ( + + {{ + label: () => (item.slots?.label ? item.slots?.label(item) : item.label), + default: () => + item.slots?.default + ? item.slots?.default(item) + : props.data[item.field] + }} + + ) + }) + } + }} + +
+
+ + ) + } + } +}) + diff --git a/src/components/Setting/src/Setting.vue b/src/components/Setting/src/Setting.vue index 49828ce..20f0eb9 100644 --- a/src/components/Setting/src/Setting.vue +++ b/src/components/Setting/src/Setting.vue @@ -47,7 +47,6 @@ const setHeaderTheme = (color: string) => { setCssVar('--top-header-bg-color', color) setCssVar('--top-header-text-color', textColor) setCssVar('--top-header-hover-color', textHoverColor) - setCssVar('--layout-border-color', topToolBorderColor) appStore.setTheme({ topHeaderBgColor: color, topHeaderTextColor: textColor, diff --git a/src/components/TagsView/src/TagsView.vue b/src/components/TagsView/src/TagsView.vue index ffcab3e..b8383a6 100644 --- a/src/components/TagsView/src/TagsView.vue +++ b/src/components/TagsView/src/TagsView.vue @@ -482,7 +482,7 @@ watch( left: 0; width: 100%; height: calc(~'100% - 1px'); - border-left: 1px solid var(--layout-border-color); + border-left: 1px solid var(--el-border-color); content: ''; } @@ -496,7 +496,7 @@ watch( left: 0; width: 100%; height: calc(~'100% - 1px'); - border-right: 1px solid var(--layout-border-color); + border-right: 1px solid var(--el-border-color); content: ''; } } diff --git a/src/router/index.ts b/src/router/index.ts index ad611d7..57e380e 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -313,94 +313,94 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ // } ] }, - // { - // path: '/hooks', - // component: Layout, - // redirect: '/hooks/useWatermark', - // name: 'Hooks', - // meta: { - // title: 'hooks', - // icon: 'ic:outline-webhook', - // alwaysShow: true - // }, - // children: [ - // { - // path: 'useWatermark', - // component: () => import('@/views/hooks/useWatermark.vue'), - // name: 'UseWatermark', - // meta: { - // title: 'useWatermark' - // } - // }, - // { - // path: 'useCrudSchemas', - // component: () => import('@/views/hooks/useCrudSchemas.vue'), - // name: 'UseCrudSchemas', - // meta: { - // title: 'useCrudSchemas' - // } - // } - // ] - // }, - // { - // path: '/level', - // component: Layout, - // redirect: '/level/menu1/menu1-1/menu1-1-1', - // name: 'Level', - // meta: { - // title: t('router.level'), - // icon: 'carbon:skill-level-advanced' - // }, - // children: [ - // { - // path: 'menu1', - // name: 'Menu1', - // component: getParentLayout(), - // redirect: '/level/menu1/menu1-1/menu1-1-1', - // meta: { - // title: t('router.menu1') - // }, - // children: [ - // { - // path: 'menu1-1', - // name: 'Menu11', - // component: getParentLayout(), - // redirect: '/level/menu1/menu1-1/menu1-1-1', - // meta: { - // title: t('router.menu11'), - // alwaysShow: true - // }, - // children: [ - // { - // path: 'menu1-1-1', - // name: 'Menu111', - // component: () => import('@/views/Level/Menu111.vue'), - // meta: { - // title: t('router.menu111') - // } - // } - // ] - // }, - // { - // path: 'menu1-2', - // name: 'Menu12', - // component: () => import('@/views/Level/Menu12.vue'), - // meta: { - // title: t('router.menu12') - // } - // } - // ] - // }, - // { - // path: 'menu2', - // name: 'Menu2', - // component: () => import('@/views/Level/Menu2.vue'), - // meta: { - // title: t('router.menu2') - // } - // } - // ] - // }, + { + path: '/hooks', + component: Layout, + redirect: '/hooks/useWatermark', + name: 'Hooks', + meta: { + title: 'hooks', + icon: 'ic:outline-webhook', + alwaysShow: true + }, + children: [ + { + path: 'useWatermark', + component: () => import('@/views/hooks/useWatermark.vue'), + name: 'UseWatermark', + meta: { + title: 'useWatermark' + } + }, + { + path: 'useCrudSchemas', + component: () => import('@/views/hooks/useCrudSchemas.vue'), + name: 'UseCrudSchemas', + meta: { + title: 'useCrudSchemas' + } + } + ] + }, + { + path: '/level', + component: Layout, + redirect: '/level/menu1/menu1-1/menu1-1-1', + name: 'Level', + meta: { + title: t('router.level'), + icon: 'carbon:skill-level-advanced' + }, + children: [ + { + path: 'menu1', + name: 'Menu1', + component: getParentLayout(), + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: t('router.menu1') + }, + children: [ + { + path: 'menu1-1', + name: 'Menu11', + component: getParentLayout(), + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: t('router.menu11'), + alwaysShow: true + }, + children: [ + { + path: 'menu1-1-1', + name: 'Menu111', + component: () => import('@/views/Level/Menu111.vue'), + meta: { + title: t('router.menu111') + } + } + ] + }, + { + path: 'menu1-2', + name: 'Menu12', + component: () => import('@/views/Level/Menu12.vue'), + meta: { + title: t('router.menu12') + } + } + ] + }, + { + path: 'menu2', + name: 'Menu2', + component: () => import('@/views/Level/Menu2.vue'), + meta: { + title: t('router.menu2') + } + } + ] + }, // { // path: '/example', // component: Layout, diff --git a/src/styles/var.css b/src/styles/var.css index 61895d2..5b1778f 100644 --- a/src/styles/var.css +++ b/src/styles/var.css @@ -36,8 +36,6 @@ --top-tool-p-x: 0; - --layout-border-color: #eee; - --tags-view-height: 35px; --tags-view-border-color: #eee; @@ -61,7 +59,5 @@ } .dark { - --layout-border-color: var(--el-border-color); - --app-content-bg-color: var(--el-bg-color); } diff --git a/uno.config.ts b/uno.config.ts index d6cf78c..0645fe6 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -39,7 +39,7 @@ ${selector}:before { left: 0; width: 1px; height: 100%; - background-color: var(--layout-border-color); + background-color: var(--el-border-color); z-index: 3; } ` @@ -57,7 +57,7 @@ ${selector}:after { right: 0; width: 1px; height: 100%; - background-color: var(--layout-border-color); + background-color: var(--el-border-color); z-index: 3; } ` @@ -75,7 +75,7 @@ ${selector}:before { left: 0; width: 100%; height: 1px; - background-color: var(--layout-border-color); + background-color: var(--el-border-color); z-index: 3; } ` @@ -93,7 +93,7 @@ ${selector}:after { left: 0; width: 100%; height: 1px; - background-color: var(--layout-border-color); + background-color: var(--el-border-color); z-index: 3; } ` From 7ef1d1e3013cc5bf7fc574e67c2004f50792e66d Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 25 Jun 2023 18:03:26 +0800 Subject: [PATCH 29/78] =?UTF-8?q?style:=20=E7=A7=BB=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E5=BF=85=E8=A6=81=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Dialog/src/Dialog.vue | 30 +++++++++++----------------- src/components/Editor/src/Editor.vue | 4 ++-- src/styles/var.css | 2 -- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/components/Dialog/src/Dialog.vue b/src/components/Dialog/src/Dialog.vue index db1315f..14bfe8c 100644 --- a/src/components/Dialog/src/Dialog.vue +++ b/src/components/Dialog/src/Dialog.vue @@ -10,7 +10,7 @@ const props = defineProps({ modelValue: propTypes.bool.def(false), title: propTypes.string.def('Dialog'), fullscreen: propTypes.bool.def(true), - maxHeight: propTypes.oneOfType([String, Number]).def('500px') + maxHeight: propTypes.oneOfType([String, Number]).def('300px') }) const getBindValue = computed(() => { @@ -92,13 +92,17 @@ const dialogStyle = computed(() => { diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue index 3c40436..b354db0 100644 --- a/src/components/Editor/src/Editor.vue +++ b/src/components/Editor/src/Editor.vue @@ -115,12 +115,12 @@ defineExpose({