142 lines
5.1 KiB
TypeScript
142 lines
5.1 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
import { useNavigate } from 'react-router-dom';
|
||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||
import type { PartnerMe, UpdatePartnerBankRequest } from '@dukang/shared-types';
|
||
import { request } from '../lib/api';
|
||
import { usePartnerSession } from '../contexts/PartnerSessionContext';
|
||
import { toastError, toastSuccess } from '../lib/toast';
|
||
|
||
type FieldErrors = {
|
||
bankAccountName?: string;
|
||
bankAccountNo?: string;
|
||
bankBranch?: string;
|
||
};
|
||
|
||
export default function BankAccountPage() {
|
||
const navigate = useNavigate();
|
||
const { account, refresh } = usePartnerSession();
|
||
const [bankAccountName, setBankAccountName] = useState(account?.bankAccount?.bankAccountName ?? '');
|
||
const [bankAccountNo, setBankAccountNo] = useState(account?.bankAccount?.bankAccountNo ?? '');
|
||
const [bankBranch, setBankBranch] = useState(account?.bankAccount?.bankBranch ?? '');
|
||
const [submitting, setSubmitting] = useState(false);
|
||
const [fieldErrors, setFieldErrors] = useState<FieldErrors>({});
|
||
|
||
useEffect(() => {
|
||
document.title = '收款账户';
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
setBankAccountName(account?.bankAccount?.bankAccountName ?? '');
|
||
setBankAccountNo(account?.bankAccount?.bankAccountNo ?? '');
|
||
setBankBranch(account?.bankAccount?.bankBranch ?? '');
|
||
}, [account?.bankAccount]);
|
||
|
||
async function submit() {
|
||
const name = bankAccountName.trim();
|
||
const no = bankAccountNo.replace(/\s+/g, '');
|
||
const branch = bankBranch.trim();
|
||
const next: FieldErrors = {};
|
||
if (!name) next.bankAccountName = '请填写收款人';
|
||
if (!/^\d{8,32}$/.test(no)) next.bankAccountNo = '请填写 8~32 位数字账号';
|
||
if (!branch) next.bankBranch = '请填写开户行名称';
|
||
setFieldErrors(next);
|
||
if (Object.keys(next).length) return;
|
||
|
||
setSubmitting(true);
|
||
try {
|
||
const body: UpdatePartnerBankRequest = {
|
||
bankAccountName: name,
|
||
bankAccountNo: no,
|
||
bankBranch: branch,
|
||
};
|
||
await request<PartnerMe>('PARTNER_H5', '/partner/me/bank', {
|
||
method: 'PUT',
|
||
body: JSON.stringify(body),
|
||
});
|
||
await refresh();
|
||
toastSuccess('收款账户已保存');
|
||
navigate('/center');
|
||
} catch (e) {
|
||
toastError(e instanceof Error ? e.message : '保存失败');
|
||
} finally {
|
||
setSubmitting(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="partner-page-sticky">
|
||
<PageHeader title="收款账户" onBack={() => navigate('/center')} />
|
||
|
||
<section className="partner-form-card">
|
||
<div className="partner-section-title">
|
||
<div className="partner-section-bar" />
|
||
<h2 className="headline-md">银行账号</h2>
|
||
</div>
|
||
<p className="label-md text-muted" style={{ marginBottom: 16, lineHeight: 1.5 }}>
|
||
用于总部打款。请填写与合同一致的对公或对私账户。
|
||
</p>
|
||
|
||
<div className="partner-field">
|
||
<label>收款人 <span className="text-primary">*</span></label>
|
||
<div className="partner-field-input">
|
||
<span className="material-symbols-outlined">person</span>
|
||
<input
|
||
placeholder="户名 / 收款人姓名"
|
||
value={bankAccountName}
|
||
maxLength={64}
|
||
onChange={(e) => setBankAccountName(e.target.value)}
|
||
/>
|
||
</div>
|
||
{fieldErrors.bankAccountName && (
|
||
<p className="partner-field-error" role="alert">{fieldErrors.bankAccountName}</p>
|
||
)}
|
||
</div>
|
||
|
||
<div className="partner-field">
|
||
<label>银行账号 <span className="text-primary">*</span></label>
|
||
<div className="partner-field-input">
|
||
<span className="material-symbols-outlined">credit_card</span>
|
||
<input
|
||
inputMode="numeric"
|
||
placeholder="请输入银行账号"
|
||
value={bankAccountNo}
|
||
maxLength={32}
|
||
onChange={(e) => setBankAccountNo(e.target.value.replace(/[^\d]/g, ''))}
|
||
/>
|
||
</div>
|
||
{fieldErrors.bankAccountNo && (
|
||
<p className="partner-field-error" role="alert">{fieldErrors.bankAccountNo}</p>
|
||
)}
|
||
</div>
|
||
|
||
<div className="partner-field">
|
||
<label>开户行名称 <span className="text-primary">*</span></label>
|
||
<div className="partner-field-input">
|
||
<span className="material-symbols-outlined">account_balance</span>
|
||
<input
|
||
placeholder="如 中国工商银行洛阳分行"
|
||
value={bankBranch}
|
||
maxLength={128}
|
||
onChange={(e) => setBankBranch(e.target.value)}
|
||
/>
|
||
</div>
|
||
{fieldErrors.bankBranch && (
|
||
<p className="partner-field-error" role="alert">{fieldErrors.bankBranch}</p>
|
||
)}
|
||
</div>
|
||
</section>
|
||
|
||
<footer className="partner-sticky-footer">
|
||
<button
|
||
type="button"
|
||
className="partner-btn-primary"
|
||
disabled={submitting}
|
||
onClick={() => void submit()}
|
||
>
|
||
{submitting ? '保存中…' : '保存'}
|
||
</button>
|
||
</footer>
|
||
</div>
|
||
);
|
||
}
|