feat: SelectV2改造完成
This commit is contained in:
parent
cdc7c76eb5
commit
4d04734e13
|
@ -21,7 +21,7 @@ import { set } from 'lodash-es'
|
||||||
import { FormProps } from './types'
|
import { FormProps } from './types'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { FormSchema, FormSetPropsType } from '@/types/form'
|
import { FormSchema, FormSetPropsType } from '@/types/form'
|
||||||
import { ComponentNameEnum, SelectComponentProps } from '@/types/components.d'
|
import { ComponentNameEnum, SelectComponentProps, SelectOption } from '@/types/components.d'
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
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 (
|
// if (
|
||||||
// item?.component !== 'SelectV2' &&
|
// item?.component !== 'SelectV2' &&
|
||||||
// item?.component !== 'Cascader' &&
|
// item?.component !== 'Cascader' &&
|
||||||
|
@ -252,7 +259,7 @@ export default defineComponent({
|
||||||
const renderOptions = (item: FormSchema) => {
|
const renderOptions = (item: FormSchema) => {
|
||||||
switch (item.component) {
|
switch (item.component) {
|
||||||
case ComponentNameEnum.SELECT:
|
case ComponentNameEnum.SELECT:
|
||||||
const { renderSelectOptions } = useRenderSelect(slots)
|
const { renderSelectOptions } = useRenderSelect()
|
||||||
return renderSelectOptions(item)
|
return renderSelectOptions(item)
|
||||||
case 'Radio':
|
case 'Radio':
|
||||||
case 'RadioButton':
|
case 'RadioButton':
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
import { ElOption, ElOptionGroup } from 'element-plus'
|
import { ElOption, ElOptionGroup } from 'element-plus'
|
||||||
import { getSlot } from '@/utils/tsxHelper'
|
|
||||||
import { Slots } from 'vue'
|
|
||||||
import { FormSchema } from '@/types/form'
|
import { FormSchema } from '@/types/form'
|
||||||
import { SelectComponentProps, SelectOption } from '@/types/components'
|
import { SelectComponentProps, SelectOption } from '@/types/components'
|
||||||
|
|
||||||
export const useRenderSelect = (slots: Slots) => {
|
export const useRenderSelect = () => {
|
||||||
// 渲染 select options
|
// 渲染 select options
|
||||||
const renderSelectOptions = (item: FormSchema) => {
|
const renderSelectOptions = (item: FormSchema) => {
|
||||||
const componentsProps = item.componentProps as SelectComponentProps
|
const componentsProps = item.componentProps as SelectComponentProps
|
||||||
const optionGroupDefaultSlot = componentsProps.slots?.optionGroupDefault
|
const optionGroupDefaultSlot = componentsProps.slots?.optionGroupDefault
|
||||||
// 如果有别名,就取别名
|
// 如果有别名,就取别名
|
||||||
const labelAlias = componentsProps?.labelAlias
|
const labelAlias = componentsProps?.labelAlias
|
||||||
|
const keyAlias = componentsProps?.keyAlias
|
||||||
return componentsProps?.options?.map((option) => {
|
return componentsProps?.options?.map((option) => {
|
||||||
if (option?.options?.length) {
|
if (option?.options?.length) {
|
||||||
return optionGroupDefaultSlot ? (
|
return optionGroupDefaultSlot ? (
|
||||||
optionGroupDefaultSlot(option)
|
optionGroupDefaultSlot(option)
|
||||||
) : (
|
) : (
|
||||||
<ElOptionGroup label={option[labelAlias || 'label']}>
|
<ElOptionGroup label={option[labelAlias || 'label']} key={option[keyAlias || 'key']}>
|
||||||
{{
|
{{
|
||||||
default: () =>
|
default: () =>
|
||||||
option?.options?.map((v) => {
|
option?.options?.map((v) => {
|
||||||
|
@ -37,15 +36,15 @@ export const useRenderSelect = (slots: Slots) => {
|
||||||
const componentsProps = item.componentProps as SelectComponentProps
|
const componentsProps = item.componentProps as SelectComponentProps
|
||||||
const labelAlias = componentsProps?.labelAlias
|
const labelAlias = componentsProps?.labelAlias
|
||||||
const valueAlias = componentsProps?.valueAlias
|
const valueAlias = componentsProps?.valueAlias
|
||||||
|
const keyAlias = componentsProps?.keyAlias
|
||||||
const optionDefaultSlot = componentsProps.slots?.optionDefault
|
const optionDefaultSlot = componentsProps.slots?.optionDefault
|
||||||
|
|
||||||
const { label, value, ...other } = option
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ElOption
|
<ElOption
|
||||||
{...other}
|
{...option}
|
||||||
label={labelAlias ? option[labelAlias] : label}
|
key={option[keyAlias || 'key']}
|
||||||
value={valueAlias ? option[valueAlias] : value}
|
label={option[labelAlias || 'label']}
|
||||||
|
value={option[valueAlias || 'value']}
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
default: () => (optionDefaultSlot ? optionDefaultSlot(option) : undefined)
|
default: () => (optionDefaultSlot ? optionDefaultSlot(option) : undefined)
|
||||||
|
|
|
@ -2,9 +2,10 @@ import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { unref, type Slots } from 'vue'
|
import { unref, type Slots } from 'vue'
|
||||||
import { getSlot } from '@/utils/tsxHelper'
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
import { PlaceholderMoel } from './types'
|
import { PlaceholderMoel } from './types'
|
||||||
import { FormSchema } from '@/types/form'
|
import { FormSchema } from '@/types/form.d'
|
||||||
import { ColProps } from '@/types/components'
|
import { ColProps, ComponentNameEnum } from '@/types/components.d'
|
||||||
import { isFunction } from '@/utils/is'
|
import { isFunction } from '@/utils/is'
|
||||||
|
import { firstUpperCase } from '@/utils'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
@ -15,14 +16,25 @@ const { t } = useI18n()
|
||||||
* @description 用于自动设置placeholder
|
* @description 用于自动设置placeholder
|
||||||
*/
|
*/
|
||||||
export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => {
|
export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => {
|
||||||
const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword']
|
const textMap = [
|
||||||
const selectMap = ['Select', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect']
|
ComponentNameEnum.INPUT,
|
||||||
if (textMap.includes(schema?.component as string)) {
|
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 {
|
return {
|
||||||
placeholder: t('common.inputText')
|
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']
|
const twoTextMap = ['datetimerange', 'daterange', 'monthrange', 'datetimerange', 'daterange']
|
||||||
if (
|
if (
|
||||||
|
@ -74,14 +86,30 @@ export const setGridProp = (col: ColProps = {}): ColProps => {
|
||||||
*/
|
*/
|
||||||
export const setComponentProps = (item: FormSchema): Recordable => {
|
export const setComponentProps = (item: FormSchema): Recordable => {
|
||||||
// const notNeedClearable = ['ColorPicker']
|
// 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 = {
|
const componentProps: Recordable = {
|
||||||
clearable: true,
|
clearable: true,
|
||||||
...item.componentProps
|
...item.componentProps,
|
||||||
|
...newOnEvents
|
||||||
}
|
}
|
||||||
// 需要删除额外的属性
|
// 需要删除额外的属性
|
||||||
if (componentProps.slots) {
|
if (componentProps.slots) {
|
||||||
delete componentProps.slots
|
delete componentProps.slots
|
||||||
}
|
}
|
||||||
|
if (componentProps.on) {
|
||||||
|
delete componentProps.on
|
||||||
|
}
|
||||||
return componentProps
|
return componentProps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +123,8 @@ export const setItemComponentSlots = (formModel: any, slotsProps: Recordable = {
|
||||||
for (const key in slotsProps) {
|
for (const key in slotsProps) {
|
||||||
if (slotsProps[key]) {
|
if (slotsProps[key]) {
|
||||||
if (isFunction(slotsProps[key])) {
|
if (isFunction(slotsProps[key])) {
|
||||||
slotObj[key] = () => {
|
slotObj[key] = (...args: any[]) => {
|
||||||
return slotsProps[key]?.(formModel)
|
return slotsProps[key]?.(formModel, ...args)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
slotObj[key] = () => {
|
slotObj[key] = () => {
|
||||||
|
@ -124,7 +152,7 @@ export const initModel = (schema: FormSchema[], formModel: Recordable) => {
|
||||||
} else if (v.component && v.component !== 'Divider') {
|
} else if (v.component && v.component !== 'Divider') {
|
||||||
const hasField = Reflect.has(model, v.field)
|
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
|
return model
|
||||||
|
|
|
@ -105,7 +105,7 @@ export interface AutocompleteComponentProps {
|
||||||
change?: (value: string | number) => void
|
change?: (value: string | number) => void
|
||||||
}
|
}
|
||||||
slots?: {
|
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)
|
prefix?: JSX.Element | null | ((formData: any) => JSX.Element | null)
|
||||||
suffix?: 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)
|
prepend?: JSX.Element | null | ((formData: any) => JSX.Element | null)
|
||||||
|
@ -150,7 +150,7 @@ interface SelectOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectComponentProps {
|
export interface SelectComponentProps {
|
||||||
value?: Array | string | number | boolean | Object
|
value?: string | number | boolean | Object
|
||||||
multiple?: boolean
|
multiple?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
valueKey?: string
|
valueKey?: string
|
||||||
|
@ -230,6 +230,52 @@ export interface SelectComponentProps {
|
||||||
}
|
}
|
||||||
options?: SelectOption[]
|
options?: SelectOption[]
|
||||||
style?: CSSProperties
|
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 {
|
export interface ColProps {
|
||||||
|
|
|
@ -6,7 +6,8 @@ import {
|
||||||
InputComponentProps,
|
InputComponentProps,
|
||||||
AutocompleteComponentProps,
|
AutocompleteComponentProps,
|
||||||
InputNumberComponentProps,
|
InputNumberComponentProps,
|
||||||
SelectComponentProps
|
SelectComponentProps,
|
||||||
|
SelectV2ComponentProps
|
||||||
} from '@/types/components'
|
} from '@/types/components'
|
||||||
import { FormValueType, FormValueType } from '@/types/form'
|
import { FormValueType, FormValueType } from '@/types/form'
|
||||||
import type { AxiosPromise } from 'axios'
|
import type { AxiosPromise } from 'axios'
|
||||||
|
@ -58,6 +59,7 @@ export interface FormSchema {
|
||||||
| AutocompleteComponentProps
|
| AutocompleteComponentProps
|
||||||
| InputNumberComponentProps
|
| InputNumberComponentProps
|
||||||
| SelectComponentProps
|
| SelectComponentProps
|
||||||
|
| SelectV2ComponentProps
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* formItem组件属性,具体可以查看element-plus文档
|
* formItem组件属性,具体可以查看element-plus文档
|
||||||
|
|
|
@ -108,3 +108,10 @@ export function toAnyString() {
|
||||||
})
|
})
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首字母大写
|
||||||
|
*/
|
||||||
|
export function firstUpperCase(str: string) {
|
||||||
|
return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
|
||||||
|
}
|
||||||
|
|
|
@ -459,11 +459,11 @@ const schema = reactive<FormSchema[]>([
|
||||||
select: handleSelect
|
select: handleSelect
|
||||||
},
|
},
|
||||||
slots: {
|
slots: {
|
||||||
default: (item: any) => {
|
default: (_, { item }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class="value">{item.value}</div>
|
<div class="value">{item?.value}</div>
|
||||||
<span class="link">{item.link}</span>
|
<span class="link">{item?.link}</span>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -689,56 +689,75 @@ const schema = reactive<FormSchema[]>([
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<span style="margin-right: 8px">{option?.label}</span>
|
||||||
|
<span style="color: var(--el-text-color-secondary); font-size: 13px">
|
||||||
|
{option?.value}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<span style="margin-right: 8px">{option?.label}</span>
|
||||||
|
<span style="color: var(--el-text-color-secondary); font-size: 13px">
|
||||||
|
{option?.value}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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',
|
// field: 'field24',
|
||||||
// label: t('formDemo.default'),
|
// label: t('formDemo.default'),
|
||||||
// component: 'Cascader',
|
// component: 'Cascader',
|
||||||
|
|
Loading…
Reference in New Issue