<template>
|
<el-dialog v-model="dialogVisible" :title="title" :width="width" :destroy-on-close="true" @close="handleClose">
|
<el-form ref="formRef" :model="formData" :rules="finalRules" label-width="150px" size="default">
|
<!-- 动态渲染表单项 -->
|
<el-form-item v-for="(item, index) in fields" :key="index + item.prop" :label="item.label" :prop="item.prop"
|
:required="item.required" :disabled="item.disabled">
|
<!-- 输入框 -->
|
<el-input v-if="item.type === 'input'" v-model="formData[item.prop]"
|
:placeholder="item.placeholder || `请输入${item.label}`" :maxlength="item.maxlength"
|
:disabled="item.disabled" />
|
|
<!-- 下拉选择 -->
|
<el-select v-else-if="item.type === 'select'" v-model="formData[item.prop]"
|
:placeholder="item.placeholder || `请选择${item.label}`"
|
:disabled="item.disabled || !item.options || item.options.length === 0">
|
<el-option v-for="dict in item.options" :key="dict.value" :label="dict.label" :value="dict.value" />
|
</el-select>
|
|
<!-- 文本域 -->
|
<el-input v-else-if="item.type === 'textarea'" v-model="formData[item.prop]" type="textarea"
|
:rows="item.rows || 3" :placeholder="item.placeholder || `请输入${item.label}`"
|
:disabled="item.disabled" />
|
</el-form-item>
|
</el-form>
|
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="handleClose">取消</el-button>
|
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup lang="ts">
|
import useCurrentInstance from "@/utils/useCurrentInstance";
|
import { ref, reactive, watch, onMounted } from 'vue';
|
import type { FormInstance, FormRules } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
|
// 定义字段类型
|
interface FormField {
|
prop: string;
|
label: string;
|
type: 'input' | 'select' | 'textarea';
|
required?: boolean;
|
disabled?: boolean; // 禁用状态标识
|
placeholder?: string;
|
requiredMessage?: string;
|
maxlength?: number;
|
rows?: number;
|
options?: { label: string; value: string | number }[];
|
}
|
|
const { proxy } = useCurrentInstance();
|
// 获取所需字典数据
|
const {
|
sys_account_type, // 账号类型字典
|
sys_bank_type, // 账户状态字典
|
sys_currency // 币种字典
|
} = proxy.useDict(
|
'sys_account_type',
|
'sys_bank_type',
|
'sys_currency'
|
);
|
|
// 定义表单字段配置
|
const fields = ref<FormField[]>([
|
{
|
prop: 'relatedCustomerName',
|
label: '关联客户',
|
type: 'input',
|
required: true,
|
placeholder: '请输入关联客户',
|
requiredMessage: '请输入关联客户',
|
disabled: true, // 核心修改:设置为禁用,禁止修改
|
},
|
{
|
prop: 'accountNo',
|
label: '账号编号',
|
type: 'input',
|
required: true,
|
placeholder: '请输入账号编号',
|
},
|
{
|
prop: 'accountName',
|
label: '户名',
|
type: 'input',
|
required: true,
|
placeholder: '请输入户名',
|
maxlength: 18,
|
},
|
{
|
prop: 'bankName',
|
label: '银行名称',
|
type: 'input',
|
placeholder: '请输入银行名称',
|
},
|
{
|
prop: 'branchName',
|
label: '支行名称',
|
type: 'input',
|
placeholder: '请输入支行名称',
|
},
|
{
|
prop: 'accountType',
|
label: '账号类型',
|
type: 'select',
|
required: true,
|
placeholder: '请选择账号类型',
|
options: [], // 由sys_account_type字典填充
|
},
|
{
|
prop: 'currency',
|
label: '币种',
|
type: 'select',
|
required: true,
|
placeholder: '请选择币种',
|
options: [], // 由sys_currency字典填充
|
},
|
{
|
prop: 'status',
|
label: '账户状态',
|
type: 'select',
|
required: true,
|
placeholder: '请选择账户状态',
|
options: [], // 由sys_bank_status字典填充
|
},
|
]);
|
|
// 核心优化:创建字典与字段的映射关系(字典名 -> 字段prop)
|
const dictFieldMap = {
|
sys_account_type: 'accountType', // 账号类型字典对应accountType字段
|
sys_bank_type: 'status', // 账户状态字典对应status字段
|
sys_currency: 'currency' // 币种字典对应currency字段
|
};
|
|
// 用一个watch处理所有字典的绑定
|
watch(
|
// 监听所有字典的变化(返回一个包含所有字典的对象)
|
() => ({ sys_account_type, sys_bank_type, sys_currency }),
|
// 当任何字典变化时触发
|
(newDicts) => {
|
// 遍历映射关系,批量处理字典与字段的绑定
|
Object.entries(dictFieldMap).forEach(([dictName, fieldProp]) => {
|
const dictData = newDicts[dictName as keyof typeof newDicts].value;
|
const targetField = fields.value.find(item => item.prop === fieldProp);
|
if (targetField && dictData && dictData.length > 0) {
|
targetField.options = dictData;
|
}
|
});
|
},
|
{ immediate: true, deep: true } // immediate确保初始加载时执行,deep监听对象内部变化
|
);
|
|
// Props
|
const props = defineProps({
|
visible: {
|
type: Boolean,
|
default: false,
|
},
|
title: {
|
type: String,
|
default: '银行账户信息表单',
|
},
|
width: {
|
type: String,
|
default: '60%',
|
},
|
initialData: {
|
type: Object,
|
default: () => ({}),
|
},
|
rules: {
|
type: Object as () => FormRules,
|
default: () => ({}),
|
},
|
});
|
|
// Emits
|
const emit = defineEmits(['close', 'submit']);
|
|
// 表单实例
|
const formRef = ref<FormInstance>();
|
const dialogVisible = ref(false);
|
const formData = reactive<Record<string, any>>({});
|
const finalRules = ref<FormRules>({});
|
|
// 生成默认中文校验规则
|
const generateDefaultRules = () => {
|
const defaultRules: FormRules = {};
|
fields.value.forEach((field) => {
|
if (field.required) {
|
const message = field.requiredMessage ||
|
(field.type === 'select'
|
? `请选择${field.label}`
|
: `请输入${field.label}`);
|
|
defaultRules[field.prop] = [
|
{
|
required: true,
|
message,
|
trigger: field.type === 'select' ? 'change' : 'blur'
|
}
|
];
|
}
|
});
|
return defaultRules;
|
};
|
|
// 初始化表单数据和规则
|
const initForm = () => {
|
fields.value.forEach((field) => {
|
formData[field.prop] = props.initialData[field.prop] ?? (field.type === 'select' ? '' : '');
|
});
|
finalRules.value = { ...generateDefaultRules(), ...props.rules };
|
};
|
|
// 监听visible变化
|
watch(
|
() => props.visible,
|
(val) => {
|
dialogVisible.value = val;
|
if (val) initForm();
|
},
|
{ immediate: true }
|
);
|
|
// 提交表单
|
const handleSubmit = async () => {
|
if (!formRef.value) return;
|
try {
|
await formRef.value.validate();
|
emit('submit', { ...formData });
|
dialogVisible.value = false;
|
} catch (err) {
|
ElMessage({
|
message: '表单验证失败,请检查必填项',
|
type: 'warning',
|
});
|
}
|
};
|
|
// 关闭弹窗
|
const handleClose = () => {
|
dialogVisible.value = false;
|
formRef.value?.resetFields();
|
emit('close');
|
};
|
|
onMounted(() => {
|
initForm();
|
});
|
</script>
|
|
<style scoped>
|
.dialog-footer {
|
text-align: right;
|
}
|
</style>
|