mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git
synced 2026-08-06 02:47:25 +08:00
feat: 添加电子卡券功能及相关逻辑
- 在 pages.json 中新增卡密详情页面路径 - 在多个组件中实现电子卡券(E_COUPON)逻辑,包括库存管理、结算页面处理、订单详情展示等 - 优化商品页面和订单页面以支持电子卡券的特性,隐藏不适用的功能 - 新增 utils/goodsType.js 文件,集中管理与电子卡券相关的类型和工具函数 - 更新样式以适应电子卡券的展示需求
This commit is contained in:
@@ -27,8 +27,8 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- 正常商品的价格 -->
|
<!-- 正常商品的价格 -->
|
||||||
<view v-else>
|
<view v-else>
|
||||||
<!-- 批发价格 -->
|
<!-- 批发阶梯价(E_COUPON 仅零售价) -->
|
||||||
<div class="price-row flex" v-if="goodsDetail.salesModel === 'WHOLESALE'">
|
<div class="price-row flex" v-if="goodsDetail.salesModel === 'WHOLESALE' && !isECoupon(goodsDetail.goodsType)">
|
||||||
<div class="goods-price" v-for="(item, index) in wholesaleList" :key="index">
|
<div class="goods-price" v-for="(item, index) in wholesaleList" :key="index">
|
||||||
<span>
|
<span>
|
||||||
¥
|
¥
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
<view class="goods-check-skus">
|
<view class="goods-check-skus">
|
||||||
库存
|
库存
|
||||||
<span class="goods-check-skus-name">
|
<span class="goods-check-skus-name">
|
||||||
<span>{{ goodsDetail.quantity }}</span>
|
<span>{{ availableStock }}</span>
|
||||||
</span>
|
</span>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -93,18 +93,18 @@
|
|||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<div class="soldout" v-if="goodsDetail.quantity === 0">
|
<div class="soldout" v-if="availableStock === 0">
|
||||||
<u-alert type="warning" title="商品已售罄" :description="'当前商品库存为0'"></u-alert>
|
<u-alert type="warning" title="商品已售罄" :description="'当前商品库存为0'"></u-alert>
|
||||||
</div>
|
</div>
|
||||||
<!-- 数量 -->
|
<!-- 数量 -->
|
||||||
<view v-if="goodsDetail.quantity !== 0" class="goods-skus-number flex flex-a-c flex-j-sb">
|
<view v-if="availableStock !== 0" class="goods-skus-number flex flex-a-c flex-j-sb">
|
||||||
<view class="view-class-title">数量</view>
|
<view class="view-class-title">数量</view>
|
||||||
<uni-number-box class="uNumber" :min="1" :max="999" :disabled="goodsDetail.quantity === 0" v-model="num"></uni-number-box>
|
<uni-number-box class="uNumber" :min="1" :max="maxBuyNum" :disabled="availableStock === 0" v-model="num"></uni-number-box>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<!-- 按钮 -->
|
<!-- 按钮 -->
|
||||||
<view class="btns" v-if="goodsDetail.quantity !== 0">
|
<view class="btns" v-if="availableStock !== 0">
|
||||||
<view class="box-btn card" v-if="buyType != 'PINTUAN' && goodsDetail.goodsType != 'VIRTUAL_GOODS'" @click="addToCartOrBuy('cart')">加入购物车</view>
|
<view class="box-btn card" v-if="showAddToCart" @click="addToCartOrBuy('cart')">加入购物车</view>
|
||||||
<view class="box-btn buy" @click="addToCartOrBuy('buy')">立即购买</view>
|
<view class="box-btn buy" @click="addToCartOrBuy('buy')">立即购买</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -113,11 +113,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, watch, onMounted } from 'vue'
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
import * as API_trade from '@/api/trade.js'
|
import * as API_trade from '@/api/trade.js'
|
||||||
import setup from './popup.js'
|
import setup from './popup.js'
|
||||||
import uniNumberBox from '@/components/uni-number-box.vue'
|
import uniNumberBox from '@/components/uni-number-box.vue'
|
||||||
import { goodsFormatPrice } from '@/utils/filters.js'
|
import { goodsFormatPrice } from '@/utils/filters.js'
|
||||||
|
import {
|
||||||
|
isECoupon,
|
||||||
|
isVirtualGoods,
|
||||||
|
getECouponStock,
|
||||||
|
getECouponMaxBuyNum,
|
||||||
|
} from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
wholesaleList?: any[] | boolean
|
wholesaleList?: any[] | boolean
|
||||||
@@ -152,13 +158,34 @@ const formatList = ref<any[]>([])
|
|||||||
const currentSelected = ref<string[]>([])
|
const currentSelected = ref<string[]>([])
|
||||||
const skuList = ref('')
|
const skuList = ref('')
|
||||||
|
|
||||||
|
// E_COUPON 库存来自卡池 poolStock,上限 min(poolStock, 999)
|
||||||
|
const availableStock = computed(() => {
|
||||||
|
if (isECoupon(props.goodsDetail?.goodsType)) {
|
||||||
|
return getECouponStock(props.goodsDetail)
|
||||||
|
}
|
||||||
|
return Number(props.goodsDetail?.quantity) || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const maxBuyNum = computed(() => {
|
||||||
|
if (isECoupon(props.goodsDetail?.goodsType)) {
|
||||||
|
return getECouponMaxBuyNum(props.goodsDetail)
|
||||||
|
}
|
||||||
|
return 999
|
||||||
|
})
|
||||||
|
|
||||||
|
// 电子卡券禁止加购(后端 CARD_KEY_E_COUPON_CART_FORBIDDEN)
|
||||||
|
const showAddToCart = computed(() => {
|
||||||
|
return (
|
||||||
|
buyType.value != 'PINTUAN' &&
|
||||||
|
!isVirtualGoods(props.goodsDetail?.goodsType) &&
|
||||||
|
!isECoupon(props.goodsDetail?.goodsType)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
watch(num, (val) => {
|
watch(num, (val) => {
|
||||||
val == 0 ? num.value = 1 : ''
|
val == 0 ? num.value = 1 : ''
|
||||||
if (val) {
|
if (val && val > maxBuyNum.value) {
|
||||||
//超过库存后修改回库存
|
num.value = maxBuyNum.value
|
||||||
if (val > props.goodsDetail.quantity) {
|
|
||||||
num.value = props.goodsDetail.quantity
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -172,16 +199,21 @@ watch(selectSkuList, (_val) => {
|
|||||||
emit('changed', selectSkuList.value)
|
emit('changed', selectSkuList.value)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
watch(() => props.goodsDetail?.quantity, (val) => {
|
watch(
|
||||||
|
() => availableStock.value,
|
||||||
|
(val) => {
|
||||||
if (val == 0) {
|
if (val == 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '商品已售罄',
|
title: '商品已售罄',
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
icon: 'none'
|
icon: 'none',
|
||||||
})
|
})
|
||||||
num.value = 1
|
num.value = 1
|
||||||
|
} else if (num.value > maxBuyNum.value) {
|
||||||
|
num.value = maxBuyNum.value
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const numCheck = (val: number) => {
|
const numCheck = (val: number) => {
|
||||||
if (Array.isArray(props.wholesaleList) && props.wholesaleList.length > 0) {
|
if (Array.isArray(props.wholesaleList) && props.wholesaleList.length > 0) {
|
||||||
@@ -270,31 +302,32 @@ const addToCartOrBuy = (val: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (val == 'cart') {
|
if (val == 'cart') {
|
||||||
API_trade.addToCart(data).then(res => {
|
API_trade.addToCart(data).then((res) => {
|
||||||
if (res.data.code == 200) {
|
if (res.data.success) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '商品已添加到购物车',
|
title: '商品已添加到购物车',
|
||||||
icon: 'none'
|
icon: 'none',
|
||||||
})
|
})
|
||||||
|
|
||||||
emit('queryCart')
|
emit('queryCart')
|
||||||
closeMask()
|
closeMask()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 判断是否拼团商品
|
|
||||||
if (buyType.value) {
|
if (buyType.value) {
|
||||||
data.cartType = 'PINTUAN'
|
data.cartType = 'PINTUAN'
|
||||||
} else if (props.goodsDetail.goodsType == 'VIRTUAL_GOODS') {
|
} 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'
|
data.cartType = 'VIRTUAL'
|
||||||
} else {
|
} else {
|
||||||
data.cartType = 'BUY_NOW'
|
data.cartType = 'BUY_NOW'
|
||||||
}
|
}
|
||||||
|
|
||||||
API_trade.addToCart(data).then(res => {
|
API_trade.addToCart(data).then((res) => {
|
||||||
if (res.data.code == 200) {
|
if (res.data.success) {
|
||||||
uni.navigateTo({
|
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))}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -771,6 +771,13 @@
|
|||||||
"navigationBarTitleText": "订单详情"
|
"navigationBarTitleText": "订单详情"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "cardKey/cardKeyDetail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "查看卡密",
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "deliverDetail",
|
"path": "deliverDetail",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@@ -119,7 +119,7 @@
|
|||||||
<view class="btn-view">
|
<view class="btn-view">
|
||||||
<!-- 售后申请 -->
|
<!-- 售后申请 -->
|
||||||
|
|
||||||
<div class="sale" v-if="current === 0 && sku.afterSaleStatus">
|
<div class="sale" v-if="current === 0 && sku.afterSaleStatus && !isECouponOrder(order.orderType)">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
order.flowPrice != 0 &&
|
order.flowPrice != 0 &&
|
||||||
@@ -199,6 +199,8 @@ import { ref, reactive, computed } from 'vue'
|
|||||||
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
||||||
import { useStore } from '@/store'
|
import { useStore } from '@/store'
|
||||||
import { unitPrice, serviceStatusList, parseGoodsImageUrl } from '@/utils/filters.js'
|
import { unitPrice, serviceStatusList, parseGoodsImageUrl } from '@/utils/filters.js'
|
||||||
|
// E_COUPON 订单列表不展示「申请售后」入口(FR-B-04)
|
||||||
|
import { isECouponOrder } from '@/utils/goodsType.js'
|
||||||
import { getAfterSaleList, cancelAfterSale } from '@/api/after-sale.js'
|
import { getAfterSaleList, cancelAfterSale } from '@/api/after-sale.js'
|
||||||
import { getOrderList } from '@/api/order.js'
|
import { getOrderList } from '@/api/order.js'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ import { onLoad } from '@dcloudio/uni-app'
|
|||||||
import { unitPrice, parseGoodsImageUrl } from '@/utils/filters.js'
|
import { unitPrice, parseGoodsImageUrl } from '@/utils/filters.js'
|
||||||
import { getAfterSaleInfo } from '@/api/after-sale'
|
import { getAfterSaleInfo } from '@/api/after-sale'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
|
// 深链进入时拦截 E_COUPON,后端 apply/save 亦会拒绝
|
||||||
|
import { isECouponOrder } from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const sn = ref('')
|
const sn = ref('')
|
||||||
const sku = ref<any>({})
|
const sku = ref<any>({})
|
||||||
@@ -71,6 +73,16 @@ const applyInfo = ref<any>({})
|
|||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
sn.value = options?.sn || ''
|
sn.value = options?.sn || ''
|
||||||
sku.value = storage.getAfterSaleData()
|
sku.value = storage.getAfterSaleData()
|
||||||
|
if (isECouponOrder(sku.value?.orderType)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '电子卡券订单不支持售后',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack()
|
||||||
|
}, 1500)
|
||||||
|
return
|
||||||
|
}
|
||||||
init()
|
init()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
213
pages/order/cardKey/cardKeyDetail.vue
Normal file
213
pages/order/cardKey/cardKeyDetail.vue
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<!--
|
||||||
|
@Author Mike
|
||||||
|
@Date 2026-07-31
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view class="card-key-page">
|
||||||
|
<view v-if="loading" class="card-key-page__loading">加载中...</view>
|
||||||
|
<view v-else-if="errorMessage" class="card-key-page__empty">{{ errorMessage }}</view>
|
||||||
|
<view v-else-if="!cardKeyRows.length" class="card-key-page__empty">
|
||||||
|
{{ emptyMessage }}
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<view
|
||||||
|
class="card-key-item"
|
||||||
|
v-for="(row, index) in cardKeyRows"
|
||||||
|
:key="`${row.cardNo || index}-${index}`"
|
||||||
|
>
|
||||||
|
<view class="card-key-item__title">卡密 {{ index + 1 }}</view>
|
||||||
|
<view class="card-key-item__row">
|
||||||
|
<text class="card-key-item__label">卡号:</text>
|
||||||
|
<text class="card-key-item__value">{{ row.cardNo || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-key-item__row">
|
||||||
|
<text class="card-key-item__label">卡密:</text>
|
||||||
|
<text class="card-key-item__value">{{ row.cardSecret || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-key-item__actions">
|
||||||
|
<view class="card-key-item__copy" @click="copyCardKey(row)">复制</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card-key-page__footer">
|
||||||
|
<view class="card-key-page__copy-all" @click="copyAllCardKeys">复制全部</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* @Author Mike
|
||||||
|
* @Date 2026-07-31
|
||||||
|
*
|
||||||
|
* 电子卡券卡密二级页(原型 P-09)。
|
||||||
|
* 数据来源:GET /buyer/order/order/{orderSn} → orderItems[].cardKeys;
|
||||||
|
* 不展示过期时间;未发卡/非 E_COUPON 订单不泄露 cardSecret。
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
||||||
|
import { getOrderDetail } from '@/api/order.js'
|
||||||
|
import { setClipboard } from '@/utils/filters.js'
|
||||||
|
import {
|
||||||
|
isECouponOrder,
|
||||||
|
flattenOrderCardKeys,
|
||||||
|
isCardKeyDelivered,
|
||||||
|
} from '@/utils/goodsType.js'
|
||||||
|
|
||||||
|
const orderSn = ref('')
|
||||||
|
const loading = ref(true)
|
||||||
|
const errorMessage = ref('')
|
||||||
|
const orderItems = ref<any[]>([])
|
||||||
|
const orderStatus = ref('')
|
||||||
|
|
||||||
|
const cardKeyRows = computed(() => flattenOrderCardKeys(orderItems.value))
|
||||||
|
|
||||||
|
const emptyMessage = computed(() => {
|
||||||
|
if (orderStatus.value === 'CANCELLED') {
|
||||||
|
return '订单已关闭,暂无卡密信息'
|
||||||
|
}
|
||||||
|
if (orderStatus.value === 'COMPLETED') {
|
||||||
|
return '卡密尚未发放,请稍后刷新'
|
||||||
|
}
|
||||||
|
return '暂无卡密信息'
|
||||||
|
})
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
orderSn.value = options?.sn || ''
|
||||||
|
loadData()
|
||||||
|
})
|
||||||
|
|
||||||
|
onPullDownRefresh(() => {
|
||||||
|
loadData(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
function loadData(fromPullDown = false) {
|
||||||
|
if (!orderSn.value) {
|
||||||
|
loading.value = false
|
||||||
|
errorMessage.value = '订单编号无效'
|
||||||
|
if (fromPullDown) uni.stopPullDownRefresh()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!fromPullDown) {
|
||||||
|
loading.value = true
|
||||||
|
errorMessage.value = ''
|
||||||
|
}
|
||||||
|
getOrderDetail(orderSn.value)
|
||||||
|
.then((res) => {
|
||||||
|
if (!res.data.success) {
|
||||||
|
errorMessage.value = res.data.message || '加载失败'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const result = res.data.result
|
||||||
|
if (!isECouponOrder(result?.order?.orderType)) {
|
||||||
|
errorMessage.value = '该订单不是电子卡券订单'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
orderItems.value = result.orderItems || []
|
||||||
|
orderStatus.value = result.order?.orderStatus || ''
|
||||||
|
// 未 cardKeyDelivered 时不展示卡密(UNPAID/PAID 发卡中或发卡失败)
|
||||||
|
if (!isCardKeyDelivered(orderItems.value)) {
|
||||||
|
orderItems.value = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
errorMessage.value = '加载失败,请稍后重试'
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
if (fromPullDown) uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyCardKey(row: any) {
|
||||||
|
const text = `卡号:${row.cardNo || ''}\n卡密:${row.cardSecret || ''}`
|
||||||
|
setClipboard(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyAllCardKeys() {
|
||||||
|
const text = cardKeyRows.value
|
||||||
|
.map(
|
||||||
|
(row, index) =>
|
||||||
|
`${index + 1}. 卡号:${row.cardNo || ''} 卡密:${row.cardSecret || ''}`
|
||||||
|
)
|
||||||
|
.join('\n')
|
||||||
|
if (!text) {
|
||||||
|
uni.showToast({ title: '暂无可复制卡密', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setClipboard(text)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card-key-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 24rpx;
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-page__loading,
|
||||||
|
.card-key-page__empty {
|
||||||
|
padding: 120rpx 40rpx;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
padding: 28rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item__title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item__row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item__label {
|
||||||
|
color: #666;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item__value {
|
||||||
|
color: #333;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item__actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-item__copy {
|
||||||
|
color: $main-color;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-page__footer {
|
||||||
|
padding: 20rpx 0 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-page__copy-all {
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
text-align: center;
|
||||||
|
background: $main-color;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<div
|
<div
|
||||||
class="address-box"
|
class="address-box"
|
||||||
@click="clickToAddress()"
|
@click="clickToAddress()"
|
||||||
v-if="shippingText == 'LOGISTICS' && orderMessage.cartTypeEnum != 'VIRTUAL'"
|
v-if="shippingText == 'LOGISTICS' && !hidePhysicalCheckout"
|
||||||
>
|
>
|
||||||
<div class="user-box flex">
|
<div class="user-box flex">
|
||||||
<div class="flex-8">
|
<div class="flex-8">
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<div class="bar"></div>
|
<div class="bar"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 选择自提点 -->
|
<!-- 选择自提点 -->
|
||||||
<div class="address-box" v-if="shippingText == 'SELF_PICK_UP'">
|
<div class="address-box" v-if="shippingText == 'SELF_PICK_UP' && !isECouponCheckout">
|
||||||
<div @click="clickToStoreAddress()">
|
<div @click="clickToStoreAddress()">
|
||||||
<div class="user-box flex">
|
<div class="user-box flex">
|
||||||
<div class="flex-8">
|
<div class="flex-8">
|
||||||
@@ -201,14 +201,14 @@
|
|||||||
</u-row>
|
</u-row>
|
||||||
<u-row>
|
<u-row>
|
||||||
<u-col
|
<u-col
|
||||||
v-if="orderMessage.cartTypeEnum != 'VIRTUAL'"
|
v-if="!hidePhysicalCheckout"
|
||||||
:offset="0"
|
:offset="0"
|
||||||
:span="9"
|
:span="9"
|
||||||
@click="shippingFlag = true"
|
@click="shippingFlag = true"
|
||||||
>配送
|
>配送
|
||||||
</u-col>
|
</u-col>
|
||||||
<u-col
|
<u-col
|
||||||
v-if="orderMessage.cartTypeEnum != 'VIRTUAL'"
|
v-if="!hidePhysicalCheckout"
|
||||||
:span="3"
|
:span="3"
|
||||||
textAlign="right"
|
textAlign="right"
|
||||||
@click="shippingFlag = true"
|
@click="shippingFlag = true"
|
||||||
@@ -262,11 +262,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<u-row v-if="shippingText == 'LOGISTICS'">
|
<u-row v-if="shippingText == 'LOGISTICS'">
|
||||||
<u-col v-if="orderMessage.cartTypeEnum != 'VIRTUAL'" :span="7"
|
<u-col v-if="!hidePhysicalCheckout" :span="7"
|
||||||
>运费</u-col
|
>运费</u-col
|
||||||
>
|
>
|
||||||
<u-col
|
<u-col
|
||||||
v-if="orderMessage.cartTypeEnum != 'VIRTUAL'"
|
v-if="!hidePhysicalCheckout"
|
||||||
:span="5"
|
:span="5"
|
||||||
class="tr tipsColor"
|
class="tr tipsColor"
|
||||||
textAlign="right"
|
textAlign="right"
|
||||||
@@ -283,6 +283,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<u-row
|
<u-row
|
||||||
v-if="
|
v-if="
|
||||||
|
!isECouponCheckout &&
|
||||||
orderMessage.priceDetailDTO.goodsPrice != 0 &&
|
orderMessage.priceDetailDTO.goodsPrice != 0 &&
|
||||||
orderMessage.priceDetailDTO.goodsPrice != null
|
orderMessage.priceDetailDTO.goodsPrice != null
|
||||||
"
|
"
|
||||||
@@ -309,7 +310,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-col>
|
</u-col>
|
||||||
</u-row>
|
</u-row>
|
||||||
<div>
|
<div v-if="!isECouponCheckout">
|
||||||
<u-row>
|
<u-row>
|
||||||
<u-col :span="9">优惠金额</u-col>
|
<u-col :span="9">优惠金额</u-col>
|
||||||
<u-col
|
<u-col
|
||||||
@@ -324,7 +325,7 @@
|
|||||||
<u-col :span="3" textAlign="right" v-else>0.00</u-col>
|
<u-col :span="3" textAlign="right" v-else>0.00</u-col>
|
||||||
</u-row>
|
</u-row>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div v-if="!isECouponCheckout">
|
||||||
<u-row>
|
<u-row>
|
||||||
<u-col :span="6">活动优惠</u-col>
|
<u-col :span="6">活动优惠</u-col>
|
||||||
<u-col :span="6" class="tr tipsColor" textAlign="right">
|
<u-col :span="6" class="tr tipsColor" textAlign="right">
|
||||||
@@ -400,6 +401,7 @@ import {
|
|||||||
secrecyMobile,
|
secrecyMobile,
|
||||||
isLogin,
|
isLogin,
|
||||||
} from '@/utils/filters.js'
|
} from '@/utils/filters.js'
|
||||||
|
import { hasECouponInCheckout } from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const { proxy } = getCurrentInstance()!
|
const { proxy } = getCurrentInstance()!
|
||||||
@@ -424,8 +426,6 @@ const shippingText = ref('LOGISTICS')
|
|||||||
const shippingFlag = ref(false)
|
const shippingFlag = ref(false)
|
||||||
const shippingMethod = ref<ShippingOption[]>([])
|
const shippingMethod = ref<ShippingOption[]>([])
|
||||||
const isAssemble = ref(false)
|
const isAssemble = ref(false)
|
||||||
const remarkFlag = ref(false)
|
|
||||||
const selectAddressId = ref('')
|
|
||||||
const routerVal = ref<Record<string, any>>({})
|
const routerVal = ref<Record<string, any>>({})
|
||||||
const params = ref<Record<string, any>>({})
|
const params = ref<Record<string, any>>({})
|
||||||
const couponList = ref('')
|
const couponList = ref('')
|
||||||
@@ -445,6 +445,13 @@ const notSupportFreightNoticeText = ref('')
|
|||||||
const storeAddress = ref<any>('')
|
const storeAddress = ref<any>('')
|
||||||
const originOrderData = ref<any>('')
|
const originOrderData = ref<any>('')
|
||||||
|
|
||||||
|
// E_COUPON 结算:免地址、无运费/优惠券/促销(O-11);与 VIRTUAL 共用 hidePhysicalCheckout
|
||||||
|
const isECouponCheckout = computed(() => hasECouponInCheckout(orderMessage.value))
|
||||||
|
const isVirtualCheckout = computed(() => orderMessage.value?.cartTypeEnum === 'VIRTUAL')
|
||||||
|
const hidePhysicalCheckout = computed(
|
||||||
|
() => isVirtualCheckout.value || isECouponCheckout.value
|
||||||
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
remarkVal,
|
remarkVal,
|
||||||
(val) => {
|
(val) => {
|
||||||
@@ -477,15 +484,15 @@ onBackPress((e) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onShow(async () => {
|
onShow(async () => {
|
||||||
if (remark.value && remark.value.length > 0) {
|
|
||||||
remarkFlag.value = true
|
|
||||||
}
|
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
mask: true,
|
mask: true,
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
await getOrderList()
|
await getOrderList()
|
||||||
|
// E_COUPON 不需要配送方式
|
||||||
|
if (!isECouponCheckout.value) {
|
||||||
await getDistribution()
|
await getDistribution()
|
||||||
|
}
|
||||||
if (routerVal.value.way == 'PINTUAN') {
|
if (routerVal.value.way == 'PINTUAN') {
|
||||||
isAssemble.value = true
|
isAssemble.value = true
|
||||||
routerVal.value.parentOrder = JSON.parse(
|
routerVal.value.parentOrder = JSON.parse(
|
||||||
@@ -507,8 +514,8 @@ function getShippingLabel() {
|
|||||||
|
|
||||||
async function callbackInvoice(val: any) {
|
async function callbackInvoice(val: any) {
|
||||||
invoiceFlag.value = false
|
invoiceFlag.value = false
|
||||||
|
if (!val) return
|
||||||
receiptList.value = val
|
receiptList.value = val
|
||||||
if (val) {
|
|
||||||
const submit = {
|
const submit = {
|
||||||
way: routerVal.value.way,
|
way: routerVal.value.way,
|
||||||
...receiptList.value,
|
...receiptList.value,
|
||||||
@@ -519,7 +526,6 @@ async function callbackInvoice(val: any) {
|
|||||||
getOrderList()
|
getOrderList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function navigateToStore(val: any) {
|
function navigateToStore(val: any) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
@@ -614,7 +620,7 @@ function createTradeFun() {
|
|||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
shippingText.value === 'LOGISTICS' &&
|
shippingText.value === 'LOGISTICS' &&
|
||||||
orderMessage.value.cartTypeEnum !== 'VIRTUAL'
|
!hidePhysicalCheckout.value
|
||||||
) {
|
) {
|
||||||
if (!address.value.id) {
|
if (!address.value.id) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -737,6 +743,22 @@ async function confirmDistribution(val: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSavedRemark(storeId: string, index: number, fallback = '') {
|
||||||
|
const localAtIndex = remarkVal.value[index]
|
||||||
|
if (localAtIndex?.storeId === storeId) {
|
||||||
|
return localAtIndex.remark ?? ''
|
||||||
|
}
|
||||||
|
const localByStore = remarkVal.value.find((r) => r?.storeId === storeId)
|
||||||
|
if (localByStore) {
|
||||||
|
return localByStore.remark ?? ''
|
||||||
|
}
|
||||||
|
const fromStore = (remark.value || []).find((r: any) => r.storeId === storeId)
|
||||||
|
if (fromStore) {
|
||||||
|
return fromStore.remark ?? ''
|
||||||
|
}
|
||||||
|
return fallback ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
function getOrderList() {
|
function getOrderList() {
|
||||||
notSupportFreight.value = []
|
notSupportFreight.value = []
|
||||||
notSupportFreightNoticeText.value = ''
|
notSupportFreightNoticeText.value = ''
|
||||||
@@ -766,11 +788,7 @@ function getOrderList() {
|
|||||||
let repeatData
|
let repeatData
|
||||||
res.data.result.cartList.forEach((item: any, index: number) => {
|
res.data.result.cartList.forEach((item: any, index: number) => {
|
||||||
repeatData = {
|
repeatData = {
|
||||||
remark: remarkFlag.value
|
remark: getSavedRemark(item.storeId, index, item.remark),
|
||||||
? remark.value[index].storeId == item.storeId
|
|
||||||
? remark.value[index].remark
|
|
||||||
: item.remark
|
|
||||||
: item.remark,
|
|
||||||
storeId: item.storeId,
|
storeId: item.storeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,6 +799,8 @@ function getOrderList() {
|
|||||||
;(store.state as any).canUseCoupons = res.data.result.canUseCoupons
|
;(store.state as any).canUseCoupons = res.data.result.canUseCoupons
|
||||||
;(store.state as any).cantUseCoupons = res.data.result.cantUseCoupons
|
;(store.state as any).cantUseCoupons = res.data.result.cantUseCoupons
|
||||||
|
|
||||||
|
// E_COUPON 免地址,不自动回填 memberAddress
|
||||||
|
if (!hasECouponInCheckout(res.data.result)) {
|
||||||
if (!res.data.result.memberAddress) {
|
if (!res.data.result.memberAddress) {
|
||||||
getUserAddress()
|
getUserAddress()
|
||||||
} else {
|
} else {
|
||||||
@@ -788,6 +808,7 @@ function getOrderList() {
|
|||||||
res.data.result.memberAddress.consigneeAddressPath =
|
res.data.result.memberAddress.consigneeAddressPath =
|
||||||
res.data.result.memberAddress.consigneeAddressPath.split(',')
|
res.data.result.memberAddress.consigneeAddressPath.split(',')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (res.data.result.storeAddress) {
|
if (res.data.result.storeAddress) {
|
||||||
storeAddress.value = res.data.result.storeAddress
|
storeAddress.value = res.data.result.storeAddress
|
||||||
console.log('storeAddress', storeAddress.value)
|
console.log('storeAddress', storeAddress.value)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<u-popup closeable border-radius="28" @close="close" mode="bottom" height="80%" v-model:show="show">
|
<u-popup closeable border-radius="28" @close="onPopupClose" mode="bottom" height="80%" v-model:show="show">
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<!-- 发票类型 -->
|
<!-- 发票类型 -->
|
||||||
@@ -143,6 +143,7 @@ const submitData = reactive<SubmitData>({
|
|||||||
receiptEmail: '',
|
receiptEmail: '',
|
||||||
})
|
})
|
||||||
const show = ref(true)
|
const show = ref(true)
|
||||||
|
const confirmed = ref(false)
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
const tips =
|
const tips =
|
||||||
'电子发票即电子增值税发票,是税局认可的有效凭证,其法律效力、基本用途及使用规定同纸质发票。'
|
'电子发票即电子增值税发票,是税局认可的有效凭证,其法律效力、基本用途及使用规定同纸质发票。'
|
||||||
@@ -341,8 +342,10 @@ function handleClickHeader(
|
|||||||
val.active = true
|
val.active = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function close(val: SubmitData | boolean) {
|
function onPopupClose() {
|
||||||
emit('callbackInvoice', val)
|
if (confirmed.value) return
|
||||||
|
show.value = false
|
||||||
|
emit('callbackInvoice', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitInvoice() {
|
function submitInvoice() {
|
||||||
@@ -438,8 +441,9 @@ function submitInvoice() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirmed.value = true
|
||||||
show.value = false
|
show.value = false
|
||||||
close(submitData)
|
emit('callbackInvoice', { ...submitData })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -67,11 +67,11 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- 等待收货 -->
|
<!-- 等待收货 -->
|
||||||
<view ripple shape="circle" class="pay-btn" size="mini"
|
<view ripple shape="circle" class="pay-btn" size="mini"
|
||||||
v-if="order.allowOperationVO.rog" @click="onRog(order.sn)">
|
v-if="order.allowOperationVO.rog && !isECouponOrder(order.orderType)" @click="onRog(order.sn)">
|
||||||
确认收货
|
确认收货
|
||||||
</view>
|
</view>
|
||||||
<view ripple shape="circle" class="cancel-btn" size="mini"
|
<view ripple shape="circle" class="cancel-btn" size="mini"
|
||||||
v-if="order.groupAfterSaleStatus && ( order.groupAfterSaleStatus.includes('NOT_APPLIED') || order.groupAfterSaleStatus.includes('PART_AFTER_SALE'))"
|
v-if="!isECouponOrder(order.orderType) && order.groupAfterSaleStatus && ( order.groupAfterSaleStatus.includes('NOT_APPLIED') || order.groupAfterSaleStatus.includes('PART_AFTER_SALE'))"
|
||||||
@click="applyService(order)">
|
@click="applyService(order)">
|
||||||
退款/售后
|
退款/售后
|
||||||
</view>
|
</view>
|
||||||
@@ -122,6 +122,8 @@ import {
|
|||||||
tipsToLogin,
|
tipsToLogin,
|
||||||
orderStatusList,
|
orderStatusList,
|
||||||
} from '@/utils/filters.js'
|
} from '@/utils/filters.js'
|
||||||
|
// E_COUPON 订单不展示确认收货、退款/售后(FR-B-04)
|
||||||
|
import { isECouponOrder } from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const { proxy } = getCurrentInstance()!
|
const { proxy } = getCurrentInstance()!
|
||||||
|
|||||||
@@ -8,11 +8,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 物流信息 -->
|
<!-- 物流信息 / 卡密入口 -->
|
||||||
<view class="info-view logistics-view">
|
<view class="info-view logistics-view">
|
||||||
|
|
||||||
<view class="logistics-List">
|
<view class="logistics-List">
|
||||||
<view class="verificationCode" v-if="order.verificationCode">
|
<view v-if="isECouponOrder" class="card-key-entry">
|
||||||
|
<view v-if="ecouponCardKeyDelivered" class="card-key-entry__btn" @click="goCardKeyDetail">
|
||||||
|
查看卡密
|
||||||
|
</view>
|
||||||
|
<view v-else-if="order.orderStatus === 'COMPLETED'" class="card-key-entry__tip">
|
||||||
|
卡密尚未发放,请稍后刷新
|
||||||
|
</view>
|
||||||
|
<view v-else-if="order.orderStatus === 'CANCELLED'" class="card-key-entry__tip">
|
||||||
|
订单已关闭
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="verificationCode" v-else-if="order.verificationCode">
|
||||||
券码: {{ order.orderStatus == 'CANCELLED' ? '已失效' : order.verificationCode }}
|
券码: {{ order.orderStatus == 'CANCELLED' ? '已失效' : order.verificationCode }}
|
||||||
</view>
|
</view>
|
||||||
<view @click="handleClickDeliver()" class="info-view logi-view" v-else-if="orderPackage && orderPackage.length">
|
<view @click="handleClickDeliver()" class="info-view logi-view" v-else-if="orderPackage && orderPackage.length">
|
||||||
@@ -23,14 +33,13 @@
|
|||||||
点击此处查看
|
点击此处查看
|
||||||
</div>
|
</div>
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="logistics-List-title">
|
<view v-else-if="!isECouponOrder" class="logistics-List-title">
|
||||||
{{ '暂无物流信息' }}
|
{{ '暂无物流信息' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<!-- 地址 -->
|
<!-- 地址 -->
|
||||||
<view class="info-view" v-if="order.deliveryMethod === 'LOGISTICS' && order.orderType !== 'VIRTUAL'">
|
<view class="info-view" v-if="order.deliveryMethod === 'LOGISTICS' && !isNonPhysicalOrder">
|
||||||
<view class="address-view">
|
<view class="address-view">
|
||||||
<view>
|
<view>
|
||||||
<view class="address-title">
|
<view class="address-title">
|
||||||
@@ -83,7 +92,7 @@
|
|||||||
<view class="goods-price">
|
<view class="goods-price">
|
||||||
¥{{unitPrice(sku.goodsPrice) }}
|
¥{{unitPrice(sku.goodsPrice) }}
|
||||||
<!-- <span v-if="sku.point">+{{ sku.point }}积分</span> -->
|
<!-- <span v-if="sku.point">+{{ sku.point }}积分</span> -->
|
||||||
<span style="font-size: 24rpx;margin-left: 14rpx;color: #ff9900;" v-if="sku.isRefund && sku.isRefund !== 'NO_REFUND'">
|
<span style="font-size: 24rpx;margin-left: 14rpx;color: #ff9900;" v-if="!isECouponOrder && sku.isRefund && sku.isRefund !== 'NO_REFUND'">
|
||||||
{{refundPriceList(sku.isRefund)}} ({{unitPrice(sku.refundPrice, "¥") }})
|
{{refundPriceList(sku.isRefund)}} ({{unitPrice(sku.refundPrice, "¥") }})
|
||||||
</span>
|
</span>
|
||||||
</view>
|
</view>
|
||||||
@@ -103,15 +112,15 @@
|
|||||||
<view class="title">商品总价:</view>
|
<view class="title">商品总价:</view>
|
||||||
<view class="value">¥{{unitPrice(order.goodsPrice) }}</view>
|
<view class="value">¥{{unitPrice(order.goodsPrice) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="order-info-view" v-if="order.freightPrice">
|
<view class="order-info-view" v-if="order.freightPrice && !isECouponOrder">
|
||||||
<view class="title">运费:</view>
|
<view class="title">运费:</view>
|
||||||
<view class="value">¥{{unitPrice(order.freightPrice) }}</view>
|
<view class="value">¥{{unitPrice(order.freightPrice) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="order-info-view" v-if="order.priceDetailDTO">
|
<view class="order-info-view" v-if="!isECouponOrder && order.priceDetailDTO">
|
||||||
<view class="title">优惠券:</view>
|
<view class="title">优惠券:</view>
|
||||||
<view class="value main-color">-¥{{unitPrice(order.priceDetailDTO.couponPrice) }}</view>
|
<view class="value main-color">-¥{{unitPrice(order.priceDetailDTO.couponPrice) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="order-info-view">
|
<view class="order-info-view" v-if="!isECouponOrder">
|
||||||
<view class="title">活动优惠:</view>
|
<view class="title">活动优惠:</view>
|
||||||
<view class="value main-color">-¥{{unitPrice(order.discountPrice) }}</view>
|
<view class="value main-color">-¥{{unitPrice(order.discountPrice) }}</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -131,7 +140,7 @@
|
|||||||
<view class="customer-service"
|
<view class="customer-service"
|
||||||
v-if="orderDetail.allowOperationVO && orderDetail.allowOperationVO.cancel == true"
|
v-if="orderDetail.allowOperationVO && orderDetail.allowOperationVO.cancel == true"
|
||||||
@click="onCancel(order.sn)">取消订单</view>
|
@click="onCancel(order.sn)">取消订单</view>
|
||||||
<view class="customer-service" v-if="order.orderStatus == 'DELIVERED'" @click="onLogistics(order)">查看物流</view>
|
<view class="customer-service" v-if="order.orderStatus == 'DELIVERED' && !isECouponOrder" @click="onLogistics(order)">查看物流</view>
|
||||||
<view class="customer-service" v-if="order.orderStatus != 'UNPAID' && order.orderPromotionType == 'PINTUAN'"
|
<view class="customer-service" v-if="order.orderStatus != 'UNPAID' && order.orderPromotionType == 'PINTUAN'"
|
||||||
@click="ByUserMessage(order)">查看拼团信息</view>
|
@click="ByUserMessage(order)">查看拼团信息</view>
|
||||||
<view class="customer-service"
|
<view class="customer-service"
|
||||||
@@ -206,7 +215,7 @@
|
|||||||
>立即付款</view>
|
>立即付款</view>
|
||||||
<view
|
<view
|
||||||
class="pay-btn"
|
class="pay-btn"
|
||||||
v-if="order.orderStatus == 'DELIVERED'"
|
v-if="order.orderStatus == 'DELIVERED' && !isECouponOrder"
|
||||||
@click="onRog(order.sn)"
|
@click="onRog(order.sn)"
|
||||||
>确认收货</view>
|
>确认收货</view>
|
||||||
<view
|
<view
|
||||||
@@ -262,6 +271,11 @@ import {
|
|||||||
talkIm,
|
talkIm,
|
||||||
callPhone,
|
callPhone,
|
||||||
} from '@/utils/filters.js'
|
} from '@/utils/filters.js'
|
||||||
|
import {
|
||||||
|
isECouponOrder as checkECouponOrder,
|
||||||
|
isNonPhysicalOrder as checkNonPhysicalOrder,
|
||||||
|
isCardKeyDelivered,
|
||||||
|
} from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const lightColor = computed(() => store.getters.lightColor)
|
const lightColor = computed(() => store.getters.lightColor)
|
||||||
@@ -292,6 +306,11 @@ const rogShow = ref(false)
|
|||||||
const reason = ref('')
|
const reason = ref('')
|
||||||
const orderPackage = ref<any>('')
|
const orderPackage = ref<any>('')
|
||||||
|
|
||||||
|
// orderType=E_COUPON:无物流/核销码,卡密见 cardKeyDetail(API-B-01 orderItems[].cardKeys)
|
||||||
|
const isECouponOrder = computed(() => checkECouponOrder(order.value?.orderType))
|
||||||
|
const isNonPhysicalOrder = computed(() => checkNonPhysicalOrder(order.value?.orderType))
|
||||||
|
const ecouponCardKeyDelivered = computed(() => isCardKeyDelivered(orderGoodsList.value))
|
||||||
|
|
||||||
function hideLoadingIfNeeded() {
|
function hideLoadingIfNeeded() {
|
||||||
if (store.state.isShowToast) uni.hideLoading()
|
if (store.state.isShowToast) uni.hideLoading()
|
||||||
}
|
}
|
||||||
@@ -376,7 +395,12 @@ function loadData(orderSnParam: string) {
|
|||||||
order.value = result.order
|
order.value = result.order
|
||||||
orderGoodsList.value = result.orderItems
|
orderGoodsList.value = result.orderItems
|
||||||
orderDetail.value = result
|
orderDetail.value = result
|
||||||
if (order.value.deliveryMethod === 'LOGISTICS') {
|
if (
|
||||||
|
result.order.deliveryMethod === 'LOGISTICS' &&
|
||||||
|
!checkECouponOrder(result.order.orderType) &&
|
||||||
|
result.order.orderType !== 'VIRTUAL'
|
||||||
|
) {
|
||||||
|
// E_COUPON 无物流信息
|
||||||
loadLogistics(orderSnParam)
|
loadLogistics(orderSnParam)
|
||||||
getOrderPackage()
|
getOrderPackage()
|
||||||
}
|
}
|
||||||
@@ -384,6 +408,14 @@ function loadData(orderSnParam: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goCardKeyDetail() {
|
||||||
|
// 仅传 orderSn,卡密在二级页重新请求订单详情,不经路由/Vuex 传递明文
|
||||||
|
if (!sn.value) return
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/order/cardKey/cardKeyDetail?sn=${sn.value}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function onReceipt(val: any) {
|
function onReceipt(val: any) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/order/invoice/invoiceDetail?id=' + val.id,
|
url: '/pages/order/invoice/invoiceDetail?id=' + val.id,
|
||||||
@@ -716,6 +748,26 @@ page,
|
|||||||
letter-spacing: 2rpx;
|
letter-spacing: 2rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-key-entry {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-entry__btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20rpx 80rpx;
|
||||||
|
border: 2rpx solid $main-color;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
color: $main-color;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-key-entry__tip {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
.bottom_view {
|
.bottom_view {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100rpx;
|
height: 100rpx;
|
||||||
|
|||||||
@@ -90,8 +90,8 @@
|
|||||||
|
|
||||||
<GoodsSwiper id="main1" :res="imgList" :video="goodsDetail.goodsVideo" />
|
<GoodsSwiper id="main1" :res="imgList" :video="goodsDetail.goodsVideo" />
|
||||||
|
|
||||||
<!-- 促销活动条 -->
|
<!-- 促销活动条(E_COUPON 不参与促销 M-01) -->
|
||||||
<PromotionAssembleLayout v-if="PromotionList" :detail="goodsDetail" :res="PromotionList" />
|
<PromotionAssembleLayout v-if="PromotionList && !isECouponGoods" :detail="goodsDetail" :res="PromotionList" />
|
||||||
|
|
||||||
<view class="card-box top-radius-0" id="main2">
|
<view class="card-box top-radius-0" id="main2">
|
||||||
<!-- 活动不显示价钱 -->
|
<!-- 活动不显示价钱 -->
|
||||||
@@ -172,7 +172,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="card-box">
|
<!-- 促销/领券入口(E_COUPON 隐藏) -->
|
||||||
|
<view class="card-box" v-if="!isECouponGoods">
|
||||||
<view class="card-flex" @click="shutMask(1)">
|
<view class="card-flex" @click="shutMask(1)">
|
||||||
<view class="card-title"> 促销 </view>
|
<view class="card-title"> 促销 </view>
|
||||||
<view class="card-content">
|
<view class="card-content">
|
||||||
@@ -186,10 +187,10 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 拼团用户列表 -->
|
<!-- 拼团用户列表 -->
|
||||||
<PromotionAssembleListLayout v-if="isGroup" @to-assemble-buy-now="toAssembleBuyNow" :res="PromotionList" />
|
<PromotionAssembleListLayout v-if="isGroup && !isECouponGoods" @to-assemble-buy-now="toAssembleBuyNow" :res="PromotionList" />
|
||||||
|
|
||||||
<!-- 配置地址 如果是虚拟产品的时候不展示 -->
|
<!-- 实物配送地址;E_COUPON / VIRTUAL_GOODS 均不展示 -->
|
||||||
<view class="card-box" v-if="goodsDetail.goodsType != 'VIRTUAL_GOODS'">
|
<view class="card-box" v-if="!isNonPhysicalGoodsType">
|
||||||
<view class="card-flex" @click="shutMask(4)">
|
<view class="card-flex" @click="shutMask(4)">
|
||||||
<view class="card-title"> 已选 </view>
|
<view class="card-title"> 已选 </view>
|
||||||
<view class="card-content">
|
<view class="card-content">
|
||||||
@@ -259,9 +260,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 正常结算页面 -->
|
<!-- 正常结算页面 -->
|
||||||
<view class="detail-btn" v-if="!isGroup && !takeDownFromSale">
|
<view class="detail-btn" v-if="!isGroup && !takeDownFromSale">
|
||||||
<view class="to-store-car to-store-btn" v-if="goodsDetail.goodsType != 'VIRTUAL_GOODS'" @click="shutMask(4)">
|
<view class="to-store-car to-store-btn" v-if="showAddToCart" @click="shutMask(4)">
|
||||||
加入购物车</view>
|
加入购物车</view>
|
||||||
<view class="to-buy to-store-btn" @click="shutMask(4, 'buy')">立即购买</view>
|
<view class="to-buy to-store-btn" :class="{ 'to-buy--full': isECouponGoods }" @click="shutMask(4, 'buy')">立即购买</view>
|
||||||
<view class="to-store-car to-store-btn" v-if="startTimer">暂未开始</view>
|
<view class="to-store-car to-store-btn" v-if="startTimer">暂未开始</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 拼团结算 -->
|
<!-- 拼团结算 -->
|
||||||
@@ -328,6 +329,7 @@ import storage from '@/utils/storage.js'
|
|||||||
/************工具函数***************/
|
/************工具函数***************/
|
||||||
import { useStore } from '@/store'
|
import { useStore } from '@/store'
|
||||||
import { unitPrice, goodsFormatPrice, isLogin, parseGoodsImageUrl, clearStrComma, talkIm } from '@/utils/filters.js'
|
import { unitPrice, goodsFormatPrice, isLogin, parseGoodsImageUrl, clearStrComma, talkIm } from '@/utils/filters.js'
|
||||||
|
import { isECoupon, isNonPhysicalGoods } from '@/utils/goodsType.js'
|
||||||
|
|
||||||
/************组件***************/
|
/************组件***************/
|
||||||
import PromotionLayout from './product/promotion/-promotion'
|
import PromotionLayout from './product/promotion/-promotion'
|
||||||
@@ -428,6 +430,13 @@ const IM = computed(() => {
|
|||||||
return IMLink.value + storeDetail.value.merchantEuid
|
return IMLink.value + storeDetail.value.merchantEuid
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// E_COUPON:仅立即购买,隐藏促销/地址/加购(FR-B-01 / P-08)
|
||||||
|
const isECouponGoods = computed(() => isECoupon(goodsDetail.value?.goodsType))
|
||||||
|
const isNonPhysicalGoodsType = computed(() => isNonPhysicalGoods(goodsDetail.value?.goodsType))
|
||||||
|
const showAddToCart = computed(() => {
|
||||||
|
return !isNonPhysicalGoodsType.value && !isECouponGoods.value
|
||||||
|
})
|
||||||
|
|
||||||
// watch
|
// watch
|
||||||
watch(isGroup, (val) => {
|
watch(isGroup, (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
@@ -538,6 +547,10 @@ async function init(id: any, goodsId: any, distributionId = "") {
|
|||||||
|
|
||||||
PromotionList.value &&
|
PromotionList.value &&
|
||||||
Object.keys(PromotionList.value).forEach((item: string) => {
|
Object.keys(PromotionList.value).forEach((item: string) => {
|
||||||
|
// E_COUPON 不参与拼团/秒杀(M-01),避免底部出现拼团双按钮
|
||||||
|
if (isECoupon(goodsDetail.value?.goodsType)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (item.indexOf("PINTUAN") == 0) {
|
if (item.indexOf("PINTUAN") == 0) {
|
||||||
isGroup.value = true
|
isGroup.value = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ page {
|
|||||||
border-radius: 214px;
|
border-radius: 214px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
> .to-buy--full {
|
||||||
|
flex: 1;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
> .pt-buy {
|
> .pt-buy {
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
91
utils/goodsType.js
Normal file
91
utils/goodsType.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* @Author Mike
|
||||||
|
* @Date 2026-07-31
|
||||||
|
*
|
||||||
|
* 卡密商品(电子卡券 E_COUPON)类型与订单工具。
|
||||||
|
*
|
||||||
|
* 与 VIRTUAL_GOODS / VIRTUAL 核销商品区分:E_COUPON 走 BUY_NOW、支付后 COMPLETED + cardKeys,
|
||||||
|
* 不支持加购、促销与买家售后。需求见 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)) */
|
||||||
|
export const E_COUPON_MAX_BUY_NUM = 999
|
||||||
|
|
||||||
|
export function isECoupon(goodsType) {
|
||||||
|
return goodsType === E_COUPON_GOODS_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isECouponOrder(orderType) {
|
||||||
|
return orderType === E_COUPON_ORDER_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVirtualGoods(goodsType) {
|
||||||
|
return goodsType === VIRTUAL_GOODS_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVirtualOrder(orderType) {
|
||||||
|
return orderType === VIRTUAL_ORDER_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 非实物:含 E_COUPON 与核销型 VIRTUAL_GOODS(详情页隐藏「送至」等) */
|
||||||
|
export function isNonPhysicalGoods(goodsType) {
|
||||||
|
return isECoupon(goodsType) || isVirtualGoods(goodsType)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isNonPhysicalOrder(orderType) {
|
||||||
|
return isECouponOrder(orderType) || isVirtualOrder(orderType)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 可售库存:E_COUPON 以卡池 poolStock 为准,quantity 仅为镜像回退 */
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getECouponMaxBuyNum(sku) {
|
||||||
|
const stock = getECouponStock(sku)
|
||||||
|
if (stock <= 0) return 1
|
||||||
|
return Math.min(stock, E_COUPON_MAX_BUY_NUM)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算页识别当前交易是否含 E_COUPON SKU。
|
||||||
|
* 须从 goodsSku.goodsType 判断,不能依赖 cartTypeEnum=VIRTUAL(E_COUPON 仍是 BUY_NOW)。
|
||||||
|
*/
|
||||||
|
export function hasECouponInCheckout(orderMessage) {
|
||||||
|
if (!orderMessage) return false
|
||||||
|
const checked = orderMessage.checkedSkuList || []
|
||||||
|
if (checked.some((item) => isECoupon(item?.goodsSku?.goodsType))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const cartList = orderMessage.cartList || []
|
||||||
|
return cartList.some((cart) =>
|
||||||
|
(cart.checkedSkuList || []).some((item) =>
|
||||||
|
isECoupon(item?.goodsSku?.goodsType)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将 orderItems[].cardKeys 展平为列表,供卡密二级页展示 */
|
||||||
|
export function flattenOrderCardKeys(orderItems) {
|
||||||
|
const rows = []
|
||||||
|
;(orderItems || []).forEach((item) => {
|
||||||
|
;(item.cardKeys || []).forEach((ck) => {
|
||||||
|
rows.push({ ...ck })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否已发卡(API-B-01:cardKeyDelivered 或 orderItems 内标记) */
|
||||||
|
export function isCardKeyDelivered(orderItems) {
|
||||||
|
return (orderItems || []).some((item) => item.cardKeyDelivered)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user