zy-vue-library/components/form_builder/form_items_renderer.vue

273 lines
10 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<template v-for="(option, index) in fnVerifyType(options)" :key="option.key || index">
<template v-if="!option.hidden">
<el-col
v-if="!option.root"
v-show="!collapse || index < 3"
:span="option.type === formItemTypeEnum.DIVIDER ? 24 : option.span || span || 12"
>
<el-form-item
v-if="option.type !== formItemTypeEnum.DIVIDER"
:key="option.formItemKey"
:label-width="option.labelWidth"
:prop="option.key"
:rules="fnGetRules(option)"
>
<template #label>
<div style="display: flex; align-items: center">
{{ option.label }}
<el-tooltip v-if="option.tip" :content="option.tip">
<el-icon :size="12" class="ml-2"><info-filled /></el-icon>
</el-tooltip>
</div>
</template>
<slot :name="option.key">
<el-input
v-if="option.type === formItemTypeEnum.INPUT || !option.type"
v-model="modelValue[option.key]"
:placeholder="'请输入' + option.label"
v-bind="fnGetProps(option)"
/>
<el-input
v-else-if="option.type === formItemTypeEnum.TEXTAREA"
v-model="modelValue[option.key]"
:placeholder="'请输入' + option.label"
type="textarea"
:autosize="{ minRows: 3 }"
v-bind="fnGetProps(option)"
/>
<el-input-number
v-else-if="
option.type === formItemTypeEnum.INPUT_NUMBER || option.type === formItemTypeEnum.NUMBER
"
v-model="modelValue[option.key]"
:placeholder="'请输入' + option.label"
v-bind="fnGetProps(option)"
/>
<el-select
v-else-if="option.type === formItemTypeEnum.SELECT"
v-model="modelValue[option.key]"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
>
<el-option
v-for="item in unref(option.options)"
:key="
item[option.valueKey] || item['dictionariesId'] || item['id']
"
:label="item[option.labelKey] || item['name']"
:value="
item[option.valueKey] || item['dictionariesId'] || item['id']
"
/>
</el-select>
<el-checkbox-group
v-else-if="option.type === formItemTypeEnum.CHECKBOX"
v-model="modelValue[option.key]"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
>
<el-checkbox
v-for="item in unref(option.options)"
:key="
item[option.valueKey] || item['dictionariesId'] || item['id']
"
:value="
item[option.valueKey] || item['dictionariesId'] || item['id']
"
>
{{ item[option.labelKey] || item["name"] }}
</el-checkbox>
</el-checkbox-group>
<el-radio-group
v-else-if="option.type === formItemTypeEnum.RADIO"
v-model="modelValue[option.key]"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
>
<el-radio
v-for="item in unref(option.options)"
:key="
item[option.valueKey] || item['dictionariesId'] || item['id']
"
:value="
item[option.valueKey] || item['dictionariesId'] || item['id']
"
>
{{ item[option.labelKey] || item["name"] }}
</el-radio>
</el-radio-group>
<el-date-picker
v-else-if="option.type === formItemTypeEnum.DATE"
v-model="modelValue[option.key]"
value-format="YYYY-MM-DD"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
/>
<el-date-picker
v-else-if="option.type === formItemTypeEnum.DATE_MONTH"
v-model="modelValue[option.key]"
type="month"
value-format="YYYY-MM"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
/>
<el-date-picker
v-else-if="option.type === formItemTypeEnum.DATE_YEAR"
v-model="modelValue[option.key]"
type="year"
value-format="YYYY"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
/>
<el-date-picker
v-else-if="option.type === formItemTypeEnum.DATE_RANGE"
v-model="modelValue[option.key]"
type="daterange"
value-format="YYYY-MM-DD"
:start-placeholder="'请选择开始' + option.label"
:end-placeholder="'请选择结束' + option.label"
v-bind="fnGetProps(option)"
/>
<el-date-picker
v-else-if="option.type === formItemTypeEnum.DATETIME"
v-model="modelValue[option.key]"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="'请选择' + option.label"
v-bind="fnGetProps(option)"
/>
<el-date-picker
v-else-if="option.type === formItemTypeEnum.DATETIME_RANGE"
v-model="modelValue[option.key]"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
:start-placeholder="'请选择开始' + option.label"
:end-placeholder="'请选择结束' + option.label"
:default-time="[
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]"
v-bind="fnGetProps(option)"
/>
<component :is="option.type" v-else v-model="modelValue[option.key]" v-bind="fnGetProps(option)" />
</slot>
</el-form-item>
<el-divider v-if="option.type === formItemTypeEnum.DIVIDER" content-position="left">
{{ option.label }}
</el-divider>
</el-col>
<template v-if="option.root">
<slot :name="option.key">
<component :is="option.type" v-model="modelValue[option.key]" v-bind="fnGetProps(option)" />
</slot>
</template>
</template>
</template>
</template>
<script setup>
import { omit } from "lodash-es";
import { unref } from "vue";
import { InfoFilled } from "@element-plus/icons-vue";
import {
ElCol,
ElFormItem,
ElTooltip,
ElIcon,
ElInput,
ElInputNumber,
ElSelect,
ElOption,
ElCheckboxGroup,
ElCheckbox,
ElRadioGroup,
ElRadio,
ElDatePicker,
ElDivider,
} from "element-plus";
import "element-plus/es/components/col/style/css";
import "element-plus/es/components/form-item/style/css";
import "element-plus/es/components/tooltip/style/css";
import "element-plus/es/components/icon/style/css";
import "element-plus/es/components/input/style/css";
import "element-plus/es/components/input-number/style/css";
import "element-plus/es/components/select/style/css";
import "element-plus/es/components/option/style/css";
import "element-plus/es/components/checkbox-group/style/css";
import "element-plus/es/components/checkbox/style/css";
import "element-plus/es/components/radio-group/style/css";
import "element-plus/es/components/radio/style/css";
import "element-plus/es/components/date-picker/style/css";
import "element-plus/es/components/divider/style/css";
import formItemTypeEnum from "../../enum/formItemType/index.js";
const props = defineProps({
options: { type: Array, required: true },
span: { type: Number, default: 0 },
collapse: { type: Boolean, default: false },
autoGenerateRequired: { type: Boolean, default: true },
});
const modelValue = defineModel({ type: Object, required: true });
const rootProps = [
"label", // 表单项的标签
"key", // 唯一值对应form里的key
"type", // 要渲染的组件默认input
"span", // 栅格占据的列数默认12
"hidden", // 是否隐藏
"rules", // 表单验证规则
"options", // selectradiocheckbox 的数据源
"valueKey", // selectradiocheckbox 的 value字段
"labelKey", // selectradiocheckbox 的 label字段
"attrs", // 传给组件的属性
"root", // 是否和el-col同级
"labelWidth", // label的宽度
"tip", // 跟在label后面的提示语
"formItemKey", // el-form-item的key
"required", // el-form-item是否必填默认true
// ... // 任意参数全部当成组件属性不能和attrs同时存在优先使用attrs
];
const fnGetProps = (option) => {
if (option.attrs) return option.attrs;
return omit(option, rootProps);
};
const fnGetRules = (option) => {
if (props.autoGenerateRequired === false) return {};
if (option.type === formItemTypeEnum.DIVIDER) return {};
if (option.required !== false) {
const blur = option.type
? [
formItemTypeEnum.INPUT,
formItemTypeEnum.TEXTAREA,
formItemTypeEnum.INPUT_NUMBER,
formItemTypeEnum.NUMBER,
].includes(option.type)
: true;
const rules = [
{
required: true,
message: `${blur ? "请输入" : "请选择"}${option.label}`,
trigger: blur ? "blur" : "change",
},
];
if (option.rules) {
if (Array.isArray(option.rules)) rules.push(...option.rules);
else rules.push(option.rules);
}
return rules;
}
return {};
};
const fnVerifyType = (options) => {
for (let i = 0; i < options.length; i++) {
const option = options[i];
if (option.type && typeof option.type === 'string' && !formItemTypeEnum[option.type])
throw new Error(`${option.type} 类型枚举不存在,请参照并使用 formItemTypeEnum 类型枚举`);
}
return options;
};
</script>
<style scoped lang="scss"></style>