java-mall-admin/src/views/product/goodsImg/imgEdit.vue

364 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
title="编辑商品图片"
:visible.sync="visible"
width="800px"
:close-on-click-modal="false"
@close="handleClose"
>
<div class="edit-tip">
正在编辑商品: <strong>{{ formData.name }}</strong>
(条码: {{ formData.barcode || '无条码' }})
</div>
<el-form ref="editForm" :model="formData" label-width="100px" label-position="right">
<!-- 主图编辑 -->
<el-form-item
label="商品主图"
prop="newThumb"
:rules="[
{ required: true, message: '请上传商品主图', trigger: 'change' }
]"
>
<upload
height="100px"
:image="formData.newThumb"
width="100px"
@upImage="handleMainImageUpload"
/>
<div class="el-form-item__error" style="padding-top: 10px;">
<span>支持 JPG, PNG 格式建议尺寸 800x800px</span>
</div>
</el-form-item>
<el-form-item label="商品副图">
<div class="sub-images-container">
<!-- 副图列表 -->
<div v-for="(item, index) in formData.product_image_list" :key="item.id || `sub_${index}`" class="sub-image-item">
<el-image
:src="item.imageUrl"
style="width: 80px; height: 80px; object-fit: cover; border: 1px solid #eee;"
:preview-src-list="[formData.thumb, ...getSubImages(formData.product_image_list)]"
:preview-index="index + 1"
/>
<div class="sub-img-actions">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleEditSubImage(index)"
title="更换图片"
/>
</div>
<!-- 现有副图的隐藏上传组件 -->
<upload
ref="subImageUploadRefs"
class="sub-image-uploader"
height="80px"
width="80px"
:image="item.imageUrl"
@upImage="(url) => handleSubImageUpload(url, index)"
/>
</div>
<!-- 新增副图按钮-->
<div class="add-sub-image" @click="handleAddSubImage">
<i class="el-icon-plus" />
<span>添加副图</span>
</div>
<!-- 新增副图专用的隐藏上传组件 -->
<upload
ref="newSubImageUpload"
class="sub-image-uploader"
height="80px"
width="80px"
:image="''"
@upImage="handleNewSubImageUpload"
v-show="false"
/>
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">{{ __('取消') }}</el-button>
<el-button type="primary" @click="handleSubmit">{{ __('提交修改') }}</el-button>
</template>
</el-dialog>
</template>
<script>
import upload from '@/components/upload'
import { URL } from '@/config'
import { saveBatchBarcode } from '@/api/goodsTool';
export default {
name: 'ImgEdit',
components: {
upload
},
data() {
return {
visible: false,
formData: {
id: '',
name: '',
barcode: '',
thumb: '',
newThumb: '',
product_image_list: [],
original_product_image_list: [],
original_thumb: ''
},
currentEditingSubImageIndex: -1 // 记录当前编辑的现有副图索引
}
},
methods: {
// 获取副图URL列表用于预览
getSubImages(imageList) {
return (imageList || []).map(item => item.imageUrl).filter(url => url);
},
// 打开编辑弹窗
open(row) {
if (!row || !row.id) {
this.$message.error('无效的商品数据');
return;
}
const originalProductImages = JSON.parse(JSON.stringify(row.product_image_list || []));
const originalThumb = row.thumb || '';
this.formData = {
id: row.id,
name: row.name || '未知名称',
barcode: row.barcode || '',
thumb: originalThumb,
newThumb: originalThumb,
original_thumb: originalThumb,
product_image_list: originalProductImages.map(item => {
const { id, productId, imageUrl, seq, status, createdAt, updatedAt } = item;
return { id, productId, imageUrl, seq, status, createdAt, updatedAt };
}),
original_product_image_list: originalProductImages
};
this.visible = true;
this.$nextTick(() => {
this.$refs.editForm?.clearValidate();
});
},
// 关闭弹窗重置数据
handleClose() {
this.visible = false;
this.currentEditingSubImageIndex = -1;
this.formData = {
id: '',
name: '',
thumb: '',
newThumb: '',
product_image_list: [],
original_product_image_list: [],
original_thumb: ''
};
this.$refs.editForm?.clearValidate();
},
// 主图上传
handleMainImageUpload(imageUrl) {
this.formData.newThumb = imageUrl;
},
// 编辑现有副图 - 触发对应上传组件
handleEditSubImage(index) {
this.currentEditingSubImageIndex = index;
this.$nextTick(() => {
const uploadRefs = this.$refs.subImageUploadRefs;
const uploadComp = Array.isArray(uploadRefs) ? uploadRefs[index] : uploadRefs;
this.triggerUploadComp(uploadComp);
});
},
// 点击"添加副图" - 触发新增专用上传组件
handleAddSubImage() {
this.$nextTick(() => {
const uploadComp = this.$refs.newSubImageUpload;
this.triggerUploadComp(uploadComp);
});
},
// 通用触发上传组件的方法兼容不同upload组件实现
triggerUploadComp(uploadComp) {
if (!uploadComp) return;
// 优先调用组件暴露的open方法如果有
if (typeof uploadComp.open === 'function') {
uploadComp.open();
}
// 兼容通过input触发
else if (uploadComp.$el) {
const fileInput = uploadComp.$el.querySelector('input[type="file"]');
if (fileInput) {
fileInput.click();
} else {
this.$message.warning('上传组件初始化中,请稍候');
}
}
},
// 现有副图上传完成 - 只替换URL保留ID等信息
handleSubImageUpload(imageUrl, index) {
if (this.formData.product_image_list[index]) {
this.formData.product_image_list[index].imageUrl = imageUrl;
this.$message.success('副图更新成功');
this.currentEditingSubImageIndex = -1;
}
},
// 新增副图上传完成 - 上传成功后才创建副图条目
handleNewSubImageUpload(imageUrl) {
if (!imageUrl) {
this.$message.warning('请选择有效的图片');
return;
}
// 计算新的排序值
const maxSeq = this.formData.product_image_list.reduce((p, c) => Math.max(p, c.seq || 0), 0);
// 创建新的副图条目ID为null由后端生成
this.formData.product_image_list.push({
id: null,
productId: this.formData.id,
imageUrl: imageUrl, // 直接用上传后的URL
seq: maxSeq + 1,
status: 1,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
});
this.$message.success('新增副图成功');
},
// 提交保存
async handleSubmit() {
try {
await this.$refs.editForm.validate();
const submitData = [
{
id: this.formData.id,
name: this.formData.name,
barcode: this.formData.barcode,
thumb: this.formData.newThumb || this.formData.original_thumb,
product_image_list: this.formData.product_image_list
.filter(item => item.imageUrl)
.map((item, index) => ({
...item,
seq: index + 1 // 重新排序
}))
}
];
console.log('提交数据:', submitData);
const response = await saveBatchBarcode(submitData);
if (response.status === 200) {
this.$message.success('商品图片修改成功!');
this.handleClose();
this.$emit('success');
} else {
this.$message.error('修改失败: ' + (response.msg || '未知错误'));
}
} catch (error) {
console.error('提交失败:', error);
if (error.name !== 'ValidateError') {
this.$message.error('修改失败,请稍后重试');
}
}
},
// 判断副图是否修改
hasSubImagesChanged() {
if (this.formData.product_image_list.length !== this.formData.original_product_image_list.length) {
return true;
}
for (let i = 0; i < this.formData.product_image_list.length; i++) {
const newItem = this.formData.product_image_list[i];
const originalItem = this.formData.original_product_image_list[i];
if (!originalItem || newItem.imageUrl !== originalItem.imageUrl) {
return true;
}
}
return false;
}
}
}
</script>
<style lang="scss" scoped>
.edit-tip {
color: #666;
padding: 8px 12px;
background-color: #f5f7fa;
border-radius: 4px;
margin-bottom: 16px;
font-size: 13px;
}
.sub-images-container {
display: flex;
flex-wrap: wrap;
gap: 15px;
padding: 10px 0;
.sub-image-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
.sub-img-actions {
display: flex;
gap: 5px;
.el-button {
color: #666;
padding: 0;
&:hover { color: #409eff; }
}
}
// 隐藏所有上传组件,只通过按钮触发
.sub-image-uploader {
display: none !important;
}
}
.add-sub-image {
width: 80px;
height: 80px;
border: 1px dashed #ccc;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
color: #999;
.el-icon-plus {
font-size: 20px;
margin-bottom: 5px;
}
&:hover {
border-color: #409eff;
color: #409eff;
}
}
}
::v-deep .el-form-item {
margin-bottom: 20px;
}
</style>