import { useEffect, useRef, useState, type RefObject } from 'react'; import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { isWxAuthorizeEnabled } from '@dukang/shared-types'; import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk'; import { getLastPhone, getPartnerProfile, hasPartnerWxSession, request, saveRememberedSession, type PartnerSessionPayload, } from '../lib/api'; import { usePartnerSession } from '../contexts/PartnerSessionContext'; import { partnerHomePath } from '../lib/partnerAccess'; import type { PartnerPhoneCheckResponse } from '@dukang/shared-types'; import { bindPartnerWechatAfterSmsLogin, checkPartnerPhoneForLogin, fetchClientConfig, loginPartnerWithWechat, } from '../lib/wechat-auth'; import { toastError } from '../lib/toast'; import { isWechatEnv } from '../lib/weixin'; const REMEMBER_PHONE_KEY = 'partner_remember_phone'; const REMEMBER_FLAG_KEY = 'partner_remember_account'; function AgreementCheckbox({ agreed, onChange, inputRef, }: { agreed: boolean; onChange: (next: boolean) => void; inputRef?: RefObject; }) { return ( ); } function maskPhone(phone: string) { if (phone.length < 7) return phone; return `${phone.slice(0, 3)} **** ${phone.slice(-4)}`; } function loadRememberedPhone(): { phone: string; remember: boolean } { try { const remember = localStorage.getItem(REMEMBER_FLAG_KEY) === '1'; const phone = remember ? localStorage.getItem(REMEMBER_PHONE_KEY) || '' : ''; return { phone, remember }; } catch { return { phone: '', remember: false }; } } function formatPartnerError(e: unknown): string { const text = e instanceof Error ? e.message : '操作失败'; if (text.includes('合伙人账号不存在') || text.includes('未找到合伙人账号')) { return '未找到合伙人账号'; } if ( text.includes('合伙人账号已停用') || text.includes('账号已停用') || text.includes('暂停使用') ) { return '该账号已暂停使用,请联系客服人员'; } return text; } function formatWechatError(e: unknown): string { const text = e instanceof Error ? e.message : '微信登录失败'; if ( text.includes('合伙人账号已停用') || text.includes('账号已停用') || text.includes('暂停使用') ) { return '该账号已暂停使用,请联系客服人员'; } if (text.includes('首次登录') || text.includes('手机验证码')) { return '该微信尚未绑定合伙人账号,请先使用手机验证码登录,登录后将自动关联微信'; } return text; } export default function LoginPage() { const navigate = useNavigate(); const { applySession, refresh, account } = usePartnerSession(); const [params, setSearchParams] = useSearchParams(); const quick = params.get('quick') === '1'; const savedProfile = getPartnerProfile(); const remembered = loadRememberedPhone(); const [phone, setPhone] = useState(remembered.phone || getLastPhone()); const [code, setCode] = useState(''); const [rememberAccount, setRememberAccount] = useState(remembered.remember); const [agreed, setAgreed] = useState(false); const [loading, setLoading] = useState(false); const [wxLoading, setWxLoading] = useState(false); const [msg, setMsg] = useState(''); const [codeCooldown, setCodeCooldown] = useState(0); const [wxAuthorize, setWxAuthorize] = useState(false); const agreementRef = useRef(null); useEffect(() => { fetchClientConfig() .then((config) => setWxAuthorize(isWxAuthorizeEnabled(config))) .catch(() => setWxAuthorize(false)); }, []); useEffect(() => { if (params.get('disabled') === '1') { const tip = '账号已停用或解绑,请重新登录'; setMsg(tip); toastError(tip); const next = new URLSearchParams(params); next.delete('disabled'); setSearchParams(next, { replace: true }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const quickName = savedProfile?.name ?? '城市合伙人'; const quickCompany = savedProfile?.companyName ?? ''; const quickPhone = savedProfile?.phone || phone; function ensureAgreed() { if (!agreed) { const tip = '请先勾选并同意用户协议'; setMsg(tip); toastError(tip); agreementRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }); return false; } return true; } function persistRememberAccount(nextPhone: string) { try { if (rememberAccount) { localStorage.setItem(REMEMBER_FLAG_KEY, '1'); localStorage.setItem(REMEMBER_PHONE_KEY, nextPhone); } else { localStorage.removeItem(REMEMBER_FLAG_KEY); localStorage.removeItem(REMEMBER_PHONE_KEY); } } catch { /* ignore */ } } async function sendCode() { if (!ensureAgreed()) return; const trimmedPhone = phone.trim(); if (!trimmedPhone) { setMsg('请输入手机号'); return; } if (!/^1\d{10}$/.test(trimmedPhone)) { setMsg('请输入正确的手机号'); return; } setMsg(''); try { await checkPartnerPhoneForLogin(trimmedPhone); await request('PARTNER_H5', '/partner/auth/sms/send', { method: 'POST', body: JSON.stringify({ phone: trimmedPhone, scene: 'PARTNER_LOGIN' }), silent: true, }); setMsg('验证码已发送'); setCodeCooldown(60); const timer = setInterval(() => { setCodeCooldown((s) => { if (s <= 1) { clearInterval(timer); return 0; } return s - 1; }); }, 1000); } catch (e) { setMsg(formatPartnerError(e)); } } async function finishLoginNavigate() { const me = await refresh(); navigate(partnerHomePath(me ?? account ?? savedProfile)); } async function login() { if (!ensureAgreed()) return; const trimmedPhone = phone.trim(); const trimmedCode = code.trim(); if (!trimmedPhone) { setMsg('请输入手机号'); return; } if (!/^1\d{10}$/.test(trimmedPhone)) { setMsg('请输入正确的手机号'); return; } if (!trimmedCode) { setMsg('请输入验证码'); return; } setLoading(true); setMsg(''); try { await checkPartnerPhoneForLogin(trimmedPhone); const data = await request('PARTNER_H5', '/partner/auth/login/sms', { method: 'POST', body: JSON.stringify({ phone: trimmedPhone, code: trimmedCode }), silent: true, }); saveRememberedSession(data); applySession(data); persistRememberAccount(phone); if (isWechatEnv() && wxAuthorize) { setMsg('登录成功,正在关联微信…'); await bindPartnerWechatAfterSmsLogin(); return; } await finishLoginNavigate(); } catch (e) { setMsg(formatPartnerError(e)); } finally { setLoading(false); } } async function wechatLogin() { if (!ensureAgreed()) return; setMsg(''); if (!isWechatEnv()) { setMsg(WECHAT_INAPP_REQUIRED_MSG); toastError(WECHAT_INAPP_REQUIRED_MSG); return; } setWxLoading(true); try { // 直接发起 OAuth;未绑定账号由后端返回「请先短信登录」提示 const session = await loginPartnerWithWechat(); if (session) { applySession(session); await finishLoginNavigate(); return; } if (session === null) { const tip = '微信授权暂未开启,请使用验证码登录'; setMsg(tip); toastError(tip); } // session === undefined:已跳转微信授权页 } catch (e) { const tip = formatWechatError(e); setMsg(tip); toastError(tip); } finally { setWxLoading(false); } } if (quick) { const canWechatQuick = wxAuthorize && isWechatEnv() && hasPartnerWxSession() && !!savedProfile && savedProfile.hasWechat === true; return (
wine_bar

杜康好客

城市合伙人端

已识别账号
person

{quickName} {quickCompany ? ( ({quickCompany}) ) : null}

{quickPhone ? maskPhone(quickPhone) : '暂无已保存账号'}

verified_user {canWechatQuick ? '微信验证 · 7 天内免登录' : 'Secured by Dukang Heritage'}
); } return (
wine_bar

杜康好客

城市合伙人端

城市合伙人登录

smartphone { setPhone(e.target.value); setMsg(''); }} />
shield setCode(e.target.value)} />
{msg &&

{msg}

} {wxAuthorize && ( <>
其他登录方式
{msg && (

{msg}

)} )}

请在微信内打开;首次请先用验证码登录,成功后将自动关联微信,之后可一键登录

{hasPartnerWxSession() && savedProfile?.hasWechat && ( 微信快捷登录 )}
); }