import * as React from "react" import { useState, useEffect } from "react" import { toast } from "sonner" import { TablePagination, FilterSelect } from "@/components/common/general/table-filter" import { Inbox, ListRestart, Gift, Coins, Check, Copy, ExternalLink } from "lucide-react" import { EmptyStateWithBorder } from "@/components/layout/empty" import { LoadingStateWithBorder } from "@/components/layout/loading" import { Badge } from "@/components/ui/badge" import { Card, CardContent } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { formatDateTime } from "@/lib/utils" import type { RedEnvelope } from "@/lib/services" export interface ListDataProps { fetchData: (params: { page: number, page_size: number, type: string }) => Promise<{ list: RedEnvelope[], total: number }> tabs: { value: string, label: string, color?: string }[] defaultTab?: string pageSize?: number className?: string emptyState?: (tab: string) => React.ReactNode refreshTrigger?: number } /** * 红包列表数据组件 * * 提供分页、标签筛选、数据加载状态管理和网格布局,专门用于展示红包列表 */ export function ListData({ fetchData, tabs, defaultTab, pageSize = 20, className, emptyState, refreshTrigger = 0 }: ListDataProps) { const [activeTab, setActiveTab] = useState(defaultTab || tabs[0]?.value) /* 数据状态 */ const [items, setItems] = useState([]) const [total, setTotal] = useState(0) const [loading, setLoading] = useState(false) const [page, setPage] = useState(1) const [currentPageSize, setCurrentPageSize] = useState(pageSize) const [copiedId, setCopiedId] = useState(null) /* 缓存页码 */ const loadData = async (type: string, p: number, s: number) => { setLoading(true) try { const result = await fetchData({ page: p, page_size: s, type }) setItems(result.list) setTotal(result.total) } catch (error) { toast.error('加载数据失败') console.error(error) } finally { setLoading(false) } } /* 初始加载和Tab切换 */ useEffect(() => { setPage(1) loadData(activeTab, 1, currentPageSize) // eslint-disable-next-line react-hooks/exhaustive-deps }, [activeTab, refreshTrigger]) const handlePageChange = (p: number) => { setPage(p) loadData(activeTab, p, currentPageSize) } const handlePageSizeChange = (s: number) => { setCurrentPageSize(s) setPage(1) loadData(activeTab, 1, s) } const totalPages = Math.ceil(total / currentPageSize) const getEnvelopeLink = (id: string) => { if (typeof window !== 'undefined') { return `${ window.location.origin }/redenvelope/${ id }` } return `/redenvelope/${ id }` } const handleCopyLink = async (link: string, envelopeId: string) => { try { await navigator.clipboard.writeText(link) setCopiedId(envelopeId) toast.success("链接已复制") setTimeout(() => setCopiedId(null), 2000) } catch { toast.error("复制失败") } } const getStatusBadge = (status: string) => { switch (status) { case 'active': return 进行中 case 'finished': return 已领完 case 'expired': return 已过期 default: return {status} } } /* 默认空状态 */ const defaultEmptyState = ( ) return (
label="视图" selectedValues={[activeTab]} options={tabs.reduce((acc, tab) => ({ ...acc, [tab.value]: { label: tab.label, color: tab.color } }), {})} onToggleValue={(v) => setActiveTab(v)} />
0 ? page : 0} totalPages={totalPages} total={total} pageSize={currentPageSize} onPageChange={handlePageChange} onPageSizeChange={handlePageSizeChange} onRefresh={() => loadData(activeTab, page, currentPageSize)} loading={loading} />
{loading && items.length === 0 ? ( ) : items.length === 0 ? ( emptyState ? emptyState(activeTab) : defaultEmptyState ) : (
{items.map((envelope) => { const isSent = activeTab === 'sent' const link = getEnvelopeLink(envelope.id) const claimedCount = envelope.total_count - envelope.remaining_count return (
{isSent ? : }
{isSent ? (envelope.type === 'random' ? '拼手气红包' : '普通红包') : envelope.creator_username } {getStatusBadge(envelope.status)}
{envelope.greeting || "恭喜发财,大吉大利"}
总金额
{envelope.total_amount}
已领取
{claimedCount}/{envelope.total_count}
{formatDateTime(envelope.created_at)}
) })}
)}
) }