合伙人端登录页面调整

This commit is contained in:
2026-07-07 14:48:49 +08:00
parent 2e61caa49c
commit 7dd8a6662b
2 changed files with 70 additions and 125 deletions
+69 -118
View File
@@ -28,6 +28,9 @@ function formatPartnerError(e: unknown): string {
if (text.includes('合伙人账号不存在') || text.includes('未找到合伙人账号')) { if (text.includes('合伙人账号不存在') || text.includes('未找到合伙人账号')) {
return '未找到合伙人账号'; return '未找到合伙人账号';
} }
if (text.includes('合伙人账号已停用')) {
return '合伙人账号已停用';
}
return text; return text;
} }
@@ -36,14 +39,8 @@ export default function LoginPage() {
const [params] = useSearchParams(); const [params] = useSearchParams();
const quick = params.get('quick') === '1'; const quick = params.get('quick') === '1';
const remembered = loadRememberedPhone(); const remembered = loadRememberedPhone();
const [step, setStep] = useState<'phone' | 'code'>('phone');
const [phone, setPhone] = useState(remembered.phone || '13700000001'); const [phone, setPhone] = useState(remembered.phone || '13700000001');
const [confirmedProfile, setConfirmedProfile] = useState<{ const [code, setCode] = useState('');
maskedPhone: string;
name?: string;
companyName?: string;
} | null>(null);
const [code, setCode] = useState('123456');
const [rememberAccount, setRememberAccount] = useState(remembered.remember); const [rememberAccount, setRememberAccount] = useState(remembered.remember);
const [agreed, setAgreed] = useState(true); const [agreed, setAgreed] = useState(true);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -91,37 +88,6 @@ export default function LoginPage() {
} }
} }
function backToPhoneStep() {
setStep('phone');
setConfirmedProfile(null);
setCode('');
setMsg('');
setCodeCooldown(0);
}
async function confirmPhone() {
if (!ensureAgreed()) return;
setLoading(true);
setMsg('');
try {
const data = await request<{ ok: boolean; maskedPhone: string; name?: string; companyName?: string }>(
'PARTNER_H5',
'/partner/auth/phone/check',
{ method: 'POST', body: JSON.stringify({ phone }) },
);
setConfirmedProfile({
maskedPhone: data.maskedPhone,
name: data.name,
companyName: data.companyName,
});
setStep('code');
} catch (e) {
setMsg(formatPartnerError(e));
} finally {
setLoading(false);
}
}
async function sendCode() { async function sendCode() {
if (!ensureAgreed()) return; if (!ensureAgreed()) return;
setMsg(''); setMsg('');
@@ -130,7 +96,7 @@ export default function LoginPage() {
method: 'POST', method: 'POST',
body: JSON.stringify({ phone, scene: 'PARTNER_LOGIN' }), body: JSON.stringify({ phone, scene: 'PARTNER_LOGIN' }),
}); });
setMsg('验证码已发送Mock: 123456'); setMsg('验证码已发送');
setCodeCooldown(60); setCodeCooldown(60);
const timer = setInterval(() => { const timer = setInterval(() => {
setCodeCooldown((s) => { setCodeCooldown((s) => {
@@ -146,11 +112,17 @@ export default function LoginPage() {
} }
} }
async function login() { async function login(options?: { quick?: boolean }) {
if (!ensureAgreed()) return; if (!options?.quick && !ensureAgreed()) return;
setLoading(true); setLoading(true);
setMsg(''); setMsg('');
try { try {
if (options?.quick) {
await request('PARTNER_H5', '/partner/auth/sms/send', {
method: 'POST',
body: JSON.stringify({ phone, scene: 'PARTNER_LOGIN' }),
});
}
const data = await request<{ accessToken: string }>('PARTNER_H5', '/partner/auth/login/sms', { const data = await request<{ accessToken: string }>('PARTNER_H5', '/partner/auth/login/sms', {
method: 'POST', method: 'POST',
body: JSON.stringify({ phone, code }), body: JSON.stringify({ phone, code }),
@@ -214,7 +186,7 @@ export default function LoginPage() {
<nav style={{ width: '100%', maxWidth: 384, marginTop: 16 }}> <nav style={{ width: '100%', maxWidth: 384, marginTop: 16 }}>
{msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center', marginBottom: 12 }}>{msg}</p>} {msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center', marginBottom: 12 }}>{msg}</p>}
<button type="button" className="partner-btn-primary" onClick={login} disabled={loading}> <button type="button" className="partner-btn-primary" onClick={() => void login({ quick: true })} disabled={loading}>
<span>{loading ? '登录中...' : '一键登录'}</span> <span>{loading ? '登录中...' : '一键登录'}</span>
{!loading && <span className="material-symbols-outlined">arrow_forward</span>} {!loading && <span className="material-symbols-outlined">arrow_forward</span>}
</button> </button>
@@ -244,83 +216,62 @@ export default function LoginPage() {
<main className="partner-auth-card"> <main className="partner-auth-card">
<h2 className="partner-auth-card-title"></h2> <h2 className="partner-auth-card-title"></h2>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
{step === 'phone' ? ( <div className="partner-input-wrap">
<> <span className="material-symbols-outlined partner-input-icon">smartphone</span>
<div className="partner-input-wrap"> <input
<span className="material-symbols-outlined partner-input-icon">smartphone</span> className="partner-input"
<input type="tel"
className="partner-input" maxLength={11}
type="tel" placeholder="请输入手机号"
placeholder="请输入手机号" value={phone}
value={phone} onChange={(e) => {
onChange={(e) => { setPhone(e.target.value);
setPhone(e.target.value); setMsg('');
setMsg(''); }}
}} />
/> </div>
</div>
<button type="button" className="partner-btn-primary" onClick={confirmPhone} disabled={loading}> <div className="partner-input-row">
<span>{loading ? '校验中...' : '下一步'}</span> <div className="partner-input-wrap">
{!loading && <span className="material-symbols-outlined">arrow_forward</span>} <span className="material-symbols-outlined partner-input-icon">shield</span>
</button> <input
</> className="partner-input"
) : ( type="text"
<> maxLength={6}
<div className="partner-glass-card" style={{ padding: '12px 16px' }}> placeholder="验证码"
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}> value={code}
<div> onChange={(e) => setCode(e.target.value)}
<div style={{ fontWeight: 600 }}> />
{confirmedProfile?.name || '合伙人账号'} </div>
{confirmedProfile?.companyName ? ( <button type="button" className="partner-code-btn" onClick={sendCode} disabled={codeCooldown > 0}>
<span className="text-muted body-md" style={{ fontWeight: 400, marginLeft: 8 }}> {codeCooldown > 0 ? `${codeCooldown}s` : '获取验证码'}
{confirmedProfile.companyName} </button>
</span> </div>
) : null}
</div> <label className="partner-remember-row">
<div className="text-muted body-md" style={{ marginTop: 4 }}> <input
{confirmedProfile?.maskedPhone || phone} type="checkbox"
</div> checked={rememberAccount}
</div> onChange={(e) => setRememberAccount(e.target.checked)}
<button type="button" className="partner-link" onClick={backToPhoneStep} style={{ flexShrink: 0 }}> />
<span></span>
</button> </label>
</div>
</div>
<div className="partner-input-row">
<div className="partner-input-wrap">
<span className="material-symbols-outlined partner-input-icon">shield</span>
<input className="partner-input" type="text" placeholder="验证码" value={code} onChange={(e) => setCode(e.target.value)} />
</div>
<button type="button" className="partner-code-btn" onClick={sendCode} disabled={codeCooldown > 0}>
{codeCooldown > 0 ? `${codeCooldown}s 后重发` : '获取验证码'}
</button>
</div>
<label className="partner-remember-row">
<input
type="checkbox"
checked={rememberAccount}
onChange={(e) => setRememberAccount(e.target.checked)}
/>
<span></span>
</label>
<button type="button" className="partner-btn-primary" onClick={login} disabled={loading}>
<span>{loading ? '登录中...' : '登录'}</span>
{!loading && <span className="material-symbols-outlined">arrow_forward</span>}
</button>
</>
)}
{msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center' }}>{msg}</p>} {msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center' }}>{msg}</p>}
{step === 'phone' && (
<> <button type="button" className="partner-btn-primary" onClick={() => void login()} disabled={loading}>
<div className="partner-auth-divider"><span></span></div> <span>{loading ? '登录中...' : '登录'}</span>
<button type="button" className="partner-btn-wechat" onClick={wechatLogin} disabled={wxLoading}> {!loading && <span className="material-symbols-outlined">arrow_forward</span>}
<svg viewBox="0 0 24 24" fill="#07C160" aria-hidden> </button>
<path d="M8.25 4.5C4.52 4.5 1.5 7.04 1.5 10.17c0 1.78.98 3.37 2.5 4.48l-.63 1.88 2.19-1.09c.84.24 1.74.38 2.69.38.25 0 .5 0 .75-.03-.16-.53-.25-1.09-.25-1.66 0-3.13 3.02-5.67 6.75-5.67.57 0 1.13.06 1.66.17C15.17 6.13 12 4.5 8.25 4.5zm10.5 6.33c-3.11 0-5.62 2.12-5.62 4.73 0 2.61 2.51 4.73 5.62 4.73.79 0 1.54-.14 2.24-.38l1.83.91-.53-1.57c1.27-.92 2.08-2.25 2.08-3.73 0-2.61-2.51-4.73-5.62-4.73z" />
</svg> <div className="partner-auth-divider"><span></span></div>
<span>{wxLoading ? '登录中...' : '微信一键授权'}</span> <button type="button" className="partner-btn-wechat" onClick={wechatLogin} disabled={wxLoading}>
</button> <svg viewBox="0 0 24 24" fill="#07C160" aria-hidden>
</> <path d="M8.25 4.5C4.52 4.5 1.5 7.04 1.5 10.17c0 1.78.98 3.37 2.5 4.48l-.63 1.88 2.19-1.09c.84.24 1.74.38 2.69.38.25 0 .5 0 .75-.03-.16-.53-.25-1.09-.25-1.66 0-3.13 3.02-5.67 6.75-5.67.57 0 1.13.06 1.66.17C15.17 6.13 12 4.5 8.25 4.5zm10.5 6.33c-3.11 0-5.62 2.12-5.62 4.73 0 2.61 2.51 4.73 5.62 4.73.79 0 1.54-.14 2.24-.38l1.83.91-.53-1.57c1.27-.92 2.08-2.25 2.08-3.73 0-2.61-2.51-4.73-5.62-4.73z" />
)} </svg>
<span>{wxLoading ? '登录中...' : '微信一键授权'}</span>
</button>
<label className="partner-checkbox-row"> <label className="partner-checkbox-row">
<input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} /> <input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />
<span> <span>
+1 -7
View File
@@ -45,13 +45,7 @@ async function main() {
}); });
if (!unknownSms.includes('未找到合伙人账号')) throw new Error(`unexpected: ${unknownSms}`); if (!unknownSms.includes('未找到合伙人账号')) throw new Error(`unexpected: ${unknownSms}`);
console.log('3. PARTNER phone/check + login bound phone'); console.log('3. PARTNER sms/login bound phone');
const check = await req('PARTNER_H5', '/partner/auth/phone/check', {
method: 'POST',
body: JSON.stringify({ phone: '13700000001' }),
});
if (!check.ok || !check.maskedPhone) throw new Error('phone check failed');
const login = await loginWithSms( const login = await loginWithSms(
'PARTNER_H5', 'PARTNER_H5',
'13700000001', '13700000001',