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
380 lines
9.1 KiB
Vue
380 lines
9.1 KiB
Vue
<template>
|
||
<view :style="themeColor">
|
||
<template v-if="memberInfo">
|
||
<!-- 一键授权绑定区域(小程序环境) -->
|
||
<!-- #ifdef MP -->
|
||
<view v-if="!showManualForm" class="bind-wrap">
|
||
<view class="bind-tip">
|
||
<view class="tip-title">{{ $lang('bindMobile.tipTitle') }}</view>
|
||
<view class="tip-desc">{{ $lang('bindMobile.bindBenefitTip') }}</view>
|
||
</view>
|
||
<view class="save-item bind-mobile">
|
||
<button type="primary" open-type="getPhoneNumber" @getphonenumber="mobileAuth">{{ $lang('bindMobile.oneClickAuthBind') }}</button>
|
||
</view>
|
||
<view class="save-item bind-mobile">
|
||
<button type="primary" @click="showManualForm = true">{{ $lang('bindMobile.manualBind') }}</button>
|
||
</view>
|
||
</view>
|
||
<!-- #endif -->
|
||
|
||
<!-- 手动绑定表单 -->
|
||
<view class="edit-info">
|
||
<!-- #ifdef MP -->
|
||
<view v-if="showManualForm" class="form-switch-back" @click="showManualForm = false">
|
||
<text>{{ $lang('bindMobile.oneClickAuthBind') }}</text>
|
||
</view>
|
||
<!-- #endif -->
|
||
<view class="edit-info-box">
|
||
<text class="info-name">{{ $lang('bindMobile.phoneNumber') }}</text>
|
||
<input class="uni-input info-content" type="number" maxlength="11" :placeholder="$lang('bindMobile.pleInputMobile')" v-model="formData.mobile" />
|
||
</view>
|
||
<view class="edit-info-box">
|
||
<text class="info-name">{{ $lang('bindMobile.confirmCode') }}</text>
|
||
<input class="uni-input info-content" type="number" maxlength="4" :placeholder="$lang('bindMobile.confirmCodeInput')" v-model="formData.mobileVercode" />
|
||
<image :src="captcha.img" class="captcha" @click="getCaptcha" show-menu-by-longpress></image>
|
||
</view>
|
||
<view class="edit-info-box">
|
||
<text class="info-name">{{ $lang('bindMobile.smsCode') }}</text>
|
||
<input class="uni-input info-content" type="number" maxlength="6" :placeholder="$lang('bindMobile.animateCodeInput')" v-model="formData.mobileDynacode" />
|
||
<button type="primary" class="dynacode" @click="bindMoblieCode()">{{ formData.mobileCodeText }}</button>
|
||
</view>
|
||
<view class="save-item" @click="bindMobile">
|
||
<button type="primary">{{ $lang('bindMobile.save') }}</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<ns-login ref="login"></ns-login>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import validate from '@/common/js/validate.js';
|
||
import auth from '@/common/js/auth.js';
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
showManualForm: false,
|
||
formData: {
|
||
mobile: '',
|
||
mobileVercode: '',
|
||
mobileDynacode: '',
|
||
mobileCodeText: '',
|
||
},
|
||
seconds: 120,
|
||
timer: null,
|
||
isSend: false,
|
||
captcha: {
|
||
id: '',
|
||
img: ''
|
||
},
|
||
};
|
||
},
|
||
mixins: [auth],
|
||
onLoad() {
|
||
this.formData.mobileCodeText = this.$lang('bindMobile.findanimateCode');
|
||
this.getCaptcha();
|
||
// #ifdef MP-WEIXIN
|
||
this.getCode();
|
||
// #endif
|
||
},
|
||
onShow() {
|
||
if (!this.storeToken) {
|
||
this.redirectTologinOnShowLifecycle('/pages_tool/member/bind_mobile');
|
||
return;
|
||
}
|
||
},
|
||
onHide() {
|
||
this.seconds = 120;
|
||
this.formData.mobileCodeText = this.$lang('bindMobile.findanimateCode');
|
||
this.isSend = false;
|
||
clearInterval(this.timer);
|
||
},
|
||
watch: {
|
||
seconds(value) {
|
||
if (value == 0) {
|
||
this.seconds = 120;
|
||
this.formData.mobileCodeText = this.$lang('bindMobile.findanimateCode');
|
||
this.isSend = false;
|
||
clearInterval(this.timer);
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
themeColor() {
|
||
return this.$store.state.themeStyle ? `--main_color:${this.$store.state.themeStyle.main_color}` : '';
|
||
},
|
||
themeStyle() {
|
||
return this.$store.state.themeStyle || {};
|
||
},
|
||
memberInfo() {
|
||
return this.$store.state.memberInfo || {};
|
||
},
|
||
storeToken() {
|
||
return this.$store.state.token;
|
||
},
|
||
},
|
||
methods: {
|
||
// 获取图形验证码
|
||
getCaptcha() {
|
||
this.$api.sendRequest({
|
||
url: '/api/captcha/captcha',
|
||
data: {
|
||
captcha_id: this.captcha.id
|
||
},
|
||
success: res => {
|
||
if (res.code >= 0) {
|
||
this.captcha = res.data;
|
||
this.captcha.img = this.captcha.img.replace(/\r\n/g, '');
|
||
}
|
||
}
|
||
});
|
||
},
|
||
// 验证手机号
|
||
vertifyMobile() {
|
||
var rule = [{
|
||
name: 'mobile',
|
||
checkType: 'required',
|
||
errorMsg: this.$lang('bindMobile.pleInputMobile')
|
||
}, {
|
||
name: 'mobile',
|
||
checkType: 'phoneno',
|
||
errorMsg: this.$lang('bindMobile.surePhoneNumber')
|
||
}];
|
||
var checkRes = validate.check(this.formData, rule);
|
||
if (!checkRes) {
|
||
this.$util.showToast({
|
||
title: validate.error
|
||
});
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
// 发送短信动态码
|
||
async bindMoblieCode() {
|
||
if (this.seconds != 120) return;
|
||
var rule = [{
|
||
name: 'mobile',
|
||
checkType: 'phoneno',
|
||
errorMsg: this.$lang('bindMobile.surePhoneNumber')
|
||
},
|
||
{
|
||
name: 'mobileVercode',
|
||
checkType: 'required',
|
||
errorMsg: this.$lang('bindMobile.confirmCodeInput')
|
||
},
|
||
];
|
||
|
||
var checkRes = validate.check(this.formData, rule);
|
||
|
||
if (checkRes && !this.isSend) {
|
||
this.isSend = true;
|
||
this.$api.sendRequest({
|
||
url: '/api/member/bindmobliecode',
|
||
data: {
|
||
mobile: this.formData.mobile,
|
||
captcha_id: this.captcha.id,
|
||
captcha_code: this.formData.mobileVercode
|
||
},
|
||
success: res => {
|
||
let data = res.data;
|
||
if (data.key) {
|
||
if (this.seconds == 120 && this.timer == null) {
|
||
this.timer = setInterval(() => {
|
||
this.seconds--;
|
||
this.formData.mobileCodeText = this.$lang('bindMobile.codeSent', { seconds: this.seconds });
|
||
}, 1000);
|
||
}
|
||
uni.setStorageSync('mobile_key', data.key);
|
||
} else {
|
||
this.$util.showToast({
|
||
title: res.message
|
||
});
|
||
this.isSend = false;
|
||
}
|
||
},
|
||
fail: res => {
|
||
this.isSend = false;
|
||
this.getCaptcha();
|
||
}
|
||
});
|
||
} else {
|
||
this.$util.showToast({
|
||
title: validate.error ? validate.error : this.$lang('bindMobile.doNotRepeatedlyClick')
|
||
});
|
||
}
|
||
},
|
||
// 绑定手机号
|
||
bindMobile() {
|
||
if (!this.vertifyMobile()) return;
|
||
|
||
var mobileRule = [{
|
||
name: 'mobileVercode',
|
||
checkType: 'required',
|
||
errorMsg: this.$lang('bindMobile.confirmCodeInput')
|
||
},
|
||
{
|
||
name: 'mobileDynacode',
|
||
checkType: 'required',
|
||
errorMsg: this.$lang('bindMobile.animateCodeInput')
|
||
},
|
||
];
|
||
var checkRes = validate.check(this.formData, mobileRule);
|
||
|
||
if (checkRes) {
|
||
if (this.memberInfo.mobile && this.formData.mobile == this.memberInfo.mobile) {
|
||
this.$util.showToast({
|
||
title: this.$lang('bindMobile.alikePhone')
|
||
});
|
||
return;
|
||
}
|
||
this.$api.sendRequest({
|
||
url: '/api/member/modifymobile',
|
||
data: {
|
||
mobile: this.formData.mobile,
|
||
captcha_id: this.captcha.id,
|
||
captcha_code: this.formData.mobileVercode,
|
||
code: this.formData.mobileDynacode,
|
||
key: uni.getStorageSync("mobile_key"),
|
||
},
|
||
success: res => {
|
||
if (res.code == 0) {
|
||
this.memberInfo.mobile = this.formData.mobile;
|
||
this.$store.commit('setMemberInfo', this.memberInfo);
|
||
this.$util.showToast({
|
||
title: this.$lang('bindMobile.bindSuccess')
|
||
});
|
||
uni.navigateBack({
|
||
delta: 1
|
||
});
|
||
} else {
|
||
this.$util.showToast({
|
||
title: res.message
|
||
});
|
||
this.getCaptcha();
|
||
}
|
||
},
|
||
fail: res => {
|
||
this.isSend = false;
|
||
this.getCaptcha();
|
||
}
|
||
});
|
||
} else {
|
||
this.$util.showToast({
|
||
title: validate.error
|
||
});
|
||
}
|
||
},
|
||
// 一键授权绑定(小程序)
|
||
mobileAuth(e) {
|
||
if (e.detail.errMsg == 'getPhoneNumber:ok') {
|
||
let data = e.detail
|
||
// #ifdef MP-WEIXIN
|
||
Object.assign(data, this.authInfo)
|
||
// #endif
|
||
this.$api.sendRequest({
|
||
url: '/api/member/mobileauth',
|
||
data,
|
||
success: res => {
|
||
if (res.code == 0) {
|
||
this.$util.showToast({
|
||
title: this.$lang('bindMobile.bindSuccess')
|
||
});
|
||
uni.navigateBack({
|
||
delta: 1
|
||
});
|
||
} else {
|
||
this.$util.showToast({
|
||
title: res.message
|
||
});
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.bind-wrap {
|
||
padding: 60rpx 40rpx;
|
||
}
|
||
|
||
.bind-tip {
|
||
text-align: center;
|
||
margin-bottom: 60rpx;
|
||
|
||
.tip-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.tip-desc {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.edit-info-box {
|
||
margin-top: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 20rpx 40rpx;
|
||
min-height: 50rpx;
|
||
background-color: #fff;
|
||
|
||
.info-name {
|
||
width: 150rpx;
|
||
font-size: 28rpx;
|
||
text-align: left;
|
||
}
|
||
|
||
.info-content {
|
||
flex: 1;
|
||
width: 0;
|
||
font-size: 28rpx;
|
||
padding: 0;
|
||
}
|
||
|
||
.dynacode {
|
||
margin: 0;
|
||
padding: 0 10rpx;
|
||
width: 250rpx;
|
||
height: 60rpx;
|
||
font-size: 24rpx;
|
||
line-height: 60rpx;
|
||
word-break: break-all;
|
||
}
|
||
}
|
||
|
||
.captcha {
|
||
width: 170rpx;
|
||
height: 50rpx;
|
||
}
|
||
|
||
.save-item {
|
||
margin-top: 50rpx;
|
||
|
||
button {
|
||
font-size: 30rpx;
|
||
}
|
||
}
|
||
|
||
.bind-mobile {
|
||
button {
|
||
border-radius: 60rpx;
|
||
}
|
||
}
|
||
|
||
.form-switch-back {
|
||
text-align: center;
|
||
padding: 20rpx;
|
||
font-size: 26rpx;
|
||
color: var(--main_color);
|
||
}
|
||
</style>
|