|
|
@@ -1,10 +1,23 @@
|
|
|
<template>
|
|
|
<view class="packet-page">
|
|
|
<!-- Background -->
|
|
|
- <image src="/packet/static/index/background.png" class="bg-image" mode="widthFix"></image>
|
|
|
+ <image v-if="!isFailState" src="/packet/static/index/background.png" class="bg-image" mode="widthFix"></image>
|
|
|
|
|
|
<!-- Main Content -->
|
|
|
- <view class="content-wrapper">
|
|
|
+ <view v-if="isFailState" class="fail-wrapper">
|
|
|
+ <view class="fail-card">
|
|
|
+ <view class="fail-icon" :class="'fail-icon--' + failState.iconType">
|
|
|
+ <text class="fail-icon__text">{{ failState.iconText }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="fail-title">{{ failState.title }}</view>
|
|
|
+ <view class="fail-desc">{{ failState.desc }}</view>
|
|
|
+ <view class="fail-btn" @click="goHome">
|
|
|
+ <text>进入首页</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-else class="content-wrapper">
|
|
|
<!-- Headline -->
|
|
|
<image src="/packet/static/index/headline.png" class="headline-image" mode="widthFix"></image>
|
|
|
|
|
|
@@ -24,7 +37,8 @@
|
|
|
<!-- Receive Button -->
|
|
|
<view class="receive-btn-wrapper" @click="handleReceive">
|
|
|
<image src="/packet/static/index/btn_receive.png" class="btn-image" mode="widthFix"></image>
|
|
|
- <text class="btn-text" v-if="!redBagData.drawStatus">领{{ amount }}元红包 | 买书卖书都能用</text>
|
|
|
+ <text class="btn-text" v-if="!redBagData || !redBagData.drawStatus">领{{ amount }}元红包 |
|
|
|
+ 买书卖书都能用</text>
|
|
|
<text class="btn-text" v-else>已领取</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -48,12 +62,29 @@
|
|
|
<text>无门槛使用</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <view class="rule-footer">
|
|
|
+ <view class="rule-footer" @click="openRulePopup">
|
|
|
<text class="rule-text">活动规则</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
+
|
|
|
+ <u-popup v-model="showRulePopup" mode="center" border-radius="24" :mask-close-able="true">
|
|
|
+ <view class="rule-popup">
|
|
|
+ <view class="rule-popup__header">
|
|
|
+ <text class="rule-popup__title">活动规则</text>
|
|
|
+ <view class="rule-popup__close" @click="closeRulePopup">x</view>
|
|
|
+ </view>
|
|
|
+ <scroll-view scroll-y class="rule-popup__body">
|
|
|
+ <view class="rule-popup__item" v-for="(item, index) in ruleList" :key="index">
|
|
|
+ <text>{{ index + 1 }}.{{ item }}</text>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ <view class="rule-popup__footer" @click="closeRulePopup">
|
|
|
+ <text class="rule-popup__btn">我知道了</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </u-popup>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
@@ -65,7 +96,22 @@
|
|
|
return {
|
|
|
amount: '1.58',
|
|
|
bianhao: '', // 红包编号
|
|
|
- redBagData: null // 红包数据
|
|
|
+ redBagData: null, // 红包数据
|
|
|
+ failState: null, // 扫码失败态
|
|
|
+ showRulePopup: false,
|
|
|
+ ruleList: [
|
|
|
+ '活动时间:2026年05月01日至2028年05月30日。',
|
|
|
+ '活动期间,用户扫描书嗨专属红包码,均有机会获得书嗨无门槛红包或现金红包。',
|
|
|
+ '每位用户每获得一个红包有一次机会成为发起者。每人最多可赠送3位好友,分享者和好友均可获得书嗨无门槛红包或现金红包。',
|
|
|
+ '助力者仅限新用户。',
|
|
|
+ '助力红包发放时间:活动时间内,点击领取红包券,会实时到账小程序红包。',
|
|
|
+ '无门槛红包可用于买书或卖书,买书订单将抵扣消费金额,卖书订单将加于书款上。'
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ isFailState() {
|
|
|
+ return !!this.failState;
|
|
|
}
|
|
|
},
|
|
|
onLoad(options) {
|
|
|
@@ -102,6 +148,92 @@
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ getCantTypeValue(source = {}) {
|
|
|
+ const rawCantType = source.cantType;
|
|
|
+ if (rawCantType === undefined || rawCantType === null || rawCantType === '') {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const cantType = Number(rawCantType);
|
|
|
+ return Number.isNaN(cantType) ? null : cantType;
|
|
|
+ },
|
|
|
+ buildFailState(source = {}, fallbackMsg = '') {
|
|
|
+ const cantType = this.getCantTypeValue(source);
|
|
|
+ if (cantType === null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const scanCount = source.scanNum || source.scanCount || source.usedCount || source.count || '';
|
|
|
+ const failStateMap = {
|
|
|
+ 0: {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: scanCount ? `此二维码已被扫 ${scanCount} 次` : '扫码次数超上限',
|
|
|
+ desc: scanCount ? '该二维码可参与次数已用完,请更换二维码后重试。' : '该二维码可参与次数已达上限,请更换二维码后重试。'
|
|
|
+ },
|
|
|
+ 1: {
|
|
|
+ iconType: 'ban',
|
|
|
+ iconText: 'x',
|
|
|
+ title: '扫码禁用',
|
|
|
+ desc: '您的扫码功能已被禁用,当前无法领取红包。'
|
|
|
+ },
|
|
|
+ 3: {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: '系统繁忙',
|
|
|
+ desc: fallbackMsg || '系统开小差了,请稍后再试。'
|
|
|
+ },
|
|
|
+ 4: {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: '活动已结束',
|
|
|
+ desc: '很抱歉,当前活动已结束,无法继续领取红包。'
|
|
|
+ },
|
|
|
+ 5: {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: '您不是新用户',
|
|
|
+ desc: '抱歉!您不是新用户,无法领取分享红包。'
|
|
|
+ },
|
|
|
+ 6: {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: '分享超限',
|
|
|
+ desc: '当前分享次数已达上限,无法继续领取分享红包。'
|
|
|
+ },
|
|
|
+ 7: {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: '二维码已使用',
|
|
|
+ desc: '当前二维码已被使用,不能重复领取。'
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return failStateMap[cantType] || {
|
|
|
+ iconType: 'warn',
|
|
|
+ iconText: '!',
|
|
|
+ title: '领取失败',
|
|
|
+ desc: fallbackMsg || '当前无法领取红包,请稍后再试。'
|
|
|
+ };
|
|
|
+ },
|
|
|
+ applyCantTypeState(source = {}, fallbackMsg = '') {
|
|
|
+ const failState = this.buildFailState(source, fallbackMsg);
|
|
|
+ if (!failState) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ this.failState = failState;
|
|
|
+ this.redBagData = null;
|
|
|
+ uni.hideLoading();
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+ goHome() {
|
|
|
+ uni.switchTab({
|
|
|
+ url: '/pages/sell/index'
|
|
|
+ });
|
|
|
+ },
|
|
|
+ openRulePopup() {
|
|
|
+ this.showRulePopup = true;
|
|
|
+ },
|
|
|
+ closeRulePopup() {
|
|
|
+ this.showRulePopup = false;
|
|
|
+ },
|
|
|
// 请求前确保 token 可用,避免扫码冷启动时出现 401
|
|
|
async ensureTokenReady() {
|
|
|
const token = uni.getStorageSync('token')
|
|
|
@@ -136,7 +268,11 @@
|
|
|
|
|
|
this.$u.api.scanRedBagAjax(this.bianhao).then(res => {
|
|
|
console.log('扫码获取红包信息成功:', res);
|
|
|
+ if (this.applyCantTypeState(res.data || res, res.msg)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (res.code === 200) {
|
|
|
+ this.failState = null;
|
|
|
this.redBagData = res.data;
|
|
|
this.amount = res.data.redPrice;
|
|
|
} else {
|
|
|
@@ -149,15 +285,6 @@
|
|
|
},
|
|
|
// 领取红包
|
|
|
async handleReceive() {
|
|
|
- // 如果已领取,提示用户
|
|
|
- if (this.redBagData && this.redBagData.drawStatus === 1) {
|
|
|
- uni.showToast({
|
|
|
- title: '红包已领取',
|
|
|
- icon: 'none'
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
if (!this.bianhao) {
|
|
|
uni.showToast({
|
|
|
title: '红包编号缺失',
|
|
|
@@ -183,9 +310,19 @@
|
|
|
try {
|
|
|
const res = await this.$u.api.getRedBagAjax(this.bianhao);
|
|
|
uni.hideLoading();
|
|
|
+ if (this.applyCantTypeState(res.data || res, res.msg)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (res.code === 200) {
|
|
|
// 更新红包数据
|
|
|
+ this.failState = null;
|
|
|
this.redBagData = res.data;
|
|
|
+
|
|
|
+ //如果是现金红包,执行确认收款操作
|
|
|
+ if (res.data.redType == 1) {
|
|
|
+ return this.handleConfirmReceipt(res.data)
|
|
|
+ }
|
|
|
+
|
|
|
uni.showToast({
|
|
|
title: '领取成功',
|
|
|
icon: 'success'
|
|
|
@@ -211,6 +348,36 @@
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
+ //执行微信确认收款操作
|
|
|
+ handleConfirmReceipt(data) {
|
|
|
+ if (wx.canIUse('requestMerchantTransfer')) {
|
|
|
+ wx.requestMerchantTransfer({
|
|
|
+ mchId: data.mchId,
|
|
|
+ appId: data.appId,
|
|
|
+ package: data.packageInfo,
|
|
|
+ success: (res) => {
|
|
|
+ // res.err_msg将在页面展示成功后返回应用时返回ok,并不代表付款成功
|
|
|
+ uni.showToast({
|
|
|
+ title: '确认收款成功',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ //跳转到首页
|
|
|
+ uni.switchTab({
|
|
|
+ url: '/pages/sell/index'
|
|
|
+ });
|
|
|
+ },
|
|
|
+ fail: (res) => {
|
|
|
+ console.log('fail:', res);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ wx.showModal({
|
|
|
+ content: '你的微信版本过低,请更新至最新版本。',
|
|
|
+ showCancel: false
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
handleShare() {
|
|
|
// Share logic
|
|
|
}
|
|
|
@@ -226,6 +393,7 @@
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
overflow: hidden;
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
|
.bg-image {
|
|
|
position: absolute;
|
|
|
@@ -299,6 +467,7 @@
|
|
|
}
|
|
|
|
|
|
.btn-text {
|
|
|
+ display: inline-block;
|
|
|
position: absolute;
|
|
|
top: 45%;
|
|
|
left: 50%;
|
|
|
@@ -307,6 +476,7 @@
|
|
|
color: #D73800;
|
|
|
font-weight: 500;
|
|
|
white-space: nowrap;
|
|
|
+ word-break: keep-all;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -356,6 +526,7 @@
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
margin-top: 30rpx;
|
|
|
+ cursor: pointer;
|
|
|
|
|
|
.rule-text {
|
|
|
font-size: 26rpx;
|
|
|
@@ -392,4 +563,165 @@
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .fail-wrapper {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 100vh;
|
|
|
+ padding: 120rpx 48rpx 80rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: flex-start;
|
|
|
+ background: #FFFFFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fail-card {
|
|
|
+ width: 100%;
|
|
|
+ background: transparent;
|
|
|
+ border-radius: 0;
|
|
|
+ padding: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fail-icon {
|
|
|
+ width: 144rpx;
|
|
|
+ height: 144rpx;
|
|
|
+ border-radius: 72rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-bottom: 36rpx;
|
|
|
+ border: 6rpx solid #FF5A5F;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &--ban {
|
|
|
+ border-color: #FF9F1A;
|
|
|
+ background: rgba(255, 159, 26, 0.08);
|
|
|
+ }
|
|
|
+
|
|
|
+ &--warn {
|
|
|
+ border-color: #F34A45;
|
|
|
+ background: rgba(243, 74, 69, 0.06);
|
|
|
+ }
|
|
|
+
|
|
|
+ &__text {
|
|
|
+ font-size: 76rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1;
|
|
|
+ color: #F34A45;
|
|
|
+ text-transform: uppercase;
|
|
|
+ }
|
|
|
+
|
|
|
+ &--ban &__text {
|
|
|
+ color: #FF9F1A;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .fail-title {
|
|
|
+ font-size: 40rpx;
|
|
|
+ line-height: 56rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #222222;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fail-desc {
|
|
|
+ font-size: 30rpx;
|
|
|
+ line-height: 46rpx;
|
|
|
+ color: #666666;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 72rpx;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fail-btn {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 520rpx;
|
|
|
+ height: 88rpx;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ background: linear-gradient(90deg, #FF453A 0%, #F5221E 100%);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ text {
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .rule-popup {
|
|
|
+ width: 640rpx;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ padding: 36rpx 32rpx 30rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &__header {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 28rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__title {
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #222222;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__close {
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ width: 44rpx;
|
|
|
+ height: 44rpx;
|
|
|
+ line-height: 44rpx;
|
|
|
+ text-align: center;
|
|
|
+ border-radius: 22rpx;
|
|
|
+ background: #F2F3F5;
|
|
|
+ color: #666666;
|
|
|
+ font-size: 26rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__body {
|
|
|
+ max-height: 720rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__item {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+ line-height: 46rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__btn {
|
|
|
+ min-width: 240rpx;
|
|
|
+ height: 72rpx;
|
|
|
+ line-height: 72rpx;
|
|
|
+ text-align: center;
|
|
|
+ background: linear-gradient(90deg, #6ADD83 0%, #38C148 100%);
|
|
|
+ border-radius: 36rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ padding: 0 30rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ }
|
|
|
</style>
|