绿满眶商城微信小程序-uniapp
peng
2025-10-30 c61f03cfe1fcf023c7128f77f3d692aef309f77f
pages/product/m-buy/goods.vue
@@ -1,6 +1,6 @@
<template>
   <div class="wrapper">
      <u-popup class="popup" v-model="buyMask" :height="setup.height" closeable :mode="setup.mode" :border-radius="setup.radius" @close="closeMask()">
      <u-popup class="popup" :value="buyMask" :height="setup.height" closeable :mode="setup.mode" :border-radius="setup.radius" @input="handlePopupInput" @close="closeMask()">
         <!-- 商品 -->
         <view class="goods-box bottom">
            <view class="goods-header">
@@ -102,7 +102,98 @@
                  <uni-number-box class="uNumber" :min="1" :max="999" :disabled="goodsDetail.quantity === 0"  v-model="num"></uni-number-box>
               </view>
               <view class="template">
                  {{JSON.stringify(consumizetemplateInfo)}}
                  <view class="template-title" v-if="consumizetemplateInfo && consumizetemplateInfo.name">
                     <text class="title-text">{{ consumizetemplateInfo.name }}</text>
                  </view>
                  <!-- 图片选择区域 -->
                  <view class="template-images" v-if="consumizetemplateInfo && consumizetemplateInfo.templateImgs && consumizetemplateInfo.templateImgs.length > 0">
                     <view class="images-grid">
                        <view
                           v-for="(img, index) in consumizetemplateInfo.templateImgs"
                           :key="img.id"
                           class="image-item"
                           :class="{ selected: selectedImageObjects.some(selectedImg => selectedImg.id === img.id) }"
                           @click="handleImageClick(img, index)"
                        >
                           <image
                              :src="getFilePreviewUrlSync(img.imgUrl)"
                              class="image-preview"
                              mode="aspectFill"
                           />
                           <view v-if="selectedImageObjects.some(selectedImg => selectedImg.id === img.id)" class="selected-overlay">
                              <uni-icons type="checkmarkempty" size="30" color="#fff"></uni-icons>
                           </view>
                        </view>
                     </view>
                     <!-- 查看选中图片按钮 -->
                     <view class="view-selected-image" v-if="selectedImageObjects.length > 0" @click="viewSelectedImage">
                        查看选中模板图片
                     </view>
                  </view>
                  <!-- 动态表单项 -->
                  <view class="template-form" v-if="consumizetemplateInfo && consumizetemplateInfo.templateConstomizeTitles">
                     <view
                        v-for="(item, index) in consumizetemplateInfo.templateConstomizeTitles"
                        :key="item.id"
                        class="form-item"
                     >
                        <text class="form-label">{{ item.templateTitle }}</text>
                        <!-- 文本输入框 -->
                        <input
                           v-if="item.contentType === 'TEXT'"
                           class="form-input"
                           :value="getFormValue(item.id)"
                           @input="updateFormValue(item.id, item.templateTitle, $event.target.value)"
                           :placeholder="'请输入' + item.templateTitle"
                        />
                        <!-- 图片上传(不使用u-upload组件) -->
                        <view v-if="item.contentType === 'IMAGE'" class="form-upload">
                           <!-- 上传按钮 -->
                           <view class="upload-btn" @click="chooseImage(item.id)">
                              <uni-icons type="plusempty" size="40" color="#999"></uni-icons>
                              <text class="upload-text">点击上传</text>
                           </view>
                           <!-- 图片预览区域 -->
                           <view v-if="imagePreviewUrls[item.id]" class="image-preview-container">
                              <image
                                 :src="imagePreviewUrls[item.id]"
                                 class="uploaded-image"
                                 mode="aspectFill"
                              />
                              <uni-icons
                                 type="closeempty"
                                 class="delete-icon"
                                 @click="deleteImage(item.id)"
                                 size="20"
                                 color="#fff"
                              ></uni-icons>
                           </view>
                           <!-- 上传进度条 -->
                           <progress
                              v-if="uploadProgress[item.id] && uploadProgress[item.id] > 0 && uploadProgress[item.id] < 100"
                              :percent="uploadProgress[item.id]"
                              active-mode="forwards"
                              show-info
                              stroke-width="6"
                              :active="true"
                              active-color="#ff573e"
                              style="margin-top: 10rpx;"
                           />
                           <!-- 上传状态信息 -->
                           <text v-if="uploadStatus[item.id]" class="upload-status">
                              {{ uploadStatus[item.id] }}
                           </text>
                        </view>
                     </view>
                  </view>
               </view>
            </scroll-view>
            <!-- 按钮 -->
