Files
ckb-SuperAdmin/nkebao/src/pages/Home.tsx
笔记本里的永平 bdd4dc3832 feat: 本次提交更新内容如下
场景获客暂时搞定
2025-07-07 18:11:40 +08:00

243 lines
8.0 KiB
TypeScript

import React, { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { Bell, Smartphone, Users, Activity } from 'lucide-react';
import Chart from 'chart.js/auto';
import Layout from '@/components/Layout';
import BottomNav from '@/components/BottomNav';
import '@/components/Layout.css';
// 模拟数据
const stats = {
totalDevices: 12,
totalWechatAccounts: 8,
onlineWechatAccounts: 6,
};
const scenarioFeatures = [
{
id: "3",
name: "抖音获客",
value: 156,
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-QR8ManuDplYTySUJsY4mymiZkDYnQ9.png",
color: "bg-red-100",
},
{
id: "4",
name: "小红书获客",
value: 89,
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-yvnMxpoBUzcvEkr8DfvHgPHEo1kmQ3.png",
color: "bg-pink-100",
},
{
id: "6",
name: "公众号获客",
value: 234,
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-Gsg0CMf5tsZb41mioszdjqU1WmsRxW.png",
color: "bg-green-100",
},
{
id: "1",
name: "海报获客",
value: 167,
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-x92XJgXy4MI7moNYlA1EAes2FqDxMH.png",
color: "bg-blue-100",
},
];
export default function Home() {
const navigate = useNavigate();
const chartRef = useRef<HTMLCanvasElement>(null);
const chartInstance = useRef<any>(null);
const handleDevicesClick = () => {
navigate('/devices');
};
const handleWechatClick = () => {
navigate('/wechat-accounts');
};
useEffect(() => {
if (!chartRef.current) return;
// 销毁旧实例
if (chartInstance.current) {
chartInstance.current.destroy();
chartInstance.current = null;
}
const ctx = chartRef.current.getContext('2d');
if (ctx) {
chartInstance.current = new Chart(ctx, {
type: 'line',
data: {
labels: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
datasets: [
{
label: '获客数量',
data: [12, 19, 15, 25, 22, 30, 28],
backgroundColor: 'rgba(59, 130, 246, 0.2)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 2,
tension: 0.3,
pointRadius: 4,
pointBackgroundColor: 'rgba(59, 130, 246, 1)',
pointHoverRadius: 6,
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
tooltip: {
backgroundColor: 'rgba(255, 255, 255, 0.9)',
titleColor: '#333',
bodyColor: '#666',
borderColor: '#ddd',
borderWidth: 1,
padding: 10,
displayColors: false,
callbacks: {
label: (context: any) => `获客数量: ${context.parsed.y}`,
},
},
},
scales: {
x: {
grid: {
display: false,
},
ticks: {
font: {
size: 12, // 0.75rem
},
},
},
y: {
beginAtZero: true,
grid: {
color: 'rgba(0, 0, 0, 0.05)',
},
ticks: {
font: {
size: 12, // 0.75rem
},
},
},
},
},
});
}
// 卸载时销毁
return () => {
if (chartInstance.current) {
chartInstance.current.destroy();
chartInstance.current = null;
}
};
}, []);
return (
<Layout
header={
<div className="bg-white border-b">
<div className="flex justify-between items-center p-4">
<h1 className="text-xl font-semibold text-blue-600"></h1>
<button className="p-2 hover:bg-gray-100 rounded-full">
<Bell className="h-5 w-5 text-gray-600" />
</button>
</div>
</div>
}
footer={<BottomNav />}
>
<div className="bg-gray-50">
<div className="p-4 space-y-6">
{/* 统计卡片 */}
<div className="grid grid-cols-3 gap-4">
<div
className="p-4 bg-white hover:shadow-lg transition-all cursor-pointer rounded shadow"
onClick={handleDevicesClick}
>
<div className="flex flex-col">
<span className="text-sm text-gray-500 mb-2"></span>
<div className="flex items-center justify-between">
<span className="text-2xl font-bold text-blue-600">{stats.totalDevices}</span>
<Smartphone className="w-6 h-6 text-blue-600" />
</div>
</div>
</div>
<div
className="p-4 bg-white hover:shadow-lg transition-all cursor-pointer rounded shadow"
onClick={handleWechatClick}
>
<div className="flex flex-col">
<span className="text-sm text-gray-500 mb-2"></span>
<div className="flex items-center justify-between">
<span className="text-2xl font-bold text-blue-600">{stats.totalWechatAccounts}</span>
<Users className="w-6 h-6 text-blue-600" />
</div>
</div>
</div>
<div className="p-4 bg-white rounded shadow">
<div className="flex flex-col">
<span className="text-sm text-gray-500 mb-2">线</span>
<div className="flex items-center justify-between mb-2">
<span className="text-2xl font-bold text-blue-600">{stats.onlineWechatAccounts}</span>
<Activity className="w-6 h-6 text-blue-600" />
</div>
<div className="w-full bg-gray-200 rounded-full h-1">
<div
className="bg-blue-600 h-1 rounded-full"
style={{ width: `${(stats.onlineWechatAccounts / stats.totalWechatAccounts) * 100}%` }}
></div>
</div>
</div>
</div>
</div>
{/* 场景获客统计 */}
<div className="p-4 bg-white rounded shadow">
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-semibold"></h2>
</div>
<div className="flex justify-between">
{scenarioFeatures
.sort((a, b) => b.value - a.value)
.map((scenario) => (
<div
key={scenario.id}
className="block flex-1 cursor-pointer"
onClick={() => navigate(`/scenarios/${scenario.id}?name=${encodeURIComponent(scenario.name)}`)}
>
<div className="flex flex-col items-center text-center space-y-2">
<div className={`w-12 h-12 rounded-full ${scenario.color} flex items-center justify-center`}>
<img src={scenario.icon || "/placeholder.svg"} alt={scenario.name} className="w-6 h-6" />
</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>
</div>
</div>
))}
</div>
</div>
{/* 每日获客趋势 */}
<div className="p-4 bg-white rounded shadow">
<h2 className="text-lg font-semibold mb-4"></h2>
<div className="w-full h-64 relative">
<canvas ref={chartRef} />
</div>
</div>
</div>
</div>
</Layout>
);
}