22 changed files with 425 additions and 53 deletions
@ -1,10 +1,142 @@ |
|||||
import {Component} from "@angular/core"; |
import {Component} from "@angular/core"; |
||||
|
import {AbstractSearchTable} from "../../pages/internal-components/abstract-search-table.component"; |
||||
|
import {DbFile} from "../../entities/DbFile"; |
||||
|
import {SearchFilter} from "../../entities/search/SearchFilter"; |
||||
|
import {AuthService} from "../../services/auth.service"; |
||||
|
import {ServerService} from "../../services/server.service"; |
||||
|
import {PlayerService} from "../../services/player.service"; |
||||
|
import {ActivatedRoute, Router} from "@angular/router"; |
||||
|
import {VipService} from "../../services/vip.service"; |
||||
|
import {FileService} from "../../services/file.service"; |
||||
|
import {MatTableDataSource} from "@angular/material/table"; |
||||
|
import {ActionService} from "../../services/action.service"; |
||||
|
|
||||
@Component({ |
@Component({ |
||||
selector: 'app-files-search-table', |
selector: 'app-files-search-table', |
||||
template: ` |
template: ` |
||||
|
<div style="padding-bottom: 10px;"> |
||||
|
<mat-chip-list> |
||||
|
<mat-chip [matMenuTriggerFor]="addFilter">Искать по...</mat-chip> |
||||
|
<mat-menu #addFilter> |
||||
|
<button mat-menu-item (click)="filter.addAccountToSearch('')" [disabled]="account_id!=null">Профилю</button> |
||||
|
<button mat-menu-item [matMenuTriggerFor]="timeSelect">Времени</button> |
||||
|
</mat-menu> |
||||
|
<mat-menu #timeSelect> |
||||
|
<button mat-menu-item (click)="filter.addEndTimeToSearch()">До ...</button> |
||||
|
<button mat-menu-item (click)="filter.addBeginTimeToSearch()">После ...</button> |
||||
|
</mat-menu> |
||||
|
|
||||
|
<mat-chip *ngIf="filter.updated" (click)="updateData()">Обновить</mat-chip> |
||||
|
<app-filter-mat-chip-account |
||||
|
[filter]="filter" |
||||
|
[hidden]="account_id!=null" |
||||
|
></app-filter-mat-chip-account> |
||||
|
<app-filter-mat-chip-date-begin |
||||
|
[filter]="filter"> |
||||
|
</app-filter-mat-chip-date-begin> |
||||
|
<app-filter-mat-chip-date-end |
||||
|
[filter]="filter"> |
||||
|
</app-filter-mat-chip-date-end> |
||||
|
</mat-chip-list> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div class="loading-shade" |
||||
|
*ngIf="loading || err"> |
||||
|
<mat-spinner *ngIf="loading"></mat-spinner> |
||||
|
<div class="err" *ngIf="err"> |
||||
|
Слишком много запросов или сервер не отвечает, обнови страницу. |
||||
|
<br> |
||||
|
<button mat-button (click)="err=false; loading=false">Закрыть</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<table mat-table [dataSource]="dataSource" style="width: 100%"> |
||||
|
<ng-container matColumnDef="uploader"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Имя игрока </th> |
||||
|
<td mat-cell *matCellDef="let row" [matMenuTriggerFor]="accountMenu"> {{row.uploader}} |
||||
|
<mat-menu #accountMenu> |
||||
|
<button mat-menu-item (click)="filter.addAccountToSearch('[U:1:'+row.uploader+']')">Добавить в поиск используя ID</button> |
||||
|
<button mat-menu-item (click)="authService.searchPlayer(row.uploader)">Открыть профиль</button> |
||||
|
</mat-menu></td> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="timestamp"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Время </th> |
||||
|
<td mat-cell *matCellDef="let row" [matMenuTriggerFor]="dateMenu"> {{row.timestamp | date:"HH:mm dd/MM/yyyy"}} |
||||
|
<mat-menu #dateMenu> |
||||
|
<button mat-menu-item (click)="filter.addEndTimeToSearch(row.timestamp)">Искать до {{row.timestamp | date:"HH:mm:ss dd/MM/yyyy"}}</button> |
||||
|
<button mat-menu-item (click)="filter.addBeginTimeToSearch(row.timestamp)">Искать после {{row.timestamp | date:"HH:mm:ss dd/MM/yyyy"}}</button> |
||||
|
</mat-menu></td> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="filename"> |
||||
|
<th mat-header-cell *matHeaderCellDef>Файл</th> |
||||
|
<td mat-cell *matCellDef="let row"> {{row.filename}}</td> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="extension"> |
||||
|
<th mat-header-cell *matHeaderCellDef>Расширение</th> |
||||
|
<td mat-cell *matCellDef="let row"> {{row.extension}}</td> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="filesize"> |
||||
|
<th mat-header-cell *matHeaderCellDef>Размер</th> |
||||
|
<td mat-cell *matCellDef="let row"> {{row.filesize}}</td> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="tags"> |
||||
|
<th mat-header-cell *matHeaderCellDef>Теги</th> |
||||
|
<td mat-cell *matCellDef="let row"> {{row.tags}}</td> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="actions"> |
||||
|
<th mat-header-cell *matHeaderCellDef>Действия</th> |
||||
|
<td mat-cell *matCellDef="let row"> |
||||
|
<mat-icon style="cursor: pointer" (click)="actionService.goToUrlViaTab('api/file/'+row.id)">cloud_download</mat-icon> |
||||
|
</td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> |
||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> |
||||
|
|
||||
|
<!-- Row shown when there is no matching data. --> |
||||
|
<div *ngIf="!loading"> |
||||
|
<tr class="mat-row" *matNoDataRow> |
||||
|
<td class="mat-cell" colspan="4">А вот и нету файлов...</td> |
||||
|
</tr> |
||||
|
</div> |
||||
|
</table> |
||||
|
|
||||
|
<mat-paginator |
||||
|
[pageSizeOptions]="pageSizeOptions" |
||||
|
[pageSize]="pageSize" |
||||
|
(page)="updateData()" |
||||
|
></mat-paginator> |
||||
|
</div> |
||||
` |
` |
||||
}) |
}) |
||||
export class FilesSearchTable { |
export class FilesSearchTable extends AbstractSearchTable<DbFile, SearchFilter>{ |
||||
|
displayedColumns: string[] = ['uploader', 'timestamp','filename', 'extension','filesize', 'tags', 'actions']; |
||||
|
|
||||
|
constructor(authService: AuthService, |
||||
|
serverService: ServerService, |
||||
|
playerService: PlayerService, |
||||
|
router: Router, |
||||
|
route: ActivatedRoute, |
||||
|
private fileService: FileService, |
||||
|
public actionService: ActionService) { |
||||
|
super(authService, serverService, playerService, route, router); |
||||
|
super.filter = new SearchFilter(); |
||||
|
} |
||||
|
|
||||
|
private getFiles(): boolean { |
||||
|
this.filter.updated = false; |
||||
|
this.loading = true; |
||||
|
this.fileService.getFiles(this.filter, this.paginator).subscribe( |
||||
|
(res) => { |
||||
|
this.dataSource = new MatTableDataSource<DbFile>(res.data); |
||||
|
this.err = false; |
||||
|
}, (e) => this.err = true, () => this.loading = false |
||||
|
) |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
override updateData() { |
||||
|
if (this.lazy) return; |
||||
|
super.updateData(); |
||||
|
this.getFiles(); |
||||
|
} |
||||
} |
} |
||||
|
@ -1,10 +1,151 @@ |
|||||
import {Component} from "@angular/core"; |
import {Component, Input, OnInit} from "@angular/core"; |
||||
|
import {FilesSearchTable} from "./FilesSearchTable"; |
||||
|
import {FileService} from "../../services/file.service"; |
||||
|
import {MatTableDataSource} from "@angular/material/table"; |
||||
|
|
||||
|
export interface UploadedFile { |
||||
|
file:File; |
||||
|
status: "initial" | "uploading" | "success" | "fail"; |
||||
|
tags: string[]; |
||||
|
tag:''; |
||||
|
} |
||||
|
|
||||
@Component({ |
@Component({ |
||||
selector: 'app-files-uploader', |
selector: 'app-files-uploader', |
||||
template: ` |
template: ` |
||||
|
<input style="display: none" type="file" class="file-input" (change)="onChange($event)" #fileUpload multiple /> |
||||
|
<div> |
||||
|
<button mat-button mat-raised-button (click)="fileUpload.click()" [disabled]="status!='wait'">Выбрать файлы</button> |
||||
|
<button mat-button mat-raised-button (click)="processingFiles()" [disabled]="status!='wait'||dataSource.data.length==0">Загрузить файлы</button> |
||||
|
<mat-form-field appearance="fill"> |
||||
|
<mat-label>Общий тег</mat-label> |
||||
|
<input matInput |
||||
|
[(ngModel)]="globalTag" |
||||
|
(change)="setGlobalTag()"> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<table mat-table [dataSource]="dataSource" style="width: 100%"> |
||||
|
|
||||
|
<!-- Position Column --> |
||||
|
<ng-container matColumnDef="name"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Имя файла </th> |
||||
|
<td mat-cell *matCellDef="let element"> {{element.file.name}} </td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<!-- Name Column --> |
||||
|
<ng-container matColumnDef="size"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Размер </th> |
||||
|
<td mat-cell *matCellDef="let element"> {{element.file.size}} </td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<!-- Weight Column --> |
||||
|
<ng-container matColumnDef="status"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Статус загрузки </th> |
||||
|
<td mat-cell *matCellDef="let element"> {{status2rus(element.status)}} </td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<!-- Symbol Column --> |
||||
|
<ng-container matColumnDef="tags"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Теги </th> |
||||
|
<td mat-cell *matCellDef="let element"> |
||||
|
<mat-chip-list> |
||||
|
<mat-chip [matMenuTriggerFor]="appendTag">+</mat-chip> |
||||
|
<mat-chip *ngFor="let tag of element.tags" (removed)="removeTag(element, tag)">{{tag}} |
||||
|
<button matChipRemove> |
||||
|
<mat-icon>cancel</mat-icon> |
||||
|
</button> |
||||
|
</mat-chip> |
||||
|
<mat-menu #appendTag> |
||||
|
<mat-form-field appearance="fill" |
||||
|
(click)="$event.stopPropagation()"> |
||||
|
<mat-label>Новый тег</mat-label> |
||||
|
<input matInput |
||||
|
[(ngModel)]="element.tag" |
||||
|
(change)="element.tags.push(element.tag)"> |
||||
|
</mat-form-field> |
||||
|
</mat-menu> |
||||
|
</mat-chip-list> |
||||
|
</td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<!-- Symbol Column --> |
||||
|
<ng-container matColumnDef="action"> |
||||
|
<th mat-header-cell *matHeaderCellDef> Действия </th> |
||||
|
<td mat-cell *matCellDef="let element"> nyk </td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> |
||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> |
||||
|
|
||||
|
<tr class="mat-row" *matNoDataRow> |
||||
|
<td class="mat-cell" colspan="4">Нет выбранных файлов</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
|
||||
` |
` |
||||
}) |
}) |
||||
export class FilesUploader { |
export class FilesUploader implements OnInit { |
||||
|
displayedColumns: string[] = ['name', 'size', 'tags', 'status', 'action']; |
||||
|
dataSource!:MatTableDataSource<UploadedFile>; |
||||
|
|
||||
|
@Input('fst') |
||||
|
fst!: FilesSearchTable; |
||||
|
status: 'wait' | 'uploading' | 'done' = 'wait'; |
||||
|
globalTag: string = ''; |
||||
|
|
||||
|
constructor(private fileService:FileService) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.dataSource = new MatTableDataSource<UploadedFile>(); |
||||
|
} |
||||
|
|
||||
|
status2rus(status: "initial" | "uploading" | "success" | "fail"):string { |
||||
|
switch (status) { |
||||
|
case "initial": return 'Ожидание'; |
||||
|
case "uploading": return 'Загрузка'; |
||||
|
case "success": return 'Успешно'; |
||||
|
case "fail": return 'Ошибка'; |
||||
|
default: return ''; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onChange(event: any) { |
||||
|
if (event && event.target && event.target.files) { |
||||
|
for (const f of event.target.files) { |
||||
|
this.dataSource.data.push({file:f, status: "initial", tags: [], tag:''}); |
||||
|
} |
||||
|
} |
||||
|
this.dataSource = new MatTableDataSource<UploadedFile>(this.dataSource.data); |
||||
|
} |
||||
|
|
||||
|
processingFiles() { |
||||
|
this.status = "uploading"; |
||||
|
this.dataSource.data.forEach((f)=> { |
||||
|
if (f.status == "initial") { |
||||
|
f.status = "uploading"; |
||||
|
this.fileService.uploadFile(f.file, f.tags).subscribe( |
||||
|
(res) => { |
||||
|
f.status = "success" |
||||
|
}, |
||||
|
(err) => { |
||||
|
f.status = "fail"; |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
}); |
||||
|
this.status = "wait"; |
||||
|
} |
||||
|
|
||||
|
removeTag(f: UploadedFile, tag: string) { |
||||
|
f.tags = f.tags.filter(t => t != tag); |
||||
|
} |
||||
|
|
||||
|
setGlobalTag() { |
||||
|
if (this.globalTag.length == 0 ) return; |
||||
|
this.dataSource.data.forEach((f)=> { |
||||
|
this.removeTag(f, this.globalTag); |
||||
|
f.tags.push(this.globalTag); |
||||
|
}); |
||||
|
} |
||||
} |
} |
||||
|
@ -1,13 +0,0 @@ |
|||||
<div class="content-in-center-header" style="flex-direction: column;"> |
|
||||
<h1>Бан лист</h1> |
|
||||
<h3>Скоро и ты сюда попадешь браток</h3> |
|
||||
</div> |
|
||||
|
|
||||
<div class="content-in-center"> |
|
||||
<div class="content-in-border"> |
|
||||
<app-need-auth-to-continue *ngIf="!authService.isAuth()"></app-need-auth-to-continue> |
|
||||
<div *ngIf="authService.isAuth()"> |
|
||||
<app-banlist-search-table></app-banlist-search-table> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
@ -0,0 +1,15 @@ |
|||||
|
import {Component} from "@angular/core"; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-auth-dialog-request', |
||||
|
template: ` |
||||
|
<h1 mat-dialog-title style="color: black">Чтобы смотреть дальше...</h1> |
||||
|
<mat-dialog-content> |
||||
|
<app-need-auth-to-continue></app-need-auth-to-continue> |
||||
|
</mat-dialog-content> |
||||
|
<mat-dialog-actions> |
||||
|
<button mat-button mat-raised-button mat-dialog-close="true" style="width: 100%">Закрыть</button> |
||||
|
</mat-dialog-actions> |
||||
|
` |
||||
|
}) |
||||
|
export class AuthDialogRequest {} |
@ -0,0 +1,4 @@ |
|||||
|
export class DefaultValues { |
||||
|
public static pageSizeOptions:number[] = [5, 10, 25]; |
||||
|
public static pageSize:number = 10; |
||||
|
} |
Loading…
Reference in new issue