@@ -120,6 +211,10 @@
import * as API_trade from '@/api/trade.js';
import setup from './popup';
// import uniNumberBox from '@/components/uni-number-box'
import { getFilePreviewUrl } from "@/api/common.js";
import { getSTSToken } from "@/api/common.js";
import { getFileKey } from "@/utils/file.js";
export default {
   components: {
      // uniNumberBox
@@ -137,7 +232,26 @@
         formatList: [],
         currentSelected: [],
         skuList: '',
         isClose: false //是否可以点击遮罩关闭
         isClose: false, //是否可以点击遮罩关闭
         // 表单相关数据
         selectedImages: [], // 选中的模板图片
         selectedImageObjects: [], // 选中的模板图片对象(包含ID等完整信息)
         formValues: {
            templateId: "", // 模板ID
            templateName: "", // 模板名称
            chooseImage: "", // 选中的图片
            chooseImageId: "", // 选中图片的ID
            templateForm: [] // 表单数组 [{id, templateTitle, value}]
         }, // 表单值
         imagePreviewUrls: {}, // 图片预览URL
         uploadProgress: {}, // 上传进度
         uploadStatus: {}, // 上传状态信息
         cosClient: null, // COS客户端
         bucket: '', // 存储桶
         region: '', // 地域
         endpoint: '', // COS访问endpoint
         previewUrls: {} // 文件预览地址缓存
      };
   },
   props: {
@@ -211,6 +325,7 @@
      buyType: {
         handler(val) {
            if (val) {
               // 使用直接赋值而不是this.$set
               this.buyType = val;
            }
         },
@@ -218,39 +333,359 @@
      },
      selectSkuList: {
         handler(val, oldval) {
            this.$emit('changed', val);
            // 使用setTimeout延迟触发事件,避免影响弹窗
            setTimeout(() => {
               this.$emit('changed', val);
            }, 100);
         },
         deep: true
      },
      'goodsDetail.quantity': {
         handler(val) {
            if (val == 0) {
               uni.showToast({
                  title: '商品已售罄',
                  duration: 2000,
                  icon: 'none'
               })
               // 使用setTimeout延迟显示提示,避免影响弹窗
               setTimeout(() => {
                  uni.showToast({
                     title: '商品已售罄',
                     duration: 2000,
                     icon: 'none'
                  });
               }, 100);
               this.num = 1;
            }
         }
      },
      // 监听模板信息变化
      consumizetemplateInfo: {
         handler(newVal, oldVal) {
            if (newVal) {
               // 使用setTimeout延迟执行,避免影响弹窗
               setTimeout(() => {
                  // 预加载模板图片的预览地址
                  this.preloadTemplateImages();
                  // 初始化模板表单数据
                  this.initTemplateFormData();
                  // 设置默认选中第一张模板图片
                  this.setDefaultSelectedImage();
               }, 100);
            }
         },
         immediate: true,
         deep: true
      }
   },
   methods: {
      // 初始化腾讯云COS客户端
      initCOS() {
         getSTSToken().then(res => {
            const COS = require('@/lib/cos-wx-sdk-v5.js');
            // 使用直接赋值而不是this.$set
            this.cosClient = new COS({
               SecretId: res.data.data.tmpSecretId,
               SecretKey: res.data.data.tmpSecretKey,
               SecurityToken: res.data.data.sessionToken,
               StartTime: res.data.data.stsStartTime,
               ExpiredTime: res.data.data.stsEndTime,
               SimpleUploadMethod: 'putObject'
            });
            this.bucket = res.data.data.bucket;
            this.region = res.data.data.region;
            this.endpoint = res.data.data.endpoint; // 获取endpoint
         }).catch(err => {
            console.error('初始化COS失败', err);
            // 使用setTimeout延迟显示提示,避免影响弹窗
            setTimeout(() => {
               uni.showToast({
                  title: '上传服务初始化失败',
                  icon: 'none'
               });
            }, 100);
         });
      },
      // 获取文件预览地址
      async fetchFilePreviewUrl(fileKey) {
         // 如果是完整的URL,直接返回
         if (fileKey && (fileKey.startsWith('http://') || fileKey.startsWith('https://'))) {
            return fileKey;
         }
         // 如果已经缓存过,直接返回缓存值
         if (this.previewUrls[fileKey]) {
            return this.previewUrls[fileKey];
         }
         // 调用API获取预览地址
         try {
            const res = await getFilePreviewUrl(fileKey);
            const previewUrl = res.data.data;
            // 使用直接赋值而不是this.$set
            this.previewUrls[fileKey] = previewUrl;
            return previewUrl;
         } catch (error) {
            console.error('获取文件预览地址失败', error);
            return fileKey; // 如果获取失败,返回原始值
         }
      },
      // 选择模板图片(单选模式)
      selectImage(imgObject) {
         // 检查当前选中的图片是否就是点击的图片
         const selectedIndex = this.selectedImageObjects.findIndex(selectedImg => selectedImg.id === imgObject.id);
         if (selectedIndex > -1) {
            // 如果点击的是已选中的图片,则取消选择
            this.selectedImageObjects = [];
            this.selectedImages = [];
         } else {
            // 如果点击的是未选中的图片,则选中该图片(清空之前的选择)
            this.selectedImageObjects = [imgObject];
            this.selectedImages = [imgObject.imgUrl];
         }
         // 更新formValues中的chooseImage和chooseImageId
         this.formValues.chooseImage = this.selectedImages.join(',');
         // 将选中图片的ID也存储到formValues中
         this.formValues.chooseImageId = this.selectedImageObjects.map(img => img.id).join(',');
         // 强制更新视图以确保UI正确反映数据变化
         this.$forceUpdate();
      },
      // 选择图片(参考video.vue的实现)
      chooseImage(fieldId) {
         if (!this.cosClient) {
            // 使用setTimeout延迟显示提示,避免影响弹窗
            setTimeout(() => {
               uni.showToast({
                  title: '上传服务未初始化',
                  icon: 'none'
               });
            }, 100);
            // 重新初始化COS
            this.initCOS();
            return;
         }
         uni.chooseImage({
            count: 1,
            sizeType: ['compressed'],
            sourceType: ['album', 'camera'],
            success: (res) => {
               const tempFilePath = res.tempFilePaths[0];
               // 获取文件名
               let fileName = tempFilePath.substring(tempFilePath.lastIndexOf('/') + 1);
               // 处理安卓可能的URI编码
               if(fileName.indexOf('%') > -1) {
                  fileName = decodeURIComponent(fileName);
               }
               // 生成文件key
               const fileKey = getFileKey(fileName);
               // 显示预览图
               this.$set(this.imagePreviewUrls, fieldId, tempFilePath);
               // 初始化上传状态
               this.$set(this.uploadProgress, fieldId, 0);
               this.$set(this.uploadStatus, fieldId, '上传中...');
               // 强制更新视图
               this.$forceUpdate();
               // 执行上传
               this.cosClient.uploadFile({
                  Bucket: this.bucket,
                  Region: this.region,
                  Key: fileKey,
                  FilePath: tempFilePath,
                  SliceSize: 1024 * 1024 * 5, // 5M
                  onProgress: (progressData) => {
                     // 更新上传进度
                     const progress = Math.round(progressData.percent * 100);
                     this.$set(this.uploadProgress, fieldId, progress);
                     // 强制更新视图
                     this.$forceUpdate();
                  }
               }, (err, data) => {
                  // 清除上传进度
                  // 使用Vue.delete或this.$delete可能会触发组件更新,改用直接删除
                  delete this.uploadProgress[fieldId];
                  if (err) {
                     console.error('上传失败', err);
                     // 更新上传状态
                     this.$set(this.uploadStatus, fieldId, '上传失败');
                     // 清除预览图
                     this.$delete(this.imagePreviewUrls, fieldId);
                     // 注意:这里不再需要清除formValues中的字段,因为我们已经修改了数据结构
                     // 强制更新视图
                     this.$forceUpdate();
                     // 使用setTimeout延迟显示错误提示,避免影响弹窗
                     setTimeout(() => {
                        uni.showToast({
                           title: '上传失败',
                           icon: 'none'
                        });
                     }, 100);
                  } else {
                     // 获取当前表单项的信息
                     const currentItem = this.consumizetemplateInfo.templateConstomizeTitles.find(item => item.id === fieldId);
                     const templateTitle = currentItem ? currentItem.templateTitle : '';
                     // 上传成功,更新表单值
                     this.updateFormValue(fieldId, templateTitle, fileKey);
                     // 更新上传状态
                     this.$set(this.uploadStatus, fieldId, '上传成功');
                     // 强制更新视图
                     this.$forceUpdate();
                     // 使用setTimeout延迟显示成功提示,避免影响弹窗
                     setTimeout(() => {
                        uni.showToast({
                           title: '上传成功',
                           icon: 'success'
                        });
                     }, 100);
                  }
               });
            },
            fail: (err) => {
               console.error('选择图片失败', err);
               // 区分用户取消操作和真正的错误
               // 如果是用户主动取消,不显示提示
               if (err.errMsg && err.errMsg.indexOf('cancel') === -1 && err.errMsg.indexOf('fail') !== -1) {
                  // 使用setTimeout延迟显示提示,避免影响弹窗
                  setTimeout(() => {
                     uni.showToast({
                        title: '未选择图片',
                        icon: 'none'
                     });
                  }, 100);
               }
            }
         });
      },
      // 删除图片
      deleteImage(fieldId) {
         // 清除预览图
         this.$delete(this.imagePreviewUrls, fieldId);
         // 清除上传状态
         this.$delete(this.uploadStatus, fieldId);
         // 清除上传进度
         this.$delete(this.uploadProgress, fieldId);
         // 从formValues中移除对应的表单字段
         const index = this.formValues.templateForm.findIndex(item => item.id === fieldId);
         if (index > -1) {
            this.formValues.templateForm.splice(index, 1);
         }
         // 使用setTimeout延迟显示提示,避免影响弹窗
         setTimeout(() => {
            uni.showToast({
               title: '删除成功',
               icon: 'success'
            });
         }, 100);
         // 强制更新视图
         this.$forceUpdate();
      },
      // 获取表单值
      getFormValue(fieldId) {
         const field = this.formValues.templateForm.find(item => item.id === fieldId);
         return field ? field.value : '';
      },
      // 更新表单值
      updateFormValue(fieldId, templateTitle, value) {
         // 更新模板基本信息
         this.formValues.templateId = this.consumizetemplateInfo.id;
         this.formValues.templateName = this.consumizetemplateInfo.name;
         // 查找对应的模板字段以获取contentType
         const templateItem = this.consumizetemplateInfo.templateConstomizeTitles.find(item => item.id === fieldId);
         const contentType = templateItem ? templateItem.contentType : '';
         // 查找是否已存在该字段
         const existingIndex = this.formValues.templateForm.findIndex(item => item.id === fieldId);
         if (existingIndex > -1) {
            // 更新现有字段
            this.$set(this.formValues.templateForm, existingIndex, {
               id: fieldId,
               templateTitle: templateTitle,
               contentType: contentType, // 添加contentType
               value: value
            });
         } else {
            // 添加新字段
            this.formValues.templateForm.push({
               id: fieldId,
               templateTitle: templateTitle,
               contentType: contentType, // 添加contentType
               value: value
            });
         }
      },
      // 更新模板表单数据
      updateTemplateFormData(fieldId, templateTitle, value) {
         // 这个方法现在可以保持不变,因为我们已经在updateFormValue中处理了formValues的更新
         // 如果需要其他处理,可以在这里添加
      },
      // 表单提交处理
      handleFormSubmit() {
         // 确保选中的图片对象也被包含在提交数据中
         const formData = {
            ...this.formValues,
            selectedImageObjects: this.selectedImageObjects
         };
         console.log('表单数据:', formData);
         // 这里可以添加实际的表单提交逻辑
         // 使用setTimeout延迟显示提示,避免影响弹窗
         setTimeout(() => {
            uni.showToast({
               title: '表单提交成功',
               icon: 'success'
            });
         }, 100);
      },
      numCheck(val) {
         if (this.wholesaleList && this.wholesaleList.length > 0) {
            if (this.num <= this.wholesaleList[0].num) {
               uni.showToast({
                  title: '批发商品购买数量不能小于起批数量!',
                  duration: 2000,
                  icon: 'none'
               });
               // 使用setTimeout延迟显示提示,避免影响弹窗
               setTimeout(() => {
                  uni.showToast({
                     title: '批发商品购买数量不能小于起批数量!',
                     duration: 2000,
                     icon: 'none'
                  });
               }, 100);
               this.num = this.wholesaleList[0].num;
            }
         }
      },
      closeMask() {
         this.$emit('closeBuy', false);
      },
      // 处理弹窗输入事件,避免直接修改prop
      handlePopupInput(val) {
         this.$emit('closeBuy', val);
      },
      
      /**点击规格 */
@@ -285,11 +720,14 @@
               goodsId: this.goodsDetail.goodsId
            });
         } else {
            uni.showToast({
               title: '暂无该商品!',
               duration: 2000,
               icon: 'none'
            });
            // 使用setTimeout延迟显示提示,避免影响弹窗
            setTimeout(() => {
               uni.showToast({
                  title: '暂无该商品!',
                  duration: 2000,
                  icon: 'none'
               });
            }, 100);
         }
      },
