"use client"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { post } from "@/api/request"; /** 接口请求与返回类型定义 */ interface ConsumptionItem { /** 项目名称 */ project_name: string; /** 总消耗(字符串数字) */ total_consumption: string; } interface ConsumptionResponseData { consumption_list: ConsumptionItem[]; page: number; page_size: number; total: number; period_days: 7 | 30 | 90; } interface ApiResponse { code: number; message: string; data: T; successful: boolean; } type PeriodDays = 7 | 30 | 90; /** * Credit 使用详情页 * - 周期切换:7 / 30 / 90 * - 分页:上一页/下一页(固定每页20) * - 表格展示:项目名、总消耗;不展示项目ID * - 空/错误状态:使用 “-” 显示 */ const UsageView: React.FC = () => { const [days, setDays] = useState(7); const [page, setPage] = useState(1); const pageSize = 20; const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [items, setItems] = useState([]); const [total, setTotal] = useState(0); const [serverPeriodDays, setServerPeriodDays] = useState(90); /** 读取 user_id(参考 dashboard/page.tsx) */ const userId = useMemo(() => { try { const raw = localStorage.getItem("currentUser") || "{}"; const u = JSON.parse(raw); return String(u?.id || ""); } catch { return ""; } }, []); const canPrev = page > 1; const canNext = useMemo(() => { if (total <= 0) return false; const maxPage = Math.ceil(total / pageSize); return page < maxPage; }, [page, total]); const loadData = useCallback(async () => { if (!userId) { setItems([]); setTotal(0); setError("no-user"); return; } setLoading(true); setError(""); try { const body = { user_id: userId, page, page_size: pageSize, days, }; const res = await post>( "/api/token/consumption", body ); if (res && res.successful && res.code === 0) { setItems(res.data?.consumption_list || []); setTotal(res.data?.total || 0); setServerPeriodDays(res.data?.period_days || days); } else { setItems([]); setTotal(0); setError("api-error"); } } catch { setItems([]); setTotal(0); setError("api-error"); } finally { setLoading(false); } }, [userId, page, pageSize, days]); useEffect(() => { loadData(); }, [loadData]); const handleChangeDays = useCallback((d: PeriodDays) => { setDays(d); setPage(1); }, []); const handlePrev = useCallback(() => { if (canPrev) setPage((p) => p - 1); }, [canPrev]); const handleNext = useCallback(() => { if (canNext) setPage((p) => p + 1); }, [canNext]); const periodLabel = useMemo(() => serverPeriodDays || days, [serverPeriodDays, days]); return (

Credit Usage Details

{([7, 30, 90] as PeriodDays[]).map((d) => ( ))}
Period: {periodLabel || "-"} days
{loading ? ( ) : error ? ( ) : items.length === 0 ? ( ) : ( items.map((it, idx) => ( )) )}
Project Name Total Consumption
Loading...
- -
- -
{it?.project_name || "-"} {it?.total_consumption ?? "-"}
Total {Number.isFinite(total) ? total : 0}
Page {page}
); }; export default React.memo(UsageView);