Explorar o código

fix(goodsCollection): 移除商品收藏页面图片默认占位符

移除了商品收藏列表中图片的默认占位符路径,现在将直接使用 item.pic
作为图片源,避免在图片不存在时显示默认订单图标。
zouzexu hai 1 mes
pai
achega
b2dc95cd6d

+ 2 - 1
.claude/settings.local.json

@@ -4,7 +4,8 @@
       "WebFetch(domain:www.iconfont.cn)",
       "WebSearch",
       "Bash(curl -sL \"https://at.alicdn.com/t/c/font_4626013_vwpx4thmin.css\" -o /tmp/iconfont_cdn.css)",
-      "Read(//tmp/**)"
+      "Read(//tmp/**)",
+      "Bash(npx vue-tsc *)"
     ]
   }
 }

+ 72 - 5
src/api/api.type.d.ts

@@ -1423,18 +1423,53 @@ namespace Api {
   }
   interface AppletOrderSkuVo {
     /**
-     * 总计
+     * 第三方的 津贴/券id
      */
-    totalPrice: number
-
+    allowanceId?: string
+    /**
+     * 优惠券金额
+     */
+    coupon?: number
+    /**
+     * 优惠券展示文案
+     */
+    couponText?: string
+    /**
+     * 是否包邮 0-不包邮 1包邮
+     */
+    isFreeShipping?: number
+    /**
+     * 会员权益说明
+     */
+    memberBenefitDesc?: string
+    /**
+     * 会员优惠金额
+     */
+    memberDiscountAmount?: number
+    /**
+     * 会员折扣率,0.95表示9.5折
+     */
+    memberDiscountRate?: number
+    /**
+     * 会员价(折扣后单价)
+     */
+    memberPrice?: number
     /**
      * offsetPoints
      */
     offsetPoints?: number
+    /**
+     * 优惠券列表
+     */
+    orderCouponItemDTOS?: OrderCouponItemDTO[]
     /**
      * price
      */
     price?: number
+    /**
+     * 店铺地址信息
+     */
+    shopAddressDTO?: ShopAddressDTO
     /**
      * shopName
      */
@@ -1442,13 +1477,34 @@ namespace Api {
     /**
      * sku
      */
-    sku?: SkuConfirmVo
+    sku?: SkuConfirmVo[]
     /**
      * 店铺地址信息
      */
     shopAddressDTO?: ShopAddressDTO
     [property: string]: any
   }
+  export interface ShopSkuDTO {
+    /**
+     * 数量
+     */
+    num?: number
+    /**
+     * 商品id
+     */
+    skuId?: number
+  }
+  export interface AddressFreeShippingCheckVo {
+    addressFreeShippingVo?: AddressFreeShippingVo
+    check?: boolean
+    [property: string]: any
+  }
+  export interface AddressFreeShippingVo {
+    isFreeShipping?: number
+    totalPrice?: number
+    transfee?: number
+    [property: string]: any
+  }
   /**
    * 店铺地址信息
    */
@@ -1480,6 +1536,14 @@ namespace Api {
      * 0 正常 1 已被删除
      */
     isDelete?: string
+    /**
+     * 会员价(折扣后单价)
+     */
+    memberPrice?: number
+    /**
+     * 商品数量
+     */
+    num?: number
     /**
      * pic
      */
@@ -1504,7 +1568,10 @@ namespace Api {
      * spec
      */
     spec?: string
-    [property: string]: any
+    /**
+     * 商品重量
+     */
+    weight?: number
   }
   interface smqjhCategoryList {
     /**

+ 3 - 1
src/api/apiDefinitions.ts

@@ -60,7 +60,8 @@ export default {
   'xsb.orderInfo':['GET', '/smqjh-oms/api/v1/order/orderInfo'],
   'xsb.cancelOrder':['GET', '/smqjh-oms/api/v1/order/cancelOrder'],
   'xsb.deleteOrder':['DELETE', '/smqjh-oms/api/v1/order/deleteOrder/{ids}'],
-  'xsb.skuOrderConfirm':['POST', '/smqjh-oms/api/v1/order/skuOrderConfirmNew'],
+  'xsb.skuOrderConfirm':['POST', '/smqjh-oms/api/v1/order/skuOrderConfirmListNew'],
+  // 'xsb.skuOrderConfirm':['POST', '/smqjh-oms/api/v1/order/skuOrderConfirmNew'],
   // 'xsb.skuOrderConfirm':['GET', '/smqjh-oms/api/v1/order/skuOrderConfirm'],
   'xsb.myShoppingCartCategory':['GET', '/smqjh-oms/app-api/v1/shoppingCart/myShoppingCartCategory'],
   'xsb.delivery':['GET', '/smqjh-system/app-api/v1/delivery'],
@@ -83,6 +84,7 @@ export default {
   'xsb.cancelCollect':['GET', '/smqjh-oms/app-api/v1/collect/goodsInfoCancelCollect'],
   'xsb.myCollect':['GET', '/smqjh-oms/app-api/v1/collect/myCollect'],
   'xsb.batchCancelCollect':['DELETE', '/smqjh-oms/app-api/v1/collect/{ids}'],
+  'xsb.addressFreeShippingCheck':['GET', '/smqjh-oms/api/v1/order/addressFreeShippingCheck'],
 
   'common.myShoppingCart':['GET', '/smqjh-oms/app-api/v1/shoppingCart/myShoppingCart'],
   'common.addShoppingCart':['POST', '/smqjh-oms/app-api/v1/shoppingCart/addShoppingCart'],

+ 25 - 4
src/api/globals.d.ts

@@ -347,6 +347,15 @@ declare global {
       >(
         config: Config
       ): Alova2Method<apiResData<any>, 'xsb.batchCancelCollect', Config>;
+      addressFreeShippingCheck<
+        Config extends Alova2MethodConfig<apiResData<Api.AddressFreeShippingCheckVo>> & {
+          params: {
+            addressId: number;
+          };
+        }
+      >(
+        config: Config
+      ): Alova2Method<apiResData<Api.AddressFreeShippingCheckVo>, 'xsb.addressFreeShippingCheck', Config>;
       popupConfig<
         Config extends Alova2MethodConfig<apiResData<any>> & {}
       >(
@@ -670,22 +679,30 @@ declare global {
       skuOrderConfirm<
         Config extends Alova2MethodConfig<apiResData<Api.AppletOrderSkuVo>> & {
           data: {
+            /**
+             * 渠道id
+             */
             channelId?: number;
             /**
              * 配送类型 1:快递 2:自提 3:及时配送
              */
             dvyType?: number;
             /**
-             * 当前位置纬度
+             * 当前位置纬度 自提时必填
              */
             latitude?: number;
             /**
-             * 当前位置经度
+             * 当前位置经度 自提时必填
              */
             longitude?: number;
-            num?: number;
+            /**
+             * 店铺id
+             */
             shopId?: number;
-            skuId?: number;
+            /**
+             * 商品信息列表
+             */
+            shopSkuDTOList?: Api.ShopSkuDTO[];
           }
         }
       >(
@@ -842,6 +859,10 @@ declare global {
              * 店铺id
              */
             shopId: number;
+            /**
+             * 是否包邮
+             */
+            isFreeShipping?: number;
             [property: string]: any;
           }
         }

+ 2 - 2
src/config/index.ts

@@ -4,14 +4,14 @@ const mapEnvVersion = {
    */
   // develop: 'http://192.168.1.166:8080', // 张
   // develop: 'http://192.168.1.101:8080',
-  develop: 'http://192.168.0.157:8080', // 明
+  // develop: 'http://192.168.0.157:8080', // 明
   // develop: 'http://192.168.1.253:8080',
   // develop: 'http://192.168.0.19:8080', // 邓
   // develop: 'http://192.168.1.20:8080', // 黄
   // develop: 'http://192.168.0.11:8081', // 王
   // develop: 'http://192.168.1.21:8080', // 田
   // develop: 'http://74949mkfh190.vicp.fun', // 付
-  // develop: 'http://47.109.84.152:8081', // 测试代理
+  develop: 'http://47.109.84.152:8081', // 测试代理
   // develop: 'https://5ed0f7cc.r9.vip.cpolar.cn',
   // develop: 'https://25740642.r3.cpolar.top',
   // develop: 'https://smqjh.api.zswlgz.com',

+ 5 - 2
src/store/user.ts

@@ -229,7 +229,7 @@ export const useUserStore = defineStore('user', {
     }[], remarks?: string, allowanceId?: string, pickupInfo?: {
       consigneeName?: string
       consigneeMobile?: string
-    }): Promise<string> {
+    }, isFreeShipping?: boolean): Promise<string> {
       uni.showLoading({ mask: true })
       return new Promise((resolve, reject) => {
         if (dvyType !== 2 && !this.selectedAddress) {
@@ -237,7 +237,7 @@ export const useUserStore = defineStore('user', {
           reject(new Error('请选择收货地址'))
           return
         }
-        const orderData = {
+        const orderData: any = {
           channelId: Number(this.userInfo.channelId),
           businessType,
           addressId: Number(this.selectedAddress?.id),
@@ -249,6 +249,9 @@ export const useUserStore = defineStore('user', {
           allowanceIds: allowanceId ? [allowanceId] : [],
           ...pickupInfo,
         }
+        if (isFreeShipping) {
+          orderData.isFreeShipping = 1
+        }
         Apis.common.addOrder({
           data: orderData,
         }).then((res) => {

+ 5 - 1
src/subPack-common/feedback/index.vue

@@ -34,6 +34,10 @@ async function handleSubmit() {
     useGlobalToast().show({ msg: '请输入反馈内容' })
     return
   }
+  if (contact.value && !/^1[3-9]\d{9}$/.test(contact.value.trim())) {
+    useGlobalToast().show({ msg: '请输入正确的手机号码' })
+    return
+  }
   submitLoading.value = true
   const imgUrls = fileList.value.map(item => item.url).join(',')
   await Apis.sys.addOpinionFeedback({
@@ -100,7 +104,7 @@ async function handleSubmit() {
           您可以上传相关图片,至多4张
         </view>
         <view class="upload mt18rpx">
-          <Zupload v-model:value="fileList" />
+          <Zupload v-model:value="fileList" :limit="4" />
         </view>
       </view>
 

+ 5 - 0
src/subPack-common/feedbackList/index.vue

@@ -13,6 +13,10 @@ const { data: feedbackList, isLastPage, page } = usePagination(
   { data: resp => resp.data?.list, initialPage: 1, initialPageSize: 10, immediate: true, append: true },
 )
 
+function previewImage(urls: string[], current: string) {
+  uni.previewImage({ current, urls })
+}
+
 onReachBottom(() => {
   if (!isLastPage.value) {
     page.value++
@@ -43,6 +47,7 @@ onReachBottom(() => {
             class="h-120rpx w-120rpx rounded-32rpx"
             :src="url"
             mode="scaleToFill"
+            @click="previewImage(item.img.split(','), url)"
           />
         </view>
         <view v-if="item.replyContent" class="mt-20rpx rounded-16rpx bg-#F0F0F0 p-20rpx text-24rpx">

+ 53 - 20
src/subPack-xsb/confirmOrder/index.vue

@@ -34,8 +34,8 @@ const model = reactive<{
 const mobilePattern = /^1[3-9]\d{9}$/
 const mobileRules = [{ required: true, pattern: mobilePattern, message: '请输入正确的手机号' }]
 const deliveryType = ref(1)
+const isFreeShipping = ref(false) // isFreeShipping1免邮0不免邮
 const isMemberGiftOrder = computed(() => !!orderInfo.value?.memberGiftItems?.length)
-const isSingleSkuOrder = computed(() => (orderInfo.value?.skuList?.length || 0) <= 1)
 const isSelfPickup = computed(() => current.value === '自提')
 const shopAddressInfo = computed(() => orderInfo.value?.shopAddressDTO)
 const shopDistanceText = computed(() => {
@@ -70,7 +70,7 @@ const memberDiscountCents = computed(() => {
 })
 const offsetPoints = computed(() => {
   const couponCents = Math.round(currentCouponDiscount.value * 100)
-  const freightCents = isSelfPickup.value ? 0 : Math.round(Number(unref(orderInfo)?.transfee) * 100)
+  const freightCents = isFreeShipping.value || isSelfPickup.value ? 0 : Math.round(Number(unref(orderInfo)?.transfee) * 100)
   const money = freightCents + Math.round(Number(unref(orderInfo)?.price) * 100) - couponCents - memberDiscountCents.value
   const cap = Math.max(0, money)
   if (Number(unref(orderInfo)?.offsetPoints) > cap) {
@@ -89,7 +89,7 @@ const displayTotalPrice = computed(() => {
     return 0
   }
   const goodsPrice = Number(orderInfo.value.price || 0)
-  const freight = Number(deliveryType.value !== 2 ? orderInfo.value.transfee : 0)
+  const freight = isFreeShipping.value || isSelfPickup.value ? 0 : Number(orderInfo.value.transfee || 0)
   const couponDiscount = hasManualCouponSelection.value
     ? Number(confirmedCoupon.value?.discountMoney || 0)
     : Number(orderInfo.value?.coupon || 0)
@@ -114,16 +114,13 @@ onLoad((options: any) => {
 })
 onShow(() => {
   useUserStore().getuserAddresslist()
-  if (orderInfo.value && current.value === '即时配送' && (isSingleSkuOrder.value || isMemberGiftOrder.value)) {
-    getConfirmOrder()
-  }
+  getConfirmOrder()
+  // checkAddressFreeShipping()
 })
 
 watch(current, async (value) => {
   deliveryType.value = value === '自提' ? 2 : 3
-  if (orderInfo.value && (isSingleSkuOrder.value || isMemberGiftOrder.value)) {
-    await getConfirmOrder()
-  }
+  await getConfirmOrder()
 })
 
 function getCouponDisplayName(coupon?: Partial<Api.AppMemberCouponVO> & Record<string, any>) {
@@ -138,19 +135,26 @@ function syncCouponState() {
 }
 
 function getOrderConfirmParams() {
-  const firstSku = orderInfo.value?.skuList?.[0]
+  const skuList = orderInfo.value?.skuList || []
+  const firstSku = skuList[0]
   return {
-    skuId: firstSku?.skuId,
-    num: Number(firstSku?.num || 1),
     channelId: userInfo.value?.channelId,
     shopId: Number(firstSku?.shopId || SelectShopInfo.value?.shopId || 2),
     dvyType: deliveryType.value,
+    addressId: selectedAddress.value?.id,
+    shopSkuDTOList: skuList.map(it => ({
+      skuId: it.skuId,
+      num: Number(it.num || 1),
+    })),
   }
 }
 
 async function getConfirmOrder() {
+  if (!orderInfo.value) {
+    return
+  }
   const params: Record<string, any> = getOrderConfirmParams()
-  if (!params.skuId) {
+  if (!params.shopSkuDTOList?.length) {
     return
   }
   if (isSelfPickup.value) {
@@ -166,7 +170,6 @@ async function getConfirmOrder() {
     data: params,
   })
   if (isMemberGiftOrder.value) {
-    // 赠品订单仅更新配送费和店铺地址信息,保留原始商品数据
     orderInfo.value = {
       ...orderInfo.value,
       transfee: res.data.transfee ?? orderInfo.value?.transfee ?? 0,
@@ -174,15 +177,12 @@ async function getConfirmOrder() {
     } as ConfirmOrderInfo
   }
   else {
-    const originalSku = orderInfo.value?.skuList?.[0]
-    const skuList = res.data.sku
-      ? [{ ...res.data.sku, id: originalSku?.id, num: params.num, shopId: params.shopId }]
-      : (orderInfo.value?.skuList || [])
     orderInfo.value = {
       ...orderInfo.value,
       ...res.data,
-      skuList,
+      skuList: res.data.sku || orderInfo.value?.skuList || [],
     } as ConfirmOrderInfo
+    isFreeShipping.value = res.data.isFreeShipping === 1
     syncCouponState()
   }
 }
@@ -196,6 +196,38 @@ function openShopLocation() {
   })
 }
 
+// async function checkAddressFreeShipping() {
+//   if (isSelfPickup.value || !selectedAddress.value) {
+//     return
+//   }
+//   if (selectedAddress.value.id === lastAddressId.value) {
+//     return
+//   }
+//   lastAddressId.value = selectedAddress.value.id
+//   const res = await Apis.xsb.addressFreeShippingCheck({
+//     params: { addressId: selectedAddress.value.id },
+//   })
+//   if (res.data.check) {
+//     const freeShippingData = res.data.addressFreeShippingVo
+//     if (freeShippingData) {
+//       isFreeShipping.value = freeShippingData.isFreeShipping === 1
+//       if (freeShippingData.totalPrice !== undefined) {
+//         orderInfo.value = {
+//           ...orderInfo.value!,
+//           totalPrice: freeShippingData.totalPrice,
+//         } as ConfirmOrderInfo
+//       }
+//       if (freeShippingData.transfee !== undefined) {
+//         orderInfo.value = {
+//           ...orderInfo.value!,
+//           transfee: freeShippingData.transfee,
+//         } as ConfirmOrderInfo
+//       }
+//     }
+//     console.log(orderInfo.value, '===商品数据===')
+//   }
+// }
+
 async function openCouponPopup() {
   draftCouponId.value = confirmedCouponId.value
   couponPopup.value = true
@@ -287,6 +319,7 @@ async function handlePay() {
             consigneeMobile: model.value2,
           }
         : undefined,
+      isFreeShipping.value,
     )
     const payMent = await useUserStore().getPayMent(orderNumber)
     const skuList = orderInfo.value?.skuList || []
@@ -441,7 +474,7 @@ async function handlePay() {
           ¥{{ orderInfo?.price }}
         </view>
       </view>
-      <view class="mb28rpx flex items-center justify-between text-28rpx">
+      <view v-if="!isFreeShipping" class="mb28rpx flex items-center justify-between text-28rpx">
         <view v-if="deliveryType == 3">
           配送费(即时配送)
         </view>

+ 16 - 25
src/subPack-xsb/goods/index.vue

@@ -137,30 +137,21 @@ async function handleConfimOrder() {
     return
   }
   await useUserStore().checkLogin()
-  isLoging.value = true
-  try {
-    const res = await Apis.xsb.skuOrderConfirm({
-      data: {
-        skuId: specId.value,
-        num: SelectGoodsNum.value,
-        channelId: unref(userInfo).channelId,
-        dvyType: 3,
-        shopId: unref(goodsInfo)?.shopId || 2,
-      },
-    })
-    if (Number(res.data.sku?.shopSkuStocks) < unref(SelectGoodsNum)) {
-      useGlobalToast().show('库存不足,请调整购买数量')
-      isLoging.value = false
-      return
-    }
-    router.push({
-      name: 'xsb-confirmOrder',
-      params: { data: JSON.stringify({ ...res.data, skuList: [{ ...res.data.sku, num: SelectGoodsNum.value, shopId: unref(goodsInfo)?.shopId || 2 }] }) },
-    })
-  }
-  finally {
-    isLoging.value = false
-  }
+  const selectedSku = goodsInfo.value!.skuList.find(item => item.skuId === specId.value)
+  const skuList = [{
+    id: selectedSku?.skuId,
+    skuId: specId.value,
+    skuName: selectedSku?.skuName || goodsInfo.value!.prodName,
+    pic: selectedSku?.pic || goodsInfo.value!.pic,
+    price: selectedSku?.price || goodsInfo.value!.channelProdPrice,
+    spec: selectedSku?.spec || goodsInfo.value!.spec,
+    num: SelectGoodsNum.value,
+    shopId: unref(goodsInfo)?.shopId || 2,
+  }]
+  router.push({
+    name: 'xsb-confirmOrder',
+    params: { data: JSON.stringify({ skuList }) },
+  })
 }
 async function handleAddCart() {
   if (Number(unref(goodsInfo)?.spuStock) < unref(SelectGoodsNum)) {
@@ -412,7 +403,7 @@ function handleClick() {
 
           <view class="flex items-center">
             <view class="w220rpx">
-              <wd-button plain hairline block @click="selectGoods = true">
+              <wd-button hairline plain block @click="selectGoods = true">
                 加入购物车
               </wd-button>
             </view>

+ 1 - 1
src/subPack-xsb/goodsCollection/index.vue

@@ -122,7 +122,7 @@ function handleDelete() {
               <wd-icon :name="selectedIds.has(item.id) ? 'check-circle-filled' : 'circle1'" :color="selectedIds.has(item.id) ? themeVars.colorTheme : ''" size="16px" />
             </view>
             <view class="flex items-center gap-20rpx">
-              <image :src="item.pic || `${StaticUrl}/order-icon.png`" class="h-200rpx w-200rpx rounded-16rpx" />
+              <image :src="item.pic" class="h-200rpx w-200rpx rounded-16rpx" />
               <view>
                 <view class="flex items-start gap-8rpx">
                   <view class="funt-bold flex-1 break-words text-32rpx">

+ 1 - 1
src/subPack-xsb/orderDetaile/index.vue

@@ -510,7 +510,7 @@ function handleRefundDetail(item: any) {
             ¥{{ orderInfo?.total }}
           </view>
         </view>
-        <view v-if="orderInfo.dvyType != 2" class="mt-24rpx flex items-center justify-between">
+        <view v-if="orderInfo.dvyType != 2 && orderInfo.isFreeShipping !== 1" class="mt-24rpx flex items-center justify-between">
           <view v-if="orderInfo.dvyType == 3" class="text-28rpx">
             配送费(即时配送)
           </view>