Files
lilishop-uniapp/pages/order/cardKey/cardKeyDetail.vue
田香琪 a6ba2b3dbe feat: 添加电子卡券功能及相关逻辑
- 在 pages.json 中新增卡密详情页面路径
- 在多个组件中实现电子卡券(E_COUPON)逻辑,包括库存管理、结算页面处理、订单详情展示等
- 优化商品页面和订单页面以支持电子卡券的特性,隐藏不适用的功能
- 新增 utils/goodsType.js 文件,集中管理与电子卡券相关的类型和工具函数
- 更新样式以适应电子卡券的展示需求
2026-07-31 13:57:14 +08:00

214 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
@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>