mobile/pages/user/my_shop/product_edit.vue
@@ -47,9 +47,13 @@
            <view class="form-item" v-if="form.model.is_preview === 1">
               <view class="item-label">预告开启购买时间</view>
               <picker mode="datetime" class="item-picker" @change="previewTimeChange" :value="previewTimeArray">
               <uni-datetime-picker class="item-picker"
                  :value="previewTime"
                  @change="previewTimeChange"
                  :start="'1970-01-01'"
                  :end="'2030-12-31'">
                  <view class="picker-text">{{ previewTimeText || '请选择预告时间' }}</view>
               </picker>
               </uni-datetime-picker>
            </view>
            <view class="form-item">
@@ -133,6 +137,8 @@
                     @click="form.model.is_virtual = 1">虚拟商品</view>
                  <view class="radio-item" :class="{ active: form.model.is_virtual === 2 }"
                     @click="form.model.is_virtual = 2">券商品</view>
                  <view class="radio-item" :class="{ active: form.model.is_virtual === 3 }"
                     @click="form.model.is_virtual = 3">服务商品</view>
               </view>
            </view>
@@ -165,7 +171,7 @@
            </view>
            <!-- 虚拟商品设置 -->
            <view class="form-item" v-if="form.model.is_virtual === 1">
            <view class="form-item" v-if="form.model.is_virtual === 1 || form.model.is_virtual === 3">
               <view class="item-label">发货类型</view>
               <view class="radio-group">
                  <view class="radio-item" :class="{ active: form.model.virtual_auto === 1 }"
@@ -175,12 +181,17 @@
               </view>
            </view>
            <view class="form-item" v-if="form.model.is_virtual === 1">
            <view class="form-item" v-if="form.model.is_virtual === 1 ">
               <view class="item-label">虚拟内容</view>
               <input class="item-input" v-model="form.model.virtual_content" placeholder="请输入虚拟物品内容" />
            </view>
            <view class="form-item" v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0">
            <view class="form-item" v-if=" form.model.is_virtual === 3">
               <view class="item-label">服务商品内容</view>
               <input class="item-input" v-model="form.model.service_content" placeholder="请输入服务商品内容" />
            </view>
            <view class="form-item" v-if="(form.model.is_virtual === 1 || form.model.is_virtual === 3) && form.model.virtual_auto === 0">
               <view class="item-label">支持线下核销</view>
               <view class="radio-group">
                  <view class="radio-item" :class="{ active: form.model.is_verify === 1 }"
@@ -191,7 +202,7 @@
            </view>
            <view class="form-item"
               v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1">
               v-if="(form.model.is_virtual === 1 || form.model.is_virtual === 3) && form.model.virtual_auto === 0 && form.model.is_verify === 1">
               <view class="item-label">核销到期类型</view>
               <view class="radio-group">
                  <view class="radio-item" :class="{ active: form.model.verify_type === 10 }"
@@ -202,14 +213,14 @@
            </view>
            <view class="form-item"
               v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 10">
               v-if="(form.model.is_virtual === 1 || form.model.is_virtual === 3) && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 10">
               <view class="item-label">核销有效天数</view>
               <input class="item-input" v-model="form.model.verify_day" placeholder="请输入有效天数,0或留空表示永久有效"
                  type="number" />
            </view>
            <view class="form-item"
               v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 20">
               v-if="(form.model.is_virtual === 1 || form.model.is_virtual === 3) && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 20">
               <view class="item-label">核销有效时间</view>
               <picker mode="daterange" class="item-picker" @change="verifyTimeChange" :value="verifyTimeArray">
                  <view class="picker-text">{{ verifyTimeText || '请选择核销有效时间' }}</view>
@@ -310,7 +321,9 @@
                  <view class="item-label">SKU列表</view>
                  <view class="sku-list">
                     <view class="sku-item" v-for="(sku, index) in form.model.spec_many.spec_list" :key="index">
                        <view class="sku-info">{{ sku.spec_text }}</view>
                        <view class="sku-info">
                           <text v-for="(row, rowIdx) in sku.rows" :key="rowIdx">{{ row.spec_value }}{{ rowIdx < sku.rows.length - 1 ? ' ' : '' }}</text>
                        </view>
                        <view class="form-item">
                           <view class="item-label">规格图片</view>
                           <view class="uploader">
