From 94e846af6c8f5f49cbc99c5f633e21fdf667dc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E9=A6=99=E7=90=AA?= <624506849@qq.com> Date: Sun, 2 Aug 2026 13:49:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=A4=BC=E5=93=81?= =?UTF-8?q?=E5=8D=A1=E9=80=89=E6=8B=A9=E5=8A=9F=E8=83=BD=E5=8F=8A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 api/trade.js 中新增 selectGiftCard 函数以支持礼品卡选择 - 更新多个组件以集成礼品卡功能,包括购物车和订单页面 - 优化商品页面和订单详情展示,支持礼品卡抵扣信息 - 调整相关逻辑以确保礼品卡与其他促销活动的兼容性 --- api/trade.js | 14 +++ components/m-buy/goods.vue | 66 +++++++---- pages/order/fillorder.vue | 108 +++++++++++++++++- pages/order/orderDetail.vue | 8 +- pages/product/goods.vue | 23 ++-- .../-promotion-assemble-promotions.vue | 24 ++++ .../product/promotion/-promotion-details.vue | 20 ++++ .../product/product/promotion/-promotion.vue | 12 ++ .../product/promotion/promotion_type.js | 18 ++- utils/goodsType.js | 15 +-- 10 files changed, 246 insertions(+), 62 deletions(-) diff --git a/api/trade.js b/api/trade.js index 5d2b1a7..bc0d1b1 100644 --- a/api/trade.js +++ b/api/trade.js @@ -169,6 +169,20 @@ export function setAddressId(addressId,way) { } +/** + * 选择礼品卡 + * @param way 购物车购买:CART/立即购买:BUY_NOW/拼团:PINTUAN / 积分:POINTS / 砍价:KANJIA + * @param credentialId 礼品卡凭证 id;used=false 且不传则清空全部 + */ +export function selectGiftCard(params) { + return http.request({ + url: `/trade/carts/select/giftCard`, + method: Method.GET, + needToken: true, + params, + }); +} + /** * 创建交易 */ diff --git a/components/m-buy/goods.vue b/components/m-buy/goods.vue index e15ab39..79258a8 100644 --- a/components/m-buy/goods.vue +++ b/components/m-buy/goods.vue @@ -158,7 +158,7 @@ const formatList = ref([]) const currentSelected = ref([]) const skuList = ref('') -// E_COUPON 库存来自卡池 poolStock,上限 min(poolStock, 999) +// E_COUPON 库存读 SKU quantity,上限 min(quantity, 999) const availableStock = computed(() => { if (isECoupon(props.goodsDetail?.goodsType)) { return getECouponStock(props.goodsDetail) @@ -189,9 +189,9 @@ watch(num, (val) => { } }) -watch(() => props.buyType, (val) => { +watch(() => props.isGroup, (val) => { if (val) { - buyType.value = val as string + buyType.value = 'PINTUAN' } }, { immediate: true }) @@ -273,18 +273,36 @@ const handleClickSpec = (val: any, index: number, specValue: any) => { } /** - * 直接购买 + * 活动页/父组件直接调用购买(POINTS / KANJIA 等显式 cartType) */ const buy = (data: any) => { - API_trade.addToCart(data).then(res => { + uni.hideLoading() + API_trade.addToCart(data).then((res) => { if (res.data.success) { + const way = data.cartType || 'BUY_NOW' uni.navigateTo({ - url: `/pages/order/fillorder?way=${data.cartType}&addr=${''}&parentOrder=${encodeURIComponent(JSON.stringify(parentOrder.value))}` + url: `/pages/order/fillorder?way=${way}&addr=${''}&parentOrder=${encodeURIComponent(JSON.stringify(parentOrder.value || ''))}`, + }) + } else { + uni.showToast({ + title: res.data.message || '购买失败', + icon: 'none', }) } }) } +/** 解析 cartType:拼团 PINTUAN;核销 VIRTUAL;其余含 E_COUPON 为 BUY_NOW */ +function resolveCartType() { + if (buyType.value === 'PINTUAN') { + return 'PINTUAN' + } + if (isVirtualGoods(props.goodsDetail?.goodsType)) { + return 'VIRTUAL' + } + return 'BUY_NOW' +} + /** * 添加到购物车或购买 */ @@ -292,13 +310,13 @@ const addToCartOrBuy = (val: string) => { if (!selectSkuList.value) { uni.showToast({ title: '请选择规格商品', - icon: 'none' + icon: 'none', }) return } - let data = { + const data: Record = { skuId: props.goodsDetail.id, - num: num.value + num: num.value, } if (val == 'cart') { @@ -310,24 +328,24 @@ const addToCartOrBuy = (val: string) => { }) emit('queryCart') closeMask() + } else { + uni.showToast({ + title: res.data.message || '加购失败', + icon: 'none', + }) } }) } else { - if (buyType.value) { - data.cartType = 'PINTUAN' - } else if (isECoupon(props.goodsDetail.goodsType)) { - // 与 VIRTUAL 核销区分:E_COUPON 必须 BUY_NOW,支付后 COMPLETED + cardKeys - data.cartType = 'BUY_NOW' - } else if (isVirtualGoods(props.goodsDetail.goodsType)) { - data.cartType = 'VIRTUAL' - } else { - data.cartType = 'BUY_NOW' - } - + data.cartType = resolveCartType() API_trade.addToCart(data).then((res) => { if (res.data.success) { uni.navigateTo({ - url: `/pages/order/fillorder?way=${data.cartType}&addr=${props.addr?.id || ''}&parentOrder=${encodeURIComponent(JSON.stringify(parentOrder.value))}`, + url: `/pages/order/fillorder?way=${data.cartType}&addr=${props.addr?.id || ''}&parentOrder=${encodeURIComponent(JSON.stringify(parentOrder.value || ''))}`, + }) + } else { + uni.showToast({ + title: res.data.message || '购买失败', + icon: 'none', }) } }) @@ -405,6 +423,12 @@ const formatSku = (list: any[]) => { onMounted(() => { formatSku(props.goodsSpec) }) + +defineExpose({ + buy, + buyType, + parentOrder, +}) diff --git a/pages/order/orderDetail.vue b/pages/order/orderDetail.vue index 879fc61..93a3f1d 100644 --- a/pages/order/orderDetail.vue +++ b/pages/order/orderDetail.vue @@ -116,14 +116,18 @@ 运费: ¥{{unitPrice(order.freightPrice) }} - + 优惠券: -¥{{unitPrice(order.priceDetailDTO.couponPrice) }} - + 活动优惠: -¥{{unitPrice(order.discountPrice) }} + + 礼品卡抵扣: + -¥{{unitPrice(order.priceDetailDTO.giftCardPrice) }} + - + + @@ -172,8 +172,8 @@ - - + + 促销 @@ -187,7 +187,7 @@ - + @@ -262,7 +262,7 @@ 加入购物车 - 立即购买 + 立即购买 暂未开始 @@ -329,7 +329,7 @@ import storage from '@/utils/storage.js' /************工具函数***************/ import { useStore } from '@/store' import { unitPrice, goodsFormatPrice, isLogin, parseGoodsImageUrl, clearStrComma, talkIm } from '@/utils/filters.js' -import { isECoupon, isNonPhysicalGoods } from '@/utils/goodsType.js' +import { isNonPhysicalGoods } from '@/utils/goodsType.js' /************组件***************/ import PromotionLayout from './product/promotion/-promotion' @@ -430,11 +430,10 @@ const IM = computed(() => { return IMLink.value + storeDetail.value.merchantEuid }) -// E_COUPON:仅立即购买,隐藏促销/地址/加购(FR-B-01 / P-08) -const isECouponGoods = computed(() => isECoupon(goodsDetail.value?.goodsType)) +// E_COUPON:禁加购、免地址;促销展示与 VIRTUAL 对齐(M-02) const isNonPhysicalGoodsType = computed(() => isNonPhysicalGoods(goodsDetail.value?.goodsType)) const showAddToCart = computed(() => { - return !isNonPhysicalGoodsType.value && !isECouponGoods.value + return !isNonPhysicalGoodsType.value }) // watch @@ -547,10 +546,6 @@ async function init(id: any, goodsId: any, distributionId = "") { PromotionList.value && Object.keys(PromotionList.value).forEach((item: string) => { - // E_COUPON 不参与拼团/秒杀(M-01),避免底部出现拼团双按钮 - if (isECoupon(goodsDetail.value?.goodsType)) { - return - } if (item.indexOf("PINTUAN") == 0) { isGroup.value = true } diff --git a/pages/product/product/promotion/-promotion-assemble-promotions.vue b/pages/product/product/promotion/-promotion-assemble-promotions.vue index 6dc1bbc..6d8f69b 100644 --- a/pages/product/product/promotion/-promotion-assemble-promotions.vue +++ b/pages/product/product/promotion/-promotion-assemble-promotions.vue @@ -5,6 +5,7 @@ class="showBox" v-if=" promotion.__key == 'SECKILL' || + promotion.__key == 'FLASH_DISCOUNT' || promotion.__key == 'GROUPBUY' || promotion.__key == 'PINTUAN' " @@ -36,6 +37,29 @@ + + + + ¥ + + {{ goodsFormatPrice(detail.promotionPrice)[0] }}.{{ + goodsFormatPrice(detail.promotionPrice)[1] + }} + + + ¥{{ goodsFormatPrice(detail.price)[0] }}.{{ + goodsFormatPrice(detail.price)[1] + }} + 限时直降 + + + diff --git a/pages/product/product/promotion/-promotion-details.vue b/pages/product/product/promotion/-promotion-details.vue index c7244c7..0e1188a 100644 --- a/pages/product/product/promotion/-promotion-details.vue +++ b/pages/product/product/promotion/-promotion-details.vue @@ -40,6 +40,26 @@ + + + 限时直降 + {{ props.res[prom].promotionName || props.res[prom].title || '限时直降活动' }} + + + + + + 第N件优惠 + + 第{{ props.res[prom].nthNum || 'N' }}件 + 免费 + 半价 + 享{{ props.res[prom].discountValue }}折 + 优惠 + + + + 积分活动 diff --git a/pages/product/product/promotion/-promotion.vue b/pages/product/product/promotion/-promotion.vue index 8ff9c85..428b28f 100644 --- a/pages/product/product/promotion/-promotion.vue +++ b/pages/product/product/promotion/-promotion.vue @@ -2,6 +2,18 @@ +
+
+ {{ promotionItem.title }} +
{{ res[item].promotionName || res[item].title || '限时直降' }}
+
+
+
+
+ {{ promotionItem.title }} +
{{ res[item].promotionName || res[item].title || '第N件优惠' }}
+
+
diff --git a/pages/product/product/promotion/promotion_type.js b/pages/product/product/promotion/promotion_type.js index 6b0d8c6..a962ed2 100644 --- a/pages/product/product/promotion/promotion_type.js +++ b/pages/product/product/promotion/promotion_type.js @@ -8,21 +8,17 @@ const promotion = [ value: "KANJIA", }, { - title: "单品立减", - value: "MINUS", + title: "限时直降", + value: "FLASH_DISCOUNT", + }, + { + title: "第N件优惠", + value: "NTH_ITEM_DISCOUNT", }, { title: "团购", value: "GROUPBUY", }, - { - title: "积分换购", - value: "EXCHANGE", - }, - { - title: "第二件半价", - value: "HALF_PRICE", - }, { title: "满减优惠", value: "FULL_DISCOUNT", @@ -50,4 +46,4 @@ export function formatType(val){ } }) } -} \ No newline at end of file +} diff --git a/utils/goodsType.js b/utils/goodsType.js index fce2f7d..02fddd8 100644 --- a/utils/goodsType.js +++ b/utils/goodsType.js @@ -4,15 +4,16 @@ * * 卡密商品(电子卡券 E_COUPON)类型与订单工具。 * - * 与 VIRTUAL_GOODS / VIRTUAL 核销商品区分:E_COUPON 走 BUY_NOW、支付后 COMPLETED + cardKeys, - * 不支持加购、促销与买家售后。需求见 lilishop/docs/requirements/card-key-goods-v4.md + * 与 VIRTUAL_GOODS / VIRTUAL 核销商品区分:E_COUPON 走 BUY_NOW/PINTUAN/POINTS/KANJIA, + * 支付后 COMPLETED + cardKeys;禁加购、免地址;M-02 支持全量促销;不支持买家售后。 + * 需求见 lilishop/docs/requirements/card-key-goods-v4.md */ export const E_COUPON_GOODS_TYPE = 'E_COUPON' export const E_COUPON_ORDER_TYPE = 'E_COUPON' export const VIRTUAL_GOODS_TYPE = 'VIRTUAL_GOODS' export const VIRTUAL_ORDER_TYPE = 'VIRTUAL' -/** 单次购买数量上限(O-09 默认:min(poolStock, 999)) */ +/** 单次购买数量上限(O-09 默认:min(quantity, 999)) */ export const E_COUPON_MAX_BUY_NUM = 999 export function isECoupon(goodsType) { @@ -40,13 +41,9 @@ export function isNonPhysicalOrder(orderType) { return isECouponOrder(orderType) || isVirtualOrder(orderType) } -/** 可售库存:E_COUPON 以卡池 poolStock 为准,quantity 仅为镜像回退 */ +/** 可售库存:E_COUPON 读 SKU quantity(由卡池 syncSkuStock 同步) */ export function getECouponStock(sku) { if (!sku) return 0 - const pool = sku.poolStock - if (pool !== undefined && pool !== null) { - return Number(pool) || 0 - } return Number(sku.quantity) || 0 } @@ -57,7 +54,7 @@ export function getECouponMaxBuyNum(sku) { } /** - * 结算页识别当前交易是否含 E_COUPON SKU。 + * 结算页识别当前交易是否含 E_COUPON SKU(用于免地址/免配送,不用于促销屏蔽)。 * 须从 goodsSku.goodsType 判断,不能依赖 cartTypeEnum=VIRTUAL(E_COUPON 仍是 BUY_NOW)。 */ export function hasECouponInCheckout(orderMessage) {