feat: 本次提交更新内容如下
更新
This commit is contained in:
@@ -1,21 +1,30 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Bell, Smartphone, Users, Activity, MessageSquare, TrendingUp } from 'lucide-react';
|
||||
import Chart from 'chart.js/auto';
|
||||
import Layout from '@/components/Layout';
|
||||
import BottomNav from '@/components/BottomNav';
|
||||
import UnifiedHeader, { HeaderPresets } from '@/components/UnifiedHeader';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import '@/components/Layout.css';
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import {
|
||||
Bell,
|
||||
Smartphone,
|
||||
Users,
|
||||
Activity,
|
||||
MessageSquare,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import Chart from "chart.js/auto";
|
||||
import Layout from "@/components/Layout";
|
||||
import BottomNav from "@/components/BottomNav";
|
||||
import UnifiedHeader, { HeaderPresets } from "@/components/UnifiedHeader";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import "@/components/Layout.css";
|
||||
|
||||
// API接口定义
|
||||
const API_BASE_URL = process.env.REACT_APP_API_BASE_URL || "https://ckbapi.quwanzhi.com";
|
||||
const API_BASE_URL =
|
||||
process.env.REACT_APP_API_BASE_URL || "https://ckbapi.quwanzhi.com";
|
||||
|
||||
// 统一的API请求客户端
|
||||
async function apiRequest<T>(url: string): Promise<T> {
|
||||
try {
|
||||
const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
|
||||
const token =
|
||||
typeof window !== "undefined" ? localStorage.getItem("token") : null;
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
@@ -99,7 +108,7 @@ export default function Home() {
|
||||
growth: 12,
|
||||
},
|
||||
{
|
||||
id: "xiaohongshu",
|
||||
id: "xiaohongshu",
|
||||
name: "小红书获客",
|
||||
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-yvnMxpoBUzcvEkr8DfvHgPHEo1kmQ3.png",
|
||||
color: "bg-red-100 text-red-600",
|
||||
@@ -135,7 +144,7 @@ export default function Home() {
|
||||
},
|
||||
{
|
||||
title: "群发任务",
|
||||
value: "8",
|
||||
value: "8",
|
||||
icon: <Users className="h-4 w-4" />,
|
||||
color: "text-orange-600",
|
||||
path: "/workspace/group-push",
|
||||
@@ -180,10 +189,11 @@ export default function Home() {
|
||||
// 尝试请求API数据
|
||||
try {
|
||||
// 并行请求多个接口
|
||||
const [deviceStatsResult, wechatStatsResult] = await Promise.allSettled([
|
||||
apiRequest(`${API_BASE_URL}/v1/dashboard/device-stats`),
|
||||
apiRequest(`${API_BASE_URL}/v1/dashboard/wechat-stats`),
|
||||
]);
|
||||
const [deviceStatsResult, wechatStatsResult] =
|
||||
await Promise.allSettled([
|
||||
apiRequest(`${API_BASE_URL}/v1/dashboard/device-stats`),
|
||||
apiRequest(`${API_BASE_URL}/v1/dashboard/wechat-stats`),
|
||||
]);
|
||||
|
||||
const newStats = {
|
||||
totalDevices: 0,
|
||||
@@ -213,7 +223,9 @@ export default function Home() {
|
||||
setStats(newStats);
|
||||
} catch (apiError) {
|
||||
console.warn("API请求失败,使用默认数据:", apiError);
|
||||
setApiError(apiError instanceof Error ? apiError.message : "API连接失败");
|
||||
setApiError(
|
||||
apiError instanceof Error ? apiError.message : "API连接失败"
|
||||
);
|
||||
|
||||
// 使用默认数据
|
||||
setStats({
|
||||
@@ -247,11 +259,11 @@ export default function Home() {
|
||||
}, []); // 移除stats依赖
|
||||
|
||||
const handleDevicesClick = () => {
|
||||
navigate('/profile/devices');
|
||||
navigate("/profile/devices");
|
||||
};
|
||||
|
||||
const handleWechatClick = () => {
|
||||
navigate('/wechat-accounts');
|
||||
navigate("/wechat-accounts");
|
||||
};
|
||||
|
||||
// 使用Chart.js创建图表
|
||||
@@ -263,7 +275,7 @@ export default function Home() {
|
||||
}
|
||||
|
||||
const ctx = chartRef.current.getContext("2d");
|
||||
|
||||
|
||||
// 添加null检查
|
||||
if (!ctx) return;
|
||||
|
||||
@@ -391,9 +403,12 @@ export default function Home() {
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs text-gray-500 mb-1">设备数量</span>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-lg font-bold text-blue-600">{stats.totalDevices}</span>
|
||||
<span className="text-lg font-bold text-blue-600">
|
||||
{stats.totalDevices}
|
||||
</span>
|
||||
<Smartphone className="w-5 h-5 text-blue-600" />
|
||||
</div>
|
||||
<div className="h-2"></div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -402,22 +417,31 @@ export default function Home() {
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs text-gray-500 mb-1">微信号数量</span>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-lg font-bold text-blue-600">{stats.totalWechatAccounts}</span>
|
||||
<span className="text-lg font-bold text-blue-600">
|
||||
{stats.totalWechatAccounts}
|
||||
</span>
|
||||
<Users className="w-5 h-5 text-blue-600" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-2"></div>
|
||||
</Card>
|
||||
</div>
|
||||
<Card className="p-3 bg-white">
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs text-gray-500 mb-1">在线微信号</span>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="text-lg font-bold text-blue-600">{stats.onlineWechatAccounts}</span>
|
||||
<span className="text-lg font-bold text-blue-600">
|
||||
{stats.onlineWechatAccounts}
|
||||
</span>
|
||||
<Activity className="w-5 h-5 text-blue-600" />
|
||||
</div>
|
||||
<Progress
|
||||
value={
|
||||
stats.totalWechatAccounts > 0 ? (stats.onlineWechatAccounts / stats.totalWechatAccounts) * 100 : 0
|
||||
stats.totalWechatAccounts > 0
|
||||
? (stats.onlineWechatAccounts /
|
||||
stats.totalWechatAccounts) *
|
||||
100
|
||||
: 0
|
||||
}
|
||||
className="h-1"
|
||||
/>
|
||||
@@ -435,16 +459,30 @@ export default function Home() {
|
||||
.sort((a, b) => b.value - a.value)
|
||||
.slice(0, 4) // 只显示前4个
|
||||
.map((scenario) => (
|
||||
<div
|
||||
<div
|
||||
key={scenario.id}
|
||||
className="block flex-1 cursor-pointer"
|
||||
onClick={() => navigate(`/scenarios/${scenario.id}?name=${encodeURIComponent(scenario.name)}`)}
|
||||
onClick={() =>
|
||||
navigate(
|
||||
`/scenarios/${scenario.id}?name=${encodeURIComponent(
|
||||
scenario.name
|
||||
)}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col items-center text-center space-y-1">
|
||||
<div className={`w-10 h-10 rounded-full ${scenario.color} flex items-center justify-center`}>
|
||||
<img src={scenario.icon || "/placeholder.svg"} alt={scenario.name} className="w-5 h-5" />
|
||||
<div
|
||||
className={`w-10 h-10 rounded-full ${scenario.color} flex items-center justify-center`}
|
||||
>
|
||||
<img
|
||||
src={scenario.icon || "/placeholder.svg"}
|
||||
alt={scenario.name}
|
||||
className="w-5 h-5"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-sm font-medium">
|
||||
{scenario.value}
|
||||
</div>
|
||||
<div className="text-sm font-medium">{scenario.value}</div>
|
||||
<div className="text-xs text-gray-500 whitespace-nowrap overflow-hidden text-ellipsis w-full">
|
||||
{scenario.name}
|
||||
</div>
|
||||
@@ -466,7 +504,9 @@ export default function Home() {
|
||||
className="flex items-center space-x-3 p-3 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition-colors"
|
||||
onClick={() => stat.path && navigate(stat.path)}
|
||||
>
|
||||
<div className={`p-2 rounded-full bg-white ${stat.color}`}>{stat.icon}</div>
|
||||
<div className={`p-2 rounded-full bg-white ${stat.color}`}>
|
||||
{stat.icon}
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-lg font-semibold">{stat.value}</div>
|
||||
<div className="text-xs text-gray-500">{stat.title}</div>
|
||||
@@ -487,4 +527,4 @@ export default function Home() {
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user