合伙人端登录验证调整还有日志落地
This commit is contained in:
@@ -23,12 +23,26 @@ function loadRememberedPhone(): { phone: string; remember: boolean } {
|
||||
}
|
||||
}
|
||||
|
||||
function formatPartnerError(e: unknown): string {
|
||||
const text = e instanceof Error ? e.message : '操作失败';
|
||||
if (text.includes('合伙人账号不存在') || text.includes('未找到合伙人账号')) {
|
||||
return '未找到合伙人账号';
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
const navigate = useNavigate();
|
||||
const [params] = useSearchParams();
|
||||
const quick = params.get('quick') === '1';
|
||||
const remembered = loadRememberedPhone();
|
||||
const [step, setStep] = useState<'phone' | 'code'>('phone');
|
||||
const [phone, setPhone] = useState(remembered.phone || '13700000001');
|
||||
const [confirmedProfile, setConfirmedProfile] = useState<{
|
||||
maskedPhone: string;
|
||||
name?: string;
|
||||
companyName?: string;
|
||||
} | null>(null);
|
||||
const [code, setCode] = useState('123456');
|
||||
const [rememberAccount, setRememberAccount] = useState(remembered.remember);
|
||||
const [agreed, setAgreed] = useState(true);
|
||||
@@ -77,6 +91,37 @@ 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() {
|
||||
if (!ensureAgreed()) return;
|
||||
setMsg('');
|
||||
@@ -97,7 +142,7 @@ export default function LoginPage() {
|
||||
});
|
||||
}, 1000);
|
||||
} catch (e) {
|
||||
setMsg(e instanceof Error ? e.message : '发送失败');
|
||||
setMsg(formatPartnerError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,10 +151,6 @@ export default function LoginPage() {
|
||||
setLoading(true);
|
||||
setMsg('');
|
||||
try {
|
||||
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', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ phone, code }),
|
||||
@@ -123,7 +164,7 @@ export default function LoginPage() {
|
||||
}
|
||||
navigate('/');
|
||||
} catch (e) {
|
||||
setMsg(e instanceof Error ? e.message : '登录失败');
|
||||
setMsg(formatPartnerError(e));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -203,39 +244,83 @@ export default function LoginPage() {
|
||||
<main className="partner-auth-card">
|
||||
<h2 className="partner-auth-card-title">城市合伙人登录</h2>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div className="partner-input-wrap">
|
||||
<span className="material-symbols-outlined partner-input-icon">smartphone</span>
|
||||
<input className="partner-input" type="tel" placeholder="请输入手机号" value={phone} onChange={(e) => setPhone(e.target.value)} />
|
||||
</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>
|
||||
{step === 'phone' ? (
|
||||
<>
|
||||
<div className="partner-input-wrap">
|
||||
<span className="material-symbols-outlined partner-input-icon">smartphone</span>
|
||||
<input
|
||||
className="partner-input"
|
||||
type="tel"
|
||||
placeholder="请输入手机号"
|
||||
value={phone}
|
||||
onChange={(e) => {
|
||||
setPhone(e.target.value);
|
||||
setMsg('');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<button type="button" className="partner-btn-primary" onClick={confirmPhone} disabled={loading}>
|
||||
<span>{loading ? '校验中...' : '下一步'}</span>
|
||||
{!loading && <span className="material-symbols-outlined">arrow_forward</span>}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="partner-glass-card" style={{ padding: '12px 16px' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
|
||||
<div>
|
||||
<div style={{ fontWeight: 600 }}>
|
||||
{confirmedProfile?.name || '合伙人账号'}
|
||||
{confirmedProfile?.companyName ? (
|
||||
<span className="text-muted body-md" style={{ fontWeight: 400, marginLeft: 8 }}>
|
||||
{confirmedProfile.companyName}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="text-muted body-md" style={{ marginTop: 4 }}>
|
||||
{confirmedProfile?.maskedPhone || phone}
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" className="partner-link" onClick={backToPhoneStep} style={{ flexShrink: 0 }}>
|
||||
修改
|
||||
</button>
|
||||
</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>}
|
||||
<div className="partner-auth-divider"><span>其他登录方式</span></div>
|
||||
<button type="button" className="partner-btn-wechat" onClick={wechatLogin} disabled={wxLoading}>
|
||||
<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>
|
||||
{step === 'phone' && (
|
||||
<>
|
||||
<div className="partner-auth-divider"><span>其他登录方式</span></div>
|
||||
<button type="button" className="partner-btn-wechat" onClick={wechatLogin} disabled={wxLoading}>
|
||||
<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">
|
||||
<input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />
|
||||
<span>
|
||||
|
||||
Reference in New Issue
Block a user