import { useEffect, useMemo, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { AFTER_SALE_TICKET_TYPES, TICKET_TYPE_LABELS, type AfterSaleTicketType, } from '@dukang/shared-types'; import SubPageHeader from '../components/SubPageHeader'; import { request } from '../lib/api'; import { uploadFileToOss } from '../lib/upload'; import { usePageView } from '../lib/usePageView'; import { track } from '../lib/analytics'; type OrderRow = { id: string; orderNo: string; status: string; payAmount: number | string; productName?: string; createdAt?: string; }; const STEPS = ['类型', '订单', '凭证', '完成'] as const; export default function AfterSalePage() { usePageView('after_sale_apply'); const navigate = useNavigate(); const [params] = useSearchParams(); const presetOrderId = params.get('orderId') || ''; const presetType = (params.get('type') as AfterSaleTicketType | null) || null; const [step, setStep] = useState(0); const [ticketType, setTicketType] = useState( presetType && AFTER_SALE_TICKET_TYPES.includes(presetType) ? presetType : null, ); const [orders, setOrders] = useState([]); const [orderId, setOrderId] = useState(presetOrderId); const [remark, setRemark] = useState(''); const [evidenceUrls, setEvidenceUrls] = useState([]); const [uploading, setUploading] = useState(false); const [submitting, setSubmitting] = useState(false); const [ticketNo, setTicketNo] = useState(''); useEffect(() => { Promise.all([ request<{ list?: OrderRow[] }>('USER_H5', '/trade/orders?tab=paid&pageSize=50'), request<{ list?: OrderRow[] }>('USER_H5', '/trade/orders?tab=completed&pageSize=50'), ]) .then(([paid, completed]) => { const map = new Map(); [...(paid.list ?? []), ...(completed.list ?? [])].forEach((o) => map.set(o.id, o)); setOrders([...map.values()]); }) .catch(() => setOrders([])); }, []); const selectedOrder = useMemo(() => orders.find((o) => o.id === orderId), [orders, orderId]); async function onPickFiles(files: FileList | null) { if (!files?.length) return; setUploading(true); try { const uploaded: string[] = []; for (const file of Array.from(files).slice(0, 6 - evidenceUrls.length)) { const res = await uploadFileToOss(file, { bizType: 'after-sale' }); uploaded.push(res.url); } setEvidenceUrls((prev) => [...prev, ...uploaded].slice(0, 6)); } catch (e) { window.alert(e instanceof Error ? e.message : '上传失败'); } finally { setUploading(false); } } async function submit() { if (!ticketType || !orderId) return; setSubmitting(true); try { const ticket = await request<{ ticketNo: string }>('USER_H5', `/trade/orders/${orderId}/after-sale-tickets`, { method: 'POST', body: JSON.stringify({ ticketType, remark: remark.trim() || undefined, evidenceUrls, }), }); setTicketNo(ticket.ticketNo); setStep(3); } catch (e) { window.alert(e instanceof Error ? e.message : '提交失败'); } finally { setSubmitting(false); } } function nextFromType() { if (!ticketType) { window.alert('请选择售后类型'); return; } setStep(1); } function nextFromOrder() { if (!orderId) { window.alert('请选择订单'); return; } setStep(2); } return (
navigate(-1)} />
{STEPS.map((label, i) => ( {label} ))}
{step === 0 && (
{AFTER_SALE_TICKET_TYPES.map((t) => ( ))}
)} {step === 1 && (
{orders.length === 0 ? (

暂无可售后订单

) : ( orders.map((o) => ( )) )}
)} {step === 2 && (

{ticketType ? TICKET_TYPE_LABELS[ticketType] : ''} · {selectedOrder?.orderNo ?? orderId}