mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git
synced 2026-08-06 10:57:25 +08:00
feat: 更新电子卡券卡密详情页及相关逻辑
- 修改卡密详情页以支持多种卡密展示,优化卡密信息的结构和样式 - 增加卡密履约状态管理,支持卡密发放状态的显示 - 更新 utils/goodsType.js,增加卡密履约状态的处理逻辑 - 优化数据加载逻辑,确保卡密信息的准确性和完整性
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
@Author Mike
|
@Author Mike
|
||||||
@Date 2026-07-31
|
@Date 2026-08-03
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<view class="card-key-page">
|
<view class="card-key-page">
|
||||||
@@ -11,21 +11,34 @@
|
|||||||
</view>
|
</view>
|
||||||
<view v-else>
|
<view v-else>
|
||||||
<view
|
<view
|
||||||
class="card-key-item"
|
v-for="(line, lineIndex) in cardKeyFulfillLines"
|
||||||
v-for="(row, index) in cardKeyRows"
|
:key="line.key || lineIndex"
|
||||||
:key="`${row.cardNo || index}-${index}`"
|
class="card-key-fulfill-block"
|
||||||
>
|
>
|
||||||
<view class="card-key-item__title">卡密 {{ index + 1 }}</view>
|
<view v-if="cardKeyFulfillLines.length > 1" class="card-key-fulfill-title">
|
||||||
<view class="card-key-item__row">
|
{{ line.goodsName || (line.isGift ? '满赠电子卡券' : '电子卡券') }}
|
||||||
<text class="card-key-item__label">卡号:</text>
|
|
||||||
<text class="card-key-item__value">{{ row.cardNo || '-' }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="card-key-item__row">
|
<view
|
||||||
<text class="card-key-item__label">卡密:</text>
|
class="card-key-item"
|
||||||
<text class="card-key-item__value">{{ row.cardSecret || '-' }}</text>
|
v-for="(row, index) in line.cardKeys"
|
||||||
</view>
|
:key="`${line.key}-${row.cardNo || index}-${index}`"
|
||||||
<view class="card-key-item__actions">
|
>
|
||||||
<view class="card-key-item__copy" @click="copyCardKey(row)">复制</view>
|
<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 card-key-item__value--plain" selectable>{{
|
||||||
|
row.cardNo || '-'
|
||||||
|
}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-key-item__row">
|
||||||
|
<text class="card-key-item__label">卡密:</text>
|
||||||
|
<text class="card-key-item__value card-key-item__value--plain" selectable>{{
|
||||||
|
row.cardSecret || '-'
|
||||||
|
}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-key-item__actions">
|
||||||
|
<view class="card-key-item__copy" @click="copyCardKey(row)">复制</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-key-page__footer">
|
<view class="card-key-page__footer">
|
||||||
@@ -37,12 +50,8 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
/**
|
/**
|
||||||
* @Author Mike
|
|
||||||
* @Date 2026-07-31
|
|
||||||
*
|
|
||||||
* 电子卡券卡密二级页(原型 P-09)。
|
* 电子卡券卡密二级页(原型 P-09)。
|
||||||
* 数据来源:GET /buyer/order/order/{orderSn} → orderItems[].cardKeys;
|
* 数据来源:GET /buyer/order/order/{orderSn} → orderItems[].cardKeys(明文 cardSecret)。
|
||||||
* 不展示过期时间;未发卡/非 E_COUPON 订单不泄露 cardSecret。
|
|
||||||
*/
|
*/
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
||||||
@@ -50,22 +59,40 @@ import { getOrderDetail } from '@/api/order.js'
|
|||||||
import { setClipboard } from '@/utils/filters.js'
|
import { setClipboard } from '@/utils/filters.js'
|
||||||
import {
|
import {
|
||||||
isECouponOrder,
|
isECouponOrder,
|
||||||
|
collectCardKeyFulfillLines,
|
||||||
flattenOrderCardKeys,
|
flattenOrderCardKeys,
|
||||||
isCardKeyDelivered,
|
resolveCardKeyFulfillMessage,
|
||||||
|
CARD_KEY_FULFILL_STATUS,
|
||||||
} from '@/utils/goodsType.js'
|
} from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const orderSn = ref('')
|
const orderSn = ref('')
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
const orderItems = ref<any[]>([])
|
const orderItems = ref<any[]>([])
|
||||||
|
const giftECouponOrders = ref<any[]>([])
|
||||||
const orderStatus = ref('')
|
const orderStatus = ref('')
|
||||||
|
|
||||||
const cardKeyRows = computed(() => flattenOrderCardKeys(orderItems.value))
|
const cardKeyFulfillLines = computed(() =>
|
||||||
|
collectCardKeyFulfillLines(orderItems.value, giftECouponOrders.value).filter(
|
||||||
|
(line) => line.status === CARD_KEY_FULFILL_STATUS.DELIVERED && line.cardKeys.length
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const cardKeyRows = computed(() =>
|
||||||
|
flattenOrderCardKeys(orderItems.value, false, giftECouponOrders.value)
|
||||||
|
)
|
||||||
|
|
||||||
const emptyMessage = computed(() => {
|
const emptyMessage = computed(() => {
|
||||||
if (orderStatus.value === 'CANCELLED') {
|
if (orderStatus.value === 'CANCELLED') {
|
||||||
return '订单已关闭,暂无卡密信息'
|
return '订单已关闭,暂无卡密信息'
|
||||||
}
|
}
|
||||||
|
const pending = collectCardKeyFulfillLines(
|
||||||
|
orderItems.value,
|
||||||
|
giftECouponOrders.value
|
||||||
|
).find((line) => line.status !== CARD_KEY_FULFILL_STATUS.DELIVERED)
|
||||||
|
if (pending) {
|
||||||
|
return resolveCardKeyFulfillMessage(pending)
|
||||||
|
}
|
||||||
if (orderStatus.value === 'COMPLETED') {
|
if (orderStatus.value === 'COMPLETED') {
|
||||||
return '卡密尚未发放,请稍后刷新'
|
return '卡密尚未发放,请稍后刷新'
|
||||||
}
|
}
|
||||||
@@ -99,16 +126,16 @@ function loadData(fromPullDown = false) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const result = res.data.result
|
const result = res.data.result
|
||||||
if (!isECouponOrder(result?.order?.orderType)) {
|
const isEcoupon = isECouponOrder(result?.order?.orderType)
|
||||||
errorMessage.value = '该订单不是电子卡券订单'
|
const hasGiftEcoupon =
|
||||||
|
Array.isArray(result?.giftECouponOrders) && result.giftECouponOrders.length > 0
|
||||||
|
if (!isEcoupon && !hasGiftEcoupon) {
|
||||||
|
errorMessage.value = '该订单没有电子卡券卡密'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
orderItems.value = result.orderItems || []
|
orderItems.value = result.orderItems || []
|
||||||
|
giftECouponOrders.value = result.giftECouponOrders || []
|
||||||
orderStatus.value = result.order?.orderStatus || ''
|
orderStatus.value = result.order?.orderStatus || ''
|
||||||
// 未 cardKeyDelivered 时不展示卡密(UNPAID/PAID 发卡中或发卡失败)
|
|
||||||
if (!isCardKeyDelivered(orderItems.value)) {
|
|
||||||
orderItems.value = []
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
errorMessage.value = '加载失败,请稍后重试'
|
errorMessage.value = '加载失败,请稍后重试'
|
||||||
@@ -154,6 +181,12 @@ function copyAllCardKeys() {
|
|||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-key-fulfill-title {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.card-key-item {
|
.card-key-item {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
@@ -186,6 +219,11 @@ function copyAllCardKeys() {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-key-item__value--plain {
|
||||||
|
font-family: monospace;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.card-key-item__actions {
|
.card-key-item__actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
<view v-if="ecouponCardKeyDelivered" class="card-key-entry__btn" @click="goCardKeyDetail">
|
<view v-if="ecouponCardKeyDelivered" class="card-key-entry__btn" @click="goCardKeyDetail">
|
||||||
查看卡密
|
查看卡密
|
||||||
</view>
|
</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 v-else-if="order.orderStatus === 'CANCELLED'" class="card-key-entry__tip">
|
||||||
订单已关闭
|
订单已关闭
|
||||||
</view>
|
</view>
|
||||||
|
<view v-else class="card-key-entry__tip">
|
||||||
|
{{ ecouponPendingMessage || '卡密尚未发放,请稍后刷新' }}
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="verificationCode" v-else-if="order.verificationCode">
|
<view class="verificationCode" v-else-if="order.verificationCode">
|
||||||
券码: {{ order.orderStatus == 'CANCELLED' ? '已失效' : order.verificationCode }}
|
券码: {{ order.orderStatus == 'CANCELLED' ? '已失效' : order.verificationCode }}
|
||||||
@@ -278,7 +278,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
isECouponOrder as checkECouponOrder,
|
isECouponOrder as checkECouponOrder,
|
||||||
isNonPhysicalOrder as checkNonPhysicalOrder,
|
isNonPhysicalOrder as checkNonPhysicalOrder,
|
||||||
isCardKeyDelivered,
|
orderHasCardKeyContent,
|
||||||
|
collectCardKeyFulfillLines,
|
||||||
|
resolveCardKeyFulfillMessage,
|
||||||
|
CARD_KEY_FULFILL_STATUS,
|
||||||
} from '@/utils/goodsType.js'
|
} from '@/utils/goodsType.js'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@@ -309,11 +312,21 @@ const cancelList = ref<any[]>([])
|
|||||||
const rogShow = ref(false)
|
const rogShow = ref(false)
|
||||||
const reason = ref('')
|
const reason = ref('')
|
||||||
const orderPackage = ref<any>('')
|
const orderPackage = ref<any>('')
|
||||||
|
const giftECouponOrders = ref<any[]>([])
|
||||||
|
|
||||||
// orderType=E_COUPON:无物流/核销码,卡密见 cardKeyDetail(API-B-01 orderItems[].cardKeys)
|
// orderType=E_COUPON:无物流/核销码,卡密见 cardKeyDetail(API-B-01 orderItems[].cardKeys)
|
||||||
const isECouponOrder = computed(() => checkECouponOrder(order.value?.orderType))
|
const isECouponOrder = computed(() => checkECouponOrder(order.value?.orderType))
|
||||||
const isNonPhysicalOrder = computed(() => checkNonPhysicalOrder(order.value?.orderType))
|
const isNonPhysicalOrder = computed(() => checkNonPhysicalOrder(order.value?.orderType))
|
||||||
const ecouponCardKeyDelivered = computed(() => isCardKeyDelivered(orderGoodsList.value))
|
const ecouponCardKeyDelivered = computed(() =>
|
||||||
|
orderHasCardKeyContent(orderGoodsList.value, giftECouponOrders.value)
|
||||||
|
)
|
||||||
|
const ecouponPendingMessage = computed(() => {
|
||||||
|
const pending = collectCardKeyFulfillLines(
|
||||||
|
orderGoodsList.value,
|
||||||
|
giftECouponOrders.value
|
||||||
|
).find((line) => line.status !== CARD_KEY_FULFILL_STATUS.DELIVERED)
|
||||||
|
return pending ? resolveCardKeyFulfillMessage(pending) : ''
|
||||||
|
})
|
||||||
|
|
||||||
function hideLoadingIfNeeded() {
|
function hideLoadingIfNeeded() {
|
||||||
if (store.state.isShowToast) uni.hideLoading()
|
if (store.state.isShowToast) uni.hideLoading()
|
||||||
@@ -399,6 +412,7 @@ 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
|
||||||
|
giftECouponOrders.value = result.giftECouponOrders || []
|
||||||
if (
|
if (
|
||||||
result.order.deliveryMethod === 'LOGISTICS' &&
|
result.order.deliveryMethod === 'LOGISTICS' &&
|
||||||
!checkECouponOrder(result.order.orderType) &&
|
!checkECouponOrder(result.order.orderType) &&
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @Author Mike
|
* @Author Mike
|
||||||
* @Date 2026-07-31
|
* @Date 2026-08-03
|
||||||
*
|
*
|
||||||
* 卡密商品(电子卡券 E_COUPON)类型与订单工具。
|
* 卡密商品(电子卡券 E_COUPON)类型与订单工具。
|
||||||
*
|
*
|
||||||
@@ -71,18 +71,105 @@ export function hasECouponInCheckout(orderMessage) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 将 orderItems[].cardKeys 展平为列表,供卡密二级页展示 */
|
/** 卡密履约状态(与后端 CardKeyFulfillStatusEnum 一致) */
|
||||||
export function flattenOrderCardKeys(orderItems) {
|
export const CARD_KEY_FULFILL_STATUS = {
|
||||||
const rows = []
|
PENDING: 'PENDING',
|
||||||
|
DELIVERED: 'DELIVERED',
|
||||||
|
FAILED: 'FAILED',
|
||||||
|
NOT_APPLICABLE: 'NOT_APPLICABLE',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CARD_KEY_FULFILL_STATUS_TEXT = {
|
||||||
|
PENDING: '待发放',
|
||||||
|
DELIVERED: '已发放',
|
||||||
|
FAILED: '发放失败',
|
||||||
|
NOT_APPLICABLE: '不适用',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveCardKeyFulfillMessage(line) {
|
||||||
|
if (line && line.message) return line.message
|
||||||
|
return CARD_KEY_FULFILL_STATUS_TEXT[line?.status] || line?.status || '—'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCardKeyFulfillApplicable(item) {
|
||||||
|
if (!item) return false
|
||||||
|
const status = item.cardKeyFulfillStatus
|
||||||
|
if (status) return status !== CARD_KEY_FULFILL_STATUS.NOT_APPLICABLE
|
||||||
|
if (item.cardKeyDelivered != null || (item.cardKeys && item.cardKeys.length)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return item.goodsType === E_COUPON_GOODS_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCardKeyFulfillLine(source) {
|
||||||
|
const status =
|
||||||
|
source.cardKeyFulfillStatus ||
|
||||||
|
(source.cardKeyDelivered
|
||||||
|
? CARD_KEY_FULFILL_STATUS.DELIVERED
|
||||||
|
: CARD_KEY_FULFILL_STATUS.PENDING)
|
||||||
|
const cardKeys =
|
||||||
|
status === CARD_KEY_FULFILL_STATUS.DELIVERED ? source.cardKeys || [] : []
|
||||||
|
return {
|
||||||
|
key: source.sn || source.orderSn || source.id || source.skuId,
|
||||||
|
goodsName: source.goodsName,
|
||||||
|
status,
|
||||||
|
message: source.cardKeyFulfillMessage,
|
||||||
|
cardKeys,
|
||||||
|
isGift: !!source.isGift,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 汇总 E_COUPON 主单行 + 满赠子单摘要的履约行 */
|
||||||
|
export function collectCardKeyFulfillLines(orderItems = [], giftSummaries = []) {
|
||||||
|
const lines = []
|
||||||
;(orderItems || []).forEach((item) => {
|
;(orderItems || []).forEach((item) => {
|
||||||
;(item.cardKeys || []).forEach((ck) => {
|
if (!isCardKeyFulfillApplicable(item)) return
|
||||||
rows.push({ ...ck })
|
lines.push(normalizeCardKeyFulfillLine(item))
|
||||||
|
})
|
||||||
|
;(giftSummaries || []).forEach((gift) => {
|
||||||
|
lines.push(normalizeCardKeyFulfillLine({ ...gift, isGift: true }))
|
||||||
|
})
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenCardKeyFulfillLines(lines, withGoodsName = false) {
|
||||||
|
const rows = []
|
||||||
|
;(lines || []).forEach((line) => {
|
||||||
|
if (line.status !== CARD_KEY_FULFILL_STATUS.DELIVERED) return
|
||||||
|
;(line.cardKeys || []).forEach((ck) => {
|
||||||
|
rows.push(withGoodsName ? { ...ck, goodsName: line.goodsName } : { ...ck })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 是否已发卡(API-B-01:cardKeyDelivered 或 orderItems 内标记) */
|
/** 订单是否含已交付卡密(含满赠 E_COUPON 子单) */
|
||||||
export function isCardKeyDelivered(orderItems) {
|
export function orderHasCardKeyContent(orderItems, giftSummaries) {
|
||||||
return (orderItems || []).some((item) => item.cardKeyDelivered)
|
const lines = collectCardKeyFulfillLines(orderItems, giftSummaries)
|
||||||
|
return flattenCardKeyFulfillLines(lines).length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将 orderItems[].cardKeys 展平为明文列表(DELIVERED 且含 cardSecret) */
|
||||||
|
export function flattenOrderCardKeys(
|
||||||
|
orderItems,
|
||||||
|
withGoodsName = false,
|
||||||
|
giftSummaries
|
||||||
|
) {
|
||||||
|
const lines = collectCardKeyFulfillLines(orderItems, giftSummaries)
|
||||||
|
if (lines.some((line) => line.status)) {
|
||||||
|
return flattenCardKeyFulfillLines(lines, withGoodsName)
|
||||||
|
}
|
||||||
|
const rows = []
|
||||||
|
;(orderItems || []).forEach((item) => {
|
||||||
|
if (!item.cardKeyDelivered || !item.cardKeys || !item.cardKeys.length) return
|
||||||
|
item.cardKeys.forEach((ck) => {
|
||||||
|
rows.push(withGoodsName ? { ...ck, goodsName: item.goodsName } : { ...ck })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否已发卡(兼容旧调用;含满赠子单) */
|
||||||
|
export function isCardKeyDelivered(orderItems, giftSummaries) {
|
||||||
|
return orderHasCardKeyContent(orderItems, giftSummaries)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user