微信SDK接通

This commit is contained in:
2026-07-01 19:56:44 +08:00
parent a1cbfc7241
commit aea1513836
38 changed files with 1610 additions and 92 deletions
+71 -15
View File
@@ -1,8 +1,10 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import AppImage from '@dukang/shared-ui/AppImage';
import type { WechatLoginResult } from '@dukang/shared-types';
import { request, saveSession } from '../lib/api';
import { normalizePhoneInput, validateMobilePhone } from '../lib/phone';
import { isWechatEnv, weixinSdk } from '../lib/weixin';
export default function LoginPage() {
const navigate = useNavigate();
@@ -12,6 +14,38 @@ export default function LoginPage() {
const [agreed, setAgreed] = useState(true);
const [codeCooldown, setCodeCooldown] = useState(0);
const [msg, setMsg] = useState('');
const [wxSessionKey, setWxSessionKey] = useState<string | null>(null);
const [bindMode, setBindMode] = useState(false);
useEffect(() => {
if (!isWechatEnv()) return;
weixinSdk
.handleOAuthCallback()
.then((result) => {
if (!result) return;
handleWechatLoginResult(result);
})
.catch((e) => setMsg(e instanceof Error ? e.message : '微信登录失败'));
}, []);
function handleWechatLoginResult(result: WechatLoginResult) {
if (result.needBindPhone && result.wxSessionKey) {
setBindMode(true);
setWxSessionKey(result.wxSessionKey);
setMsg('微信授权成功,请绑定手机号完成登录');
return;
}
if (result.accessToken) {
saveSession({
accessToken: result.accessToken,
refreshToken: result.refreshToken ?? '',
deviceKey: result.deviceKey,
phoneVerified: !!result.phoneVerified,
user: result.user as never,
});
navigate('/');
}
}
function ensureAgreed() {
if (!agreed) {
@@ -31,7 +65,7 @@ export default function LoginPage() {
setMsg('');
await request('USER_H5', '/auth/sms/send', {
method: 'POST',
body: JSON.stringify({ phone, scene: 'USER_LOGIN' }),
body: JSON.stringify({ phone, scene: bindMode ? 'BIND_PHONE' : 'USER_LOGIN' }),
});
setMsg('验证码已发送(Mock: 123456');
setCodeCooldown(60);
@@ -60,6 +94,14 @@ export default function LoginPage() {
setLoading(true);
setMsg('');
try {
if (bindMode && wxSessionKey) {
const data = await request<WechatLoginResult>('USER_H5', '/auth/wechat/bind-phone', {
method: 'POST',
body: JSON.stringify({ wxSessionKey, phone, code }),
});
handleWechatLoginResult(data);
return;
}
const data = await request<{
accessToken: string;
refreshToken: string;
@@ -77,9 +119,19 @@ export default function LoginPage() {
}
}
function wechatLogin() {
async function wechatLogin() {
if (!ensureAgreed()) return;
setMsg('preV1:微信一键授权暂未开放,请使用手机验证码登录');
setMsg('');
try {
if (!isWechatEnv()) {
setMsg('请在微信内打开以使用微信一键授权');
return;
}
const result = await weixinSdk.login();
if (result) handleWechatLoginResult(result);
} catch (e) {
setMsg(e instanceof Error ? e.message : '微信登录失败');
}
}
return (
@@ -97,7 +149,7 @@ export default function LoginPage() {
<main className="login-main">
<div className="login-card">
<h3 className="login-card-title"></h3>
<h3 className="login-card-title">{bindMode ? '绑定手机号' : '手机验证码登录'}</h3>
<div className="login-field">
<span className="login-field-prefix">+86</span>
<input
@@ -138,20 +190,24 @@ export default function LoginPage() {
disabled={loading}
onClick={login}
>
{loading ? '登录中...' : '登录'}
{loading ? '登录中...' : bindMode ? '绑定并登录' : '登录'}
</button>
</div>
<div className="login-divider">
<span className="login-divider-line" />
<span className="login-divider-text"></span>
<span className="login-divider-line" />
</div>
{!bindMode && (
<>
<div className="login-divider">
<span className="login-divider-line" />
<span className="login-divider-text"></span>
<span className="login-divider-line" />
</div>
<button type="button" className="login-wechat-btn" onClick={wechatLogin}>
<span className="material-symbols-outlined login-wechat-icon">chat</span>
<span></span>
</button>
<button type="button" className="login-wechat-btn" onClick={wechatLogin}>
<span className="material-symbols-outlined login-wechat-icon">chat</span>
<span></span>
</button>
</>
)}
</main>
<footer className="login-footer">