diff --git a/config/index.ts b/config/index.ts index e36b8e5..c77a458 100644 --- a/config/index.ts +++ b/config/index.ts @@ -10,12 +10,13 @@ export default defineConfig<'webpack5'>(async (merge, { command, mode }) => { const baseConfig: UserConfigExport<'webpack5'> = { projectName: 'playBallTogether', date: '2025-8-9', - designWidth: 375, + designWidth: 390, deviceRatio: { 640: 2.34 / 2, 750: 1, 375: 2, - 828: 1.81 / 2 + 828: 1.81 / 2, + 390: 1.92 }, sourceRoot: 'src', outputRoot: 'dist', diff --git a/src/pages/login/verification/index.scss b/src/pages/login/verification/index.scss index c19131f..7bf0be3 100644 --- a/src/pages/login/verification/index.scss +++ b/src/pages/login/verification/index.scss @@ -273,6 +273,16 @@ font-size: 14px; line-height: 1.714; color: rgba(60, 60, 67, 0.3); + + .count_number { + color: rgba(60, 60, 67, 0.3); + transition: color 0.3s ease; + + &.active { + color: #000000; + font-weight: 500; + } + } } } } @@ -321,6 +331,16 @@ font-size: 14px; line-height: 1.714; color: rgba(60, 60, 67, 0.3); + + .count_number { + color: rgba(60, 60, 67, 0.3); + transition: color 0.3s ease; + + &.active { + color: #000000; + font-weight: 500; + } + } } } diff --git a/src/pages/login/verification/index.tsx b/src/pages/login/verification/index.tsx index f34e5f6..cd3e35d 100644 --- a/src/pages/login/verification/index.tsx +++ b/src/pages/login/verification/index.tsx @@ -10,11 +10,11 @@ const VerificationPage: React.FC = () => { const [countdown, setCountdown] = useState(0); const [can_send_code, setCanSendCode] = useState(true); const [is_loading, setIsLoading] = useState(false); + const [code_input_focus, setCodeInputFocus] = useState(false); + + // 计算登录按钮是否应该启用 + const can_login = phone.length === 11 && verification_code.length === 6 && !is_loading; - // 返回上一页 - const handle_go_back = () => { - Taro.navigateBack(); - }; // 发送验证码 const handle_send_code = async () => { @@ -30,10 +30,16 @@ const VerificationPage: React.FC = () => { if (!can_send_code) return; try { + console.log('开始发送验证码,手机号:', phone); + // 调用发送短信接口 const result = await send_sms_code(phone); + console.log('发送验证码结果:', result); + if (result.success) { + console.log('验证码发送成功,开始倒计时'); + Taro.showToast({ title: '验证码已发送', icon: 'success', @@ -43,7 +49,19 @@ const VerificationPage: React.FC = () => { // 开始倒计时 setCanSendCode(false); setCountdown(60); + + console.log('设置状态: can_send_code = false, countdown = 60'); + + // 发送验证码成功后,让验证码输入框获得焦点并调用系统键盘 + setTimeout(() => { + // 设置验证码输入框聚焦状态 + setCodeInputFocus(true); + // 清空验证码,让用户重新输入 + setVerificationCode(''); + console.log('设置验证码输入框聚焦'); + }, 500); // 延迟500ms确保Toast显示完成后再聚焦 } else { + console.log('验证码发送失败:', result.message); Taro.showToast({ title: result.message || '发送失败', icon: 'none', @@ -51,6 +69,7 @@ const VerificationPage: React.FC = () => { }); } } catch (error) { + console.error('发送验证码异常:', error); Taro.showToast({ title: '发送失败,请重试', icon: 'none', @@ -61,15 +80,19 @@ const VerificationPage: React.FC = () => { // 倒计时效果 useEffect(() => { + console.log('倒计时 useEffect 触发,countdown:', countdown); + if (countdown > 0) { const timer = setTimeout(() => { + console.log('倒计时减少,从', countdown, '到', countdown - 1); setCountdown(countdown - 1); }, 1000); return () => clearTimeout(timer); - } else { + } else if (countdown === 0 && !can_send_code) { + console.log('倒计时结束,重新启用发送按钮'); setCanSendCode(true); } - }, [countdown]); + }, [countdown, can_send_code]); // 手机号登录 const handle_phone_login = async () => { @@ -96,7 +119,7 @@ const VerificationPage: React.FC = () => { try { // 调用登录服务 const result = await phone_auth_login({ phone, verification_code }); - + if (result.success) { setTimeout(() => { @@ -122,12 +145,6 @@ const VerificationPage: React.FC = () => { } }; - // 查看条款 - const handle_view_terms = (type: string = 'terms') => { - Taro.navigateTo({ - url: `/pages/login/terms/index?type=${type}` - }); - }; return ( @@ -159,7 +176,12 @@ const VerificationPage: React.FC = () => { onInput={(e) => setPhone(e.detail.value)} maxlength={11} /> - {phone.length}/11 + + 0 ? 'count_number active' : 'count_number'}> + {phone.length} + + /11 + @@ -171,11 +193,20 @@ const VerificationPage: React.FC = () => { type="number" placeholder="输入短信验证码" placeholderClass="input_placeholder" + placeholderStyle="color:#999999;" + focus={code_input_focus} value={verification_code} onInput={(e) => setVerificationCode(e.detail.value)} + onFocus={() => setCodeInputFocus(true)} + onBlur={() => setCodeInputFocus(false)} maxlength={6} /> - {verification_code.length}/6 + + 0 ? 'count_number active' : 'count_number'}> + {verification_code.length} + + /6 + + {/* 调试信息 */} + {/* {process.env.NODE_ENV === 'development' && ( + + 调试: can_send_code={can_send_code.toString()}, countdown={countdown} + + )} */} {/* 登录按钮 */} + {/* 调试信息 */} + {/* {process.env.NODE_ENV === 'development' && ( + + 调试: 手机号长度={phone.length}, 验证码长度={verification_code.length}, 可登录={can_login.toString()} + + )} */} - + {/* 底部指示器 */} diff --git a/src/services/loginService.ts b/src/services/loginService.ts index 603f85f..54036ff 100644 --- a/src/services/loginService.ts +++ b/src/services/loginService.ts @@ -1,5 +1,6 @@ import Taro from '@tarojs/taro'; import httpService from './httpService'; +import tokenManager from '../utils/tokenManager'; // 微信用户信息接口 export interface WechatUserInfo { @@ -130,7 +131,8 @@ export const send_sms_code = async (phone: string): Promise => { phone: phone }); - if (response.success) { + // 修复响应检查逻辑:检查 code === 0 或 success === true + if (response.code === 0 || response.success === true) { return { success: true, message: '验证码发送成功' @@ -199,7 +201,14 @@ export const get_user_profile = (): Promise => { // 保存用户登录状态 export const save_login_state = (token: string, user_info: WechatUserInfo) => { try { - Taro.setStorageSync('user_token', token); + // 使用 tokenManager 保存令牌信息,设置24小时过期 + const expires_at = Date.now() + 24 * 60 * 60 * 1000; // 24小时后过期 + tokenManager.setToken({ + accessToken: token, + expiresAt: expires_at + }); + + // 保存用户信息 Taro.setStorageSync('user_info', user_info); Taro.setStorageSync('is_logged_in', true); Taro.setStorageSync('login_time', Date.now()); @@ -211,7 +220,10 @@ export const save_login_state = (token: string, user_info: WechatUserInfo) => { // 清除登录状态 export const clear_login_state = () => { try { - Taro.removeStorageSync('user_token'); + // 使用 tokenManager 清除令牌 + tokenManager.clearTokens(); + + // 清除其他登录状态 Taro.removeStorageSync('user_info'); Taro.removeStorageSync('is_logged_in'); Taro.removeStorageSync('login_time'); @@ -223,22 +235,53 @@ export const clear_login_state = () => { // 检查是否已登录 export const check_login_status = (): boolean => { try { - const is_logged_in = Taro.getStorageSync('is_logged_in'); - const token = Taro.getStorageSync('user_token'); - const login_time = Taro.getStorageSync('login_time'); - - // 检查登录是否过期(7天) - if (login_time && Date.now() - login_time > 7 * 24 * 60 * 60 * 1000) { + // 使用 tokenManager 检查令牌有效性 + if (!tokenManager.hasValidToken()) { clear_login_state(); return false; } - return !!(is_logged_in && token); + const is_logged_in = Taro.getStorageSync('is_logged_in'); + return !!is_logged_in; } catch (error) { return false; } }; +// 检查令牌是否需要刷新(剩余时间少于1小时时) +export const should_refresh_token = (): boolean => { + try { + const remaining_time = tokenManager.getTokenRemainingTime(); + const one_hour = 60 * 60 * 1000; // 1小时 + return remaining_time > 0 && remaining_time < one_hour; + } catch (error) { + return false; + } +}; + +// 获取令牌状态信息 +export const get_token_status = () => { + try { + const is_valid = tokenManager.hasValidToken(); + const remaining_time = tokenManager.getTokenRemainingTime(); + const is_expired = tokenManager.isTokenExpired(); + + return { + is_valid, + remaining_time, + is_expired, + expires_in_minutes: Math.floor(remaining_time / (60 * 1000)) + }; + } catch (error) { + return { + is_valid: false, + remaining_time: 0, + is_expired: true, + expires_in_minutes: 0 + }; + } +}; + // 获取用户信息 export const get_user_info = (): WechatUserInfo | null => { try { @@ -251,7 +294,8 @@ export const get_user_info = (): WechatUserInfo | null => { // 获取用户token export const get_user_token = (): string | null => { try { - return Taro.getStorageSync('user_token') || null; + // 使用 tokenManager 获取令牌 + return tokenManager.getAccessToken(); } catch (error) { return null; } diff --git a/src/utils/tokenManager.ts b/src/utils/tokenManager.ts index b2c680a..435cede 100644 --- a/src/utils/tokenManager.ts +++ b/src/utils/tokenManager.ts @@ -85,6 +85,17 @@ class TokenManager { return !!token && !this.isTokenExpired() } + // 获取令牌剩余有效时间(毫秒) + getTokenRemainingTime(): number { + const expiresAt = this.getTokenExpires() + if (!expiresAt) { + return 0 // 如果没有过期时间,返回0 + } + + const remaining = expiresAt - Date.now() + return remaining > 0 ? remaining : 0 + } + // 获取Authorization头 getAuthHeader(): Record { const token = this.getAccessToken() @@ -93,7 +104,7 @@ class TokenManager { } return { - 'Authorization': `Bearer ${token}` + 'applet-token': `${token}` } } }