Browse Source

вооо крутооо спискок серверов

master
gsd 6 days ago
parent
commit
ebbdf43b32
  1. 7
      src/app/app.module.ts
  2. 1
      src/app/entities/servers/Player.ts
  3. 1
      src/app/entities/servers/Server.ts
  4. 2
      src/app/pages/rules-page/rules-page.component.html
  5. 66
      src/app/pages/servers-page/servers-page.component.html
  6. 3
      src/app/pages/servers-page/servers-page.component.scss
  7. 52
      src/app/pages/servers-page/servers-page.component.ts
  8. 33
      src/app/services/action.service.ts
  9. 14
      src/styles.scss

7
src/app/app.module.ts

@ -1,4 +1,4 @@
import { NgModule } from '@angular/core';
import {LOCALE_ID, NgModule} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
@ -27,6 +27,10 @@ import {BanService} from "./services/ban.service";
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {FormsModule} from "@angular/forms";
import {ServerService} from "./services/server.service";
import {registerLocaleData} from "@angular/common";
import localeRu from "@angular/common/locales/ru";
registerLocaleData(localeRu, "ru")
@NgModule({
declarations: [
@ -57,6 +61,7 @@ import {ServerService} from "./services/server.service";
FormsModule
],
providers: [
{provide: LOCALE_ID, useValue: 'ru' },
AnnonceService,
PlayerService,
BanService,

1
src/app/entities/servers/Player.ts

@ -1,6 +1,7 @@
export interface Player {
clz: number|null;
deads: number;
duration: string;
duration_seconds: number;
id: number;
loss: number;

1
src/app/entities/servers/Server.ts

@ -19,4 +19,5 @@ export interface Server {
status: boolean;
uniq: Uniq;
workshop: string|null;
ip:string;
}

2
src/app/pages/rules-page/rules-page.component.html

@ -6,7 +6,7 @@
<div class="content-in-center">
<div class="content-in-border">
<div class="container responsive-grid">
<mat-card *ngFor="let rule of rules" class="example-card">
<mat-card *ngFor="let rule of rules">
<mat-card-title>{{rule.name}}</mat-card-title>
<mat-card-subtitle>{{rule.ban}}</mat-card-subtitle>
<mat-card-content>

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

@ -6,7 +6,7 @@
<div class="content-in-center">
<div class="content-in-border">
<mat-accordion>
<mat-expansion-panel hideToggle *ngFor="let server of servers | keyvalue">
<mat-expansion-panel hideToggle *ngFor="let server of servers | keyvalue: playerCountOrder">
<mat-expansion-panel-header>
<mat-panel-title>
{{server.value.name}}
@ -16,20 +16,80 @@
</mat-panel-description>
</mat-expansion-panel-header>
<div>
<p>{{server.value.description}}</p>
<div class="container responsive-grid-100">
<mat-card>
<mat-card-title>{{server.value.status?'Включен':'Выключен'}}</mat-card-title>
<mat-card-subtitle>сейчас сервер</mat-card-subtitle>
</mat-card>
<mat-card>
<mat-card-title>{{server.value.player_count}}</mat-card-title>
<mat-card-subtitle>игроков сейчас играет</mat-card-subtitle>
</mat-card>
<mat-card>
<mat-card-title>{{server.value.uniq.day}}</mat-card-title>
<mat-card-subtitle>игроков играло сегодня</mat-card-subtitle>
</mat-card>
<mat-card>
<mat-card-title>{{server.value.uniq.month}}</mat-card-title>
<mat-card-subtitle>игроков играло за месяц</mat-card-subtitle>
</mat-card>
<mat-card>
<mat-card-title>{{server.value.uniq.year}}</mat-card-title>
<mat-card-subtitle>игроков играло за год</mat-card-subtitle>
</mat-card>
<mat-card>
<mat-card-title>{{server.value.last_update * 1000 | date: "hh:mm:ss"}}</mat-card-title>
<mat-card-subtitle>обновление информации</mat-card-subtitle>
</mat-card>
<mat-card>
<mat-card-title>{{server.value.dockerStats.cpu.percent}}%</mat-card-title>
<mat-card-subtitle>нагрузка сервера</mat-card-subtitle>
</mat-card>
</div>
<div class="container responsive-grid-250">
<mat-card>
<mat-card-title>{{mapClearName(server.value.map)}}</mat-card-title>
<mat-card-subtitle>Текущая карта</mat-card-subtitle>
</mat-card>
<mat-card
style="cursor: pointer"
(click)="actionService.goToUrlViaTab('steam://connect/'+server.value.ip)">
<mat-card-title>Подключиться</mat-card-title>
<mat-card-subtitle>через Steam</mat-card-subtitle>
</mat-card>
<mat-card
style="cursor: pointer"
(click)="actionService.copyToClipboard('connect ' + server.value.ip) && actionService.showSnack('Команда для подключения через консоль скопирована в буфер обмена')">
<mat-card-title>Адрес сервера</mat-card-title>
<mat-card-subtitle>{{server.value.ip}}</mat-card-subtitle>
</mat-card>
<mat-card *ngIf="server.value.workshop != ''" style="cursor: pointer" (click)="actionService.goToUrlViaTab(server.value.workshop)">
<mat-card-title>Скачать карту</mat-card-title>
<mat-card-subtitle>из воркшопа</mat-card-subtitle>
</mat-card>
</div>
<mat-expansion-panel hideToggle *ngIf="server.value.player_count>0">
<mat-expansion-panel-header>
<mat-panel-title>
Посмотреть игроков на сервере
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
<mat-expansion-panel hideToggle *ngFor="let player of server.value.players">
<mat-expansion-panel-header>
<mat-panel-title>
{{player.name}}
</mat-panel-title>
<mat-panel-description>
{{player.score}} / {{player.deads}} / {{player.duration_seconds}}
{{player.score}} / {{player.deads}} / {{player.duration}}
</mat-panel-description>
</mat-expansion-panel-header>
<p>Ид игрока: {{player.id}}</p>
<p>Пинг: {{player.ping}}</p>
<p>Потери пакетов: {{player.loss}}</p>
</mat-expansion-panel>
</mat-expansion-panel>
</div>
</mat-expansion-panel>
</mat-accordion>

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

@ -0,0 +1,3 @@
.container {
padding: 24px;
}

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

@ -1,6 +1,8 @@
import { Component, OnInit } from '@angular/core';
import {WebsocketServersListenerService} from "../../services/websocket-servers-listener.service";
import {Server} from "../../entities/servers/Server";
import {KeyValue} from "@angular/common";
import {ActionService} from "../../services/action.service";
@Component({
selector: 'app-servers-page',
@ -9,19 +11,55 @@ import {Server} from "../../entities/servers/Server";
})
export class ServersPageComponent implements OnInit {
servers:{[srv_name: string]:Server} = {};
servers:{[srv_name: string]:Server|any} = {};
constructor(private servers_ws:WebsocketServersListenerService) { }
constructor(private servers_ws:WebsocketServersListenerService,
public actionService: ActionService) { }
ngOnInit(): void {
this.servers_ws.getServers().subscribe((r) => {
if (r.state == 0) this.servers = r.servers;
else {
for (let srv_name of Object.keys(r.servers)) {
Object.assign(this.servers[srv_name], r.servers[srv_name]);
this.setServers(r.servers);
});
}
private updateProp<TObj, K extends keyof TObj>(obj: TObj, key: K, value: TObj[K]) {
return {...obj, [key]: value};
}
});
setServers(servers: {[srv_name: string]:Server|any}) {
const keys_current = Object.keys(this.servers);
const keys_update = Object.keys(servers);
for (const srv_name of keys_update) {
if (keys_current.indexOf(srv_name) == -1) {
//init
this.servers[srv_name] = servers[srv_name];
} else {
const keys_on_server = Object.keys(servers[srv_name]);
for (const server_key of keys_on_server) {
if (server_key == "players") {
for (const player_update of servers[srv_name]["players"]) {
for (const player_current of this.servers[srv_name]["players"]) {
if (player_update.id == player_current.id) {
//todo rework this shit
Object.assign(player_current, player_update);
}
}
}
} else {
this.servers[srv_name][server_key]=servers[srv_name][server_key];
}
}
}
}
}
public playerCountOrder = (s1: KeyValue<string,Server>, s2: KeyValue<string,Server>): number => {
return s2.value.player_count - s1.value.player_count;
}
public mapClearName(name: string|undefined) {
// @ts-ignore
return name.split("workshop/").pop().split(".ugc").shift()
}
}

33
src/app/services/action.service.ts

@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import {MatSnackBar, MatSnackBarRef} from "@angular/material/snack-bar";
import {Router} from "@angular/router";
@Injectable({
providedIn: 'root'
})
export class ActionService {
constructor(private snack: MatSnackBar,
private router: Router) { }
public copyToClipboard(text:string):boolean {
navigator.clipboard.writeText(text);
return true;
}
public showSnack(text: string, action: string = "Закрыть", duration: number = 3): boolean {
this.snack.open(text, action, {duration: duration*1000})
return true;
}
public goToUrlViaRouter(...url: string[]): boolean {
this.router.navigate(url)
return true;
}
public goToUrlViaTab(url: string|null): boolean {
if (url == null) return false;
window.open(url, "_blank");
return true;
}
}

14
src/styles.scss

@ -180,3 +180,17 @@ span {
padding: 15px;
margin-top: 15px
}
.responsive-grid-100 {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: 24px;
}
.responsive-grid-250 {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
gap: 24px;
}

Loading…
Cancel
Save