import { useState } from 'react'; import { Button, Descriptions, Drawer, Form, Image, Input, Modal, Select, Space, Table, Tag, Typography, message, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { REDEEM_PENDING_STATUS_LABELS, type RedeemPendingItem, type RedeemPendingStatus, } from '@dukang/shared-types'; import { request } from '../lib/api'; import { fmtTime } from '../lib/constants'; import { useAdminList } from '../lib/useAdminList'; const STATUS_COLOR: Record = { PENDING: 'orange', COMPLETED: 'green', REJECTED: 'default', }; export default function PendingRedeemPage() { const [form] = Form.useForm(); const [filters, setFilters] = useState>({}); const { data, loading, page, pageSize, setPage, setPageSize, reload } = useAdminList( '/admin/redeem-pending', () => { const qs = new URLSearchParams(); if (filters.status) qs.set('status', filters.status); if (filters.pendingNo) qs.set('pendingNo', filters.pendingNo); if (filters.redeemToken) qs.set('redeemToken', filters.redeemToken); if (filters.storeId) qs.set('storeId', filters.storeId); return qs; }, [filters], ); const [detail, setDetail] = useState(null); const [drawerOpen, setDrawerOpen] = useState(false); const [acting, setActing] = useState(false); const [rejectOpen, setRejectOpen] = useState(false); const [rejectReason, setRejectReason] = useState(''); async function openDetail(id: string) { const res = await request(`/admin/redeem-pending/${id}`); setDetail(res); setDrawerOpen(true); } async function complete() { if (!detail) return; setActing(true); try { await request(`/admin/redeem-pending/${detail.id}/complete`, { method: 'POST', body: '{}' }); message.success('已补核销'); setDrawerOpen(false); void reload(); } catch (e) { message.error(e instanceof Error ? e.message : '补核销失败'); } finally { setActing(false); } } async function reject() { if (!detail || !rejectReason.trim()) { message.error('请填写驳回原因'); return; } setActing(true); try { await request(`/admin/redeem-pending/${detail.id}/reject`, { method: 'POST', body: JSON.stringify({ reason: rejectReason.trim() }), }); message.success('已驳回'); setRejectOpen(false); setDrawerOpen(false); void reload(); } catch (e) { message.error(e instanceof Error ? e.message : '驳回失败'); } finally { setActing(false); } } const columns: ColumnsType = [ { title: '待处理单号', dataIndex: 'pendingNo', width: 170 }, { title: '核销码 ID', dataIndex: 'redeemToken', width: 160, ellipsis: true, render: (v: string) => {v.slice(0, 8)}…, }, { title: '门店', dataIndex: ['store', 'name'], width: 140, render: (_, row) => row.store?.name || '—' }, { title: '用户', width: 120, render: (_, row) => row.user?.userNo || row.user?.phone || '—', }, { title: '金额', dataIndex: 'amount', width: 90, render: (v) => `¥${v}` }, { title: '失败次数', dataIndex: 'failCount', width: 90 }, { title: '状态', dataIndex: 'status', width: 100, render: (s: RedeemPendingStatus) => ( {REDEEM_PENDING_STATUS_LABELS[s] || s} ), }, { title: '提交时间', dataIndex: 'createdAt', width: 160, render: fmtTime }, { title: '操作', width: 80, fixed: 'right', render: (_, row) => ( ), }, ]; return (
待处理核销(弱网兜底)
{ setFilters(v); setPage(1); }} >