// import { ElInput } from "element-plus";
|
import {
|
defineComponent,
|
PropType,
|
ref,
|
Ref,
|
SetupContext,
|
computed,
|
unref,
|
markRaw,
|
DefineComponent,
|
} from 'vue'
|
import styles from './DyForm.module.scss'
|
import ElInput from 'element-plus/es/components/input/index'
|
import Option from '@/components/Select/Option'
|
import Select from '@/components/Select/Select'
|
import SelectInput from '@/components/SelectInput/SelectInput'
|
import type { FormInstance } from 'element-plus'
|
import Icon from '../Icon/Icon'
|
import {
|
FormPropsType,
|
FormItemPropType,
|
PropsType,
|
OptionItemType,
|
} from './DyForm.d'
|
import Variable from '../Variable/Variable'
|
import Title from '../Title/Title'
|
import TextareaFlow from '../Flow/Flow'
|
import get from 'lodash/get'
|
import set from 'lodash/set'
|
|
const formItemElementMap = markRaw<Record<string, any>>({
|
input: ElInput,
|
select: Select,
|
selectInput: SelectInput,
|
variable: Variable,
|
textareaFlow: TextareaFlow,
|
})
|
|
const Type: Record<string, any> = {
|
select: 'select',
|
}
|
export default defineComponent<FormPropsType>({
|
//@ts-ignore
|
name: '动态表单',
|
props: {
|
labelWidth: {
|
type: String,
|
default: '100px',
|
},
|
labelPosition: {
|
type: String,
|
default: 'right',
|
},
|
formData: {
|
type: Object as PropType<{ [key: string]: any }>,
|
default: () => ({}),
|
},
|
formItemProps: {
|
type: Array,
|
default: () => [],
|
},
|
inLine: {
|
type: Boolean,
|
default: false,
|
},
|
},
|
setup(props: PropsType, { attrs, emit, expose }: SetupContext) {
|
const formRef = ref<FormInstance>()
|
const form: any = computed({
|
get() {
|
return props.formData
|
},
|
set(v) {
|
emit('update:formData', v)
|
},
|
})
|
|
const currentWidgetModel = computed(() => {
|
return (path: string) => {
|
return get(form.value, path)
|
}
|
})
|
|
const validate = () => {
|
if (!formRef.value) return false
|
return new Promise((resolve, reject) => {
|
formRef.value?.validate((valid: boolean) => {
|
if (valid) {
|
resolve(true)
|
} else {
|
reject(false)
|
}
|
})
|
})
|
}
|
|
const resetForm = () => {
|
if (!formRef.value) return false
|
formRef.value.resetFields()
|
}
|
|
const formItemProps = computed(() => {
|
return props.formItemProps || []
|
})
|
|
expose({ validate, resetForm })
|
|
const FormRender: any = ($props: any) => {
|
const item: FormItemPropType = $props.item
|
const options = $props.item.options || []
|
if (item.el && Type[item.el as string]) {
|
return options.map((el: OptionItemType) => (
|
<Option
|
label={el.label || el.description || el.name}
|
value={el.value}
|
></Option>
|
))
|
}
|
return null
|
}
|
|
const onUpdateModelValue = (v: string | number, prop: string) => {
|
set(form.value, prop, v)
|
}
|
|
return () => {
|
return (
|
<div class={styles.formStyle}>
|
<el-form
|
labelPosition={props.labelPosition}
|
labelWidth={props.labelWidth}
|
model={form.value}
|
ref={formRef}
|
inline={props.inLine}
|
>
|
{formItemProps.value.map(
|
(item: FormItemPropType, index: number) => {
|
if (item.isTitle) {
|
if (typeof item.title === 'string') {
|
return (
|
<Title style="margin-bottom: 10px">{item.title}</Title>
|
)
|
}
|
return item.title
|
}
|
|
const itemProps: FormItemPropType = {}
|
Object.entries(item).forEach(([key, value]) => {
|
itemProps[key] = unref(value)
|
})
|
|
const el =
|
typeof itemProps.el === 'string'
|
? formItemElementMap[itemProps.el]
|
: itemProps.el || null
|
const Component = el
|
return Component && !item.isHide ? (
|
<el-form-item
|
label={itemProps.label}
|
prop={itemProps.prop}
|
rules={itemProps.rules}
|
key={itemProps.prop}
|
vSlots={
|
itemProps.labelIcon
|
? {
|
label: () => (
|
<label class={styles.formitemPropsLabel}>
|
{itemProps.label}
|
<Icon icon={itemProps.labelIcon} />
|
</label>
|
),
|
}
|
: null
|
}
|
>
|
<Component
|
style={{
|
width: itemProps.width,
|
height: itemProps.height,
|
}}
|
{...itemProps}
|
// v-model={form.value[itemProps.prop as keyof any]}
|
modelValue={currentWidgetModel.value(itemProps.prop)}
|
onUpdate:modelValue={(val: string | number) =>
|
onUpdateModelValue(val, itemProps.prop)
|
}
|
>
|
<FormRender item={itemProps} />
|
</Component>
|
</el-form-item>
|
) : null
|
}
|
)}
|
</el-form>
|
</div>
|
)
|
}
|
},
|
})
|