@@ -346,15 +359,15 @@
            <view class="form-item">
               <view class="item-label">详情类型</view>
               <view class="radio-group">
                  <view class="radio-item" :class="{ active: form.model.content_type === 10 }"
                     @click="form.model.content_type = 10">图文</view>
                  <view class="radio-item" :class="{ active: form.model.content_type === 20 }"
                     @click="form.model.content_type = 20">纯图</view>
                  <view class="radio-item" :class="{ active: form.model.is_picture == 0 }"
                     @click="form.model.is_picture = 0">图文</view>
                  <view class="radio-item" :class="{ active: form.model.is_picture == 1 }"
                     @click="form.model.is_picture = 1">纯图</view>
               </view>
            </view>
            <!-- 图文类型 -->
            <view v-if="form.model.content_type === 10" class="form-item">
            <view v-if="form.model.is_picture == 0" class="form-item">
               <view class="item-label">商品详情</view>
               <view class="editor">
                  <!-- 富文本编辑器 -->
@@ -445,7 +458,7 @@
            </view>
            <!-- 纯图类型 -->
            <view v-else-if="form.model.content_type === 20" class="form-item">
            <view v-else-if="form.model.is_picture == 1" class="form-item">
               <view class="item-label">商品详情图片</view>
               <view class="uploader">
                  <view class="uploader-item" v-for="(item, index) in form.model.contentImage" :key="index">
@@ -470,7 +483,7 @@
               <view class="item-label">积分设置</view>
               <view class="switch-item">
                  <view class="switch-label">开启积分赠送</view>
                  <switch v-model="form.model.is_points_gift" />
                  <switch :checked="form.model.is_points_gift" v-model="form.model.is_points_gift" />
               </view>
               <view class="switch-item">
                  <view class="switch-label">允许积分抵扣</view>
@@ -487,7 +500,7 @@
               <view class="item-label">团队分红设置</view>
               <view class="switch-item">
                  <view class="switch-label">是否参与团队分红</view>
                  <switch checked v-model="form.model.is_enable_team" />
                  <switch :checked="form.model.is_enable_team==1?true:false" v-model="form.model.is_enable_team" />
               </view>
            </view>
         </view>
@@ -519,6 +532,7 @@
            deliveryIndex: 0,
            // 预告时间相关
            previewTimeArray: [now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes()],
            previewTime: '',
            previewTimeText: '',
            // 核销时间相关
            verifyTimeArray: [],
@@ -548,7 +562,7 @@
                  selling_point: '',
                  spec_type: 10,
                  deduct_stock_type: 20,
                  content_type: 10,
                  is_picture: 0,
                  sku: {
                     product_no: '',
                     product_price: '',
@@ -583,6 +597,7 @@
                  deduction_price: 0,
                  virtual_auto: 0,
                  virtual_content: '',
                  service_content: '',
                  is_preview: 0,
                  preview_time: '',
                  is_verify: 0,
@@ -641,20 +656,52 @@
               product_id: self.productId
            }, (res) => {
               // 合并默认值和后端返回的数据,确保 spec_many 字段始终存在
               Object.assign(self.form, res.data);
               self.form.model = Object.assign({
                  spec_many: {
                     spec_attr: [],
                     spec_list: []
                  }
               }, res.data.model);
               // 处理单规格商品的 sku 字段,后端返回的是数组,前端需要对象
               if (self.form.model.spec_type === 10 && Array.isArray(self.form.model.sku) && self.form.model.sku.length > 0) {
                  self.form.model.sku = self.form.model.sku[0];
               }
               self.form.model.product_status = res.data.model.product_status.value;
               if(self.form.model.delivery_id == 0){
                 self.$set(self.form.model, 'is_delivery_free', 0);
               }else{
                 self.$set(self.form.model, 'is_delivery_free', 1);
               }
               if(self.form.model.notice == null){
                 self.form.model.notice = [];
               }
               //修改时审核状态
               if(self.form.audit_setting.edit_audit == 1 && self.form.scene != 'add'){
                 self.form.model.audit_status = 0;
               }
               if (self.form.model.content) {
                  setTimeout(function(){
                     self.editorCtx.setContents({
                           html: self.form.model.content
                       });
                  },1000)
                   }
               // 设置分类索引
               self.categoryIndex = self.form.category.findIndex(item => item.category_id === self.form
                  .model.category_id);
               self.selectedCategory = self.form.category[self.categoryIndex]?.category_name;
               self.selectedCategory = self.form.category[self.categoryIndex]?.name;
               // 设置运费模板索引
               self.deliveryIndex = self.form.delivery.findIndex(item => item.delivery_id === self.form
                  .model.delivery_id);
               self.selectedDelivery = self.form.delivery[self.deliveryIndex]?.delivery_name;
               self.selectedDelivery = self.form.delivery[self.deliveryIndex]?.name;
               // 设置预告时间
               if (self.form.model.is_preview === 1 && self.form.model.preview_time) {
                  const previewDate = new Date(self.form.model.preview_time * 1000);
                  self.previewTime = previewDate.toISOString().slice(0, 16);
                  self.previewTimeText = self.previewTime;
               }
               self.loading = false;
            });
         },
