1. extract common onShow login check to dedicated method redirectTologinOnShowLifecycle 2. add fallback callback for login failure to navigate back on wechat mini program 3. update all page login redirect calls to use the new unified method 4. add debug logs for redirect and auth flow tracing
430 lines
14 KiB
Vue
430 lines
14 KiB
Vue
<template>
|
|
<view class="member-level" :style="themeColor">
|
|
<block v-if="levelList.length">
|
|
<view class="level-top">
|
|
<image :src="$util.img('public/uniapp/level/card-top-bg.png')"></image>
|
|
</view>
|
|
<view class="banner-container">
|
|
<view class="memberInfo">
|
|
<image :src="$util.img(memberInfo.headimg)" v-if="memberInfo.headimg" @error="headimgError"
|
|
mode="aspectFill" show-menu-by-longpress/>
|
|
<image :src="$util.getDefaultImage().head" v-else mode="aspectFill" show-menu-by-longpress></image>
|
|
<view class="member-desc">
|
|
<view class="font-size-toolbar">{{ memberInfo.nickname }}</view>
|
|
<view class="font-size-tag expire-time" v-if="memberInfo.level_expire_time > 0">
|
|
{{ $lang('validUntil') }}{{ $util.timeStampTurnTime(memberInfo.level_expire_time, true) }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<swiper :style="{ width: '100vw', height: '390rpx' }" class="margin-bottom"
|
|
:indicator-dots="swiperConfig.indicatorDots" :indicator-color="swiperConfig.indicatorColor"
|
|
:indicator-active-color="swiperConfig.indicatorActiveColor" :autoplay="false"
|
|
:interval="swiperConfig.interval" :duration="swiperConfig.duration"
|
|
:circular="swiperConfig.circular" :previous-margin="swiperConfig.previousMargin"
|
|
:next-margin="swiperConfig.nextMargin" @change="swiperChange" @animationfinish="animationfinish"
|
|
:current="curIndex">
|
|
<swiper-item :class="levelList.length == 1 ? 'image-container-box' : ''"
|
|
v-for="(item, i) in levelList" :key="i">
|
|
<view class="image-container" :class="[
|
|
curIndex === 0
|
|
? i === listLen - 1
|
|
? 'item-left'
|
|
: i === 1
|
|
? 'item-right'
|
|
: 'item-center'
|
|
: curIndex === listLen - 1
|
|
? i === 0
|
|
? 'item-right'
|
|
: i === listLen - 2
|
|
? 'item-left'
|
|
: 'item-center'
|
|
: i === curIndex - 1
|
|
? 'item-left'
|
|
: i === curIndex + 1
|
|
? 'item-right'
|
|
: 'item-center'
|
|
]">
|
|
<view class="slide-image" style="background-size: 100% 100%;background-repeat:no-repeat"
|
|
:style="{
|
|
transform: curIndex === i ? 'scale(' + scaleX + ',' + scaleY + ')' : 'scale(1,1)',
|
|
transitionDuration: '.3s',
|
|
transitionTimingFunction: 'ease'
|
|
}">
|
|
<view class="bg-border"></view>
|
|
|
|
<image v-if="levelList[curIndex] && levelList[curIndex]['level_picture']"
|
|
:src="$util.img(levelList[curIndex]['level_picture'])" show-menu-by-longpress/>
|
|
<image v-else :style="{ backgroundColor: levelList[curIndex]['bg_color'] }" />
|
|
|
|
<view class="info">
|
|
<view class="level-detail" :style="{ color: levelList[curIndex]['level_text_color'] }">
|
|
{{ levelList[curIndex].level_name }}</view>
|
|
<view class="growr-name" :style="{ color: levelList[curIndex]['level_text_color'] }">{{
|
|
levelList[curIndex].level_name }}{{ $lang('enjoyDiscountAnd') }}</view>
|
|
<view class="growr-value" :style="{ color: levelList[curIndex]['level_text_color'] }">
|
|
{{ $lang('memberGiftBenefits') }}</view>
|
|
<view class="growth-rules font-size-tag" @click="openExplainPopup"
|
|
v-if="levelList[curIndex].remark != ''">
|
|
<text class="iconfont icon-wenhao font-size-tag"></text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</swiper-item>
|
|
</swiper>
|
|
|
|
<view class="card-content">
|
|
<view class="card-content-head">
|
|
<view class="line-box">
|
|
<view class="line right"></view>
|
|
</view>
|
|
<view class="card-content-title">{{ $lang('cardTypeSelection') }}</view>
|
|
<view class="line-box">
|
|
<view class="line"></view>
|
|
</view>
|
|
<view class="clear"></view>
|
|
</view>
|
|
<view class="card-time-list">
|
|
<view class="card-item-box" :class="{ small: currCard.charge_rule_arr.length == 4 }"
|
|
v-for="(item, index) in currCard.charge_rule_arr" :key="index">
|
|
<view class="card-time-item" :class="{ active: choiceIndex == index }"
|
|
@click="choice(index)">
|
|
<image :src="$util.img('public/uniapp/level/card-icon.png')" mode="widthFix"></image>
|
|
<view class="time-name">{{ cardType[item.key].name }}</view>
|
|
<view class="time-price">
|
|
{{ $lang('common.currencySymbol') }}
|
|
<text class="price">{{ item.value }}</text>
|
|
/{{ cardType[item.key].unit }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card-content"
|
|
v-if="currCard.is_free_shipping || currCard.consume_discount < 100 || currCard.point_feedback > 0">
|
|
<view class="card-content-head">
|
|
<view class="line-box">
|
|
<view class="line right"></view>
|
|
</view>
|
|
<view class="card-content-title">{{ $lang('memberBenefits') }}</view>
|
|
<view class="line-box">
|
|
<view class="line"></view>
|
|
</view>
|
|
<view class="clear"></view>
|
|
</view>
|
|
<view class="card-privilege-list">
|
|
<view class="card-privilege-item" v-if="currCard.is_free_shipping">
|
|
<view class="card-privilege-icon">
|
|
<text class="iconfont icon-tedianquanchangbaoyou"></text>
|
|
</view>
|
|
<view class="card-privilege-name">{{ $lang('freeShipping') }}</view>
|
|
<view class="card-privilege-text">{{ $lang('enjoyFreeShipping') }}</view>
|
|
</view>
|
|
<view class="card-privilege-item" v-if="currCard.consume_discount < 100">
|
|
<view class="card-privilege-icon"><text class="iconfont icon-zhekou"></text></view>
|
|
<view class="card-privilege-name">{{ $lang('consumptionDiscount') }}</view>
|
|
<view class="card-privilege-text">{{ $lang('enjoyDiscountOnSomeProducts', { discount: currCard.consume_discount / 10 }) }}</view>
|
|
</view>
|
|
<view class="card-privilege-item" v-if="currCard.point_feedback > 0">
|
|
<view class="card-privilege-icon"><text class="iconfont icon-jifen2 f32"></text></view>
|
|
<view class="card-privilege-name">{{ $lang('pointsReward') }}</view>
|
|
<view class="card-privilege-text">{{ $lang('earnPointsMultiplier', { multiplier: parseFloat(currCard.point_feedback) }) }}</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="currCard.send_coupon != '' || currCard.send_point > 0 || currCard.send_balance > 0">
|
|
<view class="card-content-head">
|
|
<view class="line-box">
|
|
<view class="line right"></view>
|
|
</view>
|
|
<view class="card-content-title">{{ $lang('welcomeGift') }}</view>
|
|
<view class="line-box">
|
|
<view class="line"></view>
|
|
</view>
|
|
<view class="clear"></view>
|
|
</view>
|
|
<view class="card-privilege-list">
|
|
<view class="card-privilege-item" v-if="currCard.send_point > 0">
|
|
<view class="card-privilege-icon"><text class="iconfont icon-jifen3"></text></view>
|
|
<view class="card-privilege-name">{{ $lang('pointsGift') }}</view>
|
|
<view class="card-privilege-text">{{ $lang('giftPoints', { points: currCard.send_point }) }}</view>
|
|
</view>
|
|
<view class="card-privilege-item" v-if="currCard.send_balance > 0">
|
|
<view class="card-privilege-icon"><text class="iconfont icon-hongbao"></text></view>
|
|
<view class="card-privilege-name">{{ $lang('redPacketGift') }}</view>
|
|
<view class="card-privilege-text">{{ $lang('giftRedPacket', { amount: parseFloat(currCard.send_balance) }) }}</view>
|
|
</view>
|
|
<view class="card-privilege-item" v-if="currCard.send_coupon != ''">
|
|
<view class="card-privilege-icon"><text class="iconfont icon-youhuiquan1"></text></view>
|
|
<view class="card-privilege-name">{{ $lang('couponGift') }}</view>
|
|
<view class="card-privilege-text">{{ $lang('giftCoupons', { count: currCard.send_coupon.split(',').length }) }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<block v-if="currCard.charge_rule_arr.length">
|
|
<view class="action-wrap" :class="{ 'bottom-safe-area': isIphoneX, 'have-agreement': agreement }">
|
|
</view>
|
|
<view class="action" :class="{ 'bottom-safe-area': isIphoneX, 'have-agreement': agreement }">
|
|
<view class="action-btn" @click="create">
|
|
<block v-if="currCard.level_id == levelId"><text class="bold title">{{ $lang('renewNow') }}</text></block>
|
|
<block v-else>
|
|
<text class="bold title" v-if="currCard.charge_type == 1">{{ $lang('rechargeToActivate') }}</text>
|
|
<text class="bold title" v-else>{{ $lang('activateNow') }}</text>
|
|
</block>
|
|
<text class="font-size-tag">{{ $lang('common.currencySymbol') }}</text>
|
|
<text class="bold">{{ currCard.charge_rule_arr[choiceIndex].value }}</text>
|
|
<text>/{{ cardType[currCard.charge_rule_arr[choiceIndex].key].unit }}</text>
|
|
</view>
|
|
<view class="agreement" v-if="agreement">
|
|
{{ $lang('purchaseAgreement') }}
|
|
<text @click="$util.redirectTo('/pages_tool/member/card_agreement')">《{{ agreement.title
|
|
}}》</text>
|
|
</view>
|
|
</view>
|
|
</block>
|
|
</view>
|
|
|
|
<!-- 弹出规则 -->
|
|
<view @touchmove.prevent.stop>
|
|
<uni-popup ref="explainPopup" type="bottom">
|
|
<view class="tips-layer">
|
|
<view class="head" @click="closeExplainPopup()">
|
|
<view class="title">{{ $lang('cardDescription') }}</view>
|
|
<text class="iconfont icon-close"></text>
|
|
</view>
|
|
<view class="body">
|
|
<view class="detail margin-bottom">
|
|
<block v-if="currCard.remark != ''">
|
|
<view class="tip">{{ $lang('cardDescription') }}</view>
|
|
<view class="font-size-base">{{ currCard.remark }}</view>
|
|
</block>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
</view>
|
|
|
|
<ns-payment ref="choosePaymentPopup" :payMoney="currCard.charge_rule_arr[choiceIndex].value"
|
|
@confirm="toPay" v-if="currCard.charge_rule_arr.length"></ns-payment>
|
|
</block>
|
|
<block v-else><ns-empty :text="$lang('noCardsAvailable')" :isIndex="false"></ns-empty></block>
|
|
|
|
<ns-login ref="login"></ns-login>
|
|
<loading-cover ref="loadingCover"></loading-cover>
|
|
<!-- 选择支付方式弹窗 -->
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import scroll from '@/common/js/scroll-view.js';
|
|
|
|
|
|
export default {
|
|
mixins: [scroll],
|
|
data() {
|
|
return {
|
|
isSub: false, // 是否已提交
|
|
isIphoneX: false,
|
|
couponPopList: [],
|
|
curIndex: 0,
|
|
isDescAnimating: false,
|
|
scaleX: (634 / 540).toFixed(4),
|
|
scaleY: (378 / 330).toFixed(4),
|
|
swiperConfig: {
|
|
indicatorDots: false,
|
|
indicatorColor: 'rgba(255, 255, 255, .4)',
|
|
indicatorActiveColor: 'rgba(255, 255, 255, 1)',
|
|
interval: 3000,
|
|
duration: 300,
|
|
circular: false,
|
|
previousMargin: '58rpx',
|
|
nextMargin: '58rpx'
|
|
},
|
|
levelList: [],
|
|
levelId: 0,
|
|
choiceIndex: 0,
|
|
outTradeNo: '',
|
|
agreement: null
|
|
};
|
|
},
|
|
computed: {
|
|
listLen() {
|
|
return this.levelList.length;
|
|
},
|
|
cardType() {
|
|
return {
|
|
week: {
|
|
name: this.$lang('weekCardName'),
|
|
unit: this.$lang('weekCardUnit')
|
|
},
|
|
month: {
|
|
name: this.$lang('monthCardName'),
|
|
unit: this.$lang('monthCardUnit')
|
|
},
|
|
quarter: {
|
|
name: this.$lang('quarterCardName'),
|
|
unit: this.$lang('quarterCardUnit')
|
|
},
|
|
year: {
|
|
name: this.$lang('yearCardName'),
|
|
unit: this.$lang('yearCardUnit')
|
|
}
|
|
};
|
|
},
|
|
currCard() {
|
|
if (this.levelList[this.curIndex]) {
|
|
let card = this.levelList[this.curIndex];
|
|
let charge_rule = card.charge_rule ? JSON.parse(card.charge_rule) : {};
|
|
card.charge_rule_arr = [];
|
|
Object.keys(charge_rule).forEach(key => {
|
|
card.charge_rule_arr.push({
|
|
key: key,
|
|
value: charge_rule[key]
|
|
});
|
|
});
|
|
return card;
|
|
}
|
|
}
|
|
},
|
|
onLoad() {
|
|
//会员卡
|
|
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
|
},
|
|
onShow() {
|
|
if (!this.storeToken) {
|
|
this.redirectTologinOnShowLifecycle('/pages_tool/member/card_buy');
|
|
return;
|
|
}
|
|
|
|
this.getCardList();
|
|
this.getAgreement();
|
|
},
|
|
watch: {
|
|
storeToken: function (nVal, oVal) {
|
|
if (nVal) {
|
|
this.getCardList();
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
swiperChange(e) {
|
|
this.curIndex = e.detail.current;
|
|
this.choiceIndex = 0;
|
|
this.isDescAnimating = true;
|
|
},
|
|
animationfinish(e) {
|
|
this.isDescAnimating = false;
|
|
},
|
|
getCardList() {
|
|
this.$api.sendRequest({
|
|
url: '/supermember/api/membercard/lists',
|
|
success: res => {
|
|
if (res.code == 0 && res.data) {
|
|
this.levelList = res.data;
|
|
this.levelId = this.memberInfo.member_level;
|
|
for (let i = 0; i < this.levelList.length; i++) {
|
|
if (this.levelList[i].level_id == this.levelId) {
|
|
this.curIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
this.$util.showToast({
|
|
title: res.message
|
|
});
|
|
}
|
|
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
|
|
}
|
|
});
|
|
},
|
|
choice(index) {
|
|
this.choiceIndex = index;
|
|
},
|
|
/**
|
|
* 创建
|
|
*/
|
|
create() {
|
|
if (this.memberInfo.member_level_type && this.memberInfo.member_level != this.currCard.level_id) {
|
|
uni.showModal({
|
|
title: this.$lang('common.tip'),
|
|
content: this.$lang('cardOverrideConfirm'),
|
|
success: res => {
|
|
if (res.confirm) {
|
|
this.$refs.choosePaymentPopup.open();
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
this.$refs.choosePaymentPopup.open();
|
|
}
|
|
},
|
|
/**
|
|
* 提交
|
|
*/
|
|
toPay() {
|
|
if (this.isSub) return;
|
|
this.isSub = true;
|
|
|
|
this.$api.sendRequest({
|
|
url: '/supermember/api/ordercreate/create',
|
|
data: {
|
|
level_id: this.currCard.level_id,
|
|
period_unit: this.currCard.charge_rule_arr[this.choiceIndex].key
|
|
},
|
|
success: res => {
|
|
if (res.data && res.code == 0) {
|
|
this.outTradeNo = res.data.out_trade_no;
|
|
uni.setStorageSync('paySource', 'membercard');
|
|
this.$refs.choosePaymentPopup.getPayInfo(this.outTradeNo);
|
|
} else {
|
|
this.isSub = false;
|
|
this.$util.showToast({
|
|
title: res.message
|
|
});
|
|
}
|
|
}
|
|
});
|
|
},
|
|
headimgError() {
|
|
this.memberInfo.headimg = this.$util.getDefaultImage().head;
|
|
},
|
|
/**
|
|
* 打开说明弹出层
|
|
*/
|
|
openExplainPopup() {
|
|
this.$refs.explainPopup.open();
|
|
},
|
|
/**
|
|
* 打开说明弹出层
|
|
*/
|
|
closeExplainPopup() {
|
|
this.$refs.explainPopup.close();
|
|
},
|
|
getAgreement() {
|
|
this.$api.sendRequest({
|
|
url: '/supermember/api/membercard/agreement',
|
|
success: res => {
|
|
if (res.code == 0 && res.data && res.data.title != '' && res.data.content != '') {
|
|
this.agreement = res.data;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
onBackPress(options) {
|
|
if (options.from === 'navigateBack') {
|
|
return false;
|
|
}
|
|
this.$util.redirectTo(this.$util.MEMBER_PAGE_URL);
|
|
return true;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import './public/css/card.scss';
|
|
</style> |