Bläddra i källkod

right before upload analysis

tags/2.037
Patrick Sun 4 år sedan
förälder
incheckning
816c46dfd0
32 ändrade filer med 616 tillägg och 98 borttagningar
  1. +17
    -0
      src/app/app.config.ts
  2. +3
    -1
      src/app/app.module.ts
  3. +2
    -2
      src/app/chart-past-year-monthly-performance/chart-past-year-monthly-performance.component.ts
  4. +2
    -2
      src/app/chart-top-brokers/chart-top-brokers.component.html
  5. +2
    -2
      src/app/chart-type-of-loans/chart-type-of-loans.component.ts
  6. +5
    -2
      src/app/client-profile/client-profile.component.ts
  7. +23
    -12
      src/app/lender-uploads/lender-uploads.component.html
  8. +118
    -54
      src/app/lender-uploads/lender-uploads.component.ts
  9. +2
    -2
      src/app/list-all-loans/list-all-loans.component.html
  10. +1
    -1
      src/app/list-income/list-income.component.html
  11. +1
    -1
      src/app/models/PastYearMonthly.model.ts
  12. +14
    -1
      src/app/models/uploadMetaModel.ts
  13. +13
    -0
      src/app/models/uploading.info.model.ts
  14. +1
    -3
      src/app/people-select/people-select.component.ts
  15. +2
    -4
      src/app/service/auth.service.ts
  16. +25
    -1
      src/app/service/upload.attach.service.ts
  17. +6
    -3
      src/app/upload-cards/upload-cards.component.html
  18. +35
    -0
      src/app/upload-cards/upload-cards.component.scss
  19. +24
    -2
      src/app/upload-cards/upload-cards.component.ts
  20. +5
    -3
      src/app/upload-detail/upload-detail.component.ts
  21. +59
    -0
      src/app/uploading-progress-card/uploading-progress-card.component.html
  22. +110
    -0
      src/app/uploading-progress-card/uploading-progress-card.component.scss
  23. +25
    -0
      src/app/uploading-progress-card/uploading-progress-card.component.spec.ts
  24. +108
    -0
      src/app/uploading-progress-card/uploading-progress-card.component.ts
  25. Binär
      src/assets/img/no_preview.jpg
  26. Binär
      src/assets/img/nopreview-thumb.jpg
  27. Binär
      src/assets/img/suffix/pdf.png
  28. Binär
      src/assets/img/suffix/xls.png
  29. Binär
      src/assets/img/suffix/xlsx.png
  30. Binär
      src/assets/img/thumb_file_icon.webp
  31. Binär
      src/assets/pdf/no_preview.pdf
  32. +13
    -2
      src/index.html

+ 17
- 0
src/app/app.config.ts Visa fil

@@ -55,4 +55,21 @@ export class AppConfig {
return AppConfig.config.Socket;
}

public getUrl(key: string): string{
const s = this.apiUrl + key;
const kvPair: {key: string, value: string}[] = [
{key: 'login', value: this.apiUrl + 'login'},
{key: 'logout', value: this.apiUrl + 'logout'}
];

kvPair.forEach( item => {
if ( item.key === key) {
return item.value;
}
});

// not found if arrive here
return s;
}

}

+ 3
- 1
src/app/app.module.ts Visa fil

@@ -96,6 +96,7 @@ import { ImagePopupDialogComponent } from './image-popup-dialog/image-popup-dial
import { PopupIncomeFilterComponent } from './popup-income-filter/popup-income-filter.component';
import { LoanCardComponent } from './loan-card/loan-card.component';
import {AppConfig} from './app.config';
import { UploadingProgressCardComponent } from './uploading-progress-card/uploading-progress-card.component';



