Files
ThriveX-Admin/src/components/Charts/ChartOne.tsx

316 lines
8.6 KiB
TypeScript
Raw Normal View History

2024-07-25 18:49:59 +08:00
import { ApexOptions } from 'apexcharts';
import { useEffect, useState } from 'react';
2024-07-25 18:49:59 +08:00
import ReactApexChart from 'react-apexcharts';
import dayjs from 'dayjs'
2024-08-15 14:38:26 +08:00
import { MonthlySums, Result } from './chart';
2024-07-25 18:49:59 +08:00
interface ChartOneState {
series: {
name: string;
data: number[];
}[];
}
const ChartOne = () => {
2024-08-15 14:38:26 +08:00
const [result, setResult] = useState<Result>({} as Result)
const [scope, setScope] = useState<"day" | "month" | "year">("day")
2024-08-15 13:08:31 +08:00
const [startDate, setStartDate] = useState(dayjs(new Date()).subtract(7, "day").format("YYYY/MM/DD"))
const [endDate, setEndDate] = useState(dayjs(new Date()).format("YYYY/MM/DD"))
2024-07-25 18:49:59 +08:00
const [options, setOptions] = useState<ApexOptions>({
legend: {
2024-07-25 18:49:59 +08:00
show: false,
position: 'top',
horizontalAlign: 'left',
2024-07-25 18:49:59 +08:00
},
colors: ['#3C50E0', '#80CAEE'],
chart: {
fontFamily: 'Satoshi, sans-serif',
height: 335,
type: 'area',
dropShadow: {
enabled: true,
color: '#623CEA14',
top: 10,
blur: 4,
left: 0,
opacity: 0.1,
},
toolbar: {
show: false,
2024-07-25 18:49:59 +08:00
},
},
responsive: [
{
breakpoint: 1024,
options: {
chart: {
height: 300,
},
2024-07-25 18:49:59 +08:00
},
},
{
breakpoint: 1366,
options: {
chart: {
height: 350,
},
},
2024-07-25 18:49:59 +08:00
},
],
stroke: {
width: [2, 2],
curve: 'straight',
2024-07-25 18:49:59 +08:00
},
// labels: {
// show: false,
// position: "top",
// },
grid: {
xaxis: {
lines: {
show: true,
},
},
yaxis: {
lines: {
show: true,
},
2024-07-25 18:49:59 +08:00
},
},
dataLabels: {
enabled: false,
2024-07-25 18:49:59 +08:00
},
markers: {
size: 4,
colors: '#fff',
strokeColors: ['#3056D3', '#80CAEE'],
strokeWidth: 3,
strokeOpacity: 0.9,
strokeDashArray: 0,
fillOpacity: 1,
discrete: [],
hover: {
size: undefined,
sizeOffset: 5,
},
2024-07-25 18:49:59 +08:00
},
xaxis: {
type: 'category',
2024-08-15 13:19:30 +08:00
categories: [],
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
2024-07-25 18:49:59 +08:00
},
yaxis: {
title: {
style: {
fontSize: '0px',
},
2024-07-25 18:49:59 +08:00
},
2024-08-15 13:19:30 +08:00
// min: 0,
// max: 100,
2024-07-25 18:49:59 +08:00
},
})
2024-07-25 18:49:59 +08:00
const [state, setState] = useState<ChartOneState>({
series: [
{
name: '访客数量',
2024-08-15 13:19:30 +08:00
data: [],
2024-07-25 18:49:59 +08:00
},
{
name: 'IP数量',
2024-08-15 13:19:30 +08:00
data: [],
2024-07-25 18:49:59 +08:00
},
],
});
useEffect(() => {
const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID
const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN
2024-08-15 14:38:26 +08:00
2024-08-15 13:19:30 +08:00
fetch(`/api/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${startDate}&end_date=${endDate}&metrics=pv_count%2Cip_count&method=overview%2FgetTimeTrendRpt`).then(async res => {
2024-08-15 13:08:31 +08:00
const { result } = await res.json()
2024-08-15 14:38:26 +08:00
console.log({ result });
setResult(result)
})
}, [scope])
useEffect(() => {
if (!result?.items?.length) return
switch (scope) {
// 处理天数据
case "day":
// 处理分类数据
const categories_weeks = result.items[0].map((item: string[]) => {
const year = new Date().getFullYear() + "/"
return item[0].replace(year, "")
})
setOptions((data) => (
2024-08-15 13:19:30 +08:00
{
2024-08-15 14:38:26 +08:00
...data,
xaxis: { ...options.xaxis, categories: categories_weeks }
}
))
// 处理访客和IP数据
const pvList_weeks = result.items[1].map((item: number[]) => item[0])
const ipList_weeks = result.items[1].map((item: number[]) => item[1])
setState((prevState) => ({
...prevState,
series: [
{
name: '访客数量',
data: pvList_weeks,
},
{
name: 'IP数量',
data: ipList_weeks,
},
],
}));
break
// 处理月数据
case "month":
const datesArray: string[][] = result.items[0];
const valuesArray: (string | number)[][] = result.items[1];
// 初始化一个对象来存储每个月份的累加和
const monthlySums: MonthlySums = {};
// 遍历日期数组和值数组
datesArray.forEach((dateArray, index) => {
const date: string = dateArray[0];
const [year, month, day] = date.split('/');
// 确保月份在对象中存在
if (!monthlySums[month]) {
monthlySums[month] = { pv: 0, ip: 0 };
}
// 获取对应的值对
const pair = valuesArray[index];
// 确保值对是有效的数字
if (pair.length === 2) {
const firstValue = parseFloat(pair[0] as string);
const secondValue = parseFloat(pair[1] as string);
if (!isNaN(firstValue) && !isNaN(secondValue)) {
monthlySums[month].pv += firstValue;
monthlySums[month].ip += secondValue;
}
}
});
setOptions((data) => (
2024-08-15 13:19:30 +08:00
{
2024-08-15 14:38:26 +08:00
...data,
xaxis: { ...options.xaxis, categories: Object.keys(monthlySums) }
}
))
const list = Object.values(monthlySums)
// 处理访客和IP数据
const pvList_month = list.map(item => item.pv)
const ipList_month = list.map(item => item.ip)
setState((prevState) => ({
...prevState,
series: [
{
name: '访客数量',
data: pvList_month,
},
{
name: 'IP数量',
data: ipList_month,
},
],
}));
break
case "year":
break
}
}, [result])
2024-07-25 18:49:59 +08:00
const handleReset = () => {
setState((prevState) => ({
...prevState,
}));
};
handleReset;
return (
<div className="col-span-12 rounded-sm border border-stroke bg-white px-5 pt-7.5 pb-5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:col-span-8">
<div className="flex flex-wrap items-start justify-between gap-3 sm:flex-nowrap">
<div className="flex w-full flex-wrap gap-3 sm:gap-5">
<div className="flex min-w-47.5">
<span className="mt-1 mr-2 flex h-4 w-full max-w-4 items-center justify-center rounded-full border border-primary">
<span className="block h-2.5 w-full max-w-2.5 rounded-full bg-primary"></span>
</span>
2024-07-25 18:49:59 +08:00
<div className="w-full">
<p className="font-semibold text-primary">访UV</p>
2024-07-25 18:49:59 +08:00
</div>
</div>
2024-07-25 18:49:59 +08:00
<div className="flex min-w-47.5">
<span className="mt-1 mr-2 flex h-4 w-full max-w-4 items-center justify-center rounded-full border border-secondary">
<span className="block h-2.5 w-full max-w-2.5 rounded-full bg-secondary"></span>
</span>
2024-07-25 18:49:59 +08:00
<div className="w-full">
<p className="font-semibold text-secondary">IP</p>
2024-07-25 18:49:59 +08:00
</div>
</div>
</div>
2024-07-25 18:49:59 +08:00
<div className="flex w-full max-w-45 justify-end">
<div className="inline-flex items-center rounded-md bg-whiter p-1.5 dark:bg-meta-4">
2024-08-15 14:38:26 +08:00
<button className={`rounded py-1 px-3 text-xs font-medium text-black hover:bg-white hover:shadow-card dark:bg-boxdark dark:text-white dark:hover:bg-boxdark ${scope === "day" ? "bg-white shadow-card" : ""}`} onClick={() => {
setScope("day")
setStartDate(dayjs(new Date()).subtract(7, "day").format("YYYY/MM/DD"))
}}>
2024-07-25 18:49:59 +08:00
</button>
2024-08-15 14:38:26 +08:00
<button className={`rounded py-1 px-3 text-xs font-medium text-black hover:bg-white hover:shadow-card dark:bg-boxdark dark:text-white dark:hover:bg-boxdark ${scope === "month" ? "bg-white shadow-card" : ""}`} onClick={() => {
setScope("month")
const year = new Date().getFullYear() + ""
setStartDate(year + "/01/01")
}}>
2024-07-25 18:49:59 +08:00
</button>
2024-08-15 14:38:26 +08:00
<button className={`rounded py-1 px-3 text-xs font-medium text-black hover:bg-white hover:shadow-card dark:bg-boxdark dark:text-white dark:hover:bg-boxdark ${scope === "year" ? "bg-white shadow-card" : ""}`} onClick={() => {
setScope("year")
}}>
2024-07-25 18:49:59 +08:00
</button>
</div>
</div>
</div>
2024-08-15 14:38:26 +08:00
<div id="chartOne" className="-ml-5">
<ReactApexChart
options={options}
series={state.series}
type="area"
height={350}
/>
2024-07-25 18:49:59 +08:00
</div>
</div>
);
};
export default ChartOne;