Files
dukang/apps/h5-user/src/pages/InvoiceApplyPage.tsx
T
2026-07-19 22:16:55 +08:00

159 lines
6.0 KiB
TypeScript

import { useEffect, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import {
INVOICE_KIND_LABELS,
INVOICE_TITLE_TYPE_LABELS,
type InvoiceKind,
type InvoiceTitleType,
} from '@dukang/shared-types';
import SubPageHeader from '../components/SubPageHeader';
import { request } from '../lib/api';
type OrderRow = { id: string; orderNo: string; payAmount: number | string; productName?: string };
export default function InvoiceApplyPage() {
const navigate = useNavigate();
const [params] = useSearchParams();
const presetOrderId = params.get('orderId') || '';
const [orders, setOrders] = useState<OrderRow[]>([]);
const [orderId, setOrderId] = useState(presetOrderId);
const [titleType, setTitleType] = useState<InvoiceTitleType>('PERSONAL');
const [invoiceKind, setInvoiceKind] = useState<InvoiceKind>('NORMAL');
const [titleName, setTitleName] = useState('');
const [taxNo, setTaxNo] = useState('');
const [addressPhone, setAddressPhone] = useState('');
const [bankAccount, setBankAccount] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [submitting, setSubmitting] = useState(false);
useEffect(() => {
request<{ list?: OrderRow[] }>('USER_H5', '/trade/orders?tab=completed&pageSize=50')
.then((res) => setOrders(res.list ?? []))
.catch(() => setOrders([]));
}, []);
useEffect(() => {
if (invoiceKind === 'SPECIAL') setTitleType('ENTERPRISE');
}, [invoiceKind]);
async function submit() {
if (!orderId) {
window.alert('请选择订单');
return;
}
if (!titleName.trim() || !email.trim() || !phone.trim()) {
window.alert('请填写抬头名称、邮箱与手机号');
return;
}
setSubmitting(true);
try {
await request('USER_H5', `/trade/orders/${orderId}/invoices`, {
method: 'POST',
body: JSON.stringify({
titleType,
invoiceKind,
titleName: titleName.trim(),
taxNo: taxNo.trim() || undefined,
addressPhone: addressPhone.trim() || undefined,
bankAccount: bankAccount.trim() || undefined,
email: email.trim(),
phone: phone.trim(),
}),
});
window.alert('发票申请已提交,总部将在 2 个工作日内开具');
navigate('/invoices');
} catch (e) {
window.alert(e instanceof Error ? e.message : '申请失败');
} finally {
setSubmitting(false);
}
}
return (
<div className="after-sale-page">
<SubPageHeader title="申请发票" onBack={() => navigate(-1)} />
<main className="after-sale-body after-sale-form">
<label className="after-sale-label">选择已完成订单</label>
<div className="after-sale-order-list" style={{ marginBottom: 16 }}>
{orders.length === 0 ? (
<p className="after-sale-empty">暂无已完成订单</p>
) : (
orders.map((o) => (
<button
key={o.id}
type="button"
className={`after-sale-order-item${orderId === o.id ? ' is-selected' : ''}`}
onClick={() => setOrderId(o.id)}
>
<p className="after-sale-order-no">{o.orderNo}</p>
<p className="after-sale-order-meta">
{o.productName || '商品'} · ¥{Number(o.payAmount).toFixed(2)}
</p>
</button>
))
)}
</div>
<label className="after-sale-label">发票类型</label>
<div className="invoice-chip-row">
{(Object.keys(INVOICE_KIND_LABELS) as InvoiceKind[]).map((k) => (
<button
key={k}
type="button"
className={`invoice-chip${invoiceKind === k ? ' is-selected' : ''}`}
onClick={() => setInvoiceKind(k)}
>
{INVOICE_KIND_LABELS[k]}
</button>
))}
</div>
<label className="after-sale-label">抬头类型</label>
<div className="invoice-chip-row">
{(Object.keys(INVOICE_TITLE_TYPE_LABELS) as InvoiceTitleType[]).map((t) => (
<button
key={t}
type="button"
className={`invoice-chip${titleType === t ? ' is-selected' : ''}`}
disabled={invoiceKind === 'SPECIAL' && t === 'PERSONAL'}
onClick={() => setTitleType(t)}
>
{INVOICE_TITLE_TYPE_LABELS[t]}
</button>
))}
</div>
<label className="after-sale-label">抬头名称</label>
<input className="after-sale-input" value={titleName} onChange={(e) => setTitleName(e.target.value)} placeholder="个人姓名或公司全称" />
{(titleType === 'ENTERPRISE' || invoiceKind === 'SPECIAL') && (
<>
<label className="after-sale-label">税号</label>
<input className="after-sale-input" value={taxNo} onChange={(e) => setTaxNo(e.target.value)} placeholder="纳税人识别号" />
</>
)}
{invoiceKind === 'SPECIAL' && (
<>
<label className="after-sale-label">地址与电话</label>
<input className="after-sale-input" value={addressPhone} onChange={(e) => setAddressPhone(e.target.value)} />
<label className="after-sale-label">开户行与账号</label>
<input className="after-sale-input" value={bankAccount} onChange={(e) => setBankAccount(e.target.value)} />
</>
)}
<label className="after-sale-label">接收邮箱</label>
<input className="after-sale-input" type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
<label className="after-sale-label">手机号</label>
<input className="after-sale-input" value={phone} onChange={(e) => setPhone(e.target.value)} />
<button type="button" className="after-sale-primary" disabled={submitting} onClick={() => void submit()}>
{submitting ? '提交中…' : '提交申请'}
</button>
</main>
</div>
);
}