feat:新增了绑定手机检查,抖音登录等逻辑,并且更改了页面样式以符合抖音要求
This commit is contained in:
parent
61df7fca5e
commit
05056c8188
@ -6,9 +6,23 @@ export function wechatLogin(code, invite_code) {
|
||||
}
|
||||
|
||||
// 抖音小程序登录
|
||||
/**
|
||||
* 抖音小程序登录
|
||||
* @param {string} code - 抖音登录 code(从 tt.login 获取)
|
||||
* @param {string} anonymous_code - 匿名登录 code(可选)
|
||||
* @param {string} invite_code - 邀请码(可选)
|
||||
*/
|
||||
export function douyinLogin(code, anonymous_code, invite_code) {
|
||||
const data = {}
|
||||
if (code) data.code = code
|
||||
if (anonymous_code) data.anonymous_code = anonymous_code
|
||||
if (invite_code) data.invite_code = invite_code
|
||||
return request({ url: '/api/app/users/douyin/login', method: 'POST', data })
|
||||
}
|
||||
|
||||
// 保持向后兼容
|
||||
export function toutiaoLogin(code, invite_code) {
|
||||
const data = invite_code ? { code, invite_code } : { code }
|
||||
return request({ url: '/api/app/users/toutiao/login', method: 'POST', data })
|
||||
return douyinLogin(code, null, invite_code)
|
||||
}
|
||||
|
||||
// ============================================
|
||||
@ -44,6 +58,15 @@ export function bindPhone(user_id, code, extraHeader = {}) {
|
||||
return authRequest({ url: `/api/app/users/${user_id}/phone/bind`, method: 'POST', data: { code }, header: extraHeader })
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定抖音手机号
|
||||
* @param {number} user_id - 用户ID
|
||||
* @param {string} code - 抖音手机号授权 code
|
||||
*/
|
||||
export function bindDouyinPhone(user_id, code) {
|
||||
return authRequest({ url: `/api/app/users/${user_id}/douyin/phone/bind`, method: 'POST', data: { code } })
|
||||
}
|
||||
|
||||
export function getUserStats(user_id) {
|
||||
return authRequest({ url: `/api/app/users/${user_id}/stats`, method: 'GET' })
|
||||
}
|
||||
|
||||
@ -71,7 +71,12 @@
|
||||
},
|
||||
"mp-toutiao": {
|
||||
"usingComponents": true,
|
||||
"appid": "ttf031868c6f33d91001"
|
||||
"appid": "ttf031868c6f33d91001",
|
||||
"privacy": {
|
||||
"getPhoneNumber": {
|
||||
"desc": "用于登录和账号绑定"
|
||||
}
|
||||
}
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
|
||||
@ -437,62 +437,132 @@ export default {
|
||||
setupSocketListeners() {
|
||||
nakamaManager.setListeners({
|
||||
onmatchmakermatched: async (matched) => {
|
||||
// ========== 控制台日志 - 匹配成功 ==========
|
||||
console.log('=== 匹配成功事件 ===');
|
||||
console.log('[匹配时间]', new Date().toLocaleString());
|
||||
console.log('[Match ID]', matched.match_id);
|
||||
console.log('[Match Token]', matched.token ? '存在' : '不存在');
|
||||
console.log('[完整匹配对象]', JSON.stringify(matched, null, 2));
|
||||
console.log('==================');
|
||||
|
||||
this.addLog('system', `📡 信号锁定!同步中...`);
|
||||
this.isMatching = false;
|
||||
clearInterval(this.matchInterval);
|
||||
|
||||
|
||||
// 保存匹配信息用于可能的重连
|
||||
this.pendingMatchId = matched.match_id;
|
||||
this.pendingMatchToken = matched.token;
|
||||
|
||||
|
||||
// 带重试的 joinMatch
|
||||
const maxRetries = 3;
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
console.log(`[尝试 ${i + 1}/${maxRetries}] 开始加入游戏房间...`);
|
||||
const match = await nakamaManager.joinMatch(matched.match_id, matched.token);
|
||||
|
||||
// ========== 控制台日志 - 加入成功 ==========
|
||||
console.log('=== 成功加入游戏房间 ===');
|
||||
console.log('[房间 ID]', match.match_id);
|
||||
console.log('[我的用户 ID]', this.myUserId);
|
||||
console.log('[房间对象]', JSON.stringify(match, null, 2));
|
||||
console.log('======================');
|
||||
|
||||
this.matchId = match.match_id;
|
||||
this.addLog('system', `成功接入战局`);
|
||||
setTimeout(() => {
|
||||
console.log('[发送状态请求] 请求初始游戏状态...');
|
||||
nakamaManager.sendMatchState(match.match_id, 100, JSON.stringify({ action: 'getState' }));
|
||||
}, 100);
|
||||
return; // 成功,退出重试循环
|
||||
} catch (e) {
|
||||
// ========== 控制台日志 - 加入失败 ==========
|
||||
console.error(`[尝试 ${i + 1}/${maxRetries} 失败]`, e.message);
|
||||
console.error('[错误详情]', e);
|
||||
|
||||
this.addLog('system', `⚠️ 接入尝试 ${i + 1}/${maxRetries} 失败: ${e.message}`);
|
||||
if (i < maxRetries - 1) {
|
||||
console.log(`等待 1 秒后重试...`);
|
||||
await new Promise(r => setTimeout(r, 1000)); // 等待1秒后重试
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 控制台日志 - 最终失败 ==========
|
||||
console.error('=== 加入游戏房间最终失败 ===');
|
||||
console.error('[Match ID]', matched.match_id);
|
||||
console.error('[重试次数]', maxRetries);
|
||||
console.error('============================');
|
||||
|
||||
this.addLog('system', `❌ 接入失败,请检查网络后重试`);
|
||||
},
|
||||
onmatchdata: (matchData) => {
|
||||
const opCode = matchData.op_code;
|
||||
const data = JSON.parse(new TextDecoder().decode(matchData.data));
|
||||
|
||||
// ========== 控制台日志 - 接收游戏数据 ==========
|
||||
console.log('=== 接收游戏数据 ===');
|
||||
console.log('[OpCode]', opCode, `(${this.getOpCodeName(opCode)})`);
|
||||
console.log('[数据]', data);
|
||||
console.log('[时间]', new Date().toLocaleString());
|
||||
console.log('====================');
|
||||
|
||||
this.handleGameData(opCode, data);
|
||||
},
|
||||
ondisconnect: async () => {
|
||||
// ========== 控制台日志 - 断开连接 ==========
|
||||
console.warn('=== 连接断开 ===');
|
||||
console.warn('[断开时间]', new Date().toLocaleString());
|
||||
console.warn('[Match ID]', this.matchId);
|
||||
console.warn('===============');
|
||||
|
||||
this.addLog('system', `⚠️ 连接断开,尝试重连中...`);
|
||||
this.isConnected = false;
|
||||
|
||||
|
||||
// 自动重连
|
||||
try {
|
||||
console.log('[重连] 开始重新连接...');
|
||||
await nakamaManager.authenticateWithGameToken(this.gameToken);
|
||||
this.isConnected = true;
|
||||
|
||||
console.log('[重连] 认证成功');
|
||||
|
||||
this.addLog('system', `✅ 重连成功`);
|
||||
|
||||
|
||||
// 如果有进行中的比赛,尝试重新加入
|
||||
if (this.matchId) {
|
||||
console.log('[重连] 尝试重新加入游戏房间:', this.matchId);
|
||||
const match = await nakamaManager.joinMatch(this.matchId);
|
||||
console.log('[重连] 成功重新加入游戏房间');
|
||||
|
||||
this.addLog('system', `✅ 已重新加入战局`);
|
||||
nakamaManager.sendMatchState(this.matchId, 100, JSON.stringify({ action: 'getState' }));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[重连] 失败:', e);
|
||||
this.addLog('system', `❌ 重连失败: ${e.message}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
handleGameData(opCode, data) {
|
||||
// 关键游戏状态的控制台日志
|
||||
if (opCode === 1) {
|
||||
// ========== 控制台日志 - 游戏开始 ==========
|
||||
console.log('🎮 ========== 游戏开始 ==========');
|
||||
console.log('[玩家数量]', Object.keys(data.players || {}).length);
|
||||
console.log('[我的位置]', data.turnOrder?.indexOf(this.myUserId));
|
||||
console.log('[网格大小]', data.gridSize);
|
||||
console.log('[游戏状态]', data);
|
||||
console.log('================================');
|
||||
} else if (opCode === 6) {
|
||||
// ========== 控制台日志 - 游戏结束 ==========
|
||||
console.log('🏁 ========== 游戏结束 ==========');
|
||||
console.log('[获胜者]', data.winnerId);
|
||||
console.log('[是否胜利]', data.winnerId === this.myUserId);
|
||||
console.log('[最终状态]', data);
|
||||
console.log('================================');
|
||||
}
|
||||
|
||||
if (opCode === 1 || opCode === 2) {
|
||||
this.gameState = data;
|
||||
if (opCode === 1) this.addLog('system', '战局开始,准备翻格!');
|
||||
@ -588,7 +658,18 @@ export default {
|
||||
if (content === 'empty') return '✅';
|
||||
return this.getItemIcon(content);
|
||||
},
|
||||
getNumColor(n) { return ['','blue','green','red','purple','orange'][n] || 'black'; }
|
||||
getNumColor(n) { return ['','blue','green','red','purple','orange'][n] || 'black'; },
|
||||
getOpCodeName(code) {
|
||||
const map = {
|
||||
1: '游戏开始',
|
||||
2: '状态更新',
|
||||
3: '玩家点击格子',
|
||||
5: '游戏事件',
|
||||
6: '游戏结束',
|
||||
100: '请求游戏状态'
|
||||
};
|
||||
return map[code] || '未知';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -174,14 +174,14 @@
|
||||
{
|
||||
"path": "game/minesweeper/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"navigationStyle": "default",
|
||||
"navigationBarTitleText": "扫雷 game"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "game/minesweeper/play",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"navigationStyle": "default",
|
||||
"navigationBarTitleText": "扫雷对战",
|
||||
"disableScroll": true,
|
||||
"app-plus": {
|
||||
|
||||
@ -165,6 +165,7 @@ import { ref, computed } from 'vue'
|
||||
import { onShow, onReachBottom, onShareAppMessage, onPullDownRefresh } from '@dcloudio/uni-app'
|
||||
import { getInventory, getProductDetail, redeemInventory, requestShipping, cancelShipping, listAddresses, getShipments, createAddressShare } from '@/api/appUser'
|
||||
import { vibrateShort } from '@/utils/vibrate.js'
|
||||
import { checkPhoneBound } from '@/utils/checkPhone.js'
|
||||
|
||||
const currentTab = ref(0)
|
||||
const aggregatedList = ref([])
|
||||
@ -214,6 +215,9 @@ async function fetchProductMeta(productId) {
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
// 检查手机号绑定状态
|
||||
if (!checkPhoneBound()) return
|
||||
|
||||
// Check for external tab switch request
|
||||
try {
|
||||
const targetTab = uni.getStorageSync('cabinet_target_tab')
|
||||
@ -224,13 +228,10 @@ onShow(() => {
|
||||
} catch (e) {}
|
||||
|
||||
const token = uni.getStorageSync('token')
|
||||
const phoneBound = !!uni.getStorageSync('phone_bound')
|
||||
console.log('cabinet onShow token:', token, 'isLogin:', !!token, 'phoneBound:', phoneBound)
|
||||
|
||||
if (!token || !phoneBound) {
|
||||
if (!token) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录并绑定手机号',
|
||||
content: '请先登录',
|
||||
confirmText: '去登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
|
||||
@ -132,6 +132,7 @@
|
||||
<script>
|
||||
import { authRequest, request } from '../../utils/request.js'
|
||||
import SplashScreen from '@/components/SplashScreen.vue'
|
||||
import { checkPhoneBound } from '../../utils/checkPhone.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -179,6 +180,9 @@ export default {
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 检查手机号绑定状态
|
||||
if (!checkPhoneBound()) return
|
||||
|
||||
// 延迟 200ms 首次加载,让 Token/Session 有机会就绪
|
||||
// 同时避免页面动画卡顿
|
||||
setTimeout(() => {
|
||||
|
||||
@ -77,16 +77,15 @@
|
||||
<text class="icon-emoji">🎵</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="panel-title">一键获取手机号</text>
|
||||
<text class="panel-desc">授权获取本机手机号,安全快速登录</text>
|
||||
<text class="panel-title">抖音快捷登录</text>
|
||||
<text class="panel-desc">使用抖音账号快速登录</text>
|
||||
|
||||
<button
|
||||
class="btn-primary btn-login"
|
||||
open-type="getPhoneNumber"
|
||||
:disabled="loading"
|
||||
@getphonenumber="onToutiaoGetPhoneNumber"
|
||||
@tap="handleDouyinLogin"
|
||||
>
|
||||
{{ loading ? '获取中...' : '一键获取手机号' }}
|
||||
{{ loading ? '登录中...' : '抖音登录' }}
|
||||
</button>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
@ -175,7 +174,7 @@
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { request } from '../../utils/request'
|
||||
import { wechatLogin, toutiaoLogin, bindPhone, getUserStats, getPointsBalance, sendSmsCode, smsLogin } from '../../api/appUser'
|
||||
import { wechatLogin, douyinLogin, bindPhone, bindDouyinPhone, getUserStats, getPointsBalance, sendSmsCode, smsLogin } from '../../api/appUser'
|
||||
import { vibrateShort } from '@/utils/vibrate.js'
|
||||
|
||||
const loading = ref(false)
|
||||
@ -221,14 +220,19 @@ async function ensureOpenID() {
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-TOUTIAO
|
||||
uni.login({
|
||||
provider: 'toutiao',
|
||||
// 抖音小程序使用 tt.login
|
||||
tt.login({
|
||||
success: async (loginRes) => {
|
||||
try {
|
||||
console.log('[DEBUG] 抖音登录成功,code:', loginRes.code)
|
||||
// 保存 code 用于后续登录
|
||||
uni.setStorageSync('douyin_login_code', loginRes.code)
|
||||
|
||||
// 尝试获取 openid
|
||||
const res = await request({
|
||||
url: '/api/app/common/openid',
|
||||
method: 'POST',
|
||||
data: { code: loginRes.code, platform: 'toutiao' }
|
||||
data: { code: loginRes.code, platform: 'douyin' }
|
||||
})
|
||||
if (res && res.openid) {
|
||||
console.log('[DEBUG] 静默获取 openid 成功:', res.openid)
|
||||
@ -237,6 +241,9 @@ async function ensureOpenID() {
|
||||
} catch (err) {
|
||||
console.error('[DEBUG] 静默获取 openid 失败:', err)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[DEBUG] 抖音登录失败:', err)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
@ -421,54 +428,58 @@ function onGetPhoneNumber(e) {
|
||||
})
|
||||
}
|
||||
|
||||
// 抖音登录
|
||||
function onToutiaoGetPhoneNumber(e) {
|
||||
// 抖音登录 - 不需要手机号授权
|
||||
async function handleDouyinLogin() {
|
||||
console.log('[DEBUG] 抖音登录按钮点击')
|
||||
|
||||
if (!agreementChecked.value) {
|
||||
uni.showToast({ title: '请先同意用户协议', icon: 'none' })
|
||||
vibrateShort()
|
||||
return
|
||||
}
|
||||
|
||||
const phoneCode = e.detail.code
|
||||
if (!phoneCode) {
|
||||
uni.showToast({ title: '需要授权手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
uni.login({
|
||||
provider: 'toutiao',
|
||||
success: async (res) => {
|
||||
try {
|
||||
const inviterCode = uni.getStorageSync('inviter_code')
|
||||
const data = await toutiaoLogin(res.code, inviterCode)
|
||||
try {
|
||||
// 使用保存的登录 code 或重新登录获取
|
||||
const loginCode = uni.getStorageSync('douyin_login_code')
|
||||
|
||||
saveUserData(data)
|
||||
|
||||
// 绑定手机号 (仅当后端反馈未绑定时调用)
|
||||
const isBound = data.phone || data.phone_number || data.mobile
|
||||
if (!isBound) {
|
||||
try {
|
||||
await bindPhone(data.user_id, phoneCode)
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 后台获取数据
|
||||
fetchExtraData(data.user_id)
|
||||
|
||||
uni.showToast({ title: '✨ 登录成功!', icon: 'none', duration: 1200 })
|
||||
setTimeout(() => uni.reLaunch({ url: '/pages/mine/index' }), 600)
|
||||
} catch (err) {
|
||||
uni.showToast({ title: err.message || '登录失败', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
loading.value = false
|
||||
let loginData
|
||||
if (!loginCode) {
|
||||
// 如果没有保存的 code,重新登录获取
|
||||
console.log('[DEBUG] 未保存登录 code,开始重新登录...')
|
||||
const loginRes = await new Promise((resolve, reject) => {
|
||||
tt.login({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
console.log('[DEBUG] 重新获取抖音登录 code:', loginRes.code)
|
||||
loginData = await douyinLogin(loginRes.code, null, uni.getStorageSync('inviter_code'))
|
||||
} else {
|
||||
console.log('[DEBUG] 使用保存的登录 code:', loginCode)
|
||||
loginData = await douyinLogin(loginCode, null, uni.getStorageSync('inviter_code'))
|
||||
}
|
||||
})
|
||||
|
||||
console.log('[DEBUG] 抖音登录成功:', loginData)
|
||||
|
||||
// 保存登录数据(saveUserData 会自动检查手机号绑定状态)
|
||||
saveUserData(loginData)
|
||||
|
||||
// 后台获取数据(仅在已绑定手机号时)
|
||||
const hasPhone = loginData.mobile || loginData.phone || loginData.phone_number
|
||||
if (hasPhone) {
|
||||
fetchExtraData(loginData.user_id)
|
||||
uni.showToast({ title: '✨ 登录成功!', icon: 'none', duration: 1200 })
|
||||
setTimeout(() => uni.reLaunch({ url: '/pages/mine/index' }), 600)
|
||||
}
|
||||
// 如果未绑定手机号,saveUserData 会自动切换到短信登录tab
|
||||
} catch (err) {
|
||||
console.error('[DEBUG] 抖音登录失败:', err)
|
||||
uni.showToast({ title: err.message || '登录失败,请重试', icon: 'none', duration: 2000 })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function saveUserData(data) {
|
||||
@ -481,10 +492,18 @@ function saveUserData(data) {
|
||||
if (data.nickname) uni.setStorageSync('nickname', data.nickname)
|
||||
if (data.invite_code) uni.setStorageSync('invite_code', data.invite_code)
|
||||
if (data.mobile) uni.setStorageSync('last_login_mobile', data.mobile)
|
||||
|
||||
// 核心修复:无论哪种登录方式,登录成功后都标记手机号已绑定
|
||||
uni.setStorageSync('phone_bound', true)
|
||||
|
||||
|
||||
// 检查是否已绑定手机号
|
||||
const hasPhone = data.mobile || data.phone || data.phone_number
|
||||
console.log('[DEBUG] 检查手机号绑定状态:', hasPhone ? '已绑定' : '未绑定')
|
||||
|
||||
// 根据实际是否有手机号来设置 phone_bound 状态
|
||||
if (hasPhone) {
|
||||
uni.setStorageSync('phone_bound', true)
|
||||
} else {
|
||||
uni.setStorageSync('phone_bound', false)
|
||||
}
|
||||
|
||||
// 如果返回了 openid,则存储 (短信登录现在也会返回已关联的 openid)
|
||||
const openid = data.openid || data.open_id
|
||||
if (openid) {
|
||||
@ -493,6 +512,21 @@ function saveUserData(data) {
|
||||
} else {
|
||||
console.warn('[DEBUG] 登录接口未返回 openid, 请检查后端或联系管理员')
|
||||
}
|
||||
|
||||
if (!hasPhone) {
|
||||
// 未绑定手机号,切换到短信登录tab进行绑定
|
||||
console.log('[DEBUG] 未检测到手机号,切换到短信登录tab')
|
||||
uni.showModal({
|
||||
title: '绑定手机号',
|
||||
content: '登录成功!为了账号安全,请绑定手机号',
|
||||
showCancel: false,
|
||||
confirmText: '去绑定',
|
||||
success: () => {
|
||||
// 切换到短信登录tab
|
||||
loginMode.value = 'sms'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function fetchExtraData(userId) {
|
||||
|
||||
@ -470,6 +470,7 @@ import {
|
||||
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
|
||||
getUserTasks, getTaskProgress, getInviteRecords, modifyUser
|
||||
} from '../../api/appUser.js'
|
||||
import { checkPhoneBound } from '../../utils/checkPhone.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@ -479,6 +480,7 @@ export default {
|
||||
avatar: '',
|
||||
title: '', // 用户头衔
|
||||
inviteCode: '',
|
||||
mobile: '', // 手机号
|
||||
pointsBalance: 0,
|
||||
|
||||
stats: {
|
||||
@ -535,6 +537,9 @@ export default {
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
// 检查手机号绑定状态
|
||||
if (!checkPhoneBound()) return
|
||||
|
||||
this.loadUserInfo()
|
||||
},
|
||||
onShareAppMessage() {
|
||||
@ -554,6 +559,23 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 检查是否已绑定手机号
|
||||
checkPhoneBound() {
|
||||
if (!this.mobile) {
|
||||
uni.showModal({
|
||||
title: '需要绑定手机号',
|
||||
content: '为了账号安全,请先绑定手机号',
|
||||
showCancel: false,
|
||||
confirmText: '去绑定',
|
||||
success: () => {
|
||||
uni.navigateTo({ url: '/pages/login/index?mode=sms' })
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
// 修改头像
|
||||
handleEditAvatar() {
|
||||
if (!this.userId) {
|
||||
@ -561,6 +583,8 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.checkPhoneBound()) return
|
||||
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'], // 选择压缩图
|
||||
@ -726,6 +750,7 @@ export default {
|
||||
this.inviteCode = cachedUser.invite_code
|
||||
this.title = cachedUser.title || ''
|
||||
this.pointsBalance = this.normalizePointsBalance(cachedUser.points_balance)
|
||||
this.mobile = cachedUser.mobile || cachedUser.phone || cachedUser.phone_number || ''
|
||||
} else if (cachedUserId) {
|
||||
this.userId = cachedUserId
|
||||
}
|
||||
@ -754,6 +779,7 @@ export default {
|
||||
this.title = res.title || res.level_name || ''
|
||||
this.inviteCode = res.invite_code
|
||||
this.pointsBalance = this.normalizePointsBalance(res.points_balance)
|
||||
this.mobile = res.mobile || res.phone || res.phone_number || ''
|
||||
uni.setStorageSync('user_info', res)
|
||||
uni.setStorageSync('user_id', res.id)
|
||||
|
||||
@ -779,28 +805,36 @@ export default {
|
||||
uni.navigateTo({ url: '/pages/login/index' })
|
||||
},
|
||||
toOrders(status) {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: `/pages-user/orders/index?status=${status}` })
|
||||
},
|
||||
toCabinetTab(tabIndex) {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.setStorageSync('cabinet_target_tab', tabIndex)
|
||||
uni.switchTab({ url: '/pages/cabinet/index' })
|
||||
},
|
||||
toAddresses() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: '/pages-user/address/index' })
|
||||
},
|
||||
toPointsPage() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: '/pages-user/points/index' })
|
||||
},
|
||||
toCouponsPage() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: '/pages-user/coupons/index' })
|
||||
},
|
||||
toItemCardsPage() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: '/pages-user/item-cards/index' })
|
||||
},
|
||||
toInvitesPage() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: '/pages-user/invites/index' })
|
||||
},
|
||||
toTasksPage() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
uni.navigateTo({ url: '/pages-user/tasks/index' })
|
||||
},
|
||||
toHelp() {
|
||||
@ -882,6 +916,7 @@ export default {
|
||||
|
||||
// --- Points Logic ---
|
||||
async showPointsPopup() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
this.pointsVisible = true
|
||||
this.pointsList = []
|
||||
this.pointsPage = 1
|
||||
@ -918,6 +953,7 @@ export default {
|
||||
|
||||
// --- Coupons Logic ---
|
||||
async showCouponsPopup() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
this.couponsVisible = true
|
||||
this.couponsTab = 1
|
||||
this.couponsList = []
|
||||
@ -976,6 +1012,7 @@ export default {
|
||||
|
||||
// --- Item Cards Logic ---
|
||||
async showItemCardsPopup() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
this.itemCardsVisible = true
|
||||
this.itemCardsTab = 0
|
||||
this.itemCardsList = []
|
||||
@ -1026,6 +1063,7 @@ export default {
|
||||
|
||||
// --- Tasks Logic ---
|
||||
async showTasksPopup() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
this.tasksVisible = true
|
||||
this.tasksLoading = true
|
||||
try {
|
||||
@ -1162,6 +1200,7 @@ export default {
|
||||
|
||||
// --- Invites Logic ---
|
||||
async showInvitesPopup() {
|
||||
if (!this.checkPhoneBound()) return
|
||||
this.invitesVisible = true
|
||||
this.invitesLoading = true
|
||||
try {
|
||||
|
||||
@ -157,6 +157,7 @@
|
||||
import { onShow, onReachBottom } from '@dcloudio/uni-app'
|
||||
import { ref, watch, onUnmounted } from 'vue'
|
||||
import { getStoreItems, redeemProductByPoints, redeemCouponByPoints, redeemItemCardByPoints } from '../../api/appUser'
|
||||
import { checkPhoneBound } from '../../utils/checkPhone.js'
|
||||
|
||||
const loading = ref(false)
|
||||
const keyword = ref('')
|
||||
@ -413,15 +414,15 @@ async function onRedeemTap(item) {
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
// 检查手机号绑定状态
|
||||
if (!checkPhoneBound()) return
|
||||
|
||||
const token = uni.getStorageSync('token')
|
||||
const phoneBound = !!uni.getStorageSync('phone_bound')
|
||||
if (token && phoneBound) {
|
||||
if (token) {
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
allItems.value = []
|
||||
loadItems()
|
||||
} else {
|
||||
// Redirect logic if needed
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
28
utils/checkPhone.js
Normal file
28
utils/checkPhone.js
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 检查手机号绑定状态
|
||||
* 如果未绑定手机号,则跳转到登录页面进行绑定
|
||||
* @returns {boolean} 是否已绑定手机号
|
||||
*/
|
||||
export function checkPhoneBound() {
|
||||
// 获取用户信息
|
||||
const userInfo = uni.getStorageSync('user_info') || {}
|
||||
const mobile = userInfo.mobile || userInfo.phone || userInfo.phone_number || ''
|
||||
|
||||
// 如果已绑定手机号,直接返回
|
||||
if (mobile) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 未绑定手机号,显示提示并跳转
|
||||
uni.showModal({
|
||||
title: '需要绑定手机号',
|
||||
content: '为了账号安全,请先绑定手机号',
|
||||
showCancel: false,
|
||||
confirmText: '去绑定',
|
||||
success: () => {
|
||||
uni.navigateTo({ url: '/pages/login/index?mode=sms' })
|
||||
}
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user