Browse Source

more graphs...

master
gsd 3 weeks ago
parent
commit
47846a8432
  1. 6
      src/app/app.module.ts
  2. 10
      src/app/entities/VipGiveMethod.ts
  3. 203
      src/app/pages/internal-components/abstract.perperiod.graph.component.ts
  4. 66
      src/app/pages/internal-components/connections.graph.component.ts
  5. 203
      src/app/pages/internal-components/usertime.graph.component.ts
  6. 210
      src/app/pages/internal-components/vip.graph.components.ts
  7. 9
      src/app/pages/main-page/main-page.component.html
  8. 4
      src/app/pages/main-page/main-page.component.ts
  9. 11
      src/app/pages/profile-page/profile-page.component.html
  10. 4
      src/app/pages/profile-page/profile-page.component.scss
  11. 3
      src/app/pages/profile-page/profile-page.component.ts
  12. 6
      src/app/pages/servers-page/servers-page.component.html
  13. 8
      src/app/pages/servers-page/servers-page.component.ts
  14. 5
      src/app/pages/statistic-page/statistic-page.component.html
  15. 10
      src/app/pages/vip-page/vip-page.component.html
  16. 3
      src/app/pages/vip-page/vip-page.component.scss
  17. 20
      src/app/pages/vip-page/vip-page.component.ts
  18. 15
      src/app/services/graph.service.ts
  19. 3
      src/app/utils/BaseUtils.ts

6
src/app/app.module.ts

