import { Card, Link, Space, Grid, Divider, Typography } from '@arco-design/web-react'; import { IconApps, IconUser, IconUserGroup } from 'tushan/icon'; import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from 'tushan/chart'; import dayjs from 'dayjs'; const authStorageKey = 'tushan:auth'; const PRICE_SCALE = 100000; type fetchChatData = { count: number; total?: number; date: string; increase?: number; increaseRate?: string; }; type chatDataType = { date: string; userCount: number; userIncrease?: number; userIncreaseRate?: string; payTotal: number; payCount: number; }; export const Dashboard: React.FC = React.memo(() => { const [userCount, setUserCount] = useState(0); //用户数量 const [kbCount, setkbCount] = useState(0); const [modelCount, setmodelCount] = useState(0); const [chatData, setChatData] = useState([]); useEffect(() => { const baseUrl = import.meta.env.VITE_PUBLIC_SERVER_URL; const { token } = JSON.parse(window.localStorage.getItem(authStorageKey) ?? '{}'); const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }; const fetchCounts = async () => { const userResponse = await fetch(`${baseUrl}/users?_end=1`, { headers }); const kbResponse = await fetch(`${baseUrl}/kbs?_end=1`, { headers }); const modelResponse = await fetch(`${baseUrl}/models?_end=1`, { headers }); const userTotalCount = userResponse.headers.get('X-Total-Count'); const kbTotalCount = kbResponse.headers.get('X-Total-Count'); const modelTotalCount = modelResponse.headers.get('X-Total-Count'); if (userTotalCount) { setUserCount(Number(userTotalCount)); } if (kbTotalCount) { setkbCount(Number(kbTotalCount)); } if (modelTotalCount) { setmodelCount(Number(modelTotalCount)); } }; const fetchChatData = async () => { const [userResponse, payResponse]: fetchChatData[][] = await Promise.all([ fetch(`${baseUrl}/users/data`, { headers }).then((res) => res.json()), fetch(`${baseUrl}/pays/data`, { headers }).then((res) => res.json()) ]); const data = userResponse.map((item, i) => { const pay = payResponse.find((pay) => item.date === pay.date); return { date: dayjs(item.date).format('MM/DD'), userCount: item.count, userIncrease: item.increase, userIncreaseRate: item.increaseRate, payCount: pay ? pay.count / PRICE_SCALE : 0, payTotal: pay?.total ? pay.total / PRICE_SCALE : 0 }; }); setChatData(data); }; fetchCounts(); fetchChatData(); }, []); return (
FastGpt Admin {/* 把 userCount 传递给 DataItem 组件 */} } title={'用户'} count={userCount} /> } title={'知识库'} count={kbCount} /> } title={'应用'} count={modelCount} />
用户数量 & 支付情况
); }); Dashboard.displayName = 'Dashboard'; const DashboardItem = React.memo( (props: { title: string; href?: string; children: React.ReactNode }) => { const { t } = useTranslation(); return ( {t('tushan.dashboard.more')} ) } bordered={false} style={{ overflow: 'hidden' }} > {props.children} ); } ); DashboardItem.displayName = 'DashboardItem'; const DataItem = React.memo((props: { icon: React.ReactElement; title: string; count: number }) => { return (
{props.icon}
{props.title}
{props.count}
); }); DataItem.displayName = 'DataItem'; const CustomTooltip = ({ active, payload }: any) => { const data = payload?.[0]?.payload as chatDataType; if (active && data) { return (

日期: {data.date}

用户总数: {data.userCount}

用户今日增长数量: {data.userIncrease}

今日支付: {data.payCount}

60天累计支付: {data.payTotal}

); } return null; }; const UserChart = ({ data }: { data: chatDataType[] }) => { return ( } /> ); };