seller/src/views/order/order/orderDetail.vue
@@ -146,7 +146,76 @@
            }}
          </div>
        </div>
          <div class="div-item" >
            <div class="div-item-left">商品模板:</div>
            <div class="div-item-right">
              <template  v-if="orderInfo.orderItems[0] && orderInfo.orderItems[0].goodsCustomizeTemplateVO">
                {{
                   orderInfo.orderItems[0].goodsCustomizeTemplateVO.templateName
                }}
              </template>
              <template v-else>
                暂无
              </template>
            </div>
          </div>
          <div class="div-item" >
            <div class="div-item-left">模板标题:</div>
            <div class="div-item-right">
              <!-- 先逐层判断是否存在,避免报错 -->
              <template v-if="orderInfo.orderItems[0] && orderInfo.orderItems[0].goodsCustomizeTemplateVO && orderInfo.orderItems[0].goodsCustomizeTemplateVO.titles && orderInfo.orderItems[0].goodsCustomizeTemplateVO.titles.length">
                <span
                  v-for="(item, index) in orderInfo.orderItems[0].goodsCustomizeTemplateVO.titles"
                  :key="index"
                >{{ item.templateTitle }}
                <span v-if="index !== orderInfo.orderItems[0].goodsCustomizeTemplateVO.titles.length - 1">、</span>
                </span>
              </template>
              <template v-else>
                暂无
              </template>
            </div>
          </div>
          <div class="div-item">
            <div class="div-item-left">模板图片:</div>
            <div class="div-item-right">
              <!-- 图片列表容器 -->
              <div v-if="hasImages" class="image-list">
                <div
                  class="image-item"
                  v-for="(image, index) in imageList"
                  :key="index"
                  @click="previewImage(index)"
                >
                  <img
                    :src="image.imgUrl"
                    :alt="'模板图片' + (index + 1)"
                    class="small-image"
                    loading="lazy"
                  >
                </div>
              </div>
              <!-- 无图片时显示 -->
              <div v-else >暂无图片</div>
              <!-- 图片预览弹窗 -->
              <div v-if="isPreviewVisible" class="preview-modal" @click="closePreview">
                <div class="preview-content" @click.stop>
                  <img
                    :src="currentPreviewImage"
                    :alt="`预览图片 ${currentPreviewIndex + 1}`"
                    class="preview-image"
                  >
                  <div class="preview-nav">
                    <button class="close-btn" @click="closePreview">×</button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </Col>
      </Row>
    </Card>
@@ -527,7 +596,7 @@
      </div>
    </Modal>
    <!--订单分包裹发货-->
    <Modal v-model="groupShipModal" :loading="shipLoading" title="分包裹发快递" width="1000">
    <Modal v-model="groupShipModal" :loading="shipLoading" title="分包裹发快递" width="1300">
      <div>
        <Form ref="groupOrderDeliveryForm" :model="groupOrderDeliveryForm" :label-width="90" :rules="groupOrderDeliverFormValidate" style="position: relative">
          <FormItem label="物流公司" prop="logisticsId">
@@ -571,7 +640,7 @@
          </div>
        </template>
        <template slot="numSlot" slot-scope="{ row, index }">
          <InputNumber :min="0" :max="row.___num - row.deliverNumber" v-model="data[index].canNum">
          <InputNumber :min="0" :max="row.___num - row.deliverNumber - row.returnGoodsNumber" v-model="data[index].canNum">
          </InputNumber>
        </template>
      </Table>
@@ -600,6 +669,10 @@
  },
  data () {
    return {
      isPreviewVisible: false,
      currentPreviewImage: '',
      currentPreviewIndex: 0,
      loading:false,
      typeList: [],
      showPrices: false,
@@ -760,7 +833,6 @@
            );
          },
        },
        {
          title: "数量",
          key: "num",
@@ -776,6 +848,55 @@
              this.$options.filters.unitPrice(params.row.flowPrice, "¥")
            );
          },
        },
        {
          title: "退款数量",
          key: "returnGoodsNumber",
          minWidth: 80,
        },
        {
          title: "退款金额",
          key: "refundPrice",
          minWidth: 80,
        },
        {
          title: "退款状态",
          key: "isRefund",
          minWidth: 80,
          render:(h, params) => {
            if(params.row.isRefund==='NO_REFUND'){
              return h(
                "div",
                "未退款"
              );
            }else if(params.row.isRefund==='ALL_REFUND'){
              return h(
                "div",
                { style: {color:"red"} },
                "全部退款"
              );
            }else if(params.row.isRefund==='PART_REFUND'){
              return h(
                "div",
                { style: {color:"red"} },
                "部分退款"
              );
            }else if(params.row.isRefund==='REFUNDING'){
              return h(
                "div",
                { style: {color:"red"} },
                "退款中"
              );
            }
            else {
              return h(
                "div",
                { style: {color:"red"} },
                "未知状态"
              );
            }
          }
        },
      ],
      data: [], // 商品表单数据