@ -86,6 +86,8 @@ import {ServerPlayerViewer} from "./pages/servers-page/server-player-viewer";
import {MatTabsModule} from "@angular/material/tabs";
import {MatRadioModule} from "@angular/material/radio";
import {UsertimeGraphComponent} from "./pages/internal-components/usertime.graph.component";
import {VipGraphComponents} from "./pages/internal-components/vip.graph.components";
import {ConnectionsGraphComponent} from "./pages/internal-components/connections.graph.component";
registerLocaleData(localeRu, "ru")
@ -139,7 +141,9 @@ registerLocaleData(localeRu, "ru")
FilesUploader,
ServerPlayerViewer,
//graph
UsertimeGraphComponent
UsertimeGraphComponent,
VipGraphComponents,
ConnectionsGraphComponent
],
imports: [
BrowserModule,

10
src/app/entities/VipGiveMethod.ts

@ -0,0 +1,10 @@
export const VipGiveMethod = [
"Бесплатно",
"Steam",
"Qiwi",
"Админ",
"Убрана",
"Итого",//??????
"Donation Alerts",
"Промокод"
];

203
src/app/pages/internal-components/abstract.perperiod.graph.component.ts

@ -0,0 +1,203 @@
import {Component, OnInit} from "@angular/core";
import {Chart} from "chart.js/auto";
import {PerPeriodStatistic} from "../../services/graph.service";
import {ServerService} from "../../services/server.service";
import {SearchFilter} from "../../entities/search/SearchFilter";
import {BaseUtils} from "../../utils/BaseUtils";
@Component({
selector: 'app-abstract-per-period-graph',
template: ''
})
export abstract class AbstractPerperiodGraphComponent implements OnInit {
protected constructor(protected serverService: ServerService) {}
ngOnInit(): void {
const fill = (res:any) => {
const keys = res.data ? Object.keys(res.data) : [];
for (const key of keys) {
// @ts-ignore
this.serverList.push({name: res.data[key].name, server_id: key});
}
}
this.serverService.getServers().subscribe(
(res) => {
fill(res);
}
)
}
settingsOfChart: {
chart: Chart|null
period: 'day' | 'month' | 'year',
loading: boolean
} = {
chart: null,
period: "day",
loading: false
};
serverList: {name: string, server_id: string }[] = [];
public getServerName(server_id: string|null) {
try {
// @ts-ignore
return this.serverList.filter(s => s.server_id == server_id).pop().name;
} catch (e) {
return "Неизвестно";
}
}
public getSearchFilter(steam64:string|null): SearchFilter {
const filter: SearchFilter = new SearchFilter();
if (steam64)
filter.addAccountToSearch(steam64);
let endDate = new Date();
endDate.setUTCHours(23, 59, 59);
filter.addEndTimeToSearch(endDate.getTime());
switch (this.settingsOfChart.period) {
case "day": {
endDate.setDate(endDate.getDate() - 30);
break;
}
case "month": {
endDate.setDate(endDate.getDate() - 365);
break;
}
case "year": {
endDate.setDate(endDate.getDate() - (365*10));
break;
}
}
filter.addBeginTimeToSearch(endDate);
return filter;
}
public updateGraph(objs: PerPeriodStatistic[],
canvasName: string,
tooltopFooter:any = null,
text = "",
timeDelimiter:number = -1) {
let chartConfig = {type: 'bar', data: {}, options: {
plugins: {
title: {
display: true,
text: text
},
tooltip:{
callbacks: {
footer: tooltopFooter
}
}
},
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true
}
}
}
};
let chartData: {labels: string[], datasets: any[]} = {
labels: [],//даты
datasets: []
/**
* {
* label: 'Dataset 1',
* data: Utils.numbers(NUMBER_CFG),
* backgroundColor: Utils.CHART_COLORS.red,
* },
*/
};
let valueOnServer: {[srv_name: string]: number[]} = {}
let srvList: string[] = [];
let maxValue = 0;
//////
objs.forEach((obj) => {if (obj.value > maxValue) maxValue = obj.value})
console.log(timeDelimiter)
if (timeDelimiter != -1) {
if (maxValue >= 60) {
timeDelimiter = 60;
chartConfig.options.plugins.title.text = "Наиграно минут по серверам";
} //po minutam
if (maxValue >= 60 * 60) {
timeDelimiter = 60 * 60;
chartConfig.options.plugins.title.text = "Наиграно часов по серверам";
} //po chasam
if (maxValue >= 60 * 60 * 24) {
timeDelimiter = 60 * 60 * 24;
chartConfig.options.plugins.title.text = "Наиграно дней по серверам";
}//po dnyam
const tooltipFooterInternal = (items:any) => { //todo remove
return "Наиграно: " + BaseUtils.formatSeconds(items.pop().parsed.y * timeDelimiter);
};
chartConfig.options.plugins.tooltip.callbacks.footer = tooltipFooterInternal;
}
console.log(timeDelimiter)
const groupByDate = objs.reduce((acc: {[date: string]: PerPeriodStatistic[]}, obj) => {
const key = obj.date;
if (!acc[key]) acc[key] = [];
acc[key].push(obj)
return acc;
}, {});
chartData.labels = Object.keys(groupByDate);
//console.log(groupByDate);
chartData.labels.forEach(
(date) => {
groupByDate[date].forEach((stat) => {
if (srvList.indexOf(stat.srv_id) == -1)
srvList.push(stat.srv_id)
})
}
);
//console.log(srvList)
srvList.forEach((srv) => {
valueOnServer[srv] = [];
});
chartData.labels.forEach(
(date) => {
let filled: string[] = [];
groupByDate[date].forEach(
(obj) => {
if (timeDelimiter == -1) {
valueOnServer[obj.srv_id].push(obj.value);
} else {
valueOnServer[obj.srv_id].push(obj.value / timeDelimiter);
}
filled.push(obj.srv_id);
}
)
srvList.forEach(
(srv) => {
if (filled.indexOf(srv) == -1) {
valueOnServer[srv].push(0);
}
}
)
},
)
//console.log(valueOnServer)
Object.keys(valueOnServer).forEach(
(key) => {
chartData.datasets.push(
{label: this.getServerName(key) + " ("+key+")", data: valueOnServer[key]}
)
}
)
///
chartConfig.data = chartData;
if (this.settingsOfChart.chart)
this.settingsOfChart.chart.destroy();
// @ts-ignore
this.settingsOfChart.chart = new Chart(canvasName, chartConfig);
this.settingsOfChart.loading = false;
}
}

66
src/app/pages/internal-components/connections.graph.component.ts

