feat: 搭建后台管理框架
This commit is contained in:
1 parent
6d28bab72b
commit
40546bfd01
238 files changed
+18160
-3837
No files matched your search
@@ -0,0 +1,48 @@
|
||||
import Form from './src/Form.vue'
|
||||
import type { FormSchema, FormSetProps } from './src/types'
|
||||
export type {
|
||||
ComponentNameEnum,
|
||||
ComponentName,
|
||||
InputComponentProps,
|
||||
AutocompleteComponentProps,
|
||||
InputNumberComponentProps,
|
||||
SelectOption,
|
||||
SelectComponentProps,
|
||||
SelectV2ComponentProps,
|
||||
CascaderComponentProps,
|
||||
SwitchComponentProps,
|
||||
RateComponentProps,
|
||||
ColorPickerComponentProps,
|
||||
TransferComponentProps,
|
||||
RadioOption,
|
||||
RadioGroupComponentProps,
|
||||
RadioButtonComponentProps,
|
||||
CheckboxOption,
|
||||
CheckboxGroupComponentProps,
|
||||
DividerComponentProps,
|
||||
DatePickerComponentProps,
|
||||
DateTimePickerComponentProps,
|
||||
TimePickerComponentProps,
|
||||
TimeSelectComponentProps,
|
||||
ColProps,
|
||||
FormSetProps,
|
||||
FormItemProps,
|
||||
FormSchema,
|
||||
FormProps,
|
||||
PlaceholderModel,
|
||||
InputPasswordComponentProps,
|
||||
TreeSelectComponentProps
|
||||
} from './src/types'
|
||||
|
||||
export interface FormExpose {
|
||||
setValues: (data: Recordable) => void
|
||||
setProps: (props: Recordable) => void
|
||||
delSchema: (field: string) => void
|
||||
addSchema: (formSchema: FormSchema, index?: number) => void
|
||||
setSchema: (schemaProps: FormSetProps[]) => void
|
||||
formModel: Recordable
|
||||
getComponentExpose: (field: string) => any
|
||||
getFormItemExpose: (field: string) => any
|
||||
}
|
||||
|
||||
export { Form }
|
||||
@@ -0,0 +1,420 @@
|
||||
<script lang="tsx">
|
||||
import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue'
|
||||
import {
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElRow,
|
||||
ElCol,
|
||||
FormRules,
|
||||
ComponentSize
|
||||
// FormItemProp
|
||||
} from 'element-plus'
|
||||
import { componentMap } from './helper/componentMap'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
import {
|
||||
setTextPlaceholder,
|
||||
setGridProp,
|
||||
setComponentProps,
|
||||
setItemComponentSlots,
|
||||
initModel
|
||||
} from './helper'
|
||||
import { useRenderSelect } from './components/useRenderSelect'
|
||||
import { useRenderRadio } from './components/useRenderRadio'
|
||||
import { useRenderCheckbox } from './components/useRenderCheckbox'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { findIndex } from '@/utils'
|
||||
import { get, set } from 'lodash-es'
|
||||
import { FormProps } from './types'
|
||||
import {
|
||||
FormSchema,
|
||||
FormSetProps,
|
||||
ComponentNameEnum,
|
||||
SelectComponentProps,
|
||||
RadioGroupComponentProps,
|
||||
CheckboxGroupComponentProps
|
||||
} from './types'
|
||||
|
||||
const { renderSelectOptions } = useRenderSelect()
|
||||
const { renderRadioOptions } = useRenderRadio()
|
||||
const { renderCheckboxOptions } = useRenderCheckbox()
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const prefixCls = getPrefixCls('form')
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Form',
|
||||
props: {
|
||||
// 生成Form的布局结构数组
|
||||
schema: {
|
||||
type: Array as PropType<FormSchema[]>,
|
||||
default: () => []
|
||||
},
|
||||
// 是否需要栅格布局
|
||||
isCol: propTypes.bool.def(true),
|
||||
// 表单数据对象
|
||||
model: {
|
||||
type: Object as PropType<any>,
|
||||
default: () => ({})
|
||||
},
|
||||
// 是否自动设置placeholder
|
||||
autoSetPlaceholder: propTypes.bool.def(true),
|
||||
// 是否自定义内容
|
||||
isCustom: propTypes.bool.def(false),
|
||||
// 表单label宽度
|
||||
labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
|
||||
rules: {
|
||||
type: Object as PropType<FormRules>,
|
||||
default: () => ({})
|
||||
},
|
||||
labelPosition: propTypes.oneOf(['left', 'right', 'top']).def('right'),
|
||||
labelSuffix: propTypes.string.def(''),
|
||||
hideRequiredAsterisk: propTypes.bool.def(false),
|
||||
requireAsteriskPosition: propTypes.oneOf(['left', 'right']).def('left'),
|
||||
showMessage: propTypes.bool.def(true),
|
||||
inlineMessage: propTypes.bool.def(false),
|
||||
statusIcon: propTypes.bool.def(false),
|
||||
validateOnRuleChange: propTypes.bool.def(true),
|
||||
size: {
|
||||
type: String as PropType<ComponentSize>,
|
||||
default: undefined
|
||||
},
|
||||
disabled: propTypes.bool.def(false),
|
||||
scrollToError: propTypes.bool.def(false),
|
||||
scrollToErrorOffset: propTypes.oneOfType([Boolean, Object]).def(undefined)
|
||||
// onValidate: {
|
||||
// type: Function as PropType<(prop: FormItemProp, isValid: boolean, message: string) => void>,
|
||||
// default: () => {}
|
||||
// }
|
||||
},
|
||||
emits: ['register'],
|
||||
setup(props, { slots, expose, emit }) {
|
||||
// element form 实例
|
||||
const elFormRef = ref<ComponentRef<typeof ElForm>>()
|
||||
|
||||
const mergeProps = ref<FormProps>({})
|
||||
|
||||
const getProps = computed(() => {
|
||||
const propsObj = { ...props }
|
||||
Object.assign(propsObj, unref(mergeProps))
|
||||
return propsObj
|
||||
})
|
||||
|
||||
// 存储表单实例
|
||||
const formComponents = ref({})
|
||||
|
||||
// 存储form-item实例
|
||||
const formItemComponents = ref({})
|
||||
|
||||
// 表单数据
|
||||
const formModel = ref<Recordable>(props.model)
|
||||
|
||||
onMounted(() => {
|
||||
emit('register', unref(elFormRef)?.$parent, unref(elFormRef))
|
||||
})
|
||||
|
||||
// 对表单赋值
|
||||
const setValues = (data: Recordable = {}) => {
|
||||
formModel.value = Object.assign(unref(formModel), data)
|
||||
}
|
||||
|
||||
const setProps = (props: FormProps = {}) => {
|
||||
mergeProps.value = Object.assign(unref(mergeProps), props)
|
||||
}
|
||||
|
||||
const delSchema = (field: string) => {
|
||||
const { schema } = unref(getProps)
|
||||
|
||||
const index = findIndex(schema, (v: FormSchema) => v.field === field)
|
||||
if (index > -1) {
|
||||
schema.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const addSchema = (formSchema: FormSchema, index?: number) => {
|
||||
const { schema } = unref(getProps)
|
||||
if (index !== void 0) {
|
||||
schema.splice(index, 0, formSchema)
|
||||
return
|
||||
}
|
||||
schema.push(formSchema)
|
||||
}
|
||||
|
||||
const setSchema = (schemaProps: FormSetProps[]) => {
|
||||
const { schema } = unref(getProps)
|
||||
for (const v of schema) {
|
||||
for (const item of schemaProps) {
|
||||
if (v.field === item.field) {
|
||||
set(v, item.path, item.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getOptions = async (fn: Function, item: FormSchema) => {
|
||||
const options = await fn()
|
||||
setSchema([
|
||||
{
|
||||
field: item.field,
|
||||
path:
|
||||
item.component === ComponentNameEnum.TREE_SELECT
|
||||
? 'componentProps.data'
|
||||
: 'componentProps.options',
|
||||
value: options
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取表单组件实例
|
||||
* @param filed 表单字段
|
||||
*/
|
||||
const getComponentExpose = (filed: string) => {
|
||||
return unref(formComponents)[filed]
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取formItem实例
|
||||
* @param filed 表单字段
|
||||
*/
|
||||
const getFormItemExpose = (filed: string) => {
|
||||
return unref(formItemComponents)[filed]
|
||||
}
|
||||
|
||||
const setComponentRefMap = (ref: any, filed: string) => {
|
||||
formComponents.value[filed] = ref
|
||||
}
|
||||
|
||||
const setFormItemRefMap = (ref: any, filed: string) => {
|
||||
formItemComponents.value[filed] = ref
|
||||
}
|
||||
|
||||
expose({
|
||||
setValues,
|
||||
formModel,
|
||||
setProps,
|
||||
delSchema,
|
||||
addSchema,
|
||||
setSchema,
|
||||
getComponentExpose,
|
||||
getFormItemExpose
|
||||
})
|
||||
|
||||
// 监听表单结构化数组,重新生成formModel
|
||||
watch(
|
||||
() => unref(getProps).schema,
|
||||
(schema = []) => {
|
||||
formModel.value = initModel(schema, unref(formModel))
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
// 渲染包裹标签,是否使用栅格布局
|
||||
const renderWrap = () => {
|
||||
const { isCol } = unref(getProps)
|
||||
const content = isCol ? (
|
||||
<ElRow gutter={20}>{renderFormItemWrap()}</ElRow>
|
||||
) : (
|
||||
renderFormItemWrap()
|
||||
)
|
||||
return content
|
||||
}
|
||||
|
||||
// 是否要渲染el-col
|
||||
const renderFormItemWrap = () => {
|
||||
// hidden属性表示隐藏,不做渲染
|
||||
const { schema = [], isCol } = unref(getProps)
|
||||
|
||||
return schema
|
||||
.filter((v) => !v.remove && !v.hidden)
|
||||
.map((item) => {
|
||||
// 如果是 Divider 组件,需要自己占用一行
|
||||
const isDivider = item.component === 'Divider'
|
||||
const Com = componentMap['Divider'] as ReturnType<typeof defineComponent>
|
||||
return isDivider ? (
|
||||
<Com {...{ contentPosition: 'left', ...item.componentProps }}>{item?.label}</Com>
|
||||
) : isCol ? (
|
||||
// 如果需要栅格,需要包裹 ElCol
|
||||
<ElCol {...setGridProp(item.colProps)}>{renderFormItem(item)}</ElCol>
|
||||
) : (
|
||||
renderFormItem(item)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染formItem
|
||||
const renderFormItem = (item: FormSchema) => {
|
||||
// 如果有optionApi,优先使用optionApi
|
||||
if (item.optionApi) {
|
||||
// 内部自动调用接口,不影响其它渲染
|
||||
getOptions(item.optionApi, item)
|
||||
}
|
||||
const formItemSlots: Recordable = {
|
||||
default: () => {
|
||||
if (item?.formItemProps?.slots?.default) {
|
||||
return item?.formItemProps?.slots?.default(formModel.value)
|
||||
} else {
|
||||
const Com = componentMap[item.component as string] as ReturnType<typeof defineComponent>
|
||||
|
||||
const { autoSetPlaceholder } = unref(getProps)
|
||||
|
||||
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 ||
|
||||
item.component === ComponentNameEnum.RADIO_BUTTON
|
||||
) {
|
||||
slotsMap.default = !componentSlots.default
|
||||
? () => renderRadioOptions(item)
|
||||
: () => {
|
||||
return componentSlots.default(
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const Comp = () => {
|
||||
// 如果field是多层路径,需要转换成对象
|
||||
const itemVal = computed({
|
||||
get: () => {
|
||||
return get(formModel.value, item.field)
|
||||
},
|
||||
set: (val) => {
|
||||
set(formModel.value, item.field, val)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Com
|
||||
vModel={itemVal.value}
|
||||
ref={(el: any) => setComponentRefMap(el, item.field)}
|
||||
{...(autoSetPlaceholder && setTextPlaceholder(item))}
|
||||
{...setComponentProps(item)}
|
||||
style={
|
||||
item.componentProps?.style || {
|
||||
width: '100%'
|
||||
}
|
||||
}
|
||||
>
|
||||
{{ ...slotsMap }}
|
||||
</Com>
|
||||
)
|
||||
}
|
||||
|
||||
return <>{Comp()}</>
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item?.formItemProps?.slots?.label) {
|
||||
formItemSlots.label = (...args: any[]) => {
|
||||
return (item?.formItemProps?.slots as any)?.label(...args)
|
||||
}
|
||||
}
|
||||
if (item?.formItemProps?.slots?.error) {
|
||||
formItemSlots.error = (...args: any[]) => {
|
||||
return (item?.formItemProps?.slots as any)?.error(...args)
|
||||
}
|
||||
}
|
||||
return (
|
||||
<ElFormItem
|
||||
v-show={!item.hidden}
|
||||
ref={(el: any) => setFormItemRefMap(el, item.field)}
|
||||
{...(item.formItemProps || {})}
|
||||
prop={item.field}
|
||||
label={item.label || ''}
|
||||
>
|
||||
{formItemSlots}
|
||||
</ElFormItem>
|
||||
)
|
||||
}
|
||||
|
||||
// 过滤传入Form组件的属性
|
||||
const getFormBindValue = () => {
|
||||
// 避免在标签上出现多余的属性
|
||||
const delKeys = ['schema', 'isCol', 'autoSetPlaceholder', 'isCustom', 'model']
|
||||
const props = { ...unref(getProps) }
|
||||
for (const key in props) {
|
||||
if (delKeys.indexOf(key) !== -1) {
|
||||
delete props[key]
|
||||
}
|
||||
}
|
||||
return props as FormProps
|
||||
}
|
||||
|
||||
return () => (
|
||||
<ElForm
|
||||
ref={elFormRef}
|
||||
{...getFormBindValue()}
|
||||
model={unref(getProps).isCustom ? unref(getProps).model : formModel}
|
||||
class={prefixCls}
|
||||
>
|
||||
{{
|
||||
// 如果需要自定义,就什么都不渲染,而是提供默认插槽
|
||||
default: () => {
|
||||
const { isCustom } = unref(getProps)
|
||||
return isCustom ? getSlot(slots, 'default') : renderWrap()
|
||||
}
|
||||
}}
|
||||
</ElForm>
|
||||
)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.@{elNamespace}-form.@{namespace}-form .@{elNamespace}-row {
|
||||
margin-right: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.@{elNamespace}-form--inline {
|
||||
:deep(.el-form-item__content) {
|
||||
& > :first-child {
|
||||
min-width: 229.5px;
|
||||
}
|
||||
}
|
||||
.@{elNamespace}-input-number {
|
||||
// 229.5px是兼容el-input-number的最小宽度,
|
||||
min-width: 229.5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
import { FormSchema, ComponentNameEnum, CheckboxGroupComponentProps } from '../types'
|
||||
import { ElCheckbox, ElCheckboxButton } from 'element-plus'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export const useRenderCheckbox = () => {
|
||||
const renderCheckboxOptions = (item: FormSchema) => {
|
||||
// 如果有别名,就取别名
|
||||
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<typeof defineComponent>
|
||||
return componentProps?.options?.map((option) => {
|
||||
const { value, ...other } = option
|
||||
return (
|
||||
<Com
|
||||
{...other}
|
||||
disabled={option[disabledAlias || 'disabled']}
|
||||
label={option[valueAlias || 'value']}
|
||||
>
|
||||
{option[labelAlias || 'label']}
|
||||
</Com>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
renderCheckboxOptions
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { FormSchema, ComponentNameEnum, RadioGroupComponentProps } from '../types'
|
||||
import { ElRadio, ElRadioButton } from 'element-plus'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export const useRenderRadio = () => {
|
||||
const renderRadioOptions = (item: FormSchema) => {
|
||||
// 如果有别名,就取别名
|
||||
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<typeof defineComponent>
|
||||
return componentProps?.options?.map((option) => {
|
||||
const { value, ...other } = option
|
||||
return (
|
||||
<Com
|
||||
{...other}
|
||||
disabled={option[disabledAlias || 'disabled']}
|
||||
label={option[valueAlias || 'value']}
|
||||
>
|
||||
{option[labelAlias || 'label']}
|
||||
</Com>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
renderRadioOptions
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { ElOption, ElOptionGroup } from 'element-plus'
|
||||
import { FormSchema, SelectComponentProps, SelectOption } from '../types'
|
||||
|
||||
export const useRenderSelect = () => {
|
||||
// 渲染 select options
|
||||
const renderSelectOptions = (item: FormSchema) => {
|
||||
const componentsProps = item?.componentProps as SelectComponentProps
|
||||
const optionGroupDefaultSlot = componentsProps?.slots?.optionGroupDefault
|
||||
// 如果有别名,就取别名
|
||||
const labelAlias = componentsProps?.props?.label
|
||||
const keyAlias = componentsProps?.props?.key
|
||||
return componentsProps?.options?.map((option) => {
|
||||
if (option?.options?.length) {
|
||||
return optionGroupDefaultSlot ? (
|
||||
optionGroupDefaultSlot(option)
|
||||
) : (
|
||||
<ElOptionGroup label={option[labelAlias || 'label']} key={option[keyAlias || 'key']}>
|
||||
{{
|
||||
default: () =>
|
||||
option?.options?.map((v) => {
|
||||
return renderSelectOptionItem(item, v)
|
||||
})
|
||||
}}
|
||||
</ElOptionGroup>
|
||||
)
|
||||
} else {
|
||||
return renderSelectOptionItem(item, option)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染 select option item
|
||||
const renderSelectOptionItem = (item: FormSchema, option: SelectOption) => {
|
||||
// 如果有别名,就取别名
|
||||
const componentsProps = item.componentProps as SelectComponentProps
|
||||
const labelAlias = componentsProps?.props?.label
|
||||
const valueAlias = componentsProps?.props?.value
|
||||
const keyAlias = componentsProps?.props?.key
|
||||
const optionDefaultSlot = componentsProps.slots?.optionDefault
|
||||
|
||||
return (
|
||||
<ElOption
|
||||
{...option}
|
||||
key={option[keyAlias || 'key']}
|
||||
label={option[labelAlias || 'label']}
|
||||
value={option[valueAlias || 'value']}
|
||||
>
|
||||
{{
|
||||
default: () => (optionDefaultSlot ? optionDefaultSlot(option) : undefined)
|
||||
}}
|
||||
</ElOption>
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
renderSelectOptions
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { Component } from 'vue'
|
||||
import {
|
||||
ElCascader,
|
||||
ElCheckboxGroup,
|
||||
ElColorPicker,
|
||||
ElDatePicker,
|
||||
ElInput,
|
||||
ElInputNumber,
|
||||
ElRadioGroup,
|
||||
ElRate,
|
||||
ElSelect,
|
||||
ElSelectV2,
|
||||
ElSlider,
|
||||
ElSwitch,
|
||||
ElTimePicker,
|
||||
ElTimeSelect,
|
||||
ElTransfer,
|
||||
ElAutocomplete,
|
||||
ElDivider,
|
||||
ElTreeSelect,
|
||||
ElUpload
|
||||
} from 'element-plus'
|
||||
import { InputPassword } from '@/components/InputPassword'
|
||||
import { Editor } from '@/components/Editor'
|
||||
import { ComponentName } from '../types'
|
||||
|
||||
const componentMap: Recordable<Component, ComponentName> = {
|
||||
RadioGroup: ElRadioGroup,
|
||||
RadioButton: ElRadioGroup,
|
||||
CheckboxGroup: ElCheckboxGroup,
|
||||
CheckboxButton: ElCheckboxGroup,
|
||||
Input: ElInput,
|
||||
Autocomplete: ElAutocomplete,
|
||||
InputNumber: ElInputNumber,
|
||||
Select: ElSelect,
|
||||
Cascader: ElCascader,
|
||||
Switch: ElSwitch,
|
||||
Slider: ElSlider,
|
||||
TimePicker: ElTimePicker,
|
||||
DatePicker: ElDatePicker,
|
||||
Rate: ElRate,
|
||||
ColorPicker: ElColorPicker,
|
||||
Transfer: ElTransfer,
|
||||
Divider: ElDivider,
|
||||
TimeSelect: ElTimeSelect,
|
||||
SelectV2: ElSelectV2,
|
||||
InputPassword: InputPassword,
|
||||
Editor: Editor,
|
||||
TreeSelect: ElTreeSelect,
|
||||
Upload: ElUpload
|
||||
}
|
||||
|
||||
export { componentMap }
|
||||
@@ -0,0 +1,162 @@
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { PlaceholderModel, FormSchema, ComponentNameEnum, ColProps } from '../types'
|
||||
import { isFunction } from '@/utils/is'
|
||||
import { firstUpperCase, humpToDash } from '@/utils'
|
||||
import { set, get } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
/**
|
||||
*
|
||||
* @param schema 对应组件数据
|
||||
* @returns 返回提示信息对象
|
||||
* @description 用于自动设置placeholder
|
||||
*/
|
||||
export const setTextPlaceholder = (schema: FormSchema): PlaceholderModel => {
|
||||
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 ComponentNameEnum)) {
|
||||
// 一些范围选择器
|
||||
const twoTextMap = ['datetimerange', 'daterange', 'monthrange', 'datetimerange', 'daterange']
|
||||
if (
|
||||
twoTextMap.includes(
|
||||
((schema?.componentProps as any)?.type ||
|
||||
(schema?.componentProps as any)?.isRange) as string
|
||||
)
|
||||
) {
|
||||
return {
|
||||
startPlaceholder: t('common.startTimeText'),
|
||||
endPlaceholder: t('common.endTimeText'),
|
||||
rangeSeparator: '-'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
placeholder: t('common.selectText')
|
||||
}
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param col 内置栅格
|
||||
* @returns 返回栅格属性
|
||||
* @description 合并传入进来的栅格属性
|
||||
*/
|
||||
export const setGridProp = (col: ColProps = {}): ColProps => {
|
||||
const colProps: ColProps = {
|
||||
// 如果有span,代表用户优先级更高,所以不需要默认栅格
|
||||
...(col.span
|
||||
? {}
|
||||
: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 12
|
||||
}),
|
||||
...col
|
||||
}
|
||||
return colProps
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param item 传入的组件属性
|
||||
* @returns 默认添加 clearable 属性
|
||||
*/
|
||||
export const setComponentProps = (item: FormSchema): Recordable => {
|
||||
// const notNeedClearable = ['ColorPicker']
|
||||
// 拆分事件并组合
|
||||
const onEvents = (item?.componentProps as any)?.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,
|
||||
...newOnEvents
|
||||
}
|
||||
// 需要删除额外的属性
|
||||
if (componentProps.slots) {
|
||||
delete componentProps.slots
|
||||
}
|
||||
if (componentProps.on) {
|
||||
delete componentProps.on
|
||||
}
|
||||
return componentProps
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param formModel 表单数据
|
||||
* @param slotsProps 插槽属性
|
||||
*/
|
||||
export const setItemComponentSlots = (slotsProps: Recordable = {}): Recordable => {
|
||||
const slotObj: Recordable = {}
|
||||
for (const key in slotsProps) {
|
||||
if (slotsProps[key]) {
|
||||
if (isFunction(slotsProps[key])) {
|
||||
slotObj[humpToDash(key)] = (...args: any[]) => {
|
||||
return slotsProps[key]?.(...args)
|
||||
}
|
||||
} else {
|
||||
slotObj[humpToDash(key)] = () => {
|
||||
return slotsProps[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return slotObj
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param schema Form表单结构化数组
|
||||
* @param formModel FormMoel
|
||||
* @returns FormMoel
|
||||
* @description 生成对应的formModel
|
||||
*/
|
||||
export const initModel = (schema: FormSchema[], formModel: Recordable) => {
|
||||
const model: Recordable = { ...formModel }
|
||||
schema.map((v) => {
|
||||
if (v.remove) {
|
||||
delete model[v.field]
|
||||
} else if (v.component !== 'Divider') {
|
||||
// const hasField = Reflect.has(model, v.field)
|
||||
const hasField = get(model, v.field)
|
||||
// 如果先前已经有值存在,则不进行重新赋值,而是采用现有的值
|
||||
set(
|
||||
model,
|
||||
v.field,
|
||||
hasField !== void 0 ? get(model, v.field) : v.value !== void 0 ? v.value : undefined
|
||||
)
|
||||
// model[v.field] = hasField ? model[v.field] : v.value !== void 0 ? v.value : undefined
|
||||
}
|
||||
})
|
||||
return model
|
||||
}
|
||||
@@ -0,0 +1,665 @@
|
||||
import {
|
||||
AutocompleteProps,
|
||||
InputNumberProps,
|
||||
CascaderProps,
|
||||
CascaderNode,
|
||||
CascaderValue,
|
||||
SwitchProps,
|
||||
ComponentSize,
|
||||
InputProps,
|
||||
RateProps,
|
||||
ColorPickerProps,
|
||||
TransferProps,
|
||||
RadioGroupProps,
|
||||
RadioButtonProps,
|
||||
CheckboxGroupProps,
|
||||
DividerProps,
|
||||
DatePickerProps,
|
||||
FormItemProps as ElFormItemProps,
|
||||
FormProps as ElFormProps,
|
||||
ISelectProps,
|
||||
UploadProps
|
||||
} from 'element-plus'
|
||||
import { IEditorConfig } from '@wangeditor/editor'
|
||||
import { CSSProperties } from 'vue'
|
||||
|
||||
export interface PlaceholderModel {
|
||||
placeholder?: string
|
||||
startPlaceholder?: string
|
||||
endPlaceholder?: string
|
||||
rangeSeparator?: string
|
||||
}
|
||||
|
||||
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',
|
||||
TREE_SELECT = 'TreeSelect',
|
||||
UPLOAD = 'Upload'
|
||||
}
|
||||
|
||||
type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K
|
||||
? K extends string
|
||||
? K extends `${infer A}_${infer B}`
|
||||
? `${Capitalize<Lowercase<A>>}${Capitalize<Lowercase<B>>}`
|
||||
: Capitalize<Lowercase<K>>
|
||||
: never
|
||||
: never
|
||||
|
||||
export type ComponentName = CamelCaseComponentName
|
||||
|
||||
export interface InputPasswordComponentProps {
|
||||
strength?: boolean
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface InputComponentProps extends Partial<InputProps> {
|
||||
rows?: number
|
||||
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 extends Partial<AutocompleteProps> {
|
||||
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 extends Partial<InputNumberProps> {
|
||||
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 extends Omit<Partial<ISelectProps>, 'options'> {
|
||||
/**
|
||||
* 数据源的字段别名
|
||||
*/
|
||||
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 {
|
||||
multiple?: boolean
|
||||
disabled?: boolean
|
||||
valueKey?: string
|
||||
size?: ComponentSize
|
||||
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 {
|
||||
options?: Record<string, unknown>[]
|
||||
props?: CascaderProps
|
||||
size?: ComponentSize
|
||||
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 extends Partial<SwitchProps> {
|
||||
on?: {
|
||||
change?: (value: boolean | string | number) => void
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface RateComponentProps extends Partial<RateProps> {
|
||||
on?: {
|
||||
change?: (value: number) => void
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface ColorPickerComponentProps extends Partial<ColorPickerProps> {
|
||||
on?: {
|
||||
change?: (value: string) => void
|
||||
activeChange?: (value: string) => void
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface TransferComponentProps extends Partial<TransferProps> {
|
||||
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?: ComponentSize
|
||||
name?: string
|
||||
[key: string]: any
|
||||
}
|
||||
export interface RadioGroupComponentProps extends Partial<RadioGroupProps> {
|
||||
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 extends Partial<RadioButtonProps> {
|
||||
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?: ComponentSize
|
||||
name?: string
|
||||
checked?: boolean
|
||||
indeterminate?: boolean
|
||||
validateEvent?: boolean
|
||||
tabindex?: number | string
|
||||
id?: string
|
||||
controls?: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface CheckboxGroupComponentProps extends Partial<CheckboxGroupProps> {
|
||||
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 extends Partial<DividerProps> {
|
||||
on?: {
|
||||
change?: (value: number) => void
|
||||
input?: (value: number) => void
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface DatePickerComponentProps extends Partial<DatePickerProps> {
|
||||
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 {
|
||||
readonly?: boolean
|
||||
disabled?: boolean
|
||||
editable?: boolean
|
||||
clearable?: boolean
|
||||
size?: ComponentSize
|
||||
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 {
|
||||
readonly?: boolean
|
||||
disabled?: boolean
|
||||
editable?: boolean
|
||||
clearable?: boolean
|
||||
size?: ComponentSize
|
||||
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 {
|
||||
disabled?: boolean
|
||||
editable?: boolean
|
||||
clearable?: boolean
|
||||
size?: ComponentSize
|
||||
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 EditorComponentProps {
|
||||
editorConfig?: IEditorConfig
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface ColProps {
|
||||
span?: number
|
||||
xs?: number
|
||||
sm?: number
|
||||
md?: number
|
||||
lg?: number
|
||||
xl?: number
|
||||
tag?: string
|
||||
}
|
||||
|
||||
export interface FormSetProps {
|
||||
field: string
|
||||
path: string
|
||||
value: any
|
||||
}
|
||||
|
||||
export interface FormItemProps extends Partial<ElFormItemProps> {
|
||||
style?: CSSProperties
|
||||
slots?: {
|
||||
default?: (...args: any[]) => JSX.Element | null
|
||||
label?: (...args: any[]) => JSX.Element | null
|
||||
error?: (...args: any[]) => JSX.Element | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface UploadComponentProps extends Partial<UploadProps> {
|
||||
slots?: {
|
||||
default?: (...args: any[]) => JSX.Element | null
|
||||
trigger?: (...args: any[]) => JSX.Element | null
|
||||
tip?: (...args: any[]) => JSX.Element | null
|
||||
file?: (...args: any[]) => JSX.Element | null
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface TreeSelectComponentProps extends Omit<
|
||||
Partial<SelectComponentProps>,
|
||||
'props' | 'on' | 'slots'
|
||||
> {
|
||||
data?: any[]
|
||||
emptyText?: string
|
||||
nodeKey?: string
|
||||
props?: {
|
||||
children?: string
|
||||
label?: string | ((...args: any[]) => string)
|
||||
disabled?: string | ((...args: any[]) => string)
|
||||
isLeaf?: string | ((...args: any[]) => string)
|
||||
class?: string | ((...args: any[]) => string)
|
||||
}
|
||||
renderAfterExpand?: boolean
|
||||
load?: (...args: any[]) => Promise<any>
|
||||
renderContent?: (...args: any[]) => JSX.Element | null
|
||||
highlightCurrent?: boolean
|
||||
defaultExpandAll?: boolean
|
||||
expandOnClickNode?: boolean
|
||||
checkOnClickNode?: boolean
|
||||
autoExpandParent?: boolean
|
||||
defaultExpandedKeys?: any[]
|
||||
showCheckbox?: boolean
|
||||
checkStrictly?: boolean
|
||||
defaultCheckedKeys?: any[]
|
||||
currentNodeKey?: string | number
|
||||
filterNodeMethod?: (...args: any[]) => boolean
|
||||
accordion?: boolean
|
||||
indent?: number
|
||||
icon?: string | ((...args: any[]) => JSX.Element | null)
|
||||
lazy?: boolean
|
||||
draggable?: boolean
|
||||
allowDrag?: (...args: any[]) => boolean
|
||||
allowDrop?: (...args: any[]) => 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
|
||||
nodeClick?: (...args: any[]) => void
|
||||
nodeContextMenu?: (...args: any[]) => void
|
||||
checkChange?: (...args: any[]) => void
|
||||
check?: (...args: any[]) => void
|
||||
currentChange?: (...args: any[]) => void
|
||||
nodeExpand?: (...args: any[]) => void
|
||||
nodeCollapse?: (...args: any[]) => void
|
||||
nodeDragStart?: (...args: any[]) => void
|
||||
nodeDragEnter?: (...args: any[]) => void
|
||||
nodeDragLeave?: (...args: any[]) => void
|
||||
nodeDragOver?: (...args: any[]) => void
|
||||
nodeDragEnd?: (...args: any[]) => void
|
||||
nodeDrop?: (...args: any[]) => void
|
||||
}
|
||||
slots?: {
|
||||
default?: (...args: any[]) => 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
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface FormSchema {
|
||||
/**
|
||||
* 唯一标识
|
||||
*/
|
||||
field: string
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
label?: string
|
||||
|
||||
/**
|
||||
* col组件属性
|
||||
*/
|
||||
colProps?: ColProps
|
||||
|
||||
/**
|
||||
* 表单组件属性,具体可以查看element-plus文档
|
||||
*/
|
||||
componentProps?:
|
||||
| InputComponentProps
|
||||
| AutocompleteComponentProps
|
||||
| InputNumberComponentProps
|
||||
| SelectComponentProps
|
||||
| SelectV2ComponentProps
|
||||
| CascaderComponentProps
|
||||
| SwitchComponentProps
|
||||
| RateComponentProps
|
||||
| ColorPickerComponentProps
|
||||
| TransferComponentProps
|
||||
| RadioGroupComponentProps
|
||||
| RadioButtonComponentProps
|
||||
| DividerComponentProps
|
||||
| DatePickerComponentProps
|
||||
| DateTimePickerComponentProps
|
||||
| TimePickerComponentProps
|
||||
| InputPasswordComponentProps
|
||||
| TreeSelectComponentProps
|
||||
| UploadComponentProps
|
||||
| any
|
||||
|
||||
/**
|
||||
* formItem组件属性,具体可以查看element-plus文档
|
||||
*/
|
||||
formItemProps?: FormItemProps
|
||||
|
||||
/**
|
||||
* 渲染的组件名称
|
||||
*/
|
||||
component?: ComponentName
|
||||
|
||||
/**
|
||||
* 初始值
|
||||
*/
|
||||
value?: any
|
||||
|
||||
/**
|
||||
* 是否隐藏,如果为true,会连同值一同删除,类似v-if
|
||||
*/
|
||||
remove?: boolean
|
||||
|
||||
/**
|
||||
* 样式隐藏,不会把值一同删掉,类似v-show
|
||||
*/
|
||||
hidden?: boolean
|
||||
|
||||
/**
|
||||
* @returns 远程加载下拉项
|
||||
*/
|
||||
optionApi?: any
|
||||
}
|
||||
|
||||
export interface FormProps extends Partial<ElFormProps> {
|
||||
schema?: FormSchema[]
|
||||
isCol?: boolean
|
||||
model?: Recordable
|
||||
autoSetPlaceholder?: boolean
|
||||
isCustom?: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
Reference in new issue
Block a user