@@ -807,6 +928,7 @@
      // 分包裹发货
      groupShipModal: false,
      groupShipModalOpened: false, // 标识分包裹发货弹窗是否已打开过
      shipLoading: true,
      groupOrderDeliveryForm: {
        logisticsNo: "", //发货单号
@@ -849,19 +971,110 @@
            return h("div", this.$options.filters.unitPrice(params.row.subTotal, "¥"));
          },
        },
        {
          title: "退款数量",
          key: "returnGoodsNumber",
          minWidth: 80,
        },
        {
          title: "退款金额",
          key: "refundPrice",
          minWidth: 80,
        },
        {
          title: "退款状态",
          key: "isRefund",
          minWidth: 80,
          render:(h, params) => {
            if(params.row.isRefund==='NO_REFUND'){
              return h(
                "div",
                "未退款"
              );
            }else if(params.row.isRefund==='ALL_REFUND'){
              return h(
                "div",
                { style: {color:"red"} },
                "全部退款"
              );
            }else if(params.row.isRefund==='PART_REFUND'){
              return h(
                "div",
                { style: {color:"red"} },
                "部分退款"
              );
            }else if(params.row.isRefund==='REFUNDING'){
              return h(
                "div",
                { style: {color:"red"} },
                "退款中"
              );
            }
            else {
              return h(
                "div",
                { style: {color:"red"} },
                "未知状态"
              );
            }
          }
        },
      ],
      orderPackage: [],
      packageTraceList: []
    };
  },
  computed: {
    // 获取图片列表(处理空值情况)
    imageList() {
      console.log(this.orderInfo.orderItems[0].goodsCustomizeTemplateVO)
      if (this.orderInfo &&
        this.orderInfo.orderItems &&
        this.orderInfo.orderItems[0] &&
        this.orderInfo.orderItems[0].goodsCustomizeTemplateVO &&
        this.orderInfo.orderItems[0].goodsCustomizeTemplateVO.listImages &&
        Array.isArray(this.orderInfo.orderItems[0].goodsCustomizeTemplateVO.listImages)) {
        return this.orderInfo.orderItems[0].goodsCustomizeTemplateVO.listImages;
      }
      return [];
    },
    // 判断是否有图片
    hasImages() {
      return this.imageList.length > 0;
    }
  },
  methods: {
    previewImage(index) {
      if (this.imageList[index]) {
        this.currentPreviewIndex = index;
        this.currentPreviewImage = this.imageList[index].imgUrl;
        this.isPreviewVisible = true;
        // 阻止页面滚动
        document.body.style.overflow = 'hidden';
      }
    },
    // 关闭预览
    closePreview() {
      this.isPreviewVisible = false;
      // 恢复页面滚动
      document.body.style.overflow = '';
    },
    // 选中
    selectGroupShipGoodsMethods (selected) {
      console.log('selectGroupShipGoodsMethods被调用, selected:', JSON.stringify(selected));
      // 简化逻辑,直接保存选中的商品,数量在提交时从data数组获取
      this.selectGroupShipGoods = selected;
      console.log('selectGroupShipGoods已更新');
    },
    // 分包裹发货
    groupShip () {
      this.groupShipModal = true;
      this.groupShipModalOpened = true; // 标记弹窗已打开
      this.groupOrderDeliveryForm = {
        logisticsNo: "", //发货单号
        logisticsId: "", //物流公司
      }
      this.getLogisticsList();
    },
    // 分页获取物流公司
@@ -874,6 +1087,7 @@
    },
    // 分包裹发货
    confirmShipGroupGoods () {
      console.log('表单原始数据--------------------------》',JSON.stringify(this.selectGroupShipGoods))
      this.$refs.groupOrderDeliveryForm.validate(async (valid) => {
        if (valid) {
          if (this.selectGroupShipGoods.length) {
@@ -881,16 +1095,33 @@
              ...this.groupOrderDeliveryForm,
              orderSn: this.sn,
              partDeliveryDTOList: this.selectGroupShipGoods.map((item) => {
                // 直接从data数组中获取最新的canNum值,而不依赖选择时的数据
                const currentDataItem = this.data.find(d => d.id === item.id);
                const finalDeliveryNum = currentDataItem ? currentDataItem.canNum : item.num;
                console.log('处理商品项:', {
                  id: item.id,
                  selectedCanNum: item.canNum,
                  dataCanNum: currentDataItem?.canNum,
                  num: item.num,
                  finalDeliveryNum: finalDeliveryNum
                });
                return {
                  orderItemId: item.id,
                  deliveryNum: item.canNum ? item.canNum : item.num,
                  deliveryNum: finalDeliveryNum,
                };
              }),
            };
            console.log('---------------------->',JSON.stringify(submit));
            const res = await API_Order.partDelivery(this.sn, submit);
            if (res.success) {
              this.$Message.success("发货成功!");
              this.shipLoading = false;
              // 清空选中的商品数据,避免数据残留
              this.selectGroupShipGoods = [];
              // 重置弹窗打开标识,下次打开时显示默认值
              this.groupShipModalOpened = false;
              this.getDataDetail();
              this.getOrderPackage();
              this.groupShipModal = false;
@@ -987,13 +1218,21 @@
          this.allowOperation = res.result.allowOperationVO;
          if (res.result.orderItems.length) {
            this.data = res.result.orderItems.map((item) => {
              // 只在弹窗打开状态下才保留用户修改的canNum值
              const existingItem = this.groupShipModalOpened ? this.data.find(d => d.id === item.id) : null;
              const defaultCanNum = item.num - item.deliverNumber - item.returnGoodsNumber;
              return {
                ...item,
                ___num: item.num,
                _disabled: item.deliverNumber >= item.num,
                canNum: item.num - item.deliverNumber
                // 如果弹窗已打开且用户已经修改过canNum且值合理,则保留;否则使用默认值
                canNum: (existingItem && existingItem.canNum !== undefined && existingItem.canNum <= defaultCanNum)
                  ? existingItem.canNum
                  : defaultCanNum
              };
            });
            console.log('---------------------->订单详情',this.data)
          }
          this.orderLogData = res.result.orderLogs;
          this.typeList = JSON.parse(JSON.stringify(res.result.order.priceDetailDTO.discountPriceDetail));
@@ -1071,6 +1310,7 @@
      }
    },
    logisticsList () {
      this.packageTraceList = []
      this.logisticsModal = true;
      API_Order.getPackage(this.sn).then((res) => {
        if (res.success && res.result != null) {
@@ -1232,6 +1472,89 @@
};
</script>
<style lang="scss" scoped>
.image-list {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  max-width: 600px;
}
.image-item {
  cursor: pointer;
  border: 1px solid #eee;
  border-radius: 4px;
  overflow: hidden;
  transition: transform 0.2s;
}
.image-item:hover {
  transform: scale(1.02);
}
.small-image {
  width: 80px;
  height: 80px;
  object-fit: cover;
}
.no-image {
  color: #999;
  padding: 10px 0;
}
/* 预览弹窗样式 */
.preview-modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.preview-content {
  position: relative;
  max-width: 90%;
  max-height: 90%;
}
.preview-image {
  max-width: 100%;
  object-fit: contain;
}
.preview-nav {
  position: absolute;
  top: -30px;
  right: 0;
  color: white;
  display: flex;
  align-items: center;
  gap: 15px;
}
.preview-count {
  font-size: 14px;
}
.close-btn {
  background: none;
  border: none;
  color: white;
  font-size: 20px;
  cursor: pointer;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
// 建议引入通用样式 可删除下面样式代码
// @import "@/styles/table-common.scss";
.lineH30 {