优化资产编辑表单验证和服务资产配置,新增上下线时间联动校验、主图必填校验

This commit is contained in:
WUSIJIAN
2025-12-23 13:10:26 +08:00
parent ecd75164ae
commit f30ddaf400

View File

@@ -45,6 +45,7 @@
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
class="w100"
@change="onOnlineTimeChange"
/>
</el-form-item>
</el-col>
@@ -57,6 +58,7 @@
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
class="w100"
:disabled-date="disabledOfflineDate"
/>
</el-form-item>
</el-col>
@@ -139,19 +141,11 @@
</el-row>
</template>
<!-- 资产描述 -->
<el-divider content-position="left">资产描述</el-divider>
<el-form-item label="描述内容" label-width="100px">
<div class="editor-wrapper">
<Editor v-model="ruleForm.description" height="200px" placeholder="请输入资产描述" />
</div>
</el-form-item>
<!-- 图片上传 -->
<el-divider content-position="left">图片信息</el-divider>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="主图">
<el-form-item label="主图" prop="mainImage">
<el-upload
class="avatar-uploader"
:show-file-list="false"
@@ -181,6 +175,16 @@
</el-col>
</el-row>
<!-- 资产描述 -->
<el-divider content-position="left">资产描述</el-divider>
<el-form-item label="描述内容" label-width="100px">
<div class="editor-wrapper">
<Editor v-model="ruleForm.description" height="200px" placeholder="请输入资产描述" />
</div>
</el-form-item>
<!-- 实物资产配置 -->
<template v-if="ruleForm.type === 'physical'">
<el-divider content-position="left">实物资产配置</el-divider>
@@ -204,19 +208,19 @@
<!-- 预订配置 -->
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="最小提前">
<el-form-item label="最小提前" prop="serviceAssetConfig.booking.minAdvance">
<el-input-number v-model="ruleForm.serviceAssetConfig.booking.minAdvance" :min="0" class="w100" />
<span class="unit-text">分钟</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="最小时长">
<el-form-item label="最小时长" prop="serviceAssetConfig.booking.minDuration">
<el-input-number v-model="ruleForm.serviceAssetConfig.booking.minDuration" :min="0" class="w100" />
<span class="unit-text">分钟</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="取消提前">
<el-form-item label="取消提前" prop="serviceAssetConfig.booking.cancelWindow">
<el-input-number v-model="ruleForm.serviceAssetConfig.booking.cancelWindow" :min="0" class="w100" />
<span class="unit-text">分钟</span>
</el-form-item>
@@ -224,7 +228,7 @@
</el-row>
<!-- 时间段配置 -->
<el-form-item label="时间段">
<el-form-item label="服务时间" prop="serviceAssetConfig.schedule.timeSlots">
<div class="config-list-container">
<div v-for="(slot, index) in ruleForm.serviceAssetConfig.schedule.timeSlots" :key="index" class="config-list-item">
<el-select v-model="slot.dayOfWeek" placeholder="星期" style="width: 100px">
@@ -249,7 +253,7 @@
</el-form-item>
<!-- 例外日期配置 -->
<el-form-item label="例外日期">
<el-form-item label="休息时间">
<div class="config-list-container">
<div v-for="(exc, index) in ruleForm.serviceAssetConfig.schedule.exceptions" :key="index" class="config-list-item">
<el-select v-model="exc.exceptionType" placeholder="类型" style="width: 100px" @change="onExceptionTypeChange(exc)">
@@ -267,7 +271,7 @@
<el-input v-model="exc.reason" placeholder="原因" style="width: 120px" />
<el-button type="danger" :icon="Delete" circle size="small" @click="removeException(index)" />
</div>
<el-button type="primary" :icon="Plus" size="small" @click="addException">添加例外</el-button>
<el-button type="primary" :icon="Plus" size="small" @click="addException">添加休息时间</el-button>
</div>
</el-form-item>
</template>
@@ -361,6 +365,7 @@ interface RuleForm {
};
};
metadata: Record<string, any>;
mainImage?: string;
}
const emit = defineEmits(['getAssetList']);
@@ -450,6 +455,7 @@ const getInitialForm = (): RuleForm => ({
},
},
metadata: {},
mainImage: '',
});
const ruleForm = reactive<RuleForm>(getInitialForm());
@@ -462,11 +468,42 @@ const validateOfflineTime = (_rule: any, value: string, callback: Function) => {
}
};
const disabledOfflineDate = (time: Date) => {
if (!ruleForm.onlineTime) return false;
return time.getTime() < new Date(ruleForm.onlineTime).setHours(0, 0, 0, 0);
};
const validateTimeSlots = (_rule: any, value: TimeSlot[], callback: Function) => {
if (!value || value.length === 0) {
callback(new Error('请至少添加一个服务时间段'));
return;
}
for (let i = 0; i < value.length; i++) {
const slot = value[i];
if (!slot.dayOfWeek || !slot.startTime || !slot.endTime || !slot.capacity) {
callback(new Error(`${i + 1} 行服务时间配置不完整`));
return;
}
}
callback();
};
const onOnlineTimeChange = () => {
if (ruleForm.offlineTime) {
formRef.value?.validateField('offlineTime');
}
};
const rules: FormRules = {
name: [{ required: true, message: '资产名称不能为空', trigger: 'blur' }],
type: [{ required: true, message: '请选择资产类型', trigger: 'change' }],
categoryId: [{ required: true, message: '请选择资产分类', trigger: 'change' }],
offlineTime: [{ validator: validateOfflineTime, trigger: 'change' }],
mainImage: [{ required: true, message: '请上传主图', trigger: 'change' }],
'serviceAssetConfig.booking.minAdvance': [{ required: true, message: '请输入最小提前时间', trigger: 'blur' }],
'serviceAssetConfig.booking.minDuration': [{ required: true, message: '请输入最小时长', trigger: 'blur' }],
'serviceAssetConfig.booking.cancelWindow': [{ required: true, message: '请输入取消提前时间', trigger: 'blur' }],
'serviceAssetConfig.schedule.timeSlots': [{ validator: validateTimeSlots, trigger: 'change' }],
};
// 主图上传处理
@@ -474,6 +511,8 @@ const handleMainImageChange = (file: UploadFile) => {
if (file.raw) {
mainImageFile.value = file.raw;
mainImagePreview.value = URL.createObjectURL(file.raw);
ruleForm.mainImage = 'set'; // 标记已上传
formRef.value?.validateField('mainImage');
}
};
@@ -495,20 +534,34 @@ const handleRemove = (file: UploadFile) => {
// 时间段操作
const addTimeSlot = () => {
if (!ruleForm.serviceAssetConfig.schedule) {
ruleForm.serviceAssetConfig.schedule = { timeSlots: [], exceptions: [] };
}
if (!ruleForm.serviceAssetConfig.schedule.timeSlots) {
ruleForm.serviceAssetConfig.schedule.timeSlots = [];
}
ruleForm.serviceAssetConfig.schedule.timeSlots.push({
dayOfWeek: '1',
startTime: '09:00',
endTime: '18:00',
capacity: 100,
});
formRef.value?.validateField('serviceAssetConfig.schedule.timeSlots');
};
const removeTimeSlot = (index: number) => {
ruleForm.serviceAssetConfig.schedule.timeSlots.splice(index, 1);
formRef.value?.validateField('serviceAssetConfig.schedule.timeSlots');
};
// 例外日期操作
const addException = () => {
if (!ruleForm.serviceAssetConfig.schedule) {
ruleForm.serviceAssetConfig.schedule = { timeSlots: [], exceptions: [] };
}
if (!ruleForm.serviceAssetConfig.schedule.exceptions) {
ruleForm.serviceAssetConfig.schedule.exceptions = [];
}
ruleForm.serviceAssetConfig.schedule.exceptions.push({
exceptionType: 'date',
date: '',
@@ -596,6 +649,7 @@ const openDialog = (row?: any, edit?: boolean) => {
// 主图预览
if (data.imageUrl) {
mainImagePreview.value = formatImageUrl(data.imageUrl);
ruleForm.mainImage = data.imageUrl;
}
// 图片列表
@@ -615,6 +669,31 @@ const openDialog = (row?: any, edit?: boolean) => {
}
if (data.type === 'service' && data.serviceAssetConfig) {
Object.assign(ruleForm.serviceAssetConfig, data.serviceAssetConfig);
// 确保 schedule 对象存在
if (!ruleForm.serviceAssetConfig.schedule) {
ruleForm.serviceAssetConfig.schedule = { timeSlots: [], exceptions: [] };
}
// 确保数组存在,防止后端返回 null 或 undefined 导致 push 报错
if (!ruleForm.serviceAssetConfig.schedule.exceptions) {
ruleForm.serviceAssetConfig.schedule.exceptions = [];
} else {
// 补充缺失的 exceptionType
ruleForm.serviceAssetConfig.schedule.exceptions.forEach((exc) => {
if (!exc.exceptionType) {
if (exc.date) {
exc.exceptionType = 'date';
} else if (exc.dayOfWeek) {
exc.exceptionType = 'dayOfWeek';
} else {
// 默认值
exc.exceptionType = 'date';
}
}
});
}
if (!ruleForm.serviceAssetConfig.schedule.timeSlots) {
ruleForm.serviceAssetConfig.schedule.timeSlots = [];
}
}
// 元数据