|
@@ -270,6 +270,14 @@
|
|
|
</el-row>
|
|
|
<el-form-item label="商品图片" prop="image">
|
|
|
<Material v-model="imageArr" type="image" :num="1" :width="150" :height="150" />
|
|
|
+ <div class="image-size-tip">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ <span>建议尺寸:800×640px</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="productImageValidation.show" :class="['validation-message', productImageValidation.type]">
|
|
|
+ <i :class="productImageValidation.type === 'warning' ? 'el-icon-warning' : 'el-icon-success'"></i>
|
|
|
+ <span>{{ productImageValidation.message }}</span>
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
<!-- <el-form-item label="商品视频" prop="video">
|
|
|
<div>
|
|
@@ -289,6 +297,14 @@
|
|
|
</el-form-item>-->
|
|
|
<el-form-item label="轮播图" prop="sliderImage">
|
|
|
<Material v-model="photoArr" type="image" :num="10" :width="150" :height="150" />
|
|
|
+ <div class="image-size-tip">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ <span>建议尺寸:300×300px</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="carouselImageValidation.show" :class="['validation-message', carouselImageValidation.type]">
|
|
|
+ <i :class="carouselImageValidation.type === 'warning' ? 'el-icon-warning' : 'el-icon-success'"></i>
|
|
|
+ <span>{{ carouselImageValidation.message }}</span>
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
<el-row>
|
|
|
<el-col :span="24">
|
|
@@ -682,14 +698,52 @@ export default {
|
|
|
},
|
|
|
watch: {
|
|
|
imageArr: function(val) {
|
|
|
- this.form.image = val.join(',')
|
|
|
+ this.form.image = val.join(',');
|
|
|
+ // 验证商品图片
|
|
|
+ if (val.length > 0) {
|
|
|
+ const latestImage = val[val.length - 1];
|
|
|
+ if (latestImage && latestImage.trim()) {
|
|
|
+ this.validateImage(latestImage, 'product');
|
|
|
+ } else {
|
|
|
+ this.productImageValidation.show = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.productImageValidation = { show: false, type: 'success', message: '' };
|
|
|
+ }
|
|
|
},
|
|
|
photoArr: function(val) {
|
|
|
- this.form.sliderImage = val.join(',')
|
|
|
+ this.form.sliderImage = val.join(',');
|
|
|
+ // 验证轮播图片
|
|
|
+ if (val.length > 0) {
|
|
|
+ const latestImage = val[val.length - 1];
|
|
|
+ if (latestImage && latestImage.trim()) {
|
|
|
+ this.validateImage(latestImage, 'carousel');
|
|
|
+ } else {
|
|
|
+ this.carouselImageValidation.show = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.carouselImageValidation = { show: false, type: 'success', message: '' };
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
+ // 图片验证相关
|
|
|
+ productImageValidation: {
|
|
|
+ show: false,
|
|
|
+ type: 'success', // success 或 warning
|
|
|
+ message: ''
|
|
|
+ },
|
|
|
+ carouselImageValidation: {
|
|
|
+ show: false,
|
|
|
+ type: 'success',
|
|
|
+ message: ''
|
|
|
+ },
|
|
|
+ // 尺寸配置
|
|
|
+ sizeConfig: {
|
|
|
+ product: { width: 800, height: 640, tolerance: 0.15 }, // 15%容差
|
|
|
+ carousel: { width: 300, height: 300, tolerance: 0.15 }
|
|
|
+ },
|
|
|
companyId: null,
|
|
|
uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
|
|
|
//videoAccept:"video/*",
|
|
@@ -1053,6 +1107,65 @@ export default {
|
|
|
updateText(text){
|
|
|
this.form.description=text
|
|
|
},
|
|
|
+ // 验证图片尺寸
|
|
|
+ validateImage(imageUrl, type) {
|
|
|
+ if (!imageUrl || !imageUrl.trim()) {
|
|
|
+ const validation = type === 'product' ? this.productImageValidation : this.carouselImageValidation;
|
|
|
+ validation.show = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const img = new Image();
|
|
|
+ const config = this.sizeConfig[type];
|
|
|
+ const validation = type === 'product' ? this.productImageValidation : this.carouselImageValidation;
|
|
|
+
|
|
|
+ // 设置跨域属性,避免CORS问题
|
|
|
+ img.crossOrigin = 'anonymous';
|
|
|
+
|
|
|
+ img.onload = () => {
|
|
|
+ const { width: actualWidth, height: actualHeight } = img;
|
|
|
+ const { width: expectedWidth, height: expectedHeight, tolerance } = config;
|
|
|
+
|
|
|
+ // 计算比例差异
|
|
|
+ const expectedRatio = expectedWidth / expectedHeight;
|
|
|
+ const actualRatio = actualWidth / actualHeight;
|
|
|
+ const ratioDiff = Math.abs(actualRatio - expectedRatio) / expectedRatio;
|
|
|
+
|
|
|
+ validation.show = true;
|
|
|
+
|
|
|
+ if (ratioDiff <= tolerance) {
|
|
|
+ validation.type = 'success';
|
|
|
+ validation.message = `✓ 尺寸符合要求 (实际: ${actualWidth}x${actualHeight}px)`;
|
|
|
+ // 3秒后隐藏成功消息
|
|
|
+ } else {
|
|
|
+ validation.type = 'warning';
|
|
|
+ const typeName = type === 'product' ? '商品图片' : '轮播图片';
|
|
|
+ const expectedRatioText = expectedWidth / expectedHeight === 1.25 ? '5:4' : '1:1';
|
|
|
+ validation.message = `⚠ ${typeName}尺寸不符合要求!实际: ${actualWidth}x${actualHeight}px (${(actualRatio).toFixed(2)}:1),建议: ${expectedWidth}x${expectedHeight}px (${expectedRatioText})`;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ img.onerror = () => {
|
|
|
+ validation.show = true;
|
|
|
+ validation.type = 'warning';
|
|
|
+ validation.message = '图片加载失败,无法验证尺寸,请检查图片URL是否正确';
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理相对路径和绝对路径
|
|
|
+ const fullImageUrl = this.getFullImageUrl(imageUrl);
|
|
|
+ img.src = fullImageUrl;
|
|
|
+ },
|
|
|
+ // 获取完整的图片URL
|
|
|
+ getFullImageUrl(imageUrl) {
|
|
|
+ if (!imageUrl) return '';
|
|
|
+ // 如果是完整的URL,直接返回
|
|
|
+ if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://')) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ // 如果是相对路径,拼接基础URL
|
|
|
+ const baseUrl = process.env.VUE_APP_BASE_API || '';
|
|
|
+ return baseUrl + (imageUrl.startsWith('/') ? imageUrl : '/' + imageUrl);
|
|
|
+ },
|
|
|
handleClick(tab, event) {
|
|
|
this.queryParams.isShow=tab.name;
|
|
|
this.getList();
|
|
@@ -1160,6 +1273,9 @@ export default {
|
|
|
this.attrs=[];
|
|
|
this.photoArr=[];
|
|
|
this.imageArr=[];
|
|
|
+ // 重置验证状态
|
|
|
+ this.productImageValidation = { show: false, type: 'success', message: '' };
|
|
|
+ this.carouselImageValidation = { show: false, type: 'success', message: '' };
|
|
|
},
|
|
|
/** 搜索按钮操作 */
|
|
|
handleQuery() {
|
|
@@ -1259,11 +1375,21 @@ export default {
|
|
|
this.$refs.myeditor.setText(this.form.description);
|
|
|
}
|
|
|
}, 200);
|
|
|
- if(this.form.image!=null){
|
|
|
+ if(this.form.image!=null && this.form.image.trim()){
|
|
|
this.imageArr=this.form.image.split(",");
|
|
|
+ // 验证现有的商品图片
|
|
|
+ const productImages = this.imageArr.filter(img => img && img.trim());
|
|
|
+ if (productImages.length > 0) {
|
|
|
+ this.validateImage(productImages[productImages.length - 1], 'product');
|
|
|
+ }
|
|
|
}
|
|
|
- if(this.form.sliderImage!=null){
|
|
|
+ if(this.form.sliderImage!=null && this.form.sliderImage.trim()){
|
|
|
this.photoArr=this.form.sliderImage.split(",");
|
|
|
+ // 验证现有的轮播图片
|
|
|
+ const carouselImages = this.photoArr.filter(img => img && img.trim());
|
|
|
+ if (carouselImages.length > 0) {
|
|
|
+ this.validateImage(carouselImages[carouselImages.length - 1], 'carousel');
|
|
|
+ }
|
|
|
}
|
|
|
console.log(this.oneFormValidate)
|
|
|
this.open = true;
|
|
@@ -1274,53 +1400,80 @@ export default {
|
|
|
submitForm() {
|
|
|
this.$refs["form"].validate(valid => {
|
|
|
if (valid) {
|
|
|
- if(this.form.specType ===0 ){
|
|
|
- this.form.items = [];
|
|
|
- this.form.values = this.oneFormValidate;
|
|
|
- }else{
|
|
|
- this.form.items = this.attrs;
|
|
|
- this.form.values = this.manyFormValidate;
|
|
|
+ // 检查是否有图片验证警告
|
|
|
+ if (this.productImageValidation.show && this.productImageValidation.type === 'warning') {
|
|
|
+ this.$confirm('商品图片尺寸不符合建议要求,是否继续提交?', '提示', {
|
|
|
+ confirmButtonText: '继续提交',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.doSubmit();
|
|
|
+ }).catch(() => {});
|
|
|
+ return;
|
|
|
}
|
|
|
-
|
|
|
- const hasError = this.form.values.some(v => {
|
|
|
- if (v.hasDepositFeatureType === 1) {
|
|
|
- let depositAmount =Number(v.depositAmount);
|
|
|
- let onBehalfPaymentAmount=Number(v.onBehalfPaymentAmount);
|
|
|
- if (depositAmount < 1) {
|
|
|
- this.$message.warning('数据提交失败,当前商品已开启定金,定金金额不能小于1!');
|
|
|
- return true;
|
|
|
- } else if (onBehalfPaymentAmount < 1) {
|
|
|
- this.$message.warning('数据提交失败,当前商品已开启定金,代付金额不能小于1!');
|
|
|
- return true;
|
|
|
- } else if ((depositAmount + onBehalfPaymentAmount) !== Number(v.price)) {
|
|
|
- this.$message.warning('数据提交失败,当前商品已开启定金,商品定金和代付总和要与售价相等!');
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- });
|
|
|
-
|
|
|
- if (hasError) {
|
|
|
+
|
|
|
+ if (this.carouselImageValidation.show && this.carouselImageValidation.type === 'warning') {
|
|
|
+ this.$confirm('轮播图片尺寸不符合建议要求,是否继续提交?', '提示', {
|
|
|
+ confirmButtonText: '继续提交',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.doSubmit();
|
|
|
+ }).catch(() => {});
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ this.doSubmit();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 执行提交操作
|
|
|
+ doSubmit() {
|
|
|
+ if(this.form.specType ===0 ){
|
|
|
+ this.form.items = [];
|
|
|
+ this.form.values = this.oneFormValidate;
|
|
|
+ }else{
|
|
|
+ this.form.items = this.attrs;
|
|
|
+ this.form.values = this.manyFormValidate;
|
|
|
+ }
|
|
|
|
|
|
- if(this.form.specType === 1 && this.manyFormValidate.length===0){
|
|
|
- return this.$message.warning('请点击生成规格!');
|
|
|
- }
|
|
|
- // 组装companyIds
|
|
|
- if (this.form.companyIds != null && this.form.companyIds != undefined) {
|
|
|
- this.form.companyIds = this.form.companyIds.join(',');
|
|
|
+ const hasError = this.form.values.some(v => {
|
|
|
+ if (v.hasDepositFeatureType === 1) {
|
|
|
+ let depositAmount =Number(v.depositAmount);
|
|
|
+ let onBehalfPaymentAmount=Number(v.onBehalfPaymentAmount);
|
|
|
+ if (depositAmount < 1) {
|
|
|
+ this.$message.warning('数据提交失败,当前商品已开启定金,定金金额不能小于1!');
|
|
|
+ return true;
|
|
|
+ } else if (onBehalfPaymentAmount < 1) {
|
|
|
+ this.$message.warning('数据提交失败,当前商品已开启定金,代付金额不能小于1!');
|
|
|
+ return true;
|
|
|
+ } else if ((depositAmount + onBehalfPaymentAmount) !== Number(v.price)) {
|
|
|
+ this.$message.warning('数据提交失败,当前商品已开启定金,商品定金和代付总和要与售价相等!');
|
|
|
+ return true;
|
|
|
}
|
|
|
- if(this.form.productId !== null && this.form.productId !== undefined && this.form.productId === 0) {
|
|
|
- this.form.productId=null;
|
|
|
- }
|
|
|
- addOrEdit(this.form).then(response => {
|
|
|
- if (response.code === 200) {
|
|
|
- this.msgSuccess("操作成功");
|
|
|
- this.open = false;
|
|
|
- this.getList();
|
|
|
- }
|
|
|
- });
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (hasError) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.form.specType === 1 && this.manyFormValidate.length===0){
|
|
|
+ return this.$message.warning('请点击生成规格!');
|
|
|
+ }
|
|
|
+ // 组装companyIds
|
|
|
+ if (this.form.companyIds != null && this.form.companyIds != undefined) {
|
|
|
+ this.form.companyIds = this.form.companyIds.join(',');
|
|
|
+ }
|
|
|
+ if(this.form.productId !== null && this.form.productId !== undefined && this.form.productId === 0) {
|
|
|
+ this.form.productId=null;
|
|
|
+ }
|
|
|
+ addOrEdit(this.form).then(response => {
|
|
|
+ if (response.code === 200) {
|
|
|
+ this.msgSuccess("操作成功");
|
|
|
+ this.open = false;
|
|
|
+ this.getList();
|
|
|
}
|
|
|
});
|
|
|
},
|
|
@@ -1362,3 +1515,64 @@ export default {
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.image-size-tip {
|
|
|
+ margin-top: 5px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.image-size-tip i {
|
|
|
+ margin-right: 5px;
|
|
|
+ color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message {
|
|
|
+ margin-top: 8px;
|
|
|
+ padding: 6px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ animation: fadeIn 0.3s ease-in;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message i {
|
|
|
+ margin-right: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.success {
|
|
|
+ background-color: #f0f9ff;
|
|
|
+ border: 1px solid #b3d8ff;
|
|
|
+ color: #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.success i {
|
|
|
+ color: #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.warning {
|
|
|
+ background-color: #fdf6ec;
|
|
|
+ border: 1px solid #f5dab1;
|
|
|
+ color: #E6A23C;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.warning i {
|
|
|
+ color: #E6A23C;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes fadeIn {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-5px);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|