diff --git a/package-lock.json b/package-lock.json index 918baa2..87bdd84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", "@types/leaflet": "^1.9.17", + "chart.js": "^4.4.8", "leaflet": "^1.9.4", "rxjs": "~7.5.0", "tslib": "^2.3.0", @@ -2975,6 +2976,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -4500,6 +4507,18 @@ "dev": true, "license": "MIT" }, + "node_modules/chart.js": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz", + "integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", diff --git a/package.json b/package.json index 3e372bd..ec7c0e0 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", "@types/leaflet": "^1.9.17", + "chart.js": "^4.4.8", "leaflet": "^1.9.4", "rxjs": "~7.5.0", "tslib": "^2.3.0", diff --git a/src/app/app.component.html b/src/app/app.component.html index f72772a..bb47d67 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -16,9 +16,9 @@ {{link.name}} - - + diff --git a/src/app/entities/graph/GraphData.ts b/src/app/entities/graph/GraphData.ts new file mode 100644 index 0000000..da7a0f9 --- /dev/null +++ b/src/app/entities/graph/GraphData.ts @@ -0,0 +1,25 @@ +import {StatsOfPeakOfDay} from "./StatsOfPeakOfDay"; +import {StatsOfPeakOfPerFiveMinutes} from "./StatsOfPeakOfPerFiveMinutes"; + +export class GraphData { + labels: any[] = []; + data: {data:any[], label: string, backgroundColor: string}[] = []; + + static fromStatsOfPeakOfDay(d: StatsOfPeakOfDay[], color: string) { + const g = new GraphData(); + g.labels = d.map((gg) => gg.date); + g.data.push( + {label: "Игроков", data: d.map((gg) => gg.avg), backgroundColor: color} + ) + return g; + } + + static fromStatsOfPeakOfPerFiveMinutes(d: StatsOfPeakOfPerFiveMinutes[], color: string) { + const g = new GraphData(); + g.labels = d.map((gg) => gg.timestamp.toLocaleString()); + g.data.push( + {label: "Игроков", data: d.map((gg) => gg.max), backgroundColor: color} + ) + return g; + } +} diff --git a/src/app/entities/graph/StatsOfPeakOfDay.ts b/src/app/entities/graph/StatsOfPeakOfDay.ts index 7705633..48648ba 100644 --- a/src/app/entities/graph/StatsOfPeakOfDay.ts +++ b/src/app/entities/graph/StatsOfPeakOfDay.ts @@ -1,3 +1,5 @@ +import {GraphData} from "./GraphData"; + export class StatsOfPeakOfDay { date!: string; max!:number; diff --git a/src/app/entities/graph/StatsOfPeakOfPerFiveMinutes.ts b/src/app/entities/graph/StatsOfPeakOfPerFiveMinutes.ts index bf352ae..f2ee35b 100644 --- a/src/app/entities/graph/StatsOfPeakOfPerFiveMinutes.ts +++ b/src/app/entities/graph/StatsOfPeakOfPerFiveMinutes.ts @@ -1,3 +1,5 @@ +import {GraphData} from "./GraphData"; + export class StatsOfPeakOfPerFiveMinutes { timestamp!:Date; max!:number; diff --git a/src/app/entities/profile/ProfileRequestData.ts b/src/app/entities/profile/ProfileRequestData.ts index 8b24214..cb510a0 100644 --- a/src/app/entities/profile/ProfileRequestData.ts +++ b/src/app/entities/profile/ProfileRequestData.ts @@ -11,6 +11,7 @@ export class ProfileRequestData { static KILLFEED: ProfileRequestData = new ProfileRequestData("killfeed", "Информация о убийствах, смертях, помощи"); static REPORTS: ProfileRequestData = new ProfileRequestData("reports", "Информация о количестве репортах"); static MESSAGES: ProfileRequestData = new ProfileRequestData("messages", "Информация о количестве сообщений"); + static POHUY: ProfileRequestData = new ProfileRequestData("pohuy", "Проверка что авторизован") static BASIC_PROFILE: ProfileRequestData[] = [ ProfileRequestData.PLAY_ON, diff --git a/src/app/pages/internal-components/abstract-search-table.component.ts b/src/app/pages/internal-components/abstract-search-table.component.ts index 1b1babc..cd8d927 100644 --- a/src/app/pages/internal-components/abstract-search-table.component.ts +++ b/src/app/pages/internal-components/abstract-search-table.component.ts @@ -52,7 +52,7 @@ export abstract class AbstractSearchTable implements A this.filter.addAccountToSearch(`[U:1:${this.account_id}]`); this.updateData(); - this.serverService.getStats("servers").subscribe( + this.serverService.servers.subscribe( (res) => { const keys = Object.keys(res.data); for (const key of keys) { diff --git a/src/app/pages/profile-page/profile-page.component.html b/src/app/pages/profile-page/profile-page.component.html index 79bd657..ad65b7e 100644 --- a/src/app/pages/profile-page/profile-page.component.html +++ b/src/app/pages/profile-page/profile-page.component.html @@ -1,5 +1,5 @@
-
+

Профиль

Здесь можно увидеть профиль игрока на наших серверах с подробной информации о нем

@@ -15,7 +15,7 @@
- +
diff --git a/src/app/pages/statistic-page/statistic-page.component.html b/src/app/pages/statistic-page/statistic-page.component.html index 8bca3fa..0cb10de 100644 --- a/src/app/pages/statistic-page/statistic-page.component.html +++ b/src/app/pages/statistic-page/statistic-page.component.html @@ -1,15 +1,60 @@

Статистика

-

Скоро и ты сюда попадешь браток

+

Разнообразная статистика с наших серверов

График онлайна

