221 lines
5.0 KiB
Vue
221 lines
5.0 KiB
Vue
<template>
|
||
<view class="page">
|
||
<!-- 自定义导航栏 -->
|
||
<view v-if="!fromLogin" class="custom-navbar">
|
||
<view class="navbar-back" @tap="goBack">
|
||
<image class="back-icon" src="../../static/left.png" mode="aspectFit" />
|
||
</view>
|
||
<view class="navbar-title">绑定手机号</view>
|
||
<view class="navbar-placeholder"></view>
|
||
</view>
|
||
|
||
<view class="container" :style="{ paddingTop: fromLogin ? '0' : '0' }">
|
||
<view class="card flex-col-g20">
|
||
<view class="flex-row-g20">
|
||
<label for="">手机号:</label>
|
||
<up-input placeholder="请输入绑定的手机号" border="surround" v-model="bind.phone" />
|
||
</view>
|
||
|
||
<view class="flex-row-g20">
|
||
<label for="">验证码:</label>
|
||
<up-input placeholder="验证码" v-model="bind.code">
|
||
<template #suffix>
|
||
<up-button @tap="getCode" :text="codeText" type="success" :disabled="cooldown > 0"></up-button>
|
||
</template>
|
||
</up-input>
|
||
</view>
|
||
|
||
<view class="btn">
|
||
<up-button type="primary" @tap="bindPhone">绑定手机号</up-button>
|
||
</view>
|
||
|
||
<!-- 如果从登录页面跳转过来,显示退出按钮 -->
|
||
<view class="btn" v-if="fromLogin">
|
||
<up-button type="error" @tap="logout">退出</up-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue';
|
||
import { authApi } from '@/api/index.js';
|
||
import { useUserStore } from '@/store/index.js';
|
||
|
||
const POST_BIND_RELOGIN_NOTICE_KEY = 'postBindReloginNotice';
|
||
|
||
const userStore = useUserStore();
|
||
|
||
let bind = reactive({
|
||
phone: '',
|
||
code: ''
|
||
});
|
||
|
||
let cooldown = ref(0);
|
||
let codeText = ref('获取验证码');
|
||
let timer = null;
|
||
let fromLogin = ref(false);
|
||
|
||
onMounted(() => {
|
||
// 获取页面参数,判断是否从登录页面跳转过来
|
||
const pages = getCurrentPages();
|
||
const currentPage = pages[pages.length - 1];
|
||
const options = currentPage.options;
|
||
fromLogin.value = options.fromLogin === 'true';
|
||
});
|
||
|
||
const prepareManualRelogin = () => {
|
||
const preservedIdentifier = userStore.state.identifier || uni.getStorageSync('identifier') || '';
|
||
|
||
userStore.clearUser();
|
||
if (preservedIdentifier) {
|
||
userStore.setIdentifier(preservedIdentifier);
|
||
}
|
||
|
||
uni.setStorageSync(POST_BIND_RELOGIN_NOTICE_KEY, '1');
|
||
|
||
// #ifdef H5
|
||
if (typeof sessionStorage !== 'undefined') {
|
||
sessionStorage.removeItem('assetToken');
|
||
}
|
||
// #endif
|
||
};
|
||
|
||
const getCode = async () => {
|
||
if (!bind.phone) {
|
||
uni.showToast({ title: '请输入手机号', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
if (!/^1[3-9]\d{9}$/.test(bind.phone)) {
|
||
uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const data = await authApi.sendCode(bind.phone, 'bind_phone');
|
||
cooldown.value = data.cooldown_seconds || 60;
|
||
codeText.value = `${cooldown.value}s`;
|
||
|
||
timer = setInterval(() => {
|
||
cooldown.value--;
|
||
if (cooldown.value <= 0) {
|
||
clearInterval(timer);
|
||
codeText.value = '获取验证码';
|
||
} else {
|
||
codeText.value = `${cooldown.value}s`;
|
||
}
|
||
}, 1000);
|
||
|
||
uni.showToast({ title: '验证码已发送', icon: 'success' });
|
||
} catch (e) {
|
||
console.error('发送验证码失败', e);
|
||
}
|
||
};
|
||
|
||
const bindPhone = async () => {
|
||
if (!bind.phone || !bind.code) {
|
||
uni.showToast({ title: '手机号和验证码都不能为空', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await authApi.bindPhone(bind.phone, bind.code);
|
||
|
||
if (fromLogin.value) {
|
||
prepareManualRelogin();
|
||
uni.reLaunch({ url: '/pages/login/login' });
|
||
return;
|
||
}
|
||
|
||
uni.showToast({ title: '绑定成功', icon: 'success' });
|
||
setTimeout(() => {
|
||
// 从其他页面过来的,返回上一页
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
} catch (e) {
|
||
console.error('绑定手机号失败', e);
|
||
}
|
||
};
|
||
|
||
const logout = () => {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要退出登录吗?',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
uni.clearStorageSync();
|
||
uni.reLaunch({ url: '/pages/login/login' });
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
const goBack = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/index/index'
|
||
})
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.page {
|
||
min-height: 100vh;
|
||
background: var(--bg-secondary);
|
||
max-width: 750rpx;
|
||
margin: 0 auto;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.custom-navbar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 88rpx;
|
||
margin-bottom: 24rpx;
|
||
background: var(--bg-primary);
|
||
border-bottom: 1rpx solid var(--border-light);
|
||
padding: 0 24rpx;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
|
||
.navbar-back {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 8rpx;
|
||
cursor: pointer;
|
||
|
||
.back-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.back-text {
|
||
font-size: 28rpx;
|
||
color: var(--text-primary);
|
||
}
|
||
}
|
||
|
||
.navbar-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.navbar-placeholder {
|
||
width: 100rpx;
|
||
}
|
||
}
|
||
|
||
.container {
|
||
padding: var(--space-md);
|
||
}
|
||
</style>
|