@@ -692,9 +739,9 @@
         // 选择预告时间
         previewTimeChange(e) {
            const date = new Date(e.detail.value);
            this.form.model.preview_time = date.toISOString().slice(0, 19).replace('T', ' ');
            this.previewTimeText =
               `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
            this.form.model.preview_time = Math.floor(date.getTime() / 1000);
            this.previewTime = e.detail.value;
            this.previewTimeText = e.detail.value;
         },
         // 选择视频
@@ -867,12 +914,52 @@
               placeholderText: '例如:颜色',
               success: (res) => {
                  if (res.confirm && res.content.trim()) {
                     this.form.model.spec_many.spec_attr.push({
                        name: res.content.trim(),
                        values: []
                     const specName = res.content.trim();
                     // 继续输入第一个规格值
                     uni.showModal({
                        title: '添加第一个规格值',
                        content: '',
                        editable: true,
                        placeholderText: '例如:红色',
                        success: (valueRes) => {
                           if (valueRes.confirm && valueRes.content.trim()) {
                              const specValue = valueRes.content.trim();
                              // 调用API添加规格组和第一个规格值
                              this._post('supplier.product.spec/addSpec', {
                                 spec_name: specName,
                                 spec_value: specValue
                              }, (response) => {
                                 if (response.code === 1 && response.data) {
                                    this.form.model.spec_many.spec_attr.push({
                                       group_id: response.data.spec_id,
                                       name: specName,
                                       values: [specValue],
                                       items: [{
                                          item_id: response.data.spec_value_id,
                                          spec_value: specValue
                                       }]
                                    });
                                    // 生成SKU列表
                                    this.generateSkuList();
                                    uni.showToast({
                                       title: '添加成功',
                                       icon: 'success'
                                    });
                                 } else {
                                    uni.showToast({
                                       title: response.msg || '添加失败',
                                       icon: 'none'
                                    });
                                 }
                              });
                           } else if (valueRes.confirm) {
                              uni.showToast({
                                 title: '请输入规格值',
                                 icon: 'none'
                              });
                           }
                        }
                     });
                     // 生成SKU列表
                     this.generateSkuList();
                  }
               }
            });
@@ -894,10 +981,32 @@
               placeholderText: '例如:红色',
               success: (res) => {
                  if (res.confirm && res.content.trim()) {
                     const specValue = res.content.trim();
                     const attr = this.form.model.spec_many.spec_attr[attrIndex];
                     attr.values.push(res.content.trim());
                     // 重新生成SKU列表
                     this.generateSkuList();
                     // 调用API添加规格值
                     this._post('supplier.product.spec/addSpecValue', {
                        spec_id: attr.group_id,
                        spec_value: specValue
                     }, (response) => {
                        if (response.code === 1 && response.data) {
                           attr.values.push(specValue);
                           attr.items.push({
                              item_id: response.data.spec_value_id,
                              spec_value: specValue
                           });
                           // 重新生成SKU列表
                           this.generateSkuList();
                           uni.showToast({
                              title: '添加成功',
                              icon: 'success'
                           });
                        } else {
                           uni.showToast({
                              title: response.msg || '添加失败',
                              icon: 'none'
                           });
                        }
                     });
                  }
               }
            });
@@ -906,11 +1015,13 @@
         // 删除规格值
         deleteSpecValue(attrIndex, valueIndex) {
            const attr = this.form.model.spec_many.spec_attr[attrIndex];
            if (attr.values.length > 1) {
               attr.values.splice(valueIndex, 1);
               // 重新生成SKU列表
               this.generateSkuList();
            attr.values.splice(valueIndex, 1);
            if (attr.items && attr.items.length > valueIndex) {
               attr.items.splice(valueIndex, 1);
            }
            // 重新生成SKU列表
            this.generateSkuList();
         },
         // 生成SKU列表
@@ -926,17 +1037,37 @@
            // 生成SKU列表
            const skuList = combinations.map(comb => {
               const spec_text = comb.map((val, idx) => `${attrs[idx].name}:${val}`).join('; ');
               const rows = [];
               const specSkuIdAttr = [];
               comb.forEach((val, idx) => {
                  const attr = attrs[idx];
                  // 查找对应的 item_id
                  const itemIndex = attr.values.indexOf(val);
                  const itemId = (attr.items && attr.items[itemIndex]) ? attr.items[itemIndex].item_id : 0;
                  rows.push({
                     item_id: itemId,
                     spec_value: val
                  });
                  specSkuIdAttr.push(itemId);
               });
               const spec_sku_id = specSkuIdAttr.join('_');
               return {
                  spec_text,
                  product_sku_id: 0,
                  spec_sku_id,
                  rows,
                  image: [],
                  product_no: '',
                  price: '',
                  line_price: '',
                  stock: '',
                  weight: '',
                  cost_price: '',
                  bar_code: ''
                  spec_form: {
                     product_no: '',
                     product_price: '',
                     line_price: '',
                     stock_num: '',
                     product_weight: '',
                     bar_code: ''
                  }
               };
            });
@@ -1020,7 +1151,7 @@
         save() {
            let self = this;
            // 先获取富文本编辑器内容
            if (self.form.model.content_type === 10 && self.editorCtx) {
            if (self.form.model.is_picture == 0 && self.editorCtx) {
               // 图文类型,获取编辑器内容
               self.editorCtx.getContents({
                  success: (res) => {
@@ -1118,7 +1249,7 @@
            }
            // 根据详情类型验证内容
            if (self.form.model.content_type === 10) {
            if (self.form.model.is_picture == 0) {
               // 图文类型,验证富文本内容
               if (!self.form.model.content || self.form.model.content.trim() === '') {
                  uni.showToast({
@@ -1127,7 +1258,7 @@
                  });
                  return;
               }
            } else if (self.form.model.content_type === 20) {
            } else if (self.form.model.is_picture == 1) {
               // 纯图类型,验证详情图片
               if (self.form.model.contentImage.length === 0) {
                  uni.showToast({
@@ -1138,12 +1269,27 @@
               }
            }
            // 转换spec_attr数据格式为后端期望的格式
            let submitData = JSON.parse(JSON.stringify(self.form.model));
            if (submitData.spec_type == 20 && submitData.spec_many && submitData.spec_many.spec_attr) {
               submitData.spec_many.spec_attr = submitData.spec_many.spec_attr.map(attr => {
                  return {
                     group_id: attr.group_id || 0,
                     name: attr.name,
                     spec_items: attr.values.map((val, idx) => ({
                        item_id: (attr.items && attr.items[idx] && attr.items[idx].item_id) ? attr.items[idx].item_id : 0,
                        spec_value: val
                     }))
                  };
               });
            }
            self.loading = true;
            self._post('supplier.product/edit', {
               product_id: self.productId,
               params: JSON.stringify(self.form.model)
               params: JSON.stringify(submitData)
            }, (res) => {
               if (res.code === 0) {
               if (res.code === 1) {
                  uni.showToast({
                     title: '保存成功'
                  });
@@ -1394,7 +1540,8 @@
   .radio-group {
      display: flex;
      gap: 40rpx;
      gap: 15rpx;
      flex-wrap: wrap;
   }
   .radio-item {