捕梦者基础前端框架
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

333 lines
9.1 KiB

<template>
<ele-drawer
:size="430"
title="表单项配置"
:append-to-body="true"
style="max-width: 100%"
:model-value="modelValue"
:body-style="{ paddingLeft: '10px' }"
@update:modelValue="updateModelValue"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="92px"
@submit.prevent=""
>
<el-form-item label="标题" prop="label">
<el-input
clearable
:maxlength="20"
v-model="form.label"
placeholder="请输入标题"
/>
</el-form-item>
<el-form-item label="字段名" prop="prop">
<el-input
clearable
:maxlength="20"
v-model="form.prop"
placeholder="请输入字段名"
/>
</el-form-item>
<el-form-item label="是否必填" prop="required">
<el-radio-group v-model="form.required">
<el-radio :value="true" label="是" />
<el-radio :value="false" label="否" />
</el-radio-group>
</el-form-item>
<el-form-item prop="itemProps">
<el-input
:rows="2"
type="textarea"
v-model="form.itemProps"
placeholder="请输入 ElFormItem 属性"
/>
<template #label>
<ele-tooltip
placement="top-start"
:popperOptions="{
modifiers: [{ name: 'offset', options: { offset: [-12, 10] } }]
}"
>
<el-icon
:size="15"
style="align-self: center; margin-right: 4px; cursor: help"
>
<QuestionCircleOutlined style="opacity: 0.6" />
</el-icon>
<template #content>
<div>配置 ElFormItem 组件的其它属性(JSON格式),如:</div>
<div>{"rules": [{"required": true, "type": "string", </div>
<div>"message": "请输入标题", "trigger": "blur"}]}</div>
</template>
</ele-tooltip>
<div>其它属性</div>
</template>
</el-form-item>
<el-form-item label="组件类型" prop="type">
<el-select
v-model="form.type"
placeholder="请选择组件类型"
class="ele-fluid"
@change="onTypeChange"
>
<el-option
v-for="item in typeOptions"
:key="item.value"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item prop="props">
<el-input
:rows="5"
type="textarea"
v-model="form.props"
placeholder="请输入组件属性"
/>
<template #label>
<ele-tooltip
placement="top-start"
:popperOptions="{
modifiers: [{ name: 'offset', options: { offset: [-12, 10] } }]
}"
>
<el-icon
:size="15"
style="align-self: center; margin-right: 4px; cursor: help"
>
<QuestionCircleOutlined style="opacity: 0.6" />
</el-icon>
<template #content>
<div>配置组件的属性(JSON格式),如:</div>
<div>{"clearable": false, "maxlength": 20}</div>
</template>
</ele-tooltip>
<div>组件属性</div>
</template>
</el-form-item>
<el-form-item label="所占列数" prop="colSpan">
<el-select
v-model="form.colSpan"
placeholder="请选择所占列数"
class="ele-fluid"
>
<el-option
v-for="item in gridOptions"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="item.value > grid"
/>
</el-select>
</el-form-item>
<el-form-item prop="options">
<el-input
:rows="5"
type="textarea"
v-model="form.options"
placeholder="请输入选项数据"
/>
<template #label>
<ele-tooltip
placement="top-start"
:popperOptions="{
modifiers: [{ name: 'offset', options: { offset: [-12, 10] } }]
}"
>
<el-icon
:size="15"
style="align-self: center; margin-right: 4px; cursor: help"
>
<QuestionCircleOutlined style="opacity: 0.6" />
</el-icon>
<template #content>
<div>下拉或多选、单选等组件的选项数据(JSON格式),如:</div>
<div>
[{"label": "男", "value": 1}, {"label": "女", "value": 2}]
</div>
</template>
</ele-tooltip>
<div>选项数据</div>
</template>
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" class="ele-fluid" @click="save">保存</el-button>
</template>
</ele-drawer>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import type { FormInstance, FormRules } from 'element-plus/es';
import { QuestionCircleOutlined } from '@/components/icons';
import { useFormData } from '@/utils/use-form-data';
import type { ProFormItemProps } from '@/components/ProForm/types';
import {
gridOptions,
itemTypes,
getOptionsAndProps,
getColProps,
getColSpan
} from './util';
const emit = defineEmits<{
(e: 'done', data: ProFormItemProps): void;
(e: 'update:modelValue', modelValue: boolean): void;
}>();
const props = defineProps<{
/** 弹窗是否打开 */
modelValue: boolean;
/** 修改回显的数据 */
data?: ProFormItemProps | null;
/** 表单显示列数 */
grid: number;
}>();
/** 配置项表单 */
const formRef = ref<FormInstance | null>(null);
/** 配置项表单数据 */
const [form, resetFields, assignFields] = useFormData({
key: void 0,
label: '',
prop: '',
required: false,
itemProps: '',
type: void 0,
props: '',
//colProps: '',
options: '',
colSpan: 1
});
/** 验证JSON格式 */
const validateJSON = (value?: string) => {
if (value) {
const msg = '请输入正确的JSON格式';
try {
const obj = JSON.parse(value);
if (obj == null || typeof obj !== 'object') {
return msg;
}
} catch (_e) {
return msg;
}
}
};
/** 配置项表单验证规则 */
const rules = reactive<FormRules>({
label: [
{
required: true,
type: 'string',
message: '请输入标题',
trigger: 'blur'
}
],
prop: [
{
required: true,
type: 'string',
message: '请输入字段名',
trigger: 'blur'
}
],
itemProps: [
{
validator: (_rule: any, value: string, callback: any) => {
callback(validateJSON(value));
},
trigger: 'blur'
}
],
props: [
{
validator: (_rule: any, value: string, callback: any) => {
callback(validateJSON(value));
},
trigger: 'blur'
}
],
colProps: [
{
validator: (_rule: any, value: string, callback: any) => {
callback(validateJSON(value));
},
trigger: 'blur'
}
]
});
/** 组件类型下拉数据 */
const typeOptions = ref(
itemTypes.map((d) => {
return { ...d, label: `${d.label}(${d.value})` };
})
);
/** 组件类型选择改变 */
const onTypeChange = (type: string) => {
const { options, props } = getOptionsAndProps(type);
form.props = props;
form.options = options;
};
/** 保存表单项配置 */
const save = () => {
formRef.value?.validate?.((valid) => {
if (valid) {
//updateModelValue(false);
emit('done', {
key: form.key,
label: form.label,
prop: form.prop,
type: form.type,
required: form.required,
itemProps: form.itemProps ? JSON.parse(form.itemProps) : void 0,
props: form.props ? JSON.parse(form.props) : void 0,
//colProps: form.colProps ? JSON.parse(form.colProps) : void 0,
colProps: getColProps(props.grid, form.colSpan),
options: form.options ? JSON.parse(form.options) : void 0
});
}
});
};
/** 更新modelValue */
const updateModelValue = (value: boolean) => {
emit('update:modelValue', value);
};
watch(
() => props.modelValue,
(modelValue) => {
if (modelValue) {
const item = props.data;
if (item) {
assignFields({
...item,
itemProps: item.itemProps
? JSON.stringify(item.itemProps, void 0, 2)
: '',
props: item.props ? JSON.stringify(item.props, void 0, 2) : '',
//colProps: item.colProps ? JSON.stringify(item.colProps, void 0, 2) : '',
options: item.options
? JSON.stringify(item.options, void 0, 2)
: '',
colSpan: getColSpan(props.grid, item.colProps?.span)
});
}
} else {
resetFields();
formRef.value?.clearValidate?.();
}
}
);
</script>