update general statistic and analytic

This commit is contained in:
smanylov
2026-03-19 12:49:46 +07:00
parent 07eb00c705
commit f2428d7fde
14 changed files with 210 additions and 94 deletions
+3 -1
View File
@@ -5,6 +5,7 @@ import AnalyticsCardGeography from '@/app/ui/reports/analytics-card-geography';
import ActivityByContentType from '@/app/ui/reports/activity-by-content-type';
import PageTitle from '@/app/ui/page-title';
import ReportsInfo from '@/app/ui/reports/reports-info';
import AnalyticsCardDistribution from '@/app/ui/reports/analytics-card-distribution';
export default function Page() {
return (
@@ -13,7 +14,8 @@ export default function Page() {
<ReportsInfo />
<ActivityByContentType />
<div className="analytics-grid">
<AnalyticsCardMonth />
{/* <AnalyticsCardMonth /> */}
<AnalyticsCardDistribution />
<AnalyticsCardGeography />
</div>
<ViolationsTable />
+6 -7
View File
@@ -1,13 +1,12 @@
import PageTitleColorFrame from '@/app/ui/page-title-color-frame';
import DahboardGeographySection from '@/app/ui/dashboard/new/dashboard-geography-section';
import DashboardPlatformsList from '@/app/ui/dashboard/new/dashboard-platforms-list';
import ViolationsMyCases from '@/app/ui/violations/violations-my-cases';
import ViolationsCheckAllSection from '@/app/ui/violations/violations-check-all-section';
import ViolationsTable from '@/app/ui/violations/violations-table';
import ViolationsStatistic from '@/app/ui/violations/violations-statistic';
export default function Page() {
const FILE_TYPE = "all";
import AnalyticsCardGeography from '@/app/ui/reports/analytics-card-geography';
import AnalyticsCardDistribution from '@/app/ui/reports/analytics-card-distribution';
export default function Page() {
return (
<>
<PageTitleColorFrame
@@ -18,9 +17,9 @@ export default function Page() {
<ViolationsMyCases />
<ViolationsCheckAllSection />
<ViolationsTable />
<div className="dashboard-main-grid">
<DashboardPlatformsList />
<DahboardGeographySection />
<div className="analytics-grid">
<AnalyticsCardDistribution />
<AnalyticsCardGeography />
</div>
</>
)
+43 -7
View File
@@ -186,11 +186,9 @@ export async function getFileViolations(fileId: string, page: number) {
}
}
export async function fetchViolationGeography() {
export async function fetchViolationAnalyticStatistic(group: 'domain' | 'tld') {
const token = await getSessionData('token');
/* "group_by": "tld" */
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST',
@@ -198,8 +196,10 @@ export async function fetchViolationGeography() {
version: 1,
msg_id: 30009,
message_body: {
group_by: "domain",
token: token
group_by: group,
action: "group",
token: token,
sort_direction: 'desc'
}
}),
headers: {
@@ -210,8 +210,44 @@ export async function fetchViolationGeography() {
if (response.ok) {
let parsed = await response.json();
if (parsed) {
return parsed;
if (parsed?.message_body) {
return parsed?.message_body;
} else {
throw null;
}
} else {
throw (`${response.status}`);
}
} catch (error) {
return null
}
}
export async function fetchViolationStatistic() {
const token = await getSessionData('token');
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST',
body: JSON.stringify({
version: 1,
msg_id: 30010,
message_body: {
token: token,
}
}),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
if (response.ok) {
let parsed = await response.json();
if (parsed?.message_body) {
return parsed?.message_body;
} else {
throw null;
}
@@ -488,9 +488,6 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
);
const handleView = async (file: FileItem) => {
console.log(`Просмотр файла: ${file.fileName}`);
console.log(file);
const fileInfo = await viewFileInfo(file.id);
setOpenWindowChildren(() => {
@@ -0,0 +1,22 @@
import { useQuery } from '@tanstack/react-query';
import { fetchViolationAnalyticStatistic } from '@/app/actions/violationActions';
export interface UseViolationStatistic {
[key: string]: number
}
export const useViolationAnalyticStatistic = (group: 'domain' | 'tld') => {
return useQuery({
queryKey: ['violationAnalyticStatistic', group],
queryFn: () => {
return fetchViolationAnalyticStatistic(group)
},
select: (data: UseViolationStatistic | null) => {
if (!data) {
return null
}
return data;
},
retry: false
});
};
@@ -1,24 +0,0 @@
import { useQuery } from '@tanstack/react-query';
import { fetchViolationGeography } from '@/app/actions/violationActions';
export interface UseViolationGeography {
ru: number;
usa: number;
uk: number;
ge: number;
}
export const useViolationGeography = () => {
return useQuery({
queryKey: ['violationGeography'],
queryFn: fetchViolationGeography,
select: (data): any | null => {
if (!data) {
return []
}
return data;
},
retry: false
});
};
@@ -0,0 +1,25 @@
import { useQuery } from '@tanstack/react-query';
import { fetchViolationStatistic } from '@/app/actions/violationActions';
export interface UseViolationStatistic {
total_violations: 2565,
new_violations: 2565,
in_progress_violations: 0,
resolved_violations: 0
}
export const useViolationStatistic = () => {
return useQuery({
queryKey: ['violationStatistic'],
queryFn: () => {
return fetchViolationStatistic()
},
select: (data: UseViolationStatistic | null) => {
if (!data) {
return null
}
return data;
},
retry: false
});
};
@@ -0,0 +1,52 @@
'use client'
import { useTranslations } from 'next-intl'
import { useViolationAnalyticStatistic, UseViolationStatistic } from '@/app/hooks/react-query/useViolationAnalyticStatistic';
interface DomainListProps {
data: UseViolationStatistic;
}
export default function AnalyticsCardDistribution() {
const t = useTranslations('Global');
const { data: violationGeography, isLoading, isError, error } = useViolationAnalyticStatistic('domain');
const DomainList = ({ data }: DomainListProps) => {
const topDomains = Object.entries(data)
.map(([domain, count]) => ({ domain, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 6);
return (
<div className="storage-timeline">
{topDomains.map((item, index) => (
<div
className="timeline-item"
key={item.domain}
>
<span className="timeline-month">
{item.domain}
</span>
<span className="method-count">
{item.count}
</span>
</div>
))}
</div>
);
};
return (
<div className="analytics-card">
<div className="analytics-header">
<div className="analytics-icon"></div>
<h3 className="analytics-title">
{t('distribution-analytics')}
</h3>
</div>
{violationGeography && (
<DomainList data={violationGeography} />
)}
</div>
)
}
+34 -40
View File
@@ -1,11 +1,40 @@
'use client'
import { useTranslations } from 'next-intl'
import {useViolationGeography} from '@/app/hooks/react-query/useViolationGeography';
import {useViolationAnalyticStatistic, UseViolationStatistic} from '@/app/hooks/react-query/useViolationAnalyticStatistic';
interface DomainListProps {
data: UseViolationStatistic;
}
export default function AnalyticsCardGeography() {
const t = useTranslations('Global');
const { data: violationGeography, isLoading, isError, error } = useViolationGeography();
const { data: violationGeography, isLoading, isError, error } = useViolationAnalyticStatistic('tld');
const DomainList = ({ data }: DomainListProps) => {
const topDomains = Object.entries(data)
.map(([domain, count]) => ({ domain, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 6);
return (
<div className="storage-timeline">
{topDomains.map((item, index) => (
<div
className="timeline-item"
key={item.domain}
>
<span className="timeline-month">
{item.domain}
</span>
<span className="method-count">
{item.count}
</span>
</div>
))}
</div>
);
};
return (
<div className="analytics-card">
@@ -15,44 +44,9 @@ export default function AnalyticsCardGeography() {
{t('geography-of-violations')}
</h3>
</div>
<div className="storage-timeline">
<div className="timeline-item">
<span className="timeline-month">
{t('russia')}
</span>
<span className="method-count">0</span>
</div>
<div className="timeline-item">
<span className="timeline-month">
{t('usa')}
</span>
<span className="method-count">0</span>
</div>
<div className="timeline-item">
<span className="timeline-month">
{t('germany')}
</span>
<span className="method-count">0</span>
</div>
<div className="timeline-item">
<span className="timeline-month">
{t('france')}
</span>
<span className="method-count">0</span>
</div>
<div className="timeline-item">
<span className="timeline-month">
{t('uk')}
</span>
<span className="method-count">0</span>
</div>
<div className="timeline-item">
<span className="timeline-month">
{t('china')}
</span>
<span className="method-count">0</span>
</div>
</div>
{violationGeography && (
<DomainList data={violationGeography} />
)}
</div>
)
}
+8 -2
View File
@@ -3,10 +3,12 @@
import { useUserFilesInfo } from '@/app/hooks/react-query/useUserFilesInfo';
import { useTranslations } from 'next-intl';
import { useEffect } from 'react';
import { useViolationStatistic } from '@/app/hooks/react-query/useViolationStatistic';
export default function FinalSummary() {
const t = useTranslations('Global');
const { data: filesInfo, isLoading, isError, error } = useUserFilesInfo();
const { data: violationStatistic } = useViolationStatistic();
return (
<div className="final-summary">
@@ -30,13 +32,17 @@ export default function FinalSummary() {
<div className="summary-stat center">
{/* <div className="summary-stat-icon">🚨</div> */}
<div>
<div className="summary-stat-value">{filesInfo?.total.violation ? filesInfo?.total.violation : 0}</div>
<div className="summary-stat-value">
{violationStatistic?.new_violations ?? 0}
</div>
<div className="summary-stat-label">
{t('violations-found')}
</div>
</div>
<div>
<div className="summary-stat-value">0</div>
<div className="summary-stat-value">
{violationStatistic?.in_progress_violations ?? 0}
</div>
<div className="summary-stat-label">
{t('violations-registered')}
</div>
+3 -1
View File
@@ -3,10 +3,12 @@
import { useTranslations } from 'next-intl';
import { useUserFilesInfo } from '@/app/hooks/react-query/useUserFilesInfo';
import { IconDocument, IconSearch, IconWarning, IconGraph } from '@/app/ui/icons/icons';
import { useViolationStatistic } from '@/app/hooks/react-query/useViolationStatistic';
export default function ReportsInfo() {
const t = useTranslations("Global");
const { data: filesInfo, isLoading, isError, error } = useUserFilesInfo();
const { data: violationStatistic } = useViolationStatistic();
return (
<>
@@ -27,7 +29,7 @@ export default function ReportsInfo() {
<IconWarning />
</div>
</div>
<div className="stat-value">{filesInfo?.total.violation ? filesInfo?.total.violation : 0}</div>
<div className="stat-value">{violationStatistic?.total_violations ?? 0}</div>
<div className="stat-label">{t('violations-few')}</div>
</div>
@@ -1,35 +1,38 @@
'use client'
import { useTranslations } from 'next-intl';
import { useUserFilesInfo } from '@/app/hooks/react-query/useUserFilesInfo';
import { useViolationStatistic } from '@/app/hooks/react-query/useViolationStatistic';
export default function ViolationsStatistic() {
const t = useTranslations('Global');
const { data: filesInfo, isLoading, isError, error } = useUserFilesInfo();
const { data: violationStatistic } = useViolationStatistic();
return (
<div className="protection-statistic">
<div className="protection-statistic-stat-card">
<div className="protection-statistic-stat-number">
{filesInfo?.total.violation}
{violationStatistic?.total_violations ?? 0}
</div>
<div className="protection-statistic-stat-label">{t(`total-violations`)}</div>
</div>
<div className="protection-statistic-stat-card">
<div className="protection-statistic-stat-number">
{filesInfo?.total.violation}
{violationStatistic?.new_violations ?? 0}
</div>
<div className="protection-statistic-stat-label">{t(`new`)}</div>
</div>
<div className="protection-statistic-stat-card">
<div className="protection-statistic-stat-number">
0
{violationStatistic?.in_progress_violations ?? 0}
</div>
<div className="protection-statistic-stat-label">{t(`in-progress`)}</div>
</div>
<div className="protection-statistic-stat-card">
<div className="protection-statistic-stat-number">0</div>
<div className="protection-statistic-stat-number">
{violationStatistic?.resolved_violations ?? 0}
</div>
<div className="protection-statistic-stat-label">{t('it-decided')}</div>
</div>
</div>
+2 -1
View File
@@ -341,7 +341,8 @@
"germany": "Germany",
"france": "France",
"uk": "United Kingdom",
"china": "China"
"china": "China",
"distribution-analytics": "Distribution analytics"
},
"Login-register-form": {
"and": "and",
+2 -1
View File
@@ -341,7 +341,8 @@
"germany": "Германия",
"france": "Франция",
"uk": "Великобритания",
"china": "Китай"
"china": "Китай",
"distribution-analytics": "Аналитика распространения"
},
"Login-register-form": {
"and": "и",