@ -0,0 +1,66 @@
import {Component, Input} from "@angular/core";
import {AbstractPerperiodGraphComponent} from "./abstract.perperiod.graph.component";
import {ServerService} from "../../services/server.service";
import {GraphService} from "../../services/graph.service";
import {MatSnackBar} from "@angular/material/snack-bar";
import {BaseUtils} from "../../utils/BaseUtils";
@Component({
selector: "app-connections-graph",
template: `
<div>
<mat-radio-group
style="display: flex; justify-content: center;flex-direction: row;"
[(ngModel)]="settingsOfChart.period"
[disabled]="settingsOfChart.loading"
(ngModelChange)="updateConnectionsGraph()">
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="day">За месяц</mat-radio-button>
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="month">За год</mat-radio-button>
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="year">За 10 лет</mat-radio-button>
</mat-radio-group>
</div>
<div class="chart-container">
<canvas id="connectionsCanvasChart" >{{ settingsOfChart.chart }}</canvas>
</div>`
})
export class ConnectionsGraphComponent extends AbstractPerperiodGraphComponent {
@Input("steam64")
steam64: string|null = null;
tooltipFooter = (items:any) => {
return `Подключений: ${items.pop().parsed.y}`
};
constructor(protected override serverService: ServerService,
private graphService: GraphService,
private snack: MatSnackBar) {
super(serverService);
}
connectionsTabChanged(event: any, tabIndex: number) {
if (event.index == tabIndex) {
this.updateConnectionsGraph();
}
}
updateConnectionsGraph() {
if (this.steam64 || true) {
if (this.settingsOfChart.loading) return;
this.settingsOfChart.loading = true;
this.graphService.getConnectionsOnPeriod(this.getSearchFilter(this.steam64)).subscribe(
(objs) => {
this.updateGraph(objs, "connectionsCanvasChart",
this.tooltipFooter,
"Количество уникальных игроков по серверам (уникальность, первый заход на любой из серверов, сыграл более 5 минут,Ï последующие не учитываются)",
-1);
}, (err) => {
this.settingsOfChart.loading = false;
this.snack.open("Ошибка загрузка графика");
}
);
} else {
this.snack.open("Нельзя загрузить график т.к нельзя определить индификатор профиля");
}
}
}

203
src/app/pages/internal-components/usertime.graph.component.ts

