feat: 首页样式同步完成

This commit is contained in:
许永平
2025-07-04 11:53:05 +08:00
parent 21a0b12749
commit dbc61c54bb
4 changed files with 259 additions and 2 deletions

6
nkebao/postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',

View File

@@ -1,5 +1,242 @@
import React from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { Chart, registerables } from 'chart.js';
import { useNavigate } from 'react-router-dom';
import { Smartphone, Users, Activity, Bell } from 'lucide-react';
Chart.register(...registerables);
export default function Home() {
return <div></div>;
const chartRef = useRef<HTMLCanvasElement>(null);
const chartInstance = useRef<Chart | null>(null);
const navigate = useNavigate();
// 统计数据状态
const [stats, setStats] = useState({
totalDevices: 0,
onlineDevices: 0,
totalWechatAccounts: 0,
onlineWechatAccounts: 0,
});
// 业务场景数据
const scenarioFeatures = [
{
id: "douyin",
name: "抖音获客",
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-QR8ManuDplYTySUJsY4mymiZkDYnQ9.png",
color: "bg-blue-100 text-blue-600",
value: 156,
growth: 12,
},
{
id: "xiaohongshu",
name: "小红书获客",
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-yvnMxpoBUzcvEkr8DfvHgPHEo1kmQ3.png",
color: "bg-red-100 text-red-600",
value: 89,
growth: 8,
},
{
id: "gongzhonghao",
name: "公众号获客",
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-Gsg0CMf5tsZb41mioszdjqU1WmsRxW.png",
color: "bg-green-100 text-green-600",
value: 234,
growth: 15,
},
{
id: "haibao",
name: "海报获客",
icon: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-x92XJgXy4MI7moNYlA1EAes2FqDxMH.png",
color: "bg-orange-100 text-orange-600",
value: 167,
growth: 10,
},
];
// 获取统计数据
useEffect(() => {
const fetchStats = async () => {
try {
// 这里可以调用实际的API
// const response = await fetch('/api/stats');
// const data = await response.json();
// 模拟数据
setStats({
totalDevices: 42,
onlineDevices: 35,
totalWechatAccounts: 42,
onlineWechatAccounts: 35,
});
} catch (error) {
console.error('获取统计数据失败:', error);
}
};
fetchStats();
}, []);
useEffect(() => {
if (chartRef.current) {
if (chartInstance.current) chartInstance.current.destroy();
chartInstance.current = new Chart(chartRef.current, {
type: 'line',
data: {
labels: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
datasets: [
{
label: '获客数量',
data: [120, 150, 180, 200, 230, 210, 190],
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) => `获客数量: ${context.parsed.y}`,
},
},
},
scales: {
x: {
grid: {
display: false,
},
},
y: {
beginAtZero: true,
grid: {
color: 'rgba(0, 0, 0, 0.05)',
},
},
},
},
});
}
return () => {
if (chartInstance.current) chartInstance.current.destroy();
};
}, []);
const handleDevicesClick = () => {
navigate('/devices');
};
const handleWechatClick = () => {
navigate('/wechat-accounts');
};
return (
<div className="flex-1 overflow-y-auto pb-16 bg-gray-50">
<header className="sticky top-0 z-10 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>
</header>
<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}`)}
>
<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>
);
}

10
nkebao/tailwind.config.js Normal file
View File

@@ -0,0 +1,10 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}