@@ -299,9 +737,12 @@
      buy(data) {
         API_trade.addToCart(data).then(res => {
            if (res.data.success) {
               uni.navigateTo({
                  url: `/pages/order/fillorder?way=${data.cartType}&addr=${''}&parentOrder=${encodeURIComponent(JSON.stringify(this.parentOrder))}`
               });
               // 使用setTimeout延迟跳转,避免影响弹窗
               setTimeout(() => {
                  uni.navigateTo({
                     url: `/pages/order/fillorder?way=${data.cartType}&addr=${''}&parentOrder=${encodeURIComponent(JSON.stringify(this.parentOrder))}`
                  });
               }, 100);
            }
         });
      },
@@ -310,11 +751,23 @@
       * 添加到购物车或购买
       */
      addToCartOrBuy(val) {
         // 检查商品是否需要模板并且模板数据是否完整
         if (this.consumizetemplateInfo && this.consumizetemplateInfo.id) {
            const isValid = this.validateTemplateData();
            if (!isValid) {
               return;
            }
         }
         console.log(JSON.stringify(this.formValues))
         if (!this.selectSkuList) {
            uni.showToast({
               title: '请选择规格商品',
               icon: 'none'
            });
            // 使用setTimeout延迟显示提示,避免影响弹窗
            setTimeout(() => {
               uni.showToast({
                  title: '请选择规格商品',
                  icon: 'none'
               });
            }, 100);
            return;
         }
         let data = {
@@ -325,10 +778,13 @@
         if (val == 'cart') {
            API_trade.addToCart(data).then(res => {
               if (res.data.code == 200) {
                  uni.showToast({
                     title: '商品已添加到购物车',
                     icon: 'none'
                  });
                  // 使用setTimeout延迟显示提示,避免影响弹窗
                  setTimeout(() => {
                     uni.showToast({
                        title: '商品已添加到购物车',
                        icon: 'none'
                     });
                  }, 100);
                  this.$emit('queryCart');
                  this.closeMask();
@@ -344,14 +800,73 @@
               data.cartType = 'BUY_NOW';
            }
            // 创建包含图片ID的完整表单数据
            const templateData = {
               ...this.formValues,
               selectedImageObjects: this.selectedImageObjects
            };
            API_trade.addToCart(data).then(res => {
               if (res.data.code == 200) {
                  uni.navigateTo({
                     url: `/pages/order/fillorder?way=${data.cartType}&addr=${this.addr.id || ''}&parentOrder=${encodeURIComponent(JSON.stringify(this.parentOrder))}`
                  });
                  // 使用setTimeout延迟跳转,避免影响弹窗
                  setTimeout(() => {
                     uni.navigateTo({
                        url: `/pages/order/fillorder?way=${data.cartType}&addr=${this.addr.id || ''}&template=${encodeURIComponent(JSON.stringify(templateData))}&parentOrder=${encodeURIComponent(JSON.stringify(this.parentOrder))}`
                     });
                  }, 100);
               }
            });
         }
      },
      /**
       * 验证模板数据是否完整
       */
      validateTemplateData() {
         // 检查模板图片是否已选择(如果有模板图片)
         if (this.consumizetemplateInfo.templateImgs &&
            this.consumizetemplateInfo.templateImgs.length > 0 &&
            this.selectedImageObjects.length === 0) {
            setTimeout(() => {
               uni.showToast({
                  title: '请选择模板图片',
                  icon: 'none'
               });
            }, 100);
            return false;
         }
         // 检查动态表单项是否已填写
         if (this.consumizetemplateInfo.templateConstomizeTitles) {
            for (const item of this.consumizetemplateInfo.templateConstomizeTitles) {
               const formItem = this.formValues.templateForm.find(formItem => formItem.id === item.id);
               // 如果表单项不存在或者值为空
               if (!formItem || !formItem.value || formItem.value.trim() === '') {
                  setTimeout(() => {
                     uni.showToast({
                        title: `请填写${item.templateTitle}`,
                        icon: 'none'
                     });
                  }, 100);
                  return false;
               }
               // 特别检查图片类型的表单项是否有上传
               if (item.contentType === 'IMAGE' &&
                  (!this.imagePreviewUrls[item.id] || this.imagePreviewUrls[item.id].trim() === '')) {
                  setTimeout(() => {
                     uni.showToast({
                        title: `请上传${item.templateTitle}`,
                        icon: 'none'
                     });
                  }, 100);
                  return false;
               }
            }
         }
         return true;
      },
      formatSku(list) {
         // 格式化数据
@@ -380,6 +895,7 @@
                        return i.value === values.value;
                     })
                  ) {
                     // 使用直接赋值而不是this.$set
                     arrItem.values.push(values);
                  }
@@ -387,6 +903,7 @@
                     return key.name;
                  });
                  if (!keys.includes(name)) {
                     // 使用直接赋值而不是this.$set
                     arr.push({
                        name: name,
                        values: [values]
@@ -397,6 +914,7 @@
         });
         arr.shift();
         // 使用直接赋值而不是this.$set
         this.formatList = arr;
         list.forEach(item => {
@@ -405,6 +923,7 @@
               item.specValues
                  .filter(i => i.specName !== 'images')
                  .forEach((value, _index) => {
                     // 使用直接赋值而不是this.$set
                     this.currentSelected[_index] = value.specValue;
                     this.selectName = value.specValue;
@@ -417,15 +936,127 @@
            }
         });
         // 使用直接赋值而不是this.$set
         this.skuList = list;
         // console.log(" this.skuList", this.skuList)
      },
      // 预加载模板图片的预览地址
      async preloadTemplateImages() {
         if (this.consumizetemplateInfo && this.consumizetemplateInfo.templateImgs) {
            for (const img of this.consumizetemplateInfo.templateImgs) {
               await this.fetchFilePreviewUrl(img.imgUrl);
            }
         }
      },
      // 获取文件预览地址(同步版本)
      getFilePreviewUrlSync(fileKey) {
         // 如果是完整的URL,直接返回
         if (fileKey && (fileKey.startsWith('http://') || fileKey.startsWith('https://'))) {
            return fileKey;
         }
         // 如果有预览地址,返回预览地址
         if (this.previewUrls && this.previewUrls[fileKey]) {
            return this.previewUrls[fileKey];
         }
         // 如果没有http前缀,需要拼接endpoint进行显示
         if (fileKey && !fileKey.startsWith('http://') && !fileKey.startsWith('https://')) {
            // 使用endpoint拼接完整的URL
            if (this.endpoint) {
               return this.endpoint + '/' + fileKey;
            }
         }
         // 否则返回原始值
         return fileKey;
      },
      // 初始化模板表单数据
      initTemplateFormData() {
         if (this.consumizetemplateInfo && this.consumizetemplateInfo.templateConstomizeTitles) {
            // 初始化formValues的基本信息
            this.formValues.templateId = this.consumizetemplateInfo.id;
            this.formValues.templateName = this.consumizetemplateInfo.name;
            this.formValues.chooseImage = "";
            this.formValues.chooseImageId = "";
            this.formValues.templateForm = [];
            // 初始化选中的图片对象数组和图片URL数组
            this.selectedImageObjects = [];
            this.selectedImages = [];
         }
      },
      // 预览模板图片
      previewImage(imgObject, index) {
         // 只预览当前选中的图片
         const urls = [this.getFilePreviewUrlSync(imgObject.imgUrl)];
         // 调用uniapp原生API预览图片
         uni.previewImage({
            current: 0, // 当前显示图片的索引(只有一张图片,所以是0)
            urls: urls, // 需要预览的图片链接列表
            indicator: 'default', // 显示索引指示器
            loop: false // 只有一张图片,不需要循环预览
         });
      },
      // 处理模板图片点击事件(既可以预览又可以选中)
      handleImageClick(imgObject, index) {
         // 检查当前图片是否已选中
         const isSelected = this.selectedImageObjects.some(selectedImg => selectedImg.id === imgObject.id);
         if (isSelected) {
            // 如果已选中,则预览图片
            this.previewImage(imgObject, index);
         } else {
            // 如果未选中,则选中图片
            this.selectImage(imgObject);
         }
      },
      // 查看选中的图片
      viewSelectedImage() {
         // 检查是否有选中的图片
         if (this.selectedImageObjects.length > 0) {
            // 获取第一个选中的图片(因为是单选模式)
            const selectedImage = this.selectedImageObjects[0];
            // 预览选中的图片
            this.previewImage(selectedImage, 0);
         }
      },
      // 设置默认选中第一张模板图片
      setDefaultSelectedImage() {
         // 检查是否有模板图片且当前没有选中任何图片
         if (this.consumizetemplateInfo &&
            this.consumizetemplateInfo.templateImgs &&
            this.consumizetemplateInfo.templateImgs.length > 0 &&
            this.selectedImageObjects.length === 0) {
            // 选中第一张图片
            const firstImage = this.consumizetemplateInfo.templateImgs[0];
            this.selectImage(firstImage);
         }
      }
   },
   mounted() {
      this.formatSku(this.goodsSpec);
      // 使用setTimeout延迟执行,避免影响弹窗
      setTimeout(() => {
         this.formatSku(this.goodsSpec);
         this.initCOS(); // 初始化COS客户端
         // 预加载模板图片的预览地址
         this.preloadTemplateImages();
      console.log("goodsDetail",this.goodsDetail)
         // 初始化模板表单数据
         this.initTemplateFormData();
         // 默认选中第一张模板图片
         this.setDefaultSelectedImage();
         console.log("goodsDetail",this.goodsDetail)
      }, 100);
   }
};
</script>
@@ -580,4 +1211,147 @@
      color: #333;
   }
}
</style>
// 模板样式
.template {
   padding: 20rpx;
}
.template-title {
   margin-bottom: 30rpx;
   text-align: center;
}
.title-text {
   font-size: 36rpx;
   font-weight: bold;
}
// 查看选中图片按钮样式
.view-selected-image {
   margin-top: 20rpx;
   padding: 30rpx;
   text-align: center;
   background-color: #f0f0f0;
   border-radius: 10rpx;
   color: #333;
   font-size: 28rpx;
}
// 图片选择区域
.template-images {
   margin-bottom: 40rpx;
}
.images-grid {
   display: flex;
   flex-wrap: wrap;
   gap: 20rpx;
}
.image-item {
   width: calc((100% - 40rpx) / 3);
   height: 200rpx;
   border: 2rpx solid #e0e0e0;
   border-radius: 10rpx;
   overflow: hidden;
   position: relative;
   &.selected {
      border-color: #ff6b00;
      box-shadow: 0 0 10rpx rgba(255, 107, 0, 0.5);
   }
}
.selected-overlay {
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   background-color: rgba(0, 0, 0, 0.3);
   display: flex;
   align-items: center;
   justify-content: center;
}
.image-preview {
   width: 100%;
   height: 100%;
}
// 表单区域
.template-form {
}
.form-item {
   margin-bottom: 30rpx;
}
.form-label {
   display: block;
   margin-bottom: 15rpx;
   font-size: 28rpx;
   color: #333;
}
.form-input {
   width: 100%;
   height: 80rpx;
   padding: 0 20rpx;
   border: 2rpx solid #e0e0e0;
   border-radius: 10rpx;
   font-size: 28rpx;
   box-sizing: border-box;
}
.form-upload {
   margin-top: 15rpx;
}
// 图片上传样式
.upload-btn {
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
   width: 150rpx;
   height: 150rpx;
   border: 2rpx dashed #ccc;
   border-radius: 10rpx;
   background-color: #f8f8f8;
}
.upload-text {
   font-size: 24rpx;
   color: #999;
   margin-top: 10rpx;
}
.image-preview-container {
   position: relative;
   width: 150rpx;
   height: 150rpx;
   margin-top: 10rpx;
}
.uploaded-image {
   width: 100%;
   height: 100%;
   border-radius: 10rpx;
}
.delete-icon {
   position: absolute;
   top: -10rpx;
   right: -10rpx;
   background-color: #ff6b00;
   border-radius: 50%;
   width: 30rpx;
   height: 30rpx;
   display: flex;
   align-items: center;
   justify-content: center;
}
</style>