针对单进行封装,在编辑页面直接传入字段数组就可以展示表单:
弹窗:
javascript
<!-- 公共对话框组件 -->
<template>
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="800px"
:close-on-click-modal="false"
custom-class="fixed-dialog"
>
<common-form
ref="formRef"
:formData="formData"
:formFields="formFields"
:rules="rules"
:labelWidth="labelWidth"
@submit="(localFormData) => submitSuccess(localFormData)"
></common-form>
<template slot="footer">
<div class="dialog-footer">
<div class="dialog-footer-button">
<el-button @click="handleCancel" size="mini">取消</el-button>
<el-button type="primary" @click="submitForm" size="mini">确定</el-button>
</div>
</div>
</template>
</el-dialog>
</template>
<script>
import ImageUpload from './imageUpload.vue';
import commonForm from './commonForm.vue';
export default {
name: 'commonDialog',
components: {
ImageUpload,
commonForm
},
props: {
dialogVisible: {
type: Boolean,
default: false
},
dialogTitle: {
type: String,
default: "新增"
},
formData: {
type: Object,
default: () => ({})
},
formFields: {
type: Array,
default: () => []
},
rules: {
type: Object,
default: () => ({})
},
labelWidth: {
type: String,
default: "120px"
},
},
methods: {
submitForm() {
this.$refs.formRef.submitForm();
},
submitSuccess(localFormData) {
this.$emit("submit", localFormData);
},
handleCancel() {
this.$refs.formRef.handleCancel();
this.$emit('cancel');
},
}
};
</script>
<style scoped>
/* 引入公共对话框样式 */
@import '@/assets/styles/commonDialog.css';
/* 固定弹窗样式 */
:deep(.fixed-dialog) {
position: fixed !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
margin: 0 !important;
max-height: 90vh;
display: flex;
flex-direction: column;
z-index: 2002 !important;
}
:deep(.fixed-dialog .el-dialog__body) {
flex: 1;
overflow-y: auto;
max-height: calc(90vh - 100px);
}
/* 标题居左 */
:deep(.fixed-dialog .el-dialog__header) {
text-align: left !important;
}
</style>
form表单:
javascript
<!-- 公共表单组件 -->
<!-- 公共表单组件 -->
<template>
<el-form
:model="localFormData"
ref="formRef"
:rules="rules"
:label-width="labelWidth"
>
<el-form-item
v-for="item in formFields"
:key="item.prop"
:label="item.label"
:prop="item.prop"
>
<!-- 优先使用自定义插槽 -->
<slot
:name="item.prop"
:formData="localFormData"
:field="item"
>
<!-- 输入框 -->
<el-input
v-if="item.type === 'input'"
v-model="localFormData[item.prop]"
:placeholder="item.placeholder"
:maxlength="item.maxlength"
style="width: 100%"
size="mini"
show-word-limit
></el-input>
<!-- 文本域 -->
<el-input
v-else-if="item.type === 'textarea'"
v-model="localFormData[item.prop]"
type="textarea"
:rows="item.rows || 3"
:placeholder="item.placeholder"
:maxlength="item.maxlength"
show-word-limit
style="width: 100%"
size="mini"
></el-input>
<!-- 选择器 -->
<el-select
v-else-if="item.type === 'select'"
v-model="localFormData[item.prop]"
:placeholder="item.placeholder"
style="width: 100%"
size="mini"
:disabled="typeof item.disabled === 'string' ? evaluateCondition(item.disabled) : item.disabled"
:clearable="item.clearable"
@change="item.change ? item.change(localFormData[item.prop]) : null"
>
<el-option
v-for="option in item.options"
:key="option.value"
:label="option.label"
:value="option.value"
:disabled="option.disabled || false"
></el-option>
</el-select>
<!-- 开关 -->
<el-switch
v-else-if="item.type === 'switch'"
v-model="localFormData[item.prop]"
:active-value="1"
:inactive-value="0"
active-color="#13ce66"
inactive-color="#b6aeaeff"
></el-switch>
<!-- 图片上传 -->
<image-upload
v-else-if="item.type === 'upload'"
v-model="localFormData[item.prop]"
:image-url="localFormData[item.prop]"
:action="item.action"
:accept="item.accept"
:width="item.width"
:height="item.height"
:max-width="item.maxWidth"
:max-height="item.maxHeight"
:show-delete="item.showDelete || false"
@upload-success="(imageUrl) => handleUploadSuccess(imageUrl, item.prop)"
></image-upload>
<p v-if="item.type === 'upload'" class="hint">仅支持上传png/jpg/jpeg文件,上传尺寸为{{item.maxWidth}}*{{item.maxHeight}}px,最多允许上传1张图片,且图片大小不超过10M</p>
</slot>
</el-form-item>
</el-form>
</template>
<script>
import ImageUpload from './imageUpload.vue';
export default {
name: 'commonForm',
components: {
ImageUpload,
},
props: {
formData: {
type: Object,
default: () => ({})
},
formFields: {
type: Array,
default: () => []
},
rules: {
type: Object,
default: () => ({})
},
labelWidth: {
type: String,
default: "120px"
},
// 父组件传过来的 dialogVisible 用于清空校验
dialogVisible: {
type: Boolean,
default: false
}
},
data() {
return {
localFormData: {}
}
},
watch: {
dialogVisible(val) {
if (val) {
this.$nextTick(() => {
if (this.$refs.formRef) {
this.$refs.formRef.clearValidate();
}
});
}
},
formData: {
handler(newVal) {
this.localFormData = JSON.parse(JSON.stringify(newVal));
},
deep: true,
immediate: true
}
},
methods: {
submitForm() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$emit("submit", this.localFormData);
} else {
return false;
}
});
},
handleCancel() {
if (this.$refs.formRef) {
this.$refs.formRef.clearValidate();
this.$refs.formRef.resetFields();
}
},
handleClearValidate() {
this.$refs.formRef.clearValidate();
},
handleResetFields() {
this.$refs.formRef.resetFields();
},
handleUploadSuccess(imageUrl, prop) {
this.localFormData[prop] = imageUrl;
this.$emit('upload-success', this.localFormData);
},
evaluateCondition(condition) {
try {
return new Function('localFormData', `return ${condition}`)(this.localFormData);
} catch (error) {
console.error('条件解析错误:', error);
return true;
}
},
}
};
</script>
<style scoped>
@import '@/assets/styles/commonDialog.css';
.hint {
font-size: 12px;
color: #909399;
margin-top: 5px;
}
</style>
</script>
<style scoped>
@import '@/assets/styles/commonDialog.css';
</style>
引用方式:
javascript
<!-- 新增/编辑分类 -->
<template>
<common-dialog
:dialog-title="dialogTitle"
:dialog-visible="dialogVisible"
:form-data="formData"
:form-fields="formFields"
:rules="rules"
:label-width="'120px'"
@submit="(localFormData) => handleSubmit(localFormData)"
@cancel="handleCancel"
></common-dialog>
</template>
<script>
import CommonDialog from '@/components/commonDialog.vue';
import { addCategory ,updateCategory } from '@/api/category.js';
export default {
name: 'edit',
components: {
CommonDialog
},
props: {
dialogVisible: {
type: Boolean,
default: false
},
navList: {
type: Array,
default: () => []
},
formData: {
type: Object,
default: () => ({
id: null,
navMenuId: null,
menuId: null,
menuName: "",
menuNameInEnglish: "",
routeName: "",
routePath: "",
componentPath: "",
status: 1,
sortNum: 0,
bgImage: "",
detailImage: "",
intro: "",
isStandard: 0,
detailContent: "",
configDetail: 0
})
},
dialogTitle: {
type: String,
default: "新增"
}
},
data() {
return {
rules: {
navMenuId: [
{ required: true, message: "请输入导航菜单", trigger: "blur" }
],
menuName: [
{ required: true, message: "请输入菜单名称", trigger: "blur" }
],
menuNameInEnglish: [
{ required: true, message: "请输入菜单英文", trigger: "blur" }
],
routeName: [
{ required: true, message: "请输入路由名称", trigger: "blur" }
],
routePath: [
{ required: true, message: "请输入路由地址", trigger: "blur" }
],
componentPath: [
{ required: true, message: "请输入组件路径", trigger: "blur" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
],
bgImage: [
{ required: true, message: "请上传分类图片", trigger: "change" }
],
intro: [
{ required: true, message: "请输入分类简介", trigger: "change" }
],
detailContent: [
{ required: true, message: "请输入详情介绍", trigger: "change" }
],
configDetail: [
{ required: true, message:"请选择是否可配置详情", trigger: "change" }
]
},
baseUrl: this.$global.baseUrl
};
},
computed: {
formFields() {
return [
{
type: 'select',
label: '导航菜单',
prop: 'navMenuId',
placeholder: '请选择导航菜单',
options: this.navList.map(item => ({ label: item.menuName, value: item.id, disabled: item.status === 0 })),
showAble: false
},
{
type: 'input',
label: '菜单名称',
prop: 'menuName',
placeholder: '请输入菜单名称',
maxlength: 10
},
{
type: 'input',
label: '菜单英文',
prop: 'menuNameInEnglish',
placeholder: '请输入菜单英文',
maxlength: 100
},
{
type: 'input',
label: '路由名称',
prop: 'routeName',
placeholder: '请输入路由名称',
maxlength: 100
},
{
type: 'input',
label: '路由地址',
prop: 'routePath',
placeholder: '请输入路由地址',
maxlength: 100
},
{
type: 'input',
label: '组件路径',
prop: 'componentPath',
placeholder: '请输入组件路径',
maxlength: 100
},
{
type: 'upload',
label: '分类图片',
prop: 'bgImage',
action: this.$global.baseUrl + '/file/file/upload/category' ,
accept: 'image/png, image/jpeg, image/jpg',
maxWidth: 384,
maxHeight: 256,
width: 197,
height: 128,
},
{
prop: 'detailImage',
type: 'upload',
label: '详情图片',
action: this.$global.baseUrl + '/file/file/upload/category' ,
accept: 'image/png, image/jpeg, image/jpg',
maxWidth: 1920,
maxHeight: 480,
width: 480,
height: 120,
showDelete: true
},
{
type: 'switch',
label: '状态',
prop: 'status'
},
{
type: 'switch',
label: '是否展示标准品',
prop: 'isStandard'
},
{
type: 'textarea',
label: '分类简介',
prop: 'intro',
placeholder: '请输入分类简介',
maxlength: 100,
},
{
type: 'textarea',
label: '详情介绍',
prop: 'detailContent',
placeholder: '请输入详情介绍',
maxlength: 2000,
rows: 3
}
];
}
},
methods: {
handleSubmit(localFormData) {
if (localFormData.id) {
// 编辑
updateCategory(localFormData).then((res) => {
if (res.code === 200) {
this.$message.success('编辑成功');
this.$emit("submit");
} else {
this.$message.error('编辑失败,请联系管理员');
}
});
} else {
// 新增
addCategory(localFormData).then((res) => {
if (res.code === 200) {
this.$message.success('新增成功');
this.$emit("submit");
} else {
this.$message.error('新增失败,请联系管理员');
}
});
}
},
handleCancel() {
this.$emit('cancel');
}
}
};
</script>
<style scoped>
/* 引入公共对话框样式 */
@import '@/assets/styles/commonDialog.css';
</style>
样式:
