完成新老访客功能

This commit is contained in:
宇阳
2024-08-15 19:18:51 +08:00
parent 80eb93c547
commit 34e017ee2a
12 changed files with 150 additions and 635 deletions

6
package-lock.json generated
View File

@@ -14,7 +14,6 @@
"dicebear": "^9.2.1", "dicebear": "^9.2.1",
"flatpickr": "^4.6.13", "flatpickr": "^4.6.13",
"headlessui": "^0.0.0", "headlessui": "^0.0.0",
"jsvectormap": "^1.5.3",
"match-sorter": "^6.3.1", "match-sorter": "^6.3.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-apexcharts": "^1.4.1", "react-apexcharts": "^1.4.1",
@@ -4462,11 +4461,6 @@
"graceful-fs": "^4.1.6" "graceful-fs": "^4.1.6"
} }
}, },
"node_modules/jsvectormap": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/jsvectormap/-/jsvectormap-1.5.3.tgz",
"integrity": "sha512-HStTEhZEVr8t3t6juApO603nr1y54K/wjcdOvgGtvpE1etZ9Isg/sLdqh7OX4+RJ8srdP7WiBoTV/93aMqhLhw=="
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz",

View File

@@ -20,7 +20,6 @@
"dicebear": "^9.2.1", "dicebear": "^9.2.1",
"flatpickr": "^4.6.13", "flatpickr": "^4.6.13",
"headlessui": "^0.0.0", "headlessui": "^0.0.0",
"jsvectormap": "^1.5.3",
"match-sorter": "^6.3.1", "match-sorter": "^6.3.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-apexcharts": "^1.4.1", "react-apexcharts": "^1.4.1",

View File

@@ -1,163 +0,0 @@
import { ApexOptions } from 'apexcharts';
import React, { useState } from 'react';
import ReactApexChart from 'react-apexcharts';
interface ChartThreeState {
series: number[];
}
const options: ApexOptions = {
chart: {
fontFamily: 'Satoshi, sans-serif',
type: 'donut',
},
colors: ['#3C50E0', '#6577F3', '#8FD0EF', '#0FADCF'],
labels: ['Desktop', 'Tablet', 'Mobile', 'Unknown'],
legend: {
show: false,
position: 'bottom',
},
plotOptions: {
pie: {
donut: {
size: '65%',
background: 'transparent',
},
},
},
dataLabels: {
enabled: false,
},
responsive: [
{
breakpoint: 2600,
options: {
chart: {
width: 380,
},
},
},
{
breakpoint: 640,
options: {
chart: {
width: 200,
},
},
},
],
};
const ChartThree: React.FC = () => {
const [state, setState] = useState<ChartThreeState>({
series: [65, 34, 12, 56],
});
const handleReset = () => {
setState((prevState) => ({
...prevState,
series: [65, 34, 12, 56],
}));
};
handleReset;
return (
<div className="sm:px-7.5 col-span-12 rounded-sm border border-stroke bg-white px-5 pb-5 pt-7.5 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-5">
<div className="mb-3 justify-between gap-4 sm:flex">
<div>
<h5 className="text-xl font-semibold text-black dark:text-white">
Visitors Analytics
</h5>
</div>
<div>
<div className="relative z-20 inline-block">
<select
name=""
id=""
className="relative z-20 inline-flex appearance-none bg-transparent py-1 pl-3 pr-8 text-sm font-medium outline-none"
>
<option value="" className="dark:bg-boxdark">
Monthly
</option>
<option value="" className="dark:bg-boxdark">
Yearly
</option>
</select>
<span className="absolute right-3 top-1/2 z-10 -translate-y-1/2">
<svg
width="10"
height="6"
viewBox="0 0 10 6"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.47072 1.08816C0.47072 1.02932 0.500141 0.955772 0.54427 0.911642C0.647241 0.808672 0.809051 0.808672 0.912022 0.896932L4.85431 4.60386C4.92785 4.67741 5.06025 4.67741 5.14851 4.60386L9.09079 0.896932C9.19376 0.793962 9.35557 0.808672 9.45854 0.911642C9.56151 1.01461 9.5468 1.17642 9.44383 1.27939L5.50155 4.98632C5.22206 5.23639 4.78076 5.23639 4.51598 4.98632L0.558981 1.27939C0.50014 1.22055 0.47072 1.16171 0.47072 1.08816Z"
fill="#637381"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.22659 0.546578L5.00141 4.09604L8.76422 0.557869C9.08459 0.244537 9.54201 0.329403 9.79139 0.578788C10.112 0.899434 10.0277 1.36122 9.77668 1.61224L9.76644 1.62248L5.81552 5.33722C5.36257 5.74249 4.6445 5.7544 4.19352 5.32924C4.19327 5.32901 4.19377 5.32948 4.19352 5.32924L0.225953 1.61241C0.102762 1.48922 -4.20186e-08 1.31674 -3.20269e-08 1.08816C-2.40601e-08 0.905899 0.0780105 0.712197 0.211421 0.578787C0.494701 0.295506 0.935574 0.297138 1.21836 0.539529L1.22659 0.546578ZM4.51598 4.98632C4.78076 5.23639 5.22206 5.23639 5.50155 4.98632L9.44383 1.27939C9.5468 1.17642 9.56151 1.01461 9.45854 0.911642C9.35557 0.808672 9.19376 0.793962 9.09079 0.896932L5.14851 4.60386C5.06025 4.67741 4.92785 4.67741 4.85431 4.60386L0.912022 0.896932C0.809051 0.808672 0.647241 0.808672 0.54427 0.911642C0.500141 0.955772 0.47072 1.02932 0.47072 1.08816C0.47072 1.16171 0.50014 1.22055 0.558981 1.27939L4.51598 4.98632Z"
fill="#637381"
/>
</svg>
</span>
</div>
</div>
</div>
<div className="mb-2">
<div id="chartThree" className="mx-auto flex justify-center">
<ReactApexChart
options={options}
series={state.series}
type="donut"
/>
</div>
</div>
<div className="-mx-8 flex flex-wrap items-center justify-center gap-y-3">
<div className="sm:w-1/2 w-full px-8">
<div className="flex w-full items-center">
<span className="mr-2 block h-3 w-full max-w-3 rounded-full bg-primary"></span>
<p className="flex w-full justify-between text-sm font-medium text-black dark:text-white">
<span> Desktop </span>
<span> 65% </span>
</p>
</div>
</div>
<div className="sm:w-1/2 w-full px-8">
<div className="flex w-full items-center">
<span className="mr-2 block h-3 w-full max-w-3 rounded-full bg-[#6577F3]"></span>
<p className="flex w-full justify-between text-sm font-medium text-black dark:text-white">
<span> Tablet </span>
<span> 34% </span>
</p>
</div>
</div>
<div className="sm:w-1/2 w-full px-8">
<div className="flex w-full items-center">
<span className="mr-2 block h-3 w-full max-w-3 rounded-full bg-[#8FD0EF]"></span>
<p className="flex w-full justify-between text-sm font-medium text-black dark:text-white">
<span> Mobile </span>
<span> 45% </span>
</p>
</div>
</div>
<div className="sm:w-1/2 w-full px-8">
<div className="flex w-full items-center">
<span className="mr-2 block h-3 w-full max-w-3 rounded-full bg-[#0FADCF]"></span>
<p className="flex w-full justify-between text-sm font-medium text-black dark:text-white">
<span> Unknown </span>
<span> 12% </span>
</p>
</div>
</div>
</div>
</div>
);
};
export default ChartThree;

View File

@@ -1,54 +0,0 @@
import jsVectorMap from 'jsvectormap';
import 'jsvectormap/dist/css/jsvectormap.css';
import { useEffect } from 'react';
import '../../js/us-aea-en';
const MapOne = () => {
useEffect(() => {
const mapOne = new jsVectorMap({
selector: '#mapOne',
map: 'us_aea_en',
zoomButtons: true,
regionStyle: {
initial: {
fill: '#C8D0D8',
},
hover: {
fillOpacity: 1,
fill: '#3056D3',
},
},
regionLabelStyle: {
initial: {
fontFamily: 'Satoshi',
fontWeight: 'semibold',
fill: '#fff',
},
hover: {
cursor: 'pointer',
},
},
labels: {
regions: {
render(code: string) {
return code.split('-')[1];
},
},
},
});
mapOne;
});
return (
<div className="col-span-12 rounded-sm border border-stroke bg-white rounded-lg py-6 px-7.5 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-7">
<h4 className="mb-2 text-xl font-semibold text-black dark:text-white">
Region labels
</h4>
<div id="mapOne" className="mapOne map-btn h-90"></div>
</div>
);
};
export default MapOne;

View File

@@ -1,127 +0,0 @@
import { BRAND } from '../../types/app/brand';
import BrandOne from '../../images/brand/brand-01.svg';
import BrandTwo from '../../images/brand/brand-02.svg';
import BrandThree from '../../images/brand/brand-03.svg';
import BrandFour from '../../images/brand/brand-04.svg';
import BrandFive from '../../images/brand/brand-05.svg';
const brandData: BRAND[] = [
{
logo: BrandOne,
name: 'Google',
visitors: 3.5,
revenues: '5,768',
sales: 590,
conversion: 4.8,
},
{
logo: BrandTwo,
name: 'Twitter',
visitors: 2.2,
revenues: '4,635',
sales: 467,
conversion: 4.3,
},
{
logo: BrandThree,
name: 'Github',
visitors: 2.1,
revenues: '4,290',
sales: 420,
conversion: 3.7,
},
{
logo: BrandFour,
name: 'Vimeo',
visitors: 1.5,
revenues: '3,580',
sales: 389,
conversion: 2.5,
},
{
logo: BrandFive,
name: 'Facebook',
visitors: 3.5,
revenues: '6,768',
sales: 390,
conversion: 4.2,
},
];
const TableOne = () => {
return (
<div className="rounded-sm border border-stroke bg-white px-5 pt-6 pb-2.5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
<h4 className="mb-6 text-xl font-semibold text-black dark:text-white">
Top Channels
</h4>
<div className="flex flex-col">
<div className="grid grid-cols-3 rounded-sm bg-gray-2 dark:bg-meta-4 sm:grid-cols-5">
<div className="p-2.5 xl:p-5">
<h5 className="text-sm font-medium uppercase xsm:text-base">
Source
</h5>
</div>
<div className="p-2.5 text-center xl:p-5">
<h5 className="text-sm font-medium uppercase xsm:text-base">
Visitors
</h5>
</div>
<div className="p-2.5 text-center xl:p-5">
<h5 className="text-sm font-medium uppercase xsm:text-base">
Revenues
</h5>
</div>
<div className="hidden p-2.5 text-center sm:block xl:p-5">
<h5 className="text-sm font-medium uppercase xsm:text-base">
Sales
</h5>
</div>
<div className="hidden p-2.5 text-center sm:block xl:p-5">
<h5 className="text-sm font-medium uppercase xsm:text-base">
Conversion
</h5>
</div>
</div>
{brandData.map((brand, key) => (
<div
className={`grid grid-cols-3 sm:grid-cols-5 ${
key === brandData.length - 1
? ''
: 'border-b border-stroke dark:border-strokedark'
}`}
key={key}
>
<div className="flex items-center gap-3 p-2.5 xl:p-5">
<div className="flex-shrink-0">
<img src={brand.logo} alt="Brand" />
</div>
<p className="hidden text-black dark:text-white sm:block">
{brand.name}
</p>
</div>
<div className="flex items-center justify-center p-2.5 xl:p-5">
<p className="text-black dark:text-white">{brand.visitors}K</p>
</div>
<div className="flex items-center justify-center p-2.5 xl:p-5">
<p className="text-meta-3">${brand.revenues}</p>
</div>
<div className="hidden items-center justify-center p-2.5 sm:flex xl:p-5">
<p className="text-black dark:text-white">{brand.sales}</p>
</div>
<div className="hidden items-center justify-center p-2.5 sm:flex xl:p-5">
<p className="text-meta-5">{brand.conversion}%</p>
</div>
</div>
))}
</div>
</div>
);
};
export default TableOne;

View File

@@ -1,156 +0,0 @@
import { Package } from '../../types/app/package';
const packageData: Package[] = [
{
name: 'Free package',
price: 0.0,
invoiceDate: `Jan 13,2023`,
status: 'Paid',
},
{
name: 'Standard Package',
price: 59.0,
invoiceDate: `Jan 13,2023`,
status: 'Paid',
},
{
name: 'Business Package',
price: 99.0,
invoiceDate: `Jan 13,2023`,
status: 'Unpaid',
},
{
name: 'Standard Package',
price: 59.0,
invoiceDate: `Jan 13,2023`,
status: 'Pending',
},
];
const TableThree = () => {
return (
<div className="rounded-sm border border-stroke bg-white px-5 pt-6 pb-2.5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
<div className="max-w-full overflow-x-auto">
<table className="w-full table-auto">
<thead>
<tr className="bg-gray-2 text-left dark:bg-meta-4">
<th className="min-w-[220px] py-4 px-4 font-medium text-black dark:text-white xl:pl-11">
Package
</th>
<th className="min-w-[150px] py-4 px-4 font-medium text-black dark:text-white">
Invoice date
</th>
<th className="min-w-[120px] py-4 px-4 font-medium text-black dark:text-white">
Status
</th>
<th className="py-4 px-4 font-medium text-black dark:text-white">
Actions
</th>
</tr>
</thead>
<tbody>
{packageData.map((packageItem, key) => (
<tr key={key}>
<td className="border-b border-[#eee] py-5 px-4 pl-9 dark:border-strokedark xl:pl-11">
<h5 className="font-medium text-black dark:text-white">
{packageItem.name}
</h5>
<p className="text-sm">${packageItem.price}</p>
</td>
<td className="border-b border-[#eee] py-5 px-4 dark:border-strokedark">
<p className="text-black dark:text-white">
{packageItem.invoiceDate}
</p>
</td>
<td className="border-b border-[#eee] py-5 px-4 dark:border-strokedark">
<p
className={`inline-flex rounded-full bg-opacity-10 py-1 px-3 text-sm font-medium ${
packageItem.status === 'Paid'
? 'bg-success text-success'
: packageItem.status === 'Unpaid'
? 'bg-danger text-danger'
: 'bg-warning text-warning'
}`}
>
{packageItem.status}
</p>
</td>
<td className="border-b border-[#eee] py-5 px-4 dark:border-strokedark">
<div className="flex items-center space-x-3.5">
<button className="hover:text-primary">
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.99981 14.8219C3.43106 14.8219 0.674805 9.50624 0.562305 9.28124C0.47793 9.11249 0.47793 8.88749 0.562305 8.71874C0.674805 8.49374 3.43106 3.20624 8.99981 3.20624C14.5686 3.20624 17.3248 8.49374 17.4373 8.71874C17.5217 8.88749 17.5217 9.11249 17.4373 9.28124C17.3248 9.50624 14.5686 14.8219 8.99981 14.8219ZM1.85605 8.99999C2.4748 10.0406 4.89356 13.5562 8.99981 13.5562C13.1061 13.5562 15.5248 10.0406 16.1436 8.99999C15.5248 7.95936 13.1061 4.44374 8.99981 4.44374C4.89356 4.44374 2.4748 7.95936 1.85605 8.99999Z"
fill=""
/>
<path
d="M9 11.3906C7.67812 11.3906 6.60938 10.3219 6.60938 9C6.60938 7.67813 7.67812 6.60938 9 6.60938C10.3219 6.60938 11.3906 7.67813 11.3906 9C11.3906 10.3219 10.3219 11.3906 9 11.3906ZM9 7.875C8.38125 7.875 7.875 8.38125 7.875 9C7.875 9.61875 8.38125 10.125 9 10.125C9.61875 10.125 10.125 9.61875 10.125 9C10.125 8.38125 9.61875 7.875 9 7.875Z"
fill=""
/>
</svg>
</button>
<button className="hover:text-primary">
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M13.7535 2.47502H11.5879V1.9969C11.5879 1.15315 10.9129 0.478149 10.0691 0.478149H7.90352C7.05977 0.478149 6.38477 1.15315 6.38477 1.9969V2.47502H4.21914C3.40352 2.47502 2.72852 3.15002 2.72852 3.96565V4.8094C2.72852 5.42815 3.09414 5.9344 3.62852 6.1594L4.07852 15.4688C4.13477 16.6219 5.09102 17.5219 6.24414 17.5219H11.7004C12.8535 17.5219 13.8098 16.6219 13.866 15.4688L14.3441 6.13127C14.8785 5.90627 15.2441 5.3719 15.2441 4.78127V3.93752C15.2441 3.15002 14.5691 2.47502 13.7535 2.47502ZM7.67852 1.9969C7.67852 1.85627 7.79102 1.74377 7.93164 1.74377H10.0973C10.2379 1.74377 10.3504 1.85627 10.3504 1.9969V2.47502H7.70664V1.9969H7.67852ZM4.02227 3.96565C4.02227 3.85315 4.10664 3.74065 4.24727 3.74065H13.7535C13.866 3.74065 13.9785 3.82502 13.9785 3.96565V4.8094C13.9785 4.9219 13.8941 5.0344 13.7535 5.0344H4.24727C4.13477 5.0344 4.02227 4.95002 4.02227 4.8094V3.96565ZM11.7285 16.2563H6.27227C5.79414 16.2563 5.40039 15.8906 5.37227 15.3844L4.95039 6.2719H13.0785L12.6566 15.3844C12.6004 15.8625 12.2066 16.2563 11.7285 16.2563Z"
fill=""
/>
<path
d="M9.00039 9.11255C8.66289 9.11255 8.35352 9.3938 8.35352 9.75942V13.3313C8.35352 13.6688 8.63477 13.9782 9.00039 13.9782C9.33789 13.9782 9.64727 13.6969 9.64727 13.3313V9.75942C9.64727 9.3938 9.33789 9.11255 9.00039 9.11255Z"
fill=""
/>
<path
d="M11.2502 9.67504C10.8846 9.64692 10.6033 9.90004 10.5752 10.2657L10.4064 12.7407C10.3783 13.0782 10.6314 13.3875 10.9971 13.4157C11.0252 13.4157 11.0252 13.4157 11.0533 13.4157C11.3908 13.4157 11.6721 13.1625 11.6721 12.825L11.8408 10.35C11.8408 9.98442 11.5877 9.70317 11.2502 9.67504Z"
fill=""
/>
<path
d="M6.72245 9.67504C6.38495 9.70317 6.1037 10.0125 6.13182 10.35L6.3287 12.825C6.35683 13.1625 6.63808 13.4157 6.94745 13.4157C6.97558 13.4157 6.97558 13.4157 7.0037 13.4157C7.3412 13.3875 7.62245 13.0782 7.59433 12.7407L7.39745 10.2657C7.39745 9.90004 7.08808 9.64692 6.72245 9.67504Z"
fill=""
/>
</svg>
</button>
<button className="hover:text-primary">
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16.8754 11.6719C16.5379 11.6719 16.2285 11.9531 16.2285 12.3187V14.8219C16.2285 15.075 16.0316 15.2719 15.7785 15.2719H2.22227C1.96914 15.2719 1.77227 15.075 1.77227 14.8219V12.3187C1.77227 11.9812 1.49102 11.6719 1.12539 11.6719C0.759766 11.6719 0.478516 11.9531 0.478516 12.3187V14.8219C0.478516 15.7781 1.23789 16.5375 2.19414 16.5375H15.7785C16.7348 16.5375 17.4941 15.7781 17.4941 14.8219V12.3187C17.5223 11.9531 17.2129 11.6719 16.8754 11.6719Z"
fill=""
/>
<path
d="M8.55074 12.3469C8.66324 12.4594 8.83199 12.5156 9.00074 12.5156C9.16949 12.5156 9.31012 12.4594 9.45074 12.3469L13.4726 8.43752C13.7257 8.1844 13.7257 7.79065 13.5007 7.53752C13.2476 7.2844 12.8539 7.2844 12.6007 7.5094L9.64762 10.4063V2.1094C9.64762 1.7719 9.36637 1.46252 9.00074 1.46252C8.66324 1.46252 8.35387 1.74377 8.35387 2.1094V10.4063L5.40074 7.53752C5.14762 7.2844 4.75387 7.31252 4.50074 7.53752C4.24762 7.79065 4.27574 8.1844 4.50074 8.43752L8.55074 12.3469Z"
fill=""
/>
</svg>
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};
export default TableThree;

View File

@@ -1,106 +0,0 @@
import { Product } from '../../types/app/product';
import ProductOne from '../../images/product/product-01.png';
import ProductTwo from '../../images/product/product-02.png';
import ProductThree from '../../images/product/product-03.png';
import ProductFour from '../../images/product/product-04.png';
const productData: Product[] = [
{
image: ProductOne,
name: 'Apple Watch Series 7',
category: 'Electronics',
price: 296,
sold: 22,
profit: 45,
},
{
image: ProductTwo,
name: 'Macbook Pro M1',
category: 'Electronics',
price: 546,
sold: 12,
profit: 125,
},
{
image: ProductThree,
name: 'Dell Inspiron 15',
category: 'Electronics',
price: 443,
sold: 64,
profit: 247,
},
{
image: ProductFour,
name: 'HP Probook 450',
category: 'Electronics',
price: 499,
sold: 72,
profit: 103,
},
];
const TableTwo = () => {
return (
<div className="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
<div className="py-6 px-4 md:px-6 xl:px-7.5">
<h4 className="text-xl font-semibold text-black dark:text-white">
Top Products
</h4>
</div>
<div className="grid grid-cols-6 border-t border-stroke py-4.5 px-4 dark:border-strokedark sm:grid-cols-8 md:px-6 2xl:px-7.5">
<div className="col-span-3 flex items-center">
<p className="font-medium">Product Name</p>
</div>
<div className="col-span-2 hidden items-center sm:flex">
<p className="font-medium">Category</p>
</div>
<div className="col-span-1 flex items-center">
<p className="font-medium">Price</p>
</div>
<div className="col-span-1 flex items-center">
<p className="font-medium">Sold</p>
</div>
<div className="col-span-1 flex items-center">
<p className="font-medium">Profit</p>
</div>
</div>
{productData.map((product, key) => (
<div
className="grid grid-cols-6 border-t border-stroke py-4.5 px-4 dark:border-strokedark sm:grid-cols-8 md:px-6 2xl:px-7.5"
key={key}
>
<div className="col-span-3 flex items-center">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center">
<div className="h-12.5 w-15 rounded-md">
<img src={product.image} alt="Product" />
</div>
<p className="text-sm text-black dark:text-white">
{product.name}
</p>
</div>
</div>
<div className="col-span-2 hidden items-center sm:flex">
<p className="text-sm text-black dark:text-white">
{product.category}
</p>
</div>
<div className="col-span-1 flex items-center">
<p className="text-sm text-black dark:text-white">
${product.price}
</p>
</div>
<div className="col-span-1 flex items-center">
<p className="text-sm text-black dark:text-white">{product.sold}</p>
</div>
<div className="col-span-1 flex items-center">
<p className="text-sm text-meta-3">${product.profit}</p>
</div>
</div>
))}
</div>
);
};
export default TableTwo;

View File

@@ -0,0 +1,124 @@
import { ApexOptions } from 'apexcharts';
import React, { useEffect, useState } from 'react';
import ReactApexChart from 'react-apexcharts';
import dayjs from 'dayjs';
interface ChartThreeState {
series: number[];
}
const options: ApexOptions = {
chart: {
fontFamily: 'Satoshi, sans-serif',
type: 'donut',
},
colors: ['#91C8EA', '#727cf5'],
labels: ['新访客', '老访客'],
legend: {
show: false,
position: 'bottom',
},
plotOptions: {
pie: {
donut: {
size: '65%',
background: 'transparent',
},
},
},
dataLabels: {
enabled: false,
},
responsive: [
{
breakpoint: 2600,
options: {
chart: {
width: 380,
},
},
},
{
breakpoint: 640,
options: {
chart: {
width: 200,
},
},
},
],
};
const ChartThree: React.FC = () => {
const [result, setResult] = useState({ newVisitors: 0, oldVisitors: 0 })
const [date, setDate] = useState(dayjs(new Date()).format("YYYY/MM/DD"));
const [state, setState] = useState<ChartThreeState>({
series: [0, 0],
});
const getDataList = async () => {
const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID;
const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN;
const response = await fetch(`/api/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=new_visitor_count%2Cnew_visitor_ratio&method=trend%2Ftime%2Fa&gran=day&area=`);
const data = await response.json();
const { result } = data;
const newVisitors = result.items[1][0][1]
const oldVisitors = 100 - result.items[1][0][1]
setState({ series: [newVisitors, oldVisitors] })
setResult({ newVisitors, oldVisitors })
}
useEffect(() => {
getDataList()
}, [])
return (
<div className="sm:px-7.5 col-span-12 rounded-lg border border-stroke bg-white px-5 pb-5 pt-7.5 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
<div className="mb-3 justify-between gap-4 sm:flex">
<div>
<h5 className="text-xl font-semibold text-black dark:text-white">
访
</h5>
</div>
</div>
<div className="mb-2">
<div id="chartThree" className="mx-auto flex justify-center">
<ReactApexChart
options={options}
series={state.series}
type="donut"
/>
</div>
</div>
<div className="-mx-8 mt-8 flex flex-wrap items-center justify-center gap-y-3">
<div className="sm:w-1/2 w-full px-8">
<div className="flex w-full items-center">
<span className="mr-2 block h-3 w-full max-w-3 rounded-full bg-[#91C8EA]"></span>
<p className="flex w-full justify-between text-sm font-medium text-black dark:text-white">
<span> 访 </span>
<span> {result.newVisitors}% </span>
</p>
</div>
</div>
<div className="sm:w-1/2 w-full px-8">
<div className="flex w-full items-center">
<span className="mr-2 block h-3 w-full max-w-3 rounded-full bg-[#727cf5]"></span>
<p className="flex w-full justify-between text-sm font-medium text-black dark:text-white">
<span> 访 </span>
<span> {result.oldVisitors}% </span>
</p>
</div>
</div>
</div>
</div>
);
};
export default ChartThree;

View File

@@ -13,7 +13,7 @@ const VisitorsStatisChat = () => {
const [endDate, setEndDate] = useState(dayjs(new Date()).format("YYYY/MM/DD")); const [endDate, setEndDate] = useState(dayjs(new Date()).format("YYYY/MM/DD"));
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
// Echarts相关配置 // 图表相关配置
const [options, setOptions] = useState<ApexOptions>({ const [options, setOptions] = useState<ApexOptions>({
legend: { legend: {
show: false, show: false,

View File

@@ -1,14 +1,12 @@
import Title from "@/components/Title" import Title from "@/components/Title"
import VisitorsStatisChat from "./components/VisitorsStatisChat" import VisitorsStatisChat from "./components/VisitorsStatisChat"
import ChartThree from "@/components/Charts/ChartThree" import NewOldVisitors from './components/NewOldVisitors'
import ChartTwo from "@/components/Charts/ChartTwo" import ChartTwo from "./components/VisitorsStatisChat"
import ChatCard from "@/components/Chat/ChatCard" import ChatCard from "@/components/Chat/ChatCard"
import MapOne from "@/components/Maps/MapOne"
import TableOne from "@/components/Tables/TableOne"
import CardDataStats from "@/components/CardDataStats" import CardDataStats from "@/components/CardDataStats"
import { AiOutlineEye, AiOutlineMeh, AiOutlineStock, AiOutlineFieldTime } from "react-icons/ai"; import { AiOutlineEye, AiOutlineMeh, AiOutlineStock, AiOutlineFieldTime } from "react-icons/ai";
import { useCallback, useEffect, useState } from "react" import { useEffect, useState } from "react"
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { Result } from "./type" import { Result } from "./type"
@@ -41,6 +39,8 @@ export default () => {
const response = await fetch(`/api/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=pv_count%2Cip_count%2Cbounce_ratio%2Cavg_visit_time&method=overview%2FgetTimeTrendRpt`); const response = await fetch(`/api/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=pv_count%2Cip_count%2Cbounce_ratio%2Cavg_visit_time&method=overview%2FgetTimeTrendRpt`);
const data = await response.json(); const data = await response.json();
const { result } = data; const { result } = data;
console.log(result);
setResult(result); setResult(result);
let pv = 0; let pv = 0;
@@ -50,16 +50,25 @@ export default () => {
let count = 0 let count = 0
result.items[1].forEach((item: number[]) => { result.items[1].forEach((item: number[]) => {
if (!Number(item[0])) return; if (Number(item[3])) {
count++
pv += Number(item[0]); pv += Number(item[0]);
ip += Number(item[1]); ip += Number(item[1]);
bounce += Number(item[2]); bounce += Number(item[2]);
avgTime += Number(item[3]); avgTime += Number(item[3]);
} else if (Number(item[2])) {
pv += Number(item[0]);
ip += Number(item[1]);
bounce += Number(item[2]);
} else if (Number(item[1])) {
pv += Number(item[0]);
ip += Number(item[1]);
} else if (Number(item[0])) {
pv += Number(item[0]);
}
count++;
}); });
console.log(count, bounce, avgTime);
setStats({ pv, ip, bounce: bounce / count, avgTime: formatTime(avgTime / count) }) setStats({ pv, ip, bounce: bounce / count, avgTime: formatTime(avgTime / count) })
}; };
@@ -72,6 +81,7 @@ export default () => {
<> <>
<Title value="数据可视化" /> <Title value="数据可视化" />
{/* 基本数据 */}
<div className="mt-2 grid grid-cols-1 gap-2 md:grid-cols-2 xl:grid-cols-4"> <div className="mt-2 grid grid-cols-1 gap-2 md:grid-cols-2 xl:grid-cols-4">
<CardDataStats title="今日访客" total={stats.pv + ''} rate="0.43%" levelUp> <CardDataStats title="今日访客" total={stats.pv + ''} rate="0.43%" levelUp>
<AiOutlineEye className="fill-primary dark:fill-white text-2xl" /> <AiOutlineEye className="fill-primary dark:fill-white text-2xl" />
@@ -92,15 +102,9 @@ export default () => {
<div className="rounded-lg mt-2 grid grid-cols-12 gap-2"> <div className="rounded-lg mt-2 grid grid-cols-12 gap-2">
<VisitorsStatisChat /> <VisitorsStatisChat />
<ChartTwo /> <NewOldVisitors />
<ChartThree /> {/* <ChartTwo />
<MapOne /> <ChatCard /> */}
<div className="col-span-12 xl:col-span-8">
<TableOne />
</div>
<ChatCard />
</div> </div>
</> </>
) )