import { useCallback, useEffect, useState } from 'react'; import { View, Text, Input, Radio } from '@tarojs/components'; import '../../styles/invoice.css'; import Taro, { useDidShow, useRouter } from '@tarojs/taro'; import PageShell from '../../components/PageShell'; import SubPageHeader from '../../components/SubPageHeader'; import { request, toast } from '../../lib/api'; import { usePageView } from '../../lib/usePageView'; import { INVOICE_CATEGORY_LABELS, INVOICE_TITLE_TYPE_LABELS, type InvoiceCategory, type UserInvoiceTitleDto, } from '@dukang/shared-types'; const isH5 = process.env.TARO_ENV === 'h5'; type InvoiceStatus = { exists: boolean; status?: string | null; }; type OrderBrief = { orderNo?: string; productName?: string; productSpec?: string; quantity?: number; payAmount?: number; status?: string; }; const INVOICE_STATUS_LABELS: Record = { PENDING: '开票中', ISSUED: '已开票', REJECTED: '已驳回', }; export default function InvoiceApplyPage() { const router = useRouter(); const orderId = router.params.orderId ?? ''; usePageView('user_invoice_apply_view', orderId ? { orderId } : undefined); const [titles, setTitles] = useState([]); const [selectedId, setSelectedId] = useState(''); const [invoiceCategory, setInvoiceCategory] = useState('LIQUOR'); const [remark, setRemark] = useState(''); const [emailOverride, setEmailOverride] = useState(''); const [phoneOverride, setPhoneOverride] = useState(''); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [invoiceStatus, setInvoiceStatus] = useState(null); const [order, setOrder] = useState(null); const load = useCallback(() => { if (!orderId) return; setLoading(true); Promise.all([ request(`/trade/orders/${orderId}/invoice-titles`).catch(() => []), request(`/trade/orders/${orderId}/invoice-status`).catch(() => ({ exists: false })), request(`/trade/orders/${orderId}`).catch(() => ({})), ]) .then(([list, status, orderData]) => { const titlesList = Array.isArray(list) ? list : []; setTitles(titlesList); setInvoiceStatus(status); setOrder(orderData || {}); const def = titlesList.find((t) => t.isDefault); setSelectedId(def?.id || (titlesList[0]?.id ?? '')); }) .catch(() => { setTitles([]); setInvoiceStatus({ exists: false }); }) .finally(() => setLoading(false)); }, [orderId]); useEffect(() => { void load(); }, [load]); useDidShow(() => { void load(); }); const selected = titles.find((t) => t.id === selectedId); async function submit() { if (!orderId || submitting) return; if (order?.status && order.status !== 'COMPLETED') { toast('仅已完成订单可申请发票'); return; } if (!selected) { toast('请先选择发票抬头'); return; } const email = (selected.email || emailOverride).trim(); const phone = (selected.phone || phoneOverride).trim(); if (!email) { toast('请填写接收邮箱'); return; } if (!phone) { toast('请填写联系电话'); return; } setSubmitting(true); try { await request(`/trade/orders/${orderId}/invoices`, { method: 'POST', data: { titleId: selectedId, invoiceKind: 'NORMAL', invoiceCategory, email, phone, remark: remark.trim() || undefined, }, }); toast('发票申请已提交', 'success'); setTimeout(() => { Taro.navigateBack().catch(() => { Taro.redirectTo({ url: '/pages/orders/index?tab=completed' }); }); }, 1200); } catch (e) { toast(e instanceof Error ? e.message : '申请失败'); } finally { setSubmitting(false); } } function goAddTitle() { Taro.navigateTo({ url: '/pages/invoice-titles/index', }); } const alreadyApplied = invoiceStatus?.exists; const orderCompletable = !order?.status || order.status === 'COMPLETED'; const canApply = !alreadyApplied && orderCompletable; const productLine = order ? [order.productName, order.productSpec, order.quantity ? `×${order.quantity}` : ''] .filter(Boolean) .join(' ') : ''; return ( {isH5 ? ( Taro.navigateBack().catch(() => Taro.switchTab({ url: '/pages/mine/index' }))} /> ) : null} {order?.orderNo ? ( 订单编号 {order.orderNo} {productLine ? ( {productLine} ) : null} {order.payAmount != null ? ( 实付 ¥{Number(order.payAmount).toFixed(2)} ) : null} ) : null} {alreadyApplied ? ( 已申请发票 状态:{INVOICE_STATUS_LABELS[invoiceStatus?.status ?? ''] || invoiceStatus?.status || '处理中'} ) : null} {!alreadyApplied && !orderCompletable ? ( 当前订单不可开票 仅已完成订单可申请发票 ) : null} {canApply ? ( <> 发票类型 增值税普通发票 类型 {(['LIQUOR', 'CATERING'] as InvoiceCategory[]).map((k) => ( setInvoiceCategory(k)} > {INVOICE_CATEGORY_LABELS[k]} ))} ) : null} {canApply ? ( 选择发票抬头 + 新增抬头 ) : null} {loading ? 加载中… : null} {canApply && !loading && titles.length === 0 ? ( 暂无发票抬头 去添加 ) : null} {canApply && !loading && titles.length > 0 ? ( {titles.map((t) => ( setSelectedId(t.id)} > {t.titleName} {INVOICE_TITLE_TYPE_LABELS[t.titleType] ?? t.titleType} {t.isDefault ? 默认 : null} {t.taxNo ? 税号:{t.taxNo} : null} {t.email ? 邮箱:{t.email} : null} setSelectedId(t.id)} /> ))} ) : null} {canApply && selected && !selected.email ? ( * 接收邮箱 必填 setEmailOverride(e.detail.value)} /> ) : null} {canApply && selected && !selected.phone ? ( 联系电话 setPhoneOverride(e.detail.value)} /> ) : null} {canApply ? ( 备注 setRemark(e.detail.value)} /> ) : null} {canApply && titles.length > 0 ? ( { if (!submitting) void submit(); }} > {submitting ? '提交中…' : '提交申请'} ) : null} ); }