完善主图预览删除操作,优化元数据处理逻辑

This commit is contained in:
WUSIJIAN
2025-12-23 13:42:52 +08:00
parent f30ddaf400
commit 95da8576bc

View File

@@ -69,7 +69,11 @@
<el-divider content-position="left">分类属性</el-divider> <el-divider content-position="left">分类属性</el-divider>
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8" v-for="(attr, index) in categoryAttrs" :key="index"> <el-col :span="8" v-for="(attr, index) in categoryAttrs" :key="index">
<el-form-item :label="getAttrLabel(attr)"> <el-form-item
:label="getAttrLabel(attr)"
:prop="'metadata.' + getAttrKey(attr)"
:rules="[{ required: true, message: getAttrLabel(attr) + '不能为空', trigger: ['blur', 'change'] }]"
>
<!-- 单选类型 --> <!-- 单选类型 -->
<el-select <el-select
v-if="attr.type === 'select'" v-if="attr.type === 'select'"
@@ -127,15 +131,33 @@
v-model="ruleForm.metadata[getAttrKey(attr)]" v-model="ruleForm.metadata[getAttrKey(attr)]"
/> />
<!-- 图片类型 --> <!-- 图片类型 -->
<div v-else-if="attr.type === 'image'" class="w100">
<el-upload <el-upload
v-else-if="attr.type === 'image'"
class="attr-image-uploader" class="attr-image-uploader"
:show-file-list="false" :show-file-list="false"
:auto-upload="false" :auto-upload="false"
accept="image/*" accept="image/*"
:on-change="onAttrImageChange(attr)"
> >
<el-button type="primary" size="small">上传图片</el-button> <img
v-if="ruleForm.metadata[getAttrKey(attr)]"
:src="formatImageUrl(ruleForm.metadata[getAttrKey(attr)])"
class="avatar"
style="width: 80px; height: 80px"
/>
<el-icon v-else class="avatar-uploader-icon" style="width: 80px; height: 80px; line-height: 80px"><Plus /></el-icon>
</el-upload> </el-upload>
<el-button
v-if="ruleForm.metadata[getAttrKey(attr)]"
type="danger"
link
size="small"
@click.stop="removeAttrImage(attr)"
style="margin-top: 5px"
>
删除图片
</el-button>
</div>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -146,6 +168,7 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="主图" prop="mainImage"> <el-form-item label="主图" prop="mainImage">
<div class="w100">
<el-upload <el-upload
class="avatar-uploader" class="avatar-uploader"
:show-file-list="false" :show-file-list="false"
@@ -156,6 +179,11 @@
<img v-if="mainImagePreview" :src="mainImagePreview" class="avatar" /> <img v-if="mainImagePreview" :src="mainImagePreview" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon> <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload> </el-upload>
<div v-if="mainImagePreview" style="margin-top: 5px">
<el-button type="primary" link size="small" @click.stop="previewMainImage">预览</el-button>
<el-button type="danger" link size="small" @click.stop="removeMainImage">删除</el-button>
</div>
</div>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="16"> <el-col :span="16">
@@ -395,6 +423,7 @@ const getAttrLabel = (attr: CategoryAttr): string => {
const mainImageFile = ref<File | null>(null); const mainImageFile = ref<File | null>(null);
const mainImagePreview = ref(''); const mainImagePreview = ref('');
const imageFileList = ref<UploadUserFile[]>([]); const imageFileList = ref<UploadUserFile[]>([]);
const attrImageFiles = ref<Record<string, File>>({}); // 暂存属性图片文件
const dialogVisible = ref(false); const dialogVisible = ref(false);
const dialogImageUrl = ref(''); const dialogImageUrl = ref('');
// 图片拼接 // 图片拼接
@@ -403,6 +432,7 @@ const imgAddressPrefix = ref('');
const formatImageUrl = (url?: string) => { const formatImageUrl = (url?: string) => {
if (!url) return ''; if (!url) return '';
if (/^https?:\/\//i.test(url)) return url; if (/^https?:\/\//i.test(url)) return url;
if (/^blob:/i.test(url)) return url; // 支持本地预览地址
return `${imgAddressPrefix.value || ''}${url}`; return `${imgAddressPrefix.value || ''}${url}`;
}; };
@@ -516,6 +546,22 @@ const handleMainImageChange = (file: UploadFile) => {
} }
}; };
// 主图预览
const previewMainImage = () => {
if (mainImagePreview.value) {
dialogImageUrl.value = mainImagePreview.value;
dialogVisible.value = true;
}
};
// 主图删除
const removeMainImage = () => {
mainImageFile.value = null;
mainImagePreview.value = '';
ruleForm.mainImage = '';
formRef.value?.validateField('mainImage');
};
// 图片列表预览 // 图片列表预览
const handlePictureCardPreview = (file: UploadFile) => { const handlePictureCardPreview = (file: UploadFile) => {
console.log(file,'111'); console.log(file,'111');
@@ -532,6 +578,32 @@ const handleRemove = (file: UploadFile) => {
} }
}; };
// 属性图片上传处理
const handleAttrImageChange = (file: UploadFile, attr: CategoryAttr) => {
if (file.raw) {
const key = getAttrKey(attr);
const url = URL.createObjectURL(file.raw);
ruleForm.metadata[key] = url;
attrImageFiles.value[key] = file.raw;
formRef.value?.validateField(`metadata.${key}`);
}
};
// 生成属性图片上传回调
const onAttrImageChange = (attr: CategoryAttr) => {
return (file: UploadFile) => handleAttrImageChange(file, attr);
};
// 移除属性图片
const removeAttrImage = (attr: CategoryAttr) => {
const key = getAttrKey(attr);
ruleForm.metadata[key] = '';
if (attrImageFiles.value[key]) {
delete attrImageFiles.value[key];
}
formRef.value?.validateField(`metadata.${key}`);
};
// 时间段操作 // 时间段操作
const addTimeSlot = () => { const addTimeSlot = () => {
if (!ruleForm.serviceAssetConfig.schedule) { if (!ruleForm.serviceAssetConfig.schedule) {
@@ -591,6 +663,7 @@ const resetForm = () => {
mainImageFile.value = null; mainImageFile.value = null;
mainImagePreview.value = ''; mainImagePreview.value = '';
imageFileList.value = []; imageFileList.value = [];
attrImageFiles.value = {};
categoryAttrs.value = []; categoryAttrs.value = [];
imgAddressPrefix.value = ''; imgAddressPrefix.value = '';
}; };
@@ -618,6 +691,13 @@ const onCategoryChange = (categoryId: string) => {
const data = res.data; const data = res.data;
if (data?.attrs && Array.isArray(data.attrs)) { if (data?.attrs && Array.isArray(data.attrs)) {
categoryAttrs.value = data.attrs; categoryAttrs.value = data.attrs;
// 初始化属性值,确保 boolean 类型默认为 false
data.attrs.forEach((attr: CategoryAttr) => {
const key = getAttrKey(attr);
if (attr.type === 'boolean') {
ruleForm.metadata[key] = false;
}
});
} }
}) })
.catch(() => { .catch(() => {
@@ -708,6 +788,13 @@ const openDialog = (row?: any, edit?: boolean) => {
const catData = catRes.data; const catData = catRes.data;
if (catData?.attrs && Array.isArray(catData.attrs)) { if (catData?.attrs && Array.isArray(catData.attrs)) {
categoryAttrs.value = catData.attrs; categoryAttrs.value = catData.attrs;
// 初始化属性值,确保 boolean 类型默认为 false
catData.attrs.forEach((attr: CategoryAttr) => {
const key = getAttrKey(attr);
if (attr.type === 'boolean' && ruleForm.metadata[key] === undefined) {
ruleForm.metadata[key] = false;
}
});
} }
}) })
.catch(() => { .catch(() => {
@@ -773,9 +860,22 @@ const buildFormData = (): FormData => {
formData.append('serviceAssetConfig', JSON.stringify(ruleForm.serviceAssetConfig)); formData.append('serviceAssetConfig', JSON.stringify(ruleForm.serviceAssetConfig));
} }
// 属性图片
Object.keys(attrImageFiles.value).forEach((key) => {
formData.append(key, attrImageFiles.value[key]);
});
// 元数据(分类属性值) // 元数据(分类属性值)
if (Object.keys(ruleForm.metadata).length > 0) { if (Object.keys(ruleForm.metadata).length > 0) {
formData.append('metadata', JSON.stringify(ruleForm.metadata)); // 过滤掉 blob url避免传给后端
const metadataToSend = { ...ruleForm.metadata };
Object.keys(metadataToSend).forEach((key) => {
if (typeof metadataToSend[key] === 'string' && metadataToSend[key].startsWith('blob:')) {
// 如果有对应的文件在 attrImageFiles 中,则置空或不传,这里选择置空
metadataToSend[key] = '';
}
});
formData.append('metadata', JSON.stringify(metadataToSend));
} }
return formData; return formData;