+
+
+ + Статистика по + + + {{s.name}} + + + + + Количество минут + + + Разница в {{s}} минут + + + + + Количество дней + + + За {{s}} дней + + + + + Сервер + + + {{s.name}} + + + +
+
+ {{ chart }} +
+ + +
+ +
+
+

Уникальные игроки

-

Страны

+

Последние выданые випки

diff --git a/src/app/pages/statistic-page/statistic-page.component.ts b/src/app/pages/statistic-page/statistic-page.component.ts index a28f3b1..13e5361 100644 --- a/src/app/pages/statistic-page/statistic-page.component.ts +++ b/src/app/pages/statistic-page/statistic-page.component.ts @@ -1,5 +1,8 @@ import { Component, OnInit } from '@angular/core'; import {GraphService} from "../../services/graph.service"; +import {Chart} from "chart.js/auto"; +import {GraphData} from "../../entities/graph/GraphData"; +import {ActionService} from "../../services/action.service"; export interface Period { name: string @@ -25,14 +28,58 @@ export class StatisticPageComponent implements OnInit { days:number[] = [1,7,14,21,30,60,90,180]; selectedDays:number = 30; - constructor(private graphService: GraphService) { } + minutes:number[] = [1, 5, 10, 15, 30] + selectedMinute:number = 5; + + serverList: {name: string, server_id: string }[] = [ + {name: 'Выбрать все', server_id: '%'} + ]; + selectedServer: {name: string, server_id: string } = this.serverList[0]; + + chart!:Chart; + + constructor(private graphService: GraphService, + private actionService: ActionService) { } ngOnInit(): void { } getGraph() { + if (this.loading) { + return; + } + this.init = false; this.loading = true; + console.log(this.selectedPeriod, this.selectedMinute, this.selectedDays, this.selectedServer); + switch (this.selectedPeriod.value) { + case 'days': { + this.graphService.getOnlineStatsOfDays(this.selectedDays, this.selectedServer?this.selectedServer.server_id:'%').subscribe( + (d) => this.processingData(GraphData.fromStatsOfPeakOfDay(d, "red")), + (err) => this.actionService.showSnack('Произошла ошибка во время загрузки данных, попробуй позже'), + () => this.loading = false + ); break; + } + case 'minutes': { + this.graphService.getOnlineStatsOfMinutes(this.selectedMinute, this.selectedDays, this.selectedServer?this.selectedServer.server_id:'%').subscribe( + (d) => this.processingData(GraphData.fromStatsOfPeakOfPerFiveMinutes(d, "red")), + (err) => this.actionService.showSnack('Произошла ошибка во время загрузки данных, попробуй позже'), + () => this.loading = false + ); break; + } + } } + processingData(data:GraphData) { + if (this.chart) + this.chart.destroy(); + + this.chart = new Chart("MyChart", { + type: "line", + data: { + labels: data.labels, + datasets: data.data + } + }); + } } diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index eda8d95..6d3b2ff 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -9,27 +9,38 @@ import {map, Observable} from "rxjs"; import {HttpClient} from "@angular/common/http"; import {DiscordAccount} from "../entities/DiscordAccount"; +export interface StorageUser {steamdata: SteamData|null, steamIds: SteamIDs|null, permition: Permition|null} + @Injectable({ providedIn: 'root' }) export class AuthService { - static KEY: string = "steam_ids"; + static KEY: string = "user"; steamdata: SteamData | null = null; steamIds: SteamIDs | null = null; permition: Permition | null = null; constructor(private playerService: PlayerService, private router: Router, private http: HttpClient) { - this.playerService.getProfile(null, [ProfileRequestData.STEAM_DATA, ProfileRequestData.PERMITION]) - .subscribe((res) => { - this.steamdata = res.steam_data; - this.steamIds = res.steamids - this.permition = res.permition; - sessionStorage.setItem(AuthService.KEY, JSON.stringify(res.steamids)) - }, (err) => { - if (err.status == 401) - sessionStorage.removeItem(AuthService.KEY); - console.log(err); - }) + this.playerService.getProfile(null, [ProfileRequestData.POHUY]).subscribe( + () => { + if (sessionStorage.getItem(AuthService.KEY) == null) { + this.playerService.getProfile(null, [ProfileRequestData.STEAM_DATA, ProfileRequestData.PERMITION]) + .subscribe((res) => { + const user: StorageUser = { + steamdata: res.steam_data, steamIds: res.steamids, permition: res.permition + } + sessionStorage.setItem(AuthService.KEY, JSON.stringify(user)) + }) + } else { + // @ts-ignore + const user: StorageUser = JSON.parse(sessionStorage.getItem(AuthService.KEY)); + this.steamdata = user.steamdata; + this.steamIds = user.steamIds; + this.permition = user.permition; + console.log("user data restored", user); + } + }, (err) => {err.status==401?sessionStorage.removeItem(AuthService.KEY):null} + ) } login() { diff --git a/src/app/services/server.service.ts b/src/app/services/server.service.ts index efc4754..a7695d1 100644 --- a/src/app/services/server.service.ts +++ b/src/app/services/server.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import {HttpClient} from "@angular/common/http"; -import {map, Observable} from "rxjs"; +import {map, Observable, of} from "rxjs"; import {StatExporter} from "../entities/servers/StatExporter"; @Injectable({ @@ -8,7 +8,17 @@ import {StatExporter} from "../entities/servers/StatExporter"; }) export class ServerService { - constructor(private http: HttpClient) { } + constructor(private http: HttpClient) { + this.http.get(`api/stats?filter=servers`).pipe( + map((res) => { + const d = new StatExporter(); + d.fromData(res, 'servers'); + return d; + })).subscribe((res) => { + this.servers = of(res); + }) + } + servers: Observable> = of(); getStats(filter: string): Observable> { return this.http.get(`api/stats?filter=${filter}`).pipe(