@ -1,10 +1,9 @@
import {AfterViewInit, Component, Input, OnInit} from "@angular/core";
import {SearchFilter} from "../../entities/search/SearchFilter";
import {GraphService, PerPeriodStatistic} from "../../services/graph.service";
import {Chart} from "chart.js/auto";
import {Component, Input} from "@angular/core";
import {GraphService} from "../../services/graph.service";
import {MatSnackBar} from "@angular/material/snack-bar";
import {ServerService} from "../../services/server.service";
import {BaseUtils} from "../../utils/BaseUtils";
import {AbstractPerperiodGraphComponent} from "./abstract.perperiod.graph.component";
@Component({
selector: "app-usertime-graph",
@ -12,8 +11,8 @@ import {BaseUtils} from "../../utils/BaseUtils";
<div>
<mat-radio-group
style="display: flex; justify-content: center;flex-direction: row;"
[(ngModel)]="usertimeChart.period"
[disabled]="usertimeChart.loading"
[(ngModel)]="settingsOfChart.period"
[disabled]="settingsOfChart.loading"
(ngModelChange)="updateUsertimeGraph()">
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="day">За месяц</mat-radio-button>
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="month">За год</mat-radio-button>
@ -21,203 +20,45 @@ import {BaseUtils} from "../../utils/BaseUtils";
</mat-radio-group>
</div>
<div class="chart-container">
<canvas id="usertimeChart" >{{ usertimeChart.chart }}</canvas>
<canvas id="usertimeCanvasChart" >{{ settingsOfChart.chart }}</canvas>
</div>`
})
export class UsertimeGraphComponent implements OnInit {
usertimeChart: {
chart: Chart|null
period: 'day' | 'month' | 'year',
loading: boolean
} = {
chart: null,
period: "day",
loading: false
};
export class UsertimeGraphComponent extends AbstractPerperiodGraphComponent {
@Input("steam64")
steam64: string|null = null;
serverList: {name: string, server_id: string }[] = [];
timeDelimiter: number = 1;
tooltipFooter = (items:any) => {
tooltipFooter = (items:any) => { //todo remove
return "Наиграно: " + BaseUtils.formatSeconds(items.pop().parsed.y * this.timeDelimiter);
};
constructor(protected serverService: ServerService,
constructor(protected override serverService: ServerService,
private graphService: GraphService,
private snack: MatSnackBar) {
super(serverService);
}
ngOnInit(): void {
const fill = (res:any) => {
const keys = res.data ? Object.keys(res.data) : [];
for (const key of keys) {
// @ts-ignore
this.serverList.push({name: res.data[key].name, server_id: key});
}
}
this.serverService.getServers().subscribe(
(res) => {
fill(res);
}
)
}
getServerName(server_id: string|null) {
try {
// @ts-ignore
return this.serverList.filter(s => s.server_id == server_id).pop().name;
} catch (e) {
return "Неизвестно";
}
}
usertimeTabChanged(event: any) {
if (event.index == 1) {
usertimeTabChanged(event: any, tabIndex: number) {
if (event.index == tabIndex) {
this.updateUsertimeGraph()
}
}
updateUsertimeGraph() {
if (this.steam64 || true) {
if (this.usertimeChart.loading) return;
this.usertimeChart.loading = true;
const filter: SearchFilter = new SearchFilter();
if (this.steam64)
filter.addAccountToSearch(this.steam64);
let endDate = new Date();
endDate.setUTCHours(23, 59, 59);
filter.addEndTimeToSearch(endDate.getTime());
switch (this.usertimeChart.period) {
case "day": {
endDate.setDate(endDate.getDate() - 30);
break;
}
case "month": {
endDate.setDate(endDate.getDate() - 365);
break;
}
case "year": {
endDate.setDate(endDate.getDate() - (365*10));
break;
}
}
filter.addBeginTimeToSearch(endDate);
let chartConfig = {type: 'bar', data: {}, options: {
plugins: {
title: {
display: true,
text: "Наиграно секунд по серверам"
},
tooltip:{
callbacks: {
footer: this.tooltipFooter
}
}
},
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true
}
}
}
};
let chartData: {labels: string[], datasets: any[]} = {
labels: [],//даты
datasets: []
/**
* {
* label: 'Dataset 1',
* data: Utils.numbers(NUMBER_CFG),
* backgroundColor: Utils.CHART_COLORS.red,
* },
*/
};
let valueOnServer: {[srv_name: string]: number[]} = {}
let srvList: string[] = [];
let maxValue = 0;
this.graphService.getUsertimeOnPeriod(filter).subscribe(
if (this.settingsOfChart.loading) return;
this.settingsOfChart.loading = true;
this.graphService.getUsertimeOnPeriod(this.getSearchFilter(this.steam64)).subscribe(
(objs) => {
objs.forEach((obj) => {if (obj.value > maxValue) maxValue = obj.value})
if (maxValue >= 60) {
this.timeDelimiter = 60;
chartConfig.options.plugins.title.text = "Наиграно минут по серверам";
} //po minutam
if (maxValue >= 60 * 60) {
this.timeDelimiter = 60 * 60;
chartConfig.options.plugins.title.text = "Наиграно часов по серверам";
} //po chasam
if (maxValue >= 60 * 60 * 24) {
this.timeDelimiter = 60 * 60 * 24;
chartConfig.options.plugins.title.text = "Наиграно дней по серверам";
}//po dnyam
const groupByDate = objs.reduce((acc: {[date: string]: PerPeriodStatistic[]}, obj) => {
const key = obj.date;
if (!acc[key]) acc[key] = [];
acc[key].push(obj)
return acc;
}, {});
chartData.labels = Object.keys(groupByDate);
//console.log(groupByDate);
chartData.labels.forEach(
(date) => {
groupByDate[date].forEach((stat) => {
if (srvList.indexOf(stat.srv_id) == -1)
srvList.push(stat.srv_id)
})
}
);
//console.log(srvList)
srvList.forEach((srv) => {
valueOnServer[srv] = [];
});
chartData.labels.forEach(
(date) => {
let filled: string[] = [];
groupByDate[date].forEach(
(obj) => {
valueOnServer[obj.srv_id].push(obj.value / this.timeDelimiter)
filled.push(obj.srv_id);
this.updateGraph(objs, "usertimeCanvasChart",
this.tooltipFooter,
"Наиграно секунд по серверам",
this.timeDelimiter);
}, (err) => {
this.settingsOfChart.loading = false;
this.snack.open("Ошибка загрузка графика");
}
)
srvList.forEach(
(srv) => {
if (filled.indexOf(srv) == -1) {
valueOnServer[srv].push(0);
}
}
)
},
)
//console.log(valueOnServer)
Object.keys(valueOnServer).forEach(
(key) => {
chartData.datasets.push(
{label: this.getServerName(key) + " ("+key+")", data: valueOnServer[key]}
)
}
)
///
chartConfig.data = chartData;
if (this.usertimeChart.chart)
this.usertimeChart.chart.destroy();
// @ts-ignore
this.usertimeChart.chart = new Chart('usertimeChart', chartConfig);
this.usertimeChart.loading = false;
}, (err) => {this.usertimeChart.loading = false; this.snack.open("Ошибка загрузка графика")}
);
} else {
this.snack.open("Нельзя загрузить график т.к нельзя определить индификатор профиля");

210
src/app/pages/internal-components/vip.graph.components.ts

@ -0,0 +1,210 @@
import {Component, Input, OnInit} from "@angular/core";
import {Chart} from "chart.js/auto";
import {SearchFilter} from "../../entities/search/SearchFilter";
import {GraphService, PerPeriodStatistic, VipPerPeriodStatistic} from "../../services/graph.service";
import {MatSnackBar} from "@angular/material/snack-bar";
import {VipGiveMethod} from "../../entities/VipGiveMethod";
import {BaseUtils} from "../../utils/BaseUtils";
@Component({
selector: 'app-vip-graph',
template: `
<div style="display: flex; justify-content: space-evenly;flex-direction: row;">
<mat-radio-group
style="display: flex; justify-content: center;flex-direction: row;"
[(ngModel)]="chartConfig.period"
[disabled]="chartConfig.loading"
(ngModelChange)="updateGraph()">
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="day">За месяц</mat-radio-button>
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="month">За год</mat-radio-button>
<mat-radio-button style="padding-right: 1%; padding-left: 1%" value="year">За 10 лет</mat-radio-button>
</mat-radio-group>
<mat-checkbox [(ngModel)]="removeNotStandartValue" (ngModelChange)="processGraph()">Не учитывать нестандартное время</mat-checkbox>
</div>
<div class="chart-container">
<canvas id="vipChart"></canvas>
</div>
`
})
export class VipGraphComponents implements OnInit {
chartConfig: {
chart: Chart|null,
period: 'day' | 'month' | 'year',
loading: boolean
} = {
chart: null,
period: 'day',
loading: false
}
@Input("steam64")
steam64: string|null = null;
objs: VipPerPeriodStatistic[] = [];
removeNotStandartValue: boolean = true;
standartPeriods: number[] = [86400, 86400*7, 86400*30, 86400*31];
constructor(private graphService: GraphService,
private snack: MatSnackBar) {
}
ngOnInit(): void {
//nothing here
}
tabChangedTrigger(event: any, tabIndex: number) {
if (event.index == tabIndex) {
this.updateGraph()
}
}
updateGraph() {
if (this.chartConfig.loading) return;
this.chartConfig.loading = true;
const filter: SearchFilter = new SearchFilter();
if (this.steam64)
filter.addAccountToSearch(this.steam64)
let endDate = new Date();
endDate.setUTCHours(23, 59, 59);
filter.addEndTimeToSearch(endDate.getTime());
switch (this.chartConfig.period) {
case "day": {
endDate.setDate(endDate.getDate() - 30);
break;
}
case "month": {
endDate.setDate(endDate.getDate() - 365);
break;
}
case "year": {
endDate.setDate(endDate.getDate() - (365*10));
break;
}
}
filter.addBeginTimeToSearch(endDate);
this.graphService.getGivedVipOnPeriod(filter).subscribe(
(objs) => {
this.objs = objs;
this.processGraph();
this.chartConfig.loading = false;
}, (err) => {this.chartConfig.loading = false; this.snack.open("Ошибка загрузка графика")}
)
}
/**
* Обертка над рендер графом чтобы брать данные которые есть в переменоой обж
*/
processGraph() {
this.renderGraph(this.objs);
}
private renderGraph(objs: VipPerPeriodStatistic[]): void {
let chartConfig = {
type: 'bar', data: {}, options: {
plugins: {
title: {
display: false,
text: "ggggg"
}
},
responsive: true,
interaction: {
intersect: false
},
scales: {
x: {
stacked: true,
},
y: {
stacked: true,
}
}
}
}
let chartData: {labels: string[], datasets: any[]} = {
labels: [],
datasets: []
}
if (this.removeNotStandartValue) {
objs = objs.filter(value => this.standartPeriods.indexOf(value.amount) != -1)
}
const groupByDate = objs.reduce((acc: {[date: string]: VipPerPeriodStatistic[]}, obj) => {
const key = obj.date;
if (!acc[key]) acc[key] = [];
acc[key].push(obj)
return acc;
}, {});
let existsAmount: number[] = [];
let existsGiveMethod: number[] = []
objs.forEach((obj) => {
if (existsAmount.indexOf(obj.amount) == -1) {
existsAmount.push(obj.amount);
}
if (existsGiveMethod.indexOf(obj.givemethod) == -1) {
existsGiveMethod.push(obj.givemethod);
}
})
let datasets:{[str: string]: number[]} = {};
existsAmount.forEach((ea) => {
existsGiveMethod.forEach((egm) => {
datasets[`${ea}-${egm}`] = [];
})
})
chartData.labels = Object.keys(groupByDate);
//stack это количетсво выданного времени
chartData.labels.forEach(
(date) => {
let foundAmountsAndGiveMethods: string[] = [];
groupByDate[date].forEach((data) => {
const key = `${data.amount}-${data.givemethod}`;
datasets[key].push(data.value);
foundAmountsAndGiveMethods.push(key);
});
Object.keys(datasets).forEach(//заполняем 0 пропуски
(key) => {
if (foundAmountsAndGiveMethods.indexOf(key) == -1) {
datasets[key].push(0)
}
}
)
});
const humanGiveMethod = (num: any) => {
try {
return VipGiveMethod[Number.parseInt(num)];
} catch (e) {
return "Неизвестно"
}
}
chartData.datasets = Object.keys(datasets)
.map((key) => {
const stack = key.split("-")[0];//amount
const label = key.split("-")[1];//givemethod
return {
label: humanGiveMethod(label) + " на " + BaseUtils.formatSeconds(Number.parseInt(stack)),
data: datasets[key],
stack: stack,
skipNull: true,
}
})
chartConfig.data = chartData;
//console.log(chartData);
if (this.chartConfig.chart)
this.chartConfig.chart.destroy();
// @ts-ignore
this.chartConfig.chart = new Chart('vipChart', chartConfig);
}
}

9
src/app/pages/main-page/main-page.component.html

@ -76,4 +76,11 @@
</div>
</div>
<app-statistic-page></app-statistic-page>
<!--<app-statistic-page></app-statistic-page>-->
<footer style="position: fixed;bottom: 0;width: 100%; background-color: rgba(230,94,17,0.5);">
<div style="display: flex; justify-content: center;flex-direction: row;align-items: center">
<a matTooltip="Состояние серверов" style="color: black; text-decoration: none" href="https://status.pblr-nyk.pro/status/facti13">
Факты 13 (2019-{{getYear()}})
</a>
</div>
</footer>

4
src/app/pages/main-page/main-page.component.ts

@ -85,4 +85,8 @@ export class MainPageComponent implements OnInit {
() => this.loading = false
)
}
getYear():number {
return new Date().getFullYear();
}
}

11
src/app/pages/profile-page/profile-page.component.html

@ -109,12 +109,12 @@
Наиграно времени
</mat-panel-title>
</mat-expansion-panel-header>
<mat-tab-group (selectedTabChange)="usertimegraph.usertimeTabChanged($event)">
<mat-tab-group (selectedTabChange)="usertimegraph.usertimeTabChanged($event, 1)">
<mat-tab label="По серверами">
<mat-list role="list">
<mat-list-item role="listitem" *ngFor="let gametime of profile.gametime | keyvalue">
<mat-progress-bar *ngIf="gametime.key == 'loading'" mode="indeterminate"></mat-progress-bar>
<p *ngIf="gametime.key != 'loading'">{{gametime.key}} - {{gametime.value | ValueServerMapDate:false}} секунд</p>
<p *ngIf="gametime.key != 'loading'">{{gametime.key}} - {{gametime.value | ValueServerMapDate:false}}</p>
</mat-list-item>
</mat-list>
</mat-tab>
@ -139,7 +139,14 @@
История получения VIP
</mat-panel-title>
</mat-expansion-panel-header>
<mat-tab-group (selectedTabChange)="vipGraphComponents.tabChangedTrigger($event, 1)">
<mat-tab label="История получений\снятий">
<app-donate-search-table #appdonatesearchtable [lazy]="true" [account_id]="profile.steamids.account_id"></app-donate-search-table>
</mat-tab>
<mat-tab label="График получения">
<app-vip-graph #vipGraphComponents [steam64]="steam64"></app-vip-graph>
</mat-tab>
</mat-tab-group>
</mat-expansion-panel>
<mat-expansion-panel hideToggle *ngIf="profile!=null && profile.steamids!=null" (click)="appreportsearchtable.lazyInit()">
<mat-expansion-panel-header>

4
src/app/pages/profile-page/profile-page.component.scss

@ -1,3 +1,7 @@
p {
margin: 0 0;
}
::ng-deep .mat-tab-body-content {
overflow: unset !important;
}

3
src/app/pages/profile-page/profile-page.component.ts

@ -12,6 +12,7 @@ import {GraphService, PerPeriodStatistic} from "../../services/graph.service";
import {SearchFilter} from "../../entities/search/SearchFilter";
import _default from "chart.js/dist/plugins/plugin.legend";
import labels = _default.defaults.labels;
import {BaseUtils} from "../../utils/BaseUtils";
@Component({
selector: 'app-profile-page',
@ -116,7 +117,7 @@ export class ValueServerMapDatePipe implements PipeTransform {
transform(value: {[name: string]: number}, createDate: boolean = true, delimiter: string = " - "): any {
const keys = Object.keys(value);
return `${this.mapCleaner(keys[0])}${delimiter}${createDate?(new Date(value[keys[0]]*1000)).toLocaleString():value[keys[0]]}`;
return `${this.mapCleaner(keys[0])}${delimiter}${createDate?(new Date(value[keys[0]]*1000)).toLocaleString():BaseUtils.formatSeconds(value[keys[0]])}`;
}
}

6
src/app/pages/servers-page/servers-page.component.html

@ -162,7 +162,11 @@
</mat-tab>
<mat-tab label="Общие наигранное время">
<app-usertime-graph #usertimeGraphComponent></app-usertime-graph>
<mat-progress-bar *ngIf="usertimeGraphComponent.usertimeChart.loading" mode="indeterminate"></mat-progress-bar>
<mat-progress-bar *ngIf="usertimeGraphComponent.settingsOfChart.loading" mode="indeterminate"></mat-progress-bar>
</mat-tab>
<mat-tab label="Количество подключений">
<app-connections-graph #connectionsGraphComponent></app-connections-graph>
<mat-progress-bar *ngIf="connectionsGraphComponent.settingsOfChart.loading" mode="indeterminate"></mat-progress-bar>
</mat-tab>
</mat-tab-group>
</div>

8
src/app/pages/servers-page/servers-page.component.ts

@ -14,6 +14,7 @@ import {Period} from "../statistic-page/statistic-page.component";
import {GraphService} from "../../services/graph.service";
import {ServerService} from "../../services/server.service";
import {UsertimeGraphComponent} from "../internal-components/usertime.graph.component";
import {ConnectionsGraphComponent} from "../internal-components/connections.graph.component";
@Component({
selector: 'app-servers-page',
@ -36,6 +37,9 @@ export class ServersPageComponent implements OnInit {
@ViewChild("usertimeGraphComponent")
usertimeGraphComponent!: UsertimeGraphComponent;
@ViewChild("connectionsGraphComponent")
connectionsGraphComponent!: ConnectionsGraphComponent;
periods:Period[] = [
{name: 'По дням', value: 'days'},
{name: 'По минутам', value: 'minutes'}
@ -170,6 +174,10 @@ export class ServersPageComponent implements OnInit {
this.usertimeGraphComponent.updateUsertimeGraph();
break;
}
case 3: {
this.connectionsGraphComponent.updateConnectionsGraph();
break;
}
default: {
break;
}

5
src/app/pages/statistic-page/statistic-page.component.html

@ -1,7 +1,9 @@
<div class="content-in-center">
<div class="content-in-border" *ngIf="uniq">
<h2>Уникальные игроки</h2>
<h4>За "уникальность" берется игрок который зашел за данный период первый раз и поиграл более 5 минут</h4>
<p>Подробная статистика находиться на странице <a href="#servers">серверов</a> в закладке "Количество подключений"</p>
<div hidden>
<h4>За "уникальность" берется игрок который зашел за данный период первый раз и поиграл более 5 минут. <span>p.s на самом деле более точную статистику можно посмотреть на странице с серверами</span></h4>
<div class="container responsive-grid-250">
<mat-card>
<mat-card-title>{{uniq.day}}</mat-card-title>
@ -20,6 +22,7 @@
<mat-card-subtitle>игроков за всё время</mat-card-subtitle>
</mat-card>
</div>
</div>
<h4>Мы патриоты, но уважаем и другие народы, смотрите сколько их понабежало к нам с начала года, но не все выдержали РУССКОЙ БАЗЫ в течении 5 минут. Ну или кто-то умеет пользоваться сервисами обходов блокировок</h4>
<div class="container responsive-grid-100">
<mat-card [ngStyle]="generateStyle4Country('Flag_of_Russia.svg')">

10
src/app/pages/vip-page/vip-page.component.html

@ -64,10 +64,14 @@
</div>
<div class="content-in-border">
<h2 style="color: black">Последние выданые випки</h2>
<div>
<mat-tab-group (selectedTabChange)="onTabChanged($event)">
<mat-tab label="Последние выданые випки">
<app-donate-search-table></app-donate-search-table>
</div>
</mat-tab>
<mat-tab label="Статистика выдачи">
<app-vip-graph #vipGraphComponent></app-vip-graph>
</mat-tab>
</mat-tab-group>
</div>
</div>

3
src/app/pages/vip-page/vip-page.component.scss

@ -0,0 +1,3 @@
::ng-deep .mat-tab-body-content {
overflow: unset !important;
}

20
src/app/pages/vip-page/vip-page.component.ts

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {VipService} from "../../services/vip.service";
import {VipBuy} from "../../entities/VipBuy";
import {MatDialog, MatDialogConfig, MatDialogRef} from "@angular/material/dialog";
@ -6,6 +6,7 @@ import {VipBuyDialog} from "./VipBuyDialog";
import {VipFreeDialog} from "./VipFreeDialog";
import {VipPromocodeDialog} from "./VipPromocodeDialog";
import {AuthService} from "../../services/auth.service";
import {VipGraphComponents} from "../internal-components/vip.graph.components";
@Component({
selector: 'app-vip-page',
@ -35,6 +36,9 @@ export class VipPageComponent implements OnInit {
{name: 'Здоровье', about: 'Постоянно убивают? Так увеличь себе здоровье через !sethealth 99999 или через пункт в меню'},
];
@ViewChild("vipGraphComponent")
vipGraphComponent!:VipGraphComponents
constructor(private vipService: VipService,
private dialog: MatDialog,
public authService: AuthService) { }
@ -62,4 +66,18 @@ export class VipPageComponent implements OnInit {
return null;
}
onTabChanged(event:any) {
switch (event.index) {
case 0: {
break;
}
case 1: {
this.vipGraphComponent.updateGraph();
break;
}
default: {
break;
}
}
}
}

15
src/app/services/graph.service.ts

@ -11,6 +11,11 @@ export interface PerPeriodStatistic {
date: string;
}
export interface VipPerPeriodStatistic extends PerPeriodStatistic {
givemethod: number;
amount: number;
}
@Injectable({
providedIn: 'root'
})
@ -30,4 +35,14 @@ export class GraphService {
// @ts-ignore
return this.http.post(`api/profile/usertime/graph`, filter);
}
public getConnectionsOnPeriod(filter: SearchFilter): Observable<PerPeriodStatistic[]> {
// @ts-ignore
return this.http.post(`api/profile/usertime/connections/graph`, filter);
}
public getGivedVipOnPeriod(filter: SearchFilter): Observable<VipPerPeriodStatistic[]> {
// @ts-ignore
return this.http.post(`api/web/vip/graph`, filter);
}
}

3
src/app/utils/BaseUtils.ts

@ -45,6 +45,9 @@ export class BaseUtils {
}
}
if (timePart == '00:00:00')
return `${days} ${dayWord}`;
else
return `${days} ${dayWord} ${timePart}`.split(".")[0];
}
}

Loading…
Cancel
Save