@@ -162,7 +163,8 @@ export function initializeApp(appConfig: AppConfig): () => Promise<void> {
SafeUrlPipe,
ImagePopupDialogComponent,
PopupIncomeFilterComponent,
LoanCardComponent
LoanCardComponent,
UploadingProgressCardComponent
],
imports: [
BrowserModule,

+ 2
- 2
src/app/chart-past-year-monthly-performance/chart-past-year-monthly-performance.component.ts Visa fil

@@ -23,9 +23,9 @@ export class ChartPastYearMonthlyPerformanceComponent implements OnInit {
private getPastYearMonthly(): Observable<PastYearMonthlyData[]> {
return this.http.get<PastYearMonthlyData[]>(this.auth.getUrl('chart/past-year-monthly')).pipe(map(
data => {
let ret = [];
const ret = [];
data.forEach( (value: PastYearMonthlyData , index: number ) => {
let a = {
const a = {
Period: value.Period,
Amount: value.Amount / 1000,
Summary: '',

+ 2
- 2
src/app/chart-top-brokers/chart-top-brokers.component.html Visa fil

@@ -9,8 +9,8 @@
</kendo-grid-column>
<kendo-grid-column field="License" title="License" width="80">
</kendo-grid-column>
<kendo-grid-column field="Login" title="Login" width="80">
</kendo-grid-column>
<!-- <kendo-grid-column field="Login" title="Login" width="80">-->
<!-- </kendo-grid-column>-->
<kendo-grid-column field="Organization" title="Organization" width="80">
</kendo-grid-column>
<kendo-grid-column field="NumOfLoans" title="Num Of Loans" width="50" [style]="{'text-align':'center'}" >

+ 2
- 2
src/app/chart-type-of-loans/chart-type-of-loans.component.ts Visa fil

@@ -28,10 +28,10 @@ export class ChartTypeOfLoansComponent implements OnInit {
return this.http.get<TypeOfLoansModel[]>(this.auth.getUrl('chart/type-of-loans')).pipe(
map(
input => {
let ret = [];
const ret = [];
input.forEach( (value, index) =>{
ret.push({
Kind: value.Kind + ' ' + (value.Share * 100) + '%',
Kind: value.Kind + ' ' + (value.Share * 100).toFixed(2) + '%',
Count: value.Count,
Share: value.Share,
Amount: value.Amount

+ 5
- 2
src/app/client-profile/client-profile.component.ts Visa fil

@@ -5,6 +5,7 @@ import {AuthService} from '../service/auth.service';
import {PeopleService} from '../service/people.service';
import {FileInfo, FileRestrictions, FileSelectComponent, SelectEvent} from '@progress/kendo-angular-upload';
import {BrokerModel} from '../models/broker.model';
import {AppConfig} from '../app.config';

@Component({
selector: 'app-client-profile',
@@ -14,7 +15,7 @@ import {BrokerModel} from '../models/broker.model';
export class ClientProfileComponent implements OnInit {
@Input() User: PeopleModel = PeopleModel.EmptyNew();
@ViewChild('fileSelect', {static: true}) fs: FileSelectComponent;
public avatarUrl = 'url(https://svr2021.lawipac.com:8080/api/v1/avatar/1000)' ;
public avatarUrl = '' ;
public myRestrictions: FileRestrictions = {
allowedExtensions: ['.jpg', '.png', '.jpeg'],
maxFileSize: 2194304
@@ -23,7 +24,9 @@ export class ClientProfileComponent implements OnInit {
public opened = false; // dialog box
public Message = ''; // dialog message

constructor(private auth: AuthService, private ps: PeopleService) { }
constructor(private auth: AuthService, private ps: PeopleService) {
this.avatarUrl = 'url("' + location.origin + './assets/img/avatar.png' + '")';
}


ngOnInit(): void {

+ 23
- 12
src/app/lender-uploads/lender-uploads.component.html Visa fil

@@ -1,32 +1,43 @@
<div class="workarea">
<div class="file-manager-bar">
<div class="upload-area">
<kendo-upload class="uploadfiles" [concurrent]="false" [restrictions]="myRestrictions"
<kendo-upload class="uploadfiles" [concurrent]="true" [restrictions]="myRestrictions"
(success)="onSuccess($event)"
(upload)="onUpload($event)"
(upload)="onStartUpload($event)"
(error)="onUploadError($event)"
(complete)="onComplete()"
(uploadProgress)="uploadProgress($event)"
[showFileList]="false"
[saveUrl]="uploadSaveUrl">
<ng-template kendoUploadFileInfoTemplate let-files>
<div *ngIf="files!==undefined && files!== null && files[0] !== null">
<div (click)="onClick(files)">Name: {{ files[0].name }}</div>
<div *ngIf="files[0].validationErrors !== undefined"> Cannot upload this file {{files[0]}}</div>
<div *ngIf="map.get(files[0].uid) !== undefined"> fuck all {{map.get(files[0].uid).response.body.Funder}} </div>
</div>
</ng-template>
<!-- <ng-template kendoUploadFileInfoTemplate let-files>-->
<!-- <div *ngIf="files!==undefined && files!== null && files[0] !== null">-->
<!-- <div (click)="onClick(files)">Name: {{ files[0].name }}</div>-->
<!-- <div *ngIf="files[0].validationErrors !== undefined"> Cannot upload this file {{files[0]}}</div>-->
<!-- <div *ngIf="map.get(files[0].uid) !== undefined"> fuck all {{map.get(files[0].uid).response.body.Funder}} </div>-->
<!-- </div>-->
<!-- </ng-template>-->
</kendo-upload>
</div>
<div class="search-area">
<kendo-textbox class='search-people' [placeholder]="'Type to search/filter'" (valueChange)="onFilterUploads($event)" > </kendo-textbox>
<kendo-textbox class='search-people' [placeholder]="'Type to search/filter'"
[(ngModel)]="strFilter"
(valueChange)="onFilterUploads($event)" > </kendo-textbox>
<kendo-icon name="search" size="medium"></kendo-icon>
</div>
</div>
<bkp-divider-shadow-bottom></bkp-divider-shadow-bottom>
<div class="container">
<div *ngIf="!loading" class="row justify-content-start">
<div class="col-lg-3 text-center" *ngFor="let p of displayedUploads">
<app-upload-cards [uploadId]="p"></app-upload-cards>
<div class="col-lg-3 text-center" *ngFor="let p of allUploads" [ngClass]="{NewUpload: p.IsNew}">
<app-upload-cards *ngIf="!p.Uploading" [uploadId]="p.Meta.Id" (deleted)="onDelete($event)"></app-upload-cards>
<app-uploading-progress-card *ngIf="p.Uploading"
[MetaId]="p.Info.MetaId"
[FileName]="p.Info.FileName"
[Progress]="p.Info.Progress"
[UniqueId]="p.Info.UniqueId"
[IsDuplicate]="p.IsDuplicate"
(Complete)="onCompleteSingle($event)"
></app-uploading-progress-card>
</div>
</div>
<div *ngIf="loading" class="row justify-content-center">

+ 118
- 54
src/app/lender-uploads/lender-uploads.component.ts Visa fil

@@ -1,11 +1,21 @@
import {AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation} from '@angular/core';
import {FileInfo, FileRestrictions, SuccessEvent, UploadComponent, UploadEvent, UploadProgressEvent} from '@progress/kendo-angular-upload';
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {FileInfo, FileRestrictions, SuccessEvent, UploadEvent, UploadProgressEvent} from '@progress/kendo-angular-upload';
import {AuthService} from '../service/auth.service';
import {range} from '@progress/kendo-angular-dateinputs/dist/es2015/util';
import {debounce} from 'ts-debounce';
import {Router} from '@angular/router';
import {PageChangeEvent} from '@progress/kendo-angular-pager';
import {ImagePopupDialogComponent} from '../image-popup-dialog/image-popup-dialog.component';
import {UploadAttachService} from '../service/upload.attach.service';
import {AppConfig} from '../app.config';
import {UploadMetalList, UploadMetaModel} from '../models/uploadMetaModel';
import {UploadingInfoModel} from '../models/uploading.info.model';

class UploadingCards{
Uploading = false;
IsDuplicate = false;
IsNew = false;
Info: UploadingInfoModel = new UploadingInfoModel({});
Meta: UploadMetaModel = new UploadMetaModel({});
}

@Component({
selector: 'app-lender-uploads',
@@ -13,79 +23,113 @@ import {UploadAttachService} from '../service/upload.attach.service';
styleUrls: ['./lender-uploads.component.scss'],
})
export class LenderUploadsComponent implements OnInit {
@Output() success: EventEmitter<SuccessEvent> = new EventEmitter<SuccessEvent>();
@Output() click: EventEmitter<FileInfo> = new EventEmitter<FileInfo>();
@Output() complete: EventEmitter<FileInfo> = new EventEmitter<FileInfo>();
@Output() uploadSuccessful: EventEmitter<SuccessEvent> = new EventEmitter<SuccessEvent>();
@Output() uploadClick: EventEmitter<FileInfo> = new EventEmitter<FileInfo>();
@Output() uploadComplete: EventEmitter<FileInfo> = new EventEmitter<FileInfo>();
@Output() upload: EventEmitter<boolean> = new EventEmitter<boolean>();


private uploads: SuccessEvent[] = [];
public value = 0 ;
public map: Map<string, SuccessEvent> = new Map<string, SuccessEvent>();
public loading = false;

uploadSaveUrl = 'https://svr2021.lawipac.com:8080/api/v1/lender-upload/'; // should represent an actual API endpoint
uploadRemoveUrl = 'https://svr2021.lawipac.com:8080/api/v1/lender-upload-remove/'; // should represent an actual API endpoint
uploadSaveUrl = ''; // should represent an actual API endpoint
uploadRemoveUrl = ''; // should represent an actual API endpoint

public allUploads = [...range(30, 44 )];
public displayedUploads: any[] = [];
public filteredUploads: any[] = [];
public allUploads: UploadingCards[] = [];


public skip = 0;
public pageSize = 12;
public total = 0;
public strFilter = '';

private debouncedSearch: any;

myRestrictions: FileRestrictions = {
allowedExtensions: ['.pdf', '.xls', '.xlsx']
allowedExtensions: ['.pdf', '.xls', '.xlsx'],
maxFileSize: 30240000,
minFileSize: 1000,
};

constructor(private auth: AuthService, private router: Router, private uas: UploadAttachService) {
constructor(private auth: AuthService, private router: Router, private uas: UploadAttachService, private config: AppConfig) {
this.uploadSaveUrl = this.config.apiUrl + 'lender-upload/';
this.uploadRemoveUrl = this.config.apiUrl + 'lender-upload-remove/';
}


ngOnInit(): void {
this.debouncedSearch = debounce(this.loadDisplayRecords, 500);
this.uploadSaveUrl = this.auth.getUrl('lender-upload/');
this.uploadRemoveUrl = this.auth.getUrl('lender-upload-remove/');
this.loadDisplayedUploads();

this.loadAllUploads();
}



public onClick( files: any): void{
this.click.emit(files[0]);
this.uploadClick.emit(files[0]);
}

public onSuccess(ss: SuccessEvent ): void {
this.uploads.push(ss);
this.map.set(ss.files[0].uid, ss);
this.success.emit(ss);
this.allUploads.unshift(this.allUploads.length + 100);
this.uploadSuccessful.emit(ss);

const idx = this.uid2Idx(ss.files[0].uid);
this.allUploads[idx].Meta = new UploadMetaModel(ss.response.body);
this.allUploads[idx].Info.MetaId = this.allUploads[idx].Meta.Id; // trigger analysis
this.allUploads[idx].IsDuplicate = ss.response.body.IsDuplicate;

// remove card
const uid = ss.files[0].uid;
if (this.allUploads[idx].IsDuplicate ) {
this.allUploads[idx].Info.Progress = 100;
const timer = setInterval(() => {
this.allUploads[idx].Info.Progress -= this.randBetween(1, 10); // when many cards to be removed, it's better not altogether
if (this.allUploads[idx].Info.Progress <= 0 ) {
clearInterval(timer);
this.allUploads = this.allUploads.filter(v => {
return v.Info.UniqueId !== uid;
});
}
}, 100);
}
}

public onUpload(ss: UploadEvent ): void {
this.upload.emit(true);
private randBetween(start: number, end: number): number {
return Math.floor(Math.random() * end) + start;
}

private uid2Idx(uid: string): number {
return this.allUploads.findIndex( v => {
return v.Info.UniqueId === uid;
});
}

public onStartUpload(ss: UploadEvent ): void {
const uc = new UploadingCards();
uc.Uploading = true;
uc.IsDuplicate = false;
uc.IsNew = true;
uc.Info.UniqueId = ss.files[0].uid;
uc.Info.FileName = ss.files[0].name;
uc.Info.Progress = 0;
uc.Info.MetaId = 0 ;
this.allUploads.unshift(uc);

}

public onComplete(): void {
this.upload.emit(false);
console.log('ok completed');
}

public hasResp(uid): boolean {
let found = false;
this.uploads.every(v => {
if ( v.files[0].uid === uid ) {
found = true;
return false; // stop search
}
});
return found;
public onUploadError(e: any): void {
console.log(e);
}

public uploadProgress(prog: UploadProgressEvent): void {
this.value = prog.percentComplete.valueOf();
prog.files.forEach( v => {
const idx = this.uid2Idx(v.uid);
this.allUploads[idx].Info.Progress = prog.percentComplete.valueOf();
// console.log(prog.percentComplete.valueOf(), v.uid, v);
} );
}

public show( i: number): void{
this.router.navigate(['/upload-details/' + i]);
}
@@ -94,29 +138,49 @@ export class LenderUploadsComponent implements OnInit {
public onPageChange(e: PageChangeEvent): void {
this.skip = e.skip;
this.pageSize = e.take;
this.loadDisplayedUploads();
this.loadDisplayRecords();
}

private loadDisplayedUploads(): void {
this.filteredUploads = this.allUploads ;
this.displayedUploads = this.filteredUploads.slice(this.skip, this.skip + this.pageSize);
this.total = this.displayedUploads.length;
private loadAllUploads(): void{
this.skip = 0;
this.onFilterUploads(this.strFilter);
}

public onFilterUploads(hint: string): void {
this.skip = 0;
this.strFilter = hint;
this.debouncedSearch();
}

private loadAllUploads(): void{
private loadDisplayRecords(): void {
this.allUploads = [];
this.loading = true;
// this.uas.getUploadMetaList(this.skip, this.skip + this.pageSize).subscribe(
// resp => {
// this.loading = false;
// }
// );

this.uas.getUploadMetaList(this.skip, this.pageSize, this.strFilter).subscribe(
(resp: UploadMetalList ) => {
this.loading = false;
this.total = resp.Total;
resp.Data.forEach((v) => {
const uc = new UploadingCards();
uc.Uploading = false;
uc.Meta = new UploadMetaModel(v);
this.allUploads.push(uc);
});
}, err => { this.loading = false; },
() => { this.loading = false; }
);
}

public onFilterUploads(hint: string): void {
this.loadDisplayedUploads();
public onDelete(ulMeta: UploadMetaModel): void{
this.allUploads = this.allUploads.filter((v) => {
return v.Meta.Id !== ulMeta.Id;
});
// console.log('delete', ulMeta, this);
}


public onCompleteSingle(uid: string): void {
const idx = this.uid2Idx(uid);
if (this.allUploads[idx] !== undefined ){
this.allUploads[idx].Uploading = false;
}
}
}

+ 2
- 2
src/app/list-all-loans/list-all-loans.component.html Visa fil

@@ -165,9 +165,9 @@
</kendo-grid-numeric-filter-cell>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="Trail" title="Income Trail($) " width="200" [headerClass]="'colTrail'" [class]="'topAlign colTrail'" filter="numeric">
<kendo-grid-column field="IncomeTotal" title="Income Trail($) " width="200" [headerClass]="'colTrail'" [class]="'topAlign colTrail'" filter="numeric">
<ng-template kendoGridCellTemplate let-dataItem>
<span *ngIf="dataItem.Trail > 0" [ngClass]="{'green text-bold': dataItem.Trail < 500000}">{{ dataItem.Trail | currency }}</span>
<span *ngIf="dataItem.IncomeTotal > 0" [ngClass]="{'green text-bold': dataItem.IncomeTotal < 500000}">{{ dataItem.IncomeTotal | currency }}</span>
</ng-template>
<ng-template kendoGridFilterCellTemplate let-filter let-column="column">
<kendo-grid-numeric-filter-cell

+ 1
- 1
src/app/list-income/list-income.component.html Visa fil

@@ -14,7 +14,7 @@

<kendo-splitter-pane size="300px">
<div class="pane-content">
<app-lender-uploads (success)="onSuccess($event)"></app-lender-uploads>
<app-lender-uploads (uploadSuccessful)="onSuccess($event)"></app-lender-uploads>
</div>
</kendo-splitter-pane>


+ 1
- 1
src/app/models/PastYearMonthly.model.ts Visa fil

@@ -6,6 +6,6 @@ export class PastYearMonthlyData {
Month: number;
Year: number;
Amount: number;
Trail: number;
IncomeTotal: number;
Summary: string;
}

+ 14
- 1
src/app/models/uploadMetaModel.ts Visa fil

@@ -22,6 +22,19 @@ export class UploadMetaModel {

get iconUrl(): string {
const t = this.Format.replace( '/', '-');
return location.origin +'/assets/img/mime/' + t + '.png';
return location.origin + '/assets/img/mime/' + t.toLowerCase() + '.png';
}

static iconUrlBySuffix(suffix: string): string {
return location.origin + '/assets/img/suffix/' + suffix.toLowerCase() + '.png';
}

static thumbDefault(): string {
return location.origin + '/assets/img/thumb_file_icon.webp';
}
}

export class UploadMetalList {
Total: number;
Data: UploadMetaModel[];
}

+ 13
- 0
src/app/models/uploading.info.model.ts Visa fil

@@ -0,0 +1,13 @@
export class UploadingInfoModel {
FileName: string;
UniqueId: string;
MetaId: number;
Progress: number;

constructor (payload: Partial<UploadingInfoModel>){
this.FileName = payload.FileName || '';
this.UniqueId = payload.UniqueId || '';
this.MetaId = payload.MetaId || 0;
this.Progress = payload.Progress || 0 ;
}
}

+ 1
- 3
src/app/people-select/people-select.component.ts Visa fil

@@ -4,9 +4,7 @@ import { debounce } from 'ts-debounce';
import {PeopleModel} from '../models/people.model';
import {ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms';
import {MultiColumnComboBoxComponent} from '@progress/kendo-angular-dropdowns';
import {Observable, of} from 'rxjs';
import {PercentPipe} from '@angular/common';
import {map} from 'rxjs/operators';
import {Observable} from 'rxjs';
import {PeopleService} from '../service/people.service';

@Component({

+ 2
- 4
src/app/service/auth.service.ts Visa fil

@@ -9,11 +9,9 @@ import {AppConfig} from '../app.config';

@Injectable()
export class AuthService {
public apiUrl = '';
public apiWsUrl = '';

public apiUrl = 'https://svr2021.lawipac.com:8080/api/v1/';
public apiWsUrl = 'wss://svr2021.lawipac.com:8080/api/v1/ws';
// public apiUrl = 'https://c5016.biukop.com.au:8080/api/v1/';
// public apiWsUrl = 'wss://c5016.biukop.com.au:8080/api/v1/ws';
public loggedIn = ApiV1LoginResponse.EmptyNew();
loginSuccess = new EventEmitter <ApiV1LoginResponse>();


+ 25
- 1
src/app/service/upload.attach.service.ts Visa fil

@@ -2,7 +2,7 @@ import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {AuthService} from './auth.service';
import {Observable} from 'rxjs';
import {UploadMetaModel} from '../models/uploadMetaModel';
import {UploadMetalList, UploadMetaModel} from '../models/uploadMetaModel';
import {UploadAnalysisModel} from '../models/upload.analysis.model';


@@ -19,6 +19,14 @@ export class UploadAttachService {
return this.http.get<UploadAnalysisModel>(this.auth.getUrl('upload-analysis/' + id));
}

public getUploadMetaList(Skip: number, Take: number, Filter: string): Observable<UploadMetalList> {
return this.http.post<UploadMetalList>(this.auth.getUrl('upload-meta-list/'), {Skip, Take, Filter});
}

public deleteUpload(id: number): Observable<UploadMetaModel> {
return this.http.delete<UploadMetaModel>(this.auth.getUrl('upload/' + id));
}

public getUploadAsJpgUrl(id: number): string {
const ts = Date.now();
return this.auth.getUrl('upload-as-image/' + id + '?date=' + ts);
@@ -51,4 +59,20 @@ export class UploadAttachService {
return this.auth.getUrl('upload-as-thumbnail/' + id );
}


public createThumb(id: number): Observable<boolean> {
return this.http.put<boolean>(this.auth.getUrl('upload-as-thumbnail/' + id), {});
}

public createPreview(id: number): Observable<boolean>{
return this.http.put<boolean>(this.auth.getUrl('upload-as-image/' + id), {});
}

public createPDF(id: number): Observable<boolean>{
return this.http.put<boolean>(this.auth.getUrl('upload-as-pdf/' + id), {});
}

public createAnalysis(id: number): Observable<UploadAnalysisModel> {
return this.http.put<UploadAnalysisModel>(this.auth.getUrl('upload-analysis/' + id), {});
}
}

+ 6
- 3
src/app/upload-cards/upload-cards.component.html Visa fil

@@ -3,11 +3,14 @@
<kendo-card class="upload-card-content upload-thumb" [width]="'200px'" [ngStyle]="{'background-image' : 'url(' + thumbImage + ')'}">

<kendo-card-header class="k-hbox">
<p> some title </p>
<button class="action" kendoButton icon="trash" (click)="onDelete(uploadId)"></button>
<p> {{ ( uploadMeta.FileName.length > 17 ) ? (uploadMeta.FileName | slice:0:17) + "..." : (uploadMeta.FileName)}} </p>
</kendo-card-header>
<kendo-card-body>
<p> {{uploadId}} </p>

<p class="FileName"> {{uploadMeta.FileName}} </p>
<p class="ts" > {{uploadMeta.Ts | date:"longDate" }} </p>
<p class="Id" > Id = {{uploadMeta.Id }} </p>
<div *ngIf="IsNew" class="isNew">NEW</div>
</kendo-card-body>
<kendo-card-footer>
<button class="action" kendoButton icon="track-changes" (click)="onNavigateTo(uploadId)"></button>

+ 35
- 0
src/app/upload-cards/upload-cards.component.scss Visa fil

@@ -23,6 +23,21 @@ div.card-wrapper{
background-position: center center;
}


div.isNew {
width: 80px;
height: 20px;
color: white;
background-color: #f50606;
transform: rotate(
45deg
);
position: absolute;
bottom: 5px;
left: -25px;
z-index: 10;
}

button.action {
border-radius: 100%;
height:32px;
@@ -92,6 +107,15 @@ div.card-wrapper{
transition: all $speed ease-out;
}

kendo-card-body {
p.FileName {
display:none;
}
p.Id {
display:none;
}
}

&:hover {
p {
z-index: 100;
@@ -124,6 +148,17 @@ div.card-wrapper{
}
}

kendo-card-body {
p.FileName {
display:block;
word-break: break-all;
}
p.Id {
display:block;
word-break: break-all;
}
}

}

}

+ 24
- 2
src/app/upload-cards/upload-cards.component.ts Visa fil

@@ -4,6 +4,7 @@ import {ImagePopupDialogComponent} from '../image-popup-dialog/image-popup-dialo
import {AuthService} from '../service/auth.service';
import {UploadMetaModel} from '../models/uploadMetaModel';
import {UploadAttachService} from '../service/upload.attach.service';
import {AppConfig} from '../app.config';



@@ -15,14 +16,19 @@ import {UploadAttachService} from '../service/upload.attach.service';
export class UploadCardsComponent implements OnInit {
@Input() uploadId: number;
@Input() icon = '';
@Output() deleted = new EventEmitter<UploadMetaModel>();
@ViewChild('imgBox', {static: true}) imgBox: ImagePopupDialogComponent;
@ViewChild('downloadLink', {static: true}) downloadLink: ElementRef<HTMLAnchorElement>;
public uploadMeta: UploadMetaModel = new UploadMetaModel({});

public thumbImage = 'https://svr2021.lawipac.com:8080/api/v1/upload-as-thumbnail/31';
public thumbImage = '';
public fullImage = '';

constructor(private router: Router, private auth: AuthService, private uas: UploadAttachService) { }
public IsNew = false;

constructor(private router: Router, private auth: AuthService, private uas: UploadAttachService, private config: AppConfig) {
this.thumbImage = location.origin + '/assets/img/nopreview-thumb.png';
}

ngOnInit(): void {
let url = this.auth.getUrl('upload-as-thumbnail/' + this.uploadId);
@@ -33,9 +39,19 @@ export class UploadCardsComponent implements OnInit {
this.uas.getUploadMeta(this.uploadId).subscribe( resp => {
this.uploadMeta = new UploadMetaModel(resp);
this.icon = this.uploadMeta.iconUrl;
this.IsNew = this.DateDiff(this.uploadMeta.Ts, new Date()) < 1;
});
}


private DateDiff(date1: Date, date2: Date): number {
const dt1 = new Date(date1);
const dt2 = new Date(date2);
return Math.floor((Date.UTC(dt2.getFullYear(), dt2.getMonth(), dt2.getDate())
- Date.UTC(dt1.getFullYear(), dt1.getMonth(), dt1.getDate()) )
/ (1000 * 60 * 60 * 24));
}

public onNavigateTo(id: number ): void{
this.router.navigate(['/upload-details/', id]);
}
@@ -59,4 +75,10 @@ export class UploadCardsComponent implements OnInit {
this.imgBox.showImg(url, this.uploadId + ' - ' + this.uploadMeta.FileName);
}

public onDelete(id: number): void {
this.uas.deleteUpload(id).subscribe( resp => {
const ulMeta = new UploadMetaModel(resp);
this.deleted.emit(ulMeta);
});
}
}

+ 5
- 3
src/app/upload-detail/upload-detail.component.ts Visa fil

@@ -21,7 +21,7 @@ export class UploadDetailComponent implements OnInit, AfterViewInit {
@ViewChild('pdf', {static: false}) pdf: ElementRef;
@ViewChild('tabs', {static: true}) tab: TabStripComponent;
// 'http://africau.edu/images/default/sample.pdf';
public uploadAsPicUrl = 'https://svr2021.lawipac.com:8080/api/v1/upload-as-pdf/default';
public uploadAsPicUrl = '';
public uploadAsPdfUrl = '';
public initAnimation = false;
public iframeLoaded = false;
@@ -42,7 +42,10 @@ export class UploadDetailComponent implements OnInit, AfterViewInit {

public analysisAAA: AnalysisAaaModel[] = [];

constructor(private us: UploadAttachService, private actRoute: ActivatedRoute, private router: Router) { }
constructor(private us: UploadAttachService, private actRoute: ActivatedRoute, private router: Router) {
this.uploadAsPicUrl = location.origin + 'assets/img/no_preview.jpg';
this.uploadAsPdfUrl = location.origin + 'assets/pdf/no_preview.pdf';
}

ngOnInit(): void {
const id = this.actRoute.snapshot.params.id;
@@ -118,7 +121,6 @@ export class UploadDetailComponent implements OnInit, AfterViewInit {
}
const el = this.pdf.nativeElement;
if (el !== undefined && el.src === this.uploadAsPdfUrl) {
console.log('yes true', this);
this.iframeLoaded = true;
}
}

+ 59
- 0
src/app/uploading-progress-card/uploading-progress-card.component.html Visa fil

@@ -0,0 +1,59 @@
<div class="card-wrapper">
<div class="file-type-image" [ngStyle]="{'background-image': 'url('+ icon +')'}"></div>
<kendo-card class="upload-card-content upload-thumb" [width]="'200px'"
[ngStyle]="{'background-image' : 'url(' + thumbImage + ')'}">

<kendo-card-header class="k-hbox">
<p *ngIf="!IsDuplicate"> {{Operation}} <kendo-loader *ngIf="analyzing" size="small" type="converging-spinner"></kendo-loader></p>
<p *ngIf="IsDuplicate"> Removing... <kendo-loader *ngIf="analyzing" size="small" type="converging-spinner"></kendo-loader> </p>
</kendo-card-header>
<kendo-card-body>
<p class="FileName">
{{ ( FileName.length > 17 ) ? (FileName | slice:0:17) + "..." : (FileName)}}
</p>
<p *ngIf="IsDuplicate"> This is Duplicate </p>
<div *ngIf="!IsDuplicate" class="steps">
<div>
<kendo-icon *ngIf="!pdfSuccess" [name]="'file-pdf'" [themeColor]="'error'" class="k-badge-icon"></kendo-icon>
<kendo-icon *ngIf="pdfSuccess" [name]="'check-circle'" [themeColor]="'success'" class="k-badge-icon"></kendo-icon>
<span>
<kendo-loader *ngIf="currentStep === 'pdf'" size="small" type="pulsing"></kendo-loader>
1 pdf convert
</span>
</div>
<div>
<kendo-icon *ngIf="!previewSuccess" [name]="'file-config'" [themeColor]="'error'" class="k-badge-icon"></kendo-icon>
<kendo-icon *ngIf="previewSuccess" [name]="'check-circle'" [themeColor]="'success'" class="k-badge-icon"></kendo-icon>
<span>
<kendo-loader *ngIf="currentStep === 'preview'" size="small" type="pulsing"></kendo-loader>
2 preview
</span>
</div>
<div>
<kendo-icon *ngIf="!thumbSuccess" [name]="'file-txt'" [themeColor]="'error'" class="k-badge-icon"></kendo-icon>
<kendo-icon *ngIf="thumbSuccess" [name]="'check-circle'" [themeColor]="'success'" class="k-badge-icon"></kendo-icon>
<span>
<kendo-loader *ngIf="currentStep === 'thumb'" size="small" type="pulsing"></kendo-loader>
3 miniature
</span>
</div>

<div>
<kendo-icon *ngIf="!analysisSuccess" [name]="'file-ascx'" [themeColor]="'error'" class="k-badge-icon"></kendo-icon>
<kendo-icon *ngIf="analysisSuccess" [name]="'check-circle'" [themeColor]="'success'" class="k-badge-icon"></kendo-icon>
<span>
<kendo-loader *ngIf="currentStep === 'analysis'" size="small" type="pulsing"></kendo-loader>
4 construction
</span>
</div>
</div>
<div *ngIf="IsDuplicate" class="duplicate">DUP</div>
</kendo-card-body>
<kendo-card-footer>
<div>
<kendo-progressbar *ngIf=" Progress>0 && Progress <100" [value]="Progress" > </kendo-progressbar>
</div>
</kendo-card-footer>
</kendo-card>

</div>

+ 110
- 0
src/app/uploading-progress-card/uploading-progress-card.component.scss Visa fil

@@ -0,0 +1,110 @@
$hoverColor: #d0d9ff;
$normalHeaderColor: #01838d;
$normalFooterColor: #10838d;
$speed: 0.5s;

div.card-wrapper{
width:210px;
height: 300px;
padding:10px;
margin-bottom: 20px;

min-height:200px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;


.upload-thumb{
min-height: 100px;
overflow: hidden;
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
}

.file-type-image{
width: 32px;
// border-radius:100%;
background-repeat: no-repeat;
background-size: cover;
// border:1px white solid;
// box-shadow: inset 1px 1px 0 #b7b7b7;

z-index: 2;
height: 32px;
position: absolute;
margin-right: 10px;
left : 160px;
top: 20px;
}

kendo-card {
height: 100%;
box-shadow: 1px 1px 2px white;
border-radius: 10px;
}

.upload-card-content {
p {
z-index: 100;
transition: all 0.3s ease-out;
}

kendo-card-header,
kendo-card-footer{
background-color: $hoverColor;
}

kendo-card-header{
p {
color: black;
}

.file-type-image{
box-shadow: none;
}
}

kendo-card-body {
p {
color: black;
display:block;
background: $hoverColor;
word-break: break-all;
padding: 5px;
border-radius: 5px;

}
}
}

kendo-progressbar{
width:100%;
}


div.duplicate {
width: 80px;
height: 20px;
color: black;
background-color: yellow;
-ms-transform: rotate(45deg);
transform: rotate(
45deg
);
position: absolute;
bottom: 5px ;
left: -25px;
z-index: 10;
}

kendo-stepper{
width: 180px;
}

div.steps{
text-align:left;
}
}

+ 25
- 0
src/app/uploading-progress-card/uploading-progress-card.component.spec.ts Visa fil

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { UploadingProgressCardComponent } from './uploading-progress-card.component';

describe('UploadingProgressCardComponent', () => {
let component: UploadingProgressCardComponent;
let fixture: ComponentFixture<UploadingProgressCardComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ UploadingProgressCardComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(UploadingProgressCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 108
- 0
src/app/uploading-progress-card/uploading-progress-card.component.ts Visa fil

@@ -0,0 +1,108 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {UploadMetaModel} from '../models/uploadMetaModel';
import {UploadAttachService} from '../service/upload.attach.service';

@Component({
selector: 'app-uploading-progress-card',
templateUrl: './uploading-progress-card.component.html',
styleUrls: ['./uploading-progress-card.component.scss']
})
export class UploadingProgressCardComponent implements OnInit {

@Input() MetaId = 0 ;
@Input() FileName = '';
@Input() UniqueId = '';
@Input() Progress = 0 ;
@Input() IsDuplicate = false ;
@Output() Complete: EventEmitter<string> = new EventEmitter<string>();

public Operation = 'Uploading';
public icon = '';
public thumbImage = UploadMetaModel.thumbDefault();
// sub steps after uploading
public thumbSuccess = false;
public pdfSuccess = false;
public previewSuccess = false;
public analysisSuccess = false;
// indicator
public analyzing = false;
public currentStep = '';

private waitingTimer: any;

constructor( private uas: UploadAttachService) { }

ngOnInit(): void {
const suffix = this.FileName.split('.').pop();
this.icon = UploadMetaModel.iconUrlBySuffix(suffix);
this.prePareToStartAnalysis();
return;
}

private prePareToStartAnalysis(): void {
this.waitingTimer = setInterval(
() => {
if ( this.Progress >= 100 && this.MetaId !== 0) {
clearInterval(this.waitingTimer);
this.startAnalysis();
}
}
, 500);
}
public startAnalysis(): void {
this.thumbSuccess = false;
this.pdfSuccess = false;
this.previewSuccess = false;
this.analysisSuccess = false;

this.analyzing = true;
this.Operation = 'Processing';
this.createPdf();
}

private createPdf(): void {
this.currentStep = 'pdf';
this.uas.createPDF(this.MetaId).subscribe(
resp => { this.pdfSuccess = resp; },
error => { this.pdfSuccess = false; this.createPreview(); },
() => { this.createPreview(); }
);
}

private createPreview(): void {
this.currentStep = 'preview';
this.uas.createPreview(this.MetaId).subscribe(
resp => { this.previewSuccess = resp; },
error => { this.previewSuccess = false; this.createThumb(); },
() => { this.createThumb(); }
);
}

private createThumb(): void {
this.currentStep = 'thumb';
this.uas.createThumb(this.MetaId).subscribe(
resp => { this.thumbSuccess = resp; },
error => { this.thumbSuccess = false; this.createAnalysis(); },
() => { this.createAnalysis(); }
);
}


private createAnalysis(): void {
this.currentStep = 'analysis';
this.uas.createAnalysis(this.MetaId).subscribe(
resp => { this.analysisSuccess = true; },
error => { this.analysisSuccess = false; this.endAnalysis(); },
() => { this.endAnalysis(); }
);
}

private endAnalysis(): void{
this.analyzing = false;
this.Operation = 'Done';
this.currentStep = '';
this.Complete.emit(this.UniqueId);
}


}

Binär
src/assets/img/no_preview.jpg Visa fil

Before After
Width: 1654  |  Height: 2339  |  Size: 142KB

Binär
src/assets/img/nopreview-thumb.jpg Visa fil

Before After
Width: 256  |  Height: 362  |  Size: 3.2KB

Binär
src/assets/img/suffix/pdf.png Visa fil

Before After
Width: 512  |  Height: 512  |  Size: 17KB

Binär
src/assets/img/suffix/xls.png Visa fil

Before After
Width: 512  |  Height: 512  |  Size: 15KB

Binär
src/assets/img/suffix/xlsx.png Visa fil

Before After
Width: 512  |  Height: 512  |  Size: 15KB

Binär
src/assets/img/thumb_file_icon.webp Visa fil

Before After

Binär
src/assets/pdf/no_preview.pdf Visa fil


+ 13
- 2
src/index.html Visa fil

@@ -10,13 +10,24 @@
</head>
<body>
<script id="config" type="text/biukop-config"
server="https://svr2021.lawipac.com:8080/api/v1/"
server="https://sc5016.biukop.com.au:8080/"
version="0.9.1"
>
ICB7CiAgICAgICJTZXJ2ZXIiOiAiaHR0cHM6Ly9zdnIyMDIxLmxhd2lwYWMuY29tOjgwODAvYXBpL3YxLyIsCiAgICAgICJTb2NrZXQiOiAid3NzOi8vc3ZyMjAyMS5sYXdpcGFjLmNvbTo4MDgwL2FwaS92MS93cyIKICB9
eyJTZXJ2ZXIiOiJodHRwczpcL1wvYzUwMTYuYml1a29wLmNvbS5h
dTo4MDgwXC9hcGlcL3YxXC8iLCJTb2NrZXQiOiJ3c3M6XC9cL2M1
MDE2LmJpdWtvcC5jb20uYXU6ODA4MFwvYXBpXC92MVwvd3MifQ==
</script>
<app-root></app-root>

<script id="config-svr2021" type="text/biukop-config"
server="https://svr2021.lawipac.com:8080/"
version="0.9.1"
>
eyJTZXJ2ZXIiOiAiaHR0cHM6Ly9zdnIyMDIxLmxhd2lwYWMuY29tO
jgwODAvYXBpL3YxLyIsICJTb2NrZXQiOiAid3NzOi8vc3ZyMjAyMS
5sYXdpcGFjLmNvbTo4MDgwL2FwaS92MS93cyJ9
</script>

</body>

</html>

Laddar…
Avbryt
Spara