import { useEffect, useState } from 'react'; import { View, Text, Input, Button } from '@tarojs/components'; import { useRouter } from '@tarojs/taro'; import { SmsScene, isWxAuthorizeEnabled, type ClientRuntimeConfig, type WechatLoginResult, } from '@dukang/shared-types'; import PageShell from '../../components/PageShell'; import WechatLoginButton from '../../components/WechatLoginButton'; import { finishLoginNavigate } from '../../lib/auth-nav'; import { request, saveAuth, toast, type SessionPayload } from '../../lib/api'; import { loginWithWechat } from '../../lib/wechat-auth'; function normalizePhone(value: string) { return value.replace(/\D/g, '').slice(0, 11); } function isValidPhone(phone: string) { return /^1[3-9]\d{9}$/.test(phone); } export default function LoginPage() { const router = useRouter(); const returnTo = router.params.return || ''; const [phone, setPhone] = useState(''); const [code, setCode] = useState(''); const [loading, setLoading] = useState(false); const [wxLoading, setWxLoading] = useState(false); const [sending, setSending] = useState(false); const [cooldown, setCooldown] = useState(0); const [agreed, setAgreed] = useState(true); const [msg, setMsg] = useState(''); const [sentHint, setSentHint] = useState(''); const [bindMode, setBindMode] = useState(false); const [wxSessionKey, setWxSessionKey] = useState(null); const [wxAuthorize, setWxAuthorize] = useState(true); useEffect(() => { request('/common/client-config') .then((config) => setWxAuthorize(isWxAuthorizeEnabled(config))) .catch(() => setWxAuthorize(true)); }, []); useEffect(() => { if (cooldown <= 0) return; const timer = setTimeout(() => setCooldown((c) => Math.max(0, c - 1)), 1000); return () => clearTimeout(timer); }, [cooldown]); function ensureAgreed() { if (!agreed) { setMsg('请先勾选并同意用户协议'); return false; } return true; } function applySessionAndLeave(data: SessionPayload | WechatLoginResult) { if (!data.accessToken) return; saveAuth({ accessToken: data.accessToken, refreshToken: data.refreshToken, }); toast('登录成功', 'success'); finishLoginNavigate(returnTo); } function handleWechatLoginResult(result: WechatLoginResult) { if (result.needBindPhone && result.wxSessionKey) { setBindMode(true); setWxSessionKey(result.wxSessionKey); setMsg('微信授权成功,请绑定手机号完成登录'); setSentHint(''); return; } if (result.accessToken) { applySessionAndLeave(result); return; } setMsg('微信登录未完成,请重试或使用手机号登录'); } async function onSendCode() { if (!ensureAgreed()) return; if (cooldown > 0 || sending) return; const normalized = phone.trim(); if (!isValidPhone(normalized)) { setMsg('请输入正确的手机号'); return; } setMsg(''); setSentHint(''); setSending(true); try { await request('/auth/sms/send', { method: 'POST', data: { phone: normalized, scene: bindMode ? SmsScene.BIND_PHONE : SmsScene.USER_LOGIN, }, }); setCooldown(60); setSentHint('验证码已发送'); } catch (e) { setMsg(e instanceof Error ? e.message : '发送失败'); } finally { setSending(false); } } async function login() { if (!ensureAgreed()) return; const normalized = phone.trim(); if (!isValidPhone(normalized)) { setMsg('请输入正确的手机号'); return; } if (!code.trim()) { setMsg('请输入验证码'); return; } setLoading(true); setMsg(''); setSentHint(''); try { if (bindMode && wxSessionKey) { const data = await request('/auth/wechat/bind-phone', { method: 'POST', data: { wxSessionKey, phone: normalized, code: code.trim() }, }); handleWechatLoginResult(data); return; } const data = await request('/auth/login/sms', { method: 'POST', data: { phone: normalized, code: code.trim() }, }); applySessionAndLeave(data); } catch (e) { setMsg(e instanceof Error ? e.message : '登录失败'); } finally { setLoading(false); } } async function wechatLogin() { if (!ensureAgreed()) return; setMsg(''); setSentHint(''); setWxLoading(true); try { const result = await loginWithWechat(); handleWechatLoginResult(result); } catch (e) { const raw = e instanceof Error ? e.message : '微信登录失败'; const hint = /invalid code/i.test(raw) ? '微信 code 无效:请确认后端 WX_MINI_APP_ID 与小程序 appid 一致,或本地联调使用 MOCK_WECHAT' : raw; setMsg(hint); } finally { setWxLoading(false); } } const displayMsg = msg || sentHint; const codeDisabled = cooldown > 0 || sending; const showWechatLogin = !bindMode && (process.env.TARO_ENV === 'weapp' || wxAuthorize); return ( 官方 欢迎来到杜康好客 买美酒,享好礼 {bindMode ? '绑定手机号' : '手机验证码登录'} +86 { setPhone(normalizePhone(e.detail.value)); setMsg(''); setSentHint(''); }} /> setCode(e.detail.value.replace(/\D/g, '').slice(0, 6))} /> void onSendCode()} > {sending ? '发送中...' : cooldown > 0 ? `${cooldown}s 后重新获取` : '获取验证码'} {displayMsg ? ( {displayMsg} ) : null} {showWechatLogin ? ( <> 或者 void wechatLogin()} /> ) : null} setAgreed((v) => !v)}> {agreed ? : null} 我已阅读并同意 《用户协议》《隐私政策》 ); }