import { HttpClient } from '@angular/common/http';
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { CookieService } from 'ngx-cookie-service';
import { throwError } from 'rxjs';
import { catchError, debounceTime } from 'rxjs/operators';
import { AuthService } from 'src/app/auth/auth.service';
import { CacheService } from 'src/app/share/cache.service';
import { ShareService } from 'src/app/share/share.service';
import { environment } from 'src/environments/environment';
import { PictureCroperComponent } from '../picture-croper/picture-croper.component';
import { Picture } from '../picture-manager';
@Component({
selector: 'app-picture-upload',
templateUrl: './picture-upload.component.html',
styleUrls: ['./picture-upload.component.less']
})
export class PictureUploadComponent implements OnInit, OnDestroy {
rsPath = '';
imgSelect = 'imgUpload';
cropperLoading = false;
uploading = false;
uploaded = false;
step = 0;
loadedImage: HTMLImageElement = null;
aspectRatio = 1.618;
resizeToWidth = 900;
resizeToWidth2 = 900;
resizeToHeight = 600;
mode = 'common';
cropper: Cropper = null;
stopJitter = false;
uploadApi = `${environment.host}/picture-manager/upload`;
imageUrl = '';
@ViewChild('file')
file: ElementRef<HTMLInputElement>;
@ViewChild('pictureCroper')
pictureCroper: PictureCroperComponent;
uploadForm!: FormGroup;
constructor(
private fb: FormBuilder,
private http: HttpClient,
private authService: AuthService,
private cookie: CookieService,
private cache: CacheService,
private router: Router,
private shareService: ShareService
) {
this.uploadForm = this.fb.group({
mode: ['common', [Validators.required]],
site: [this.cookie.get('site'), [Validators.required]],
aspectRatio: ['1.618/1', [Validators.required]],
resizeToWidth: ['900', [Validators.required]],
resizeToWidth2: ['900', [Validators.required]],
resizeToHeight: ['600', [Validators.required]],
keywords: [null, [Validators.required]],
});
this.uploadForm.get('mode').valueChanges.subscribe((value: string) => {
if (this.stopJitter) { return; }
this.mode = value;
if (value === 'advance') {
this.aspectRatio = this.resizeToWidth2 / this.resizeToHeight;
} else {
const aspectRatio = this.uploadForm.get('aspectRatio').value;
if (aspectRatio === '0') {
this.aspectRatio = NaN;
} else {
const na = aspectRatio.split('/');
const n1 = Number.parseFloat(na[0]);
const n2 = Number.parseFloat(na[1]);
this.aspectRatio = n1 / n2;
}
}
if (this.cropper) { this.cropper.setAspectRatio(this.aspectRatio); }
});
this.uploadForm.get('aspectRatio').valueChanges.subscribe((value: string) => {
if (this.stopJitter) { return; }
if (this.mode === 'common') {
if (value === '0') {
this.aspectRatio = NaN;
} else {
const na = value.split('/');
const n1 = Number.parseFloat(na[0]);
const n2 = Number.parseFloat(na[1]);
this.aspectRatio = n1 / n2;
}
if (this.cropper) { this.cropper.setAspectRatio(this.aspectRatio); }
}
});
this.uploadForm.get('resizeToWidth').valueChanges.subscribe((value: string) => {
this.resizeToWidth = Number.parseInt(value, 10);
});
this.uploadForm.get('resizeToWidth2').valueChanges.pipe(
debounceTime(500)
).subscribe((value: string) => {
if (this.stopJitter) { return; }
this.resizeToWidth2 = Number.parseInt(value, 10);
if (this.mode === 'advance') {
this.aspectRatio = this.resizeToWidth2 / this.resizeToHeight;
if (this.cropper) { this.cropper.setAspectRatio(this.aspectRatio); }
}
});
this.uploadForm.get('resizeToHeight').valueChanges.pipe(
debounceTime(500)
).subscribe((value: string) => {
if (this.stopJitter) { return; }
this.resizeToHeight = Number.parseInt(value, 10);
if (this.mode === 'advance') {
this.aspectRatio = this.resizeToWidth2 / this.resizeToHeight;
if (this.cropper) { this.cropper.setAspectRatio(this.aspectRatio); }
}
});
this.uploadForm.get('site').valueChanges.subscribe((value: string) => {
this.cookie.set('site', value, new Date('2088-12-12'), undefined, undefined, undefined, 'Lax');
});
}
fileChange(event: InputEvent) {
this.step = 0;
this.loadedImage = null;
if (this.file.nativeElement.value) {
this.step = 1;
const files = this.file.nativeElement.files;
if (files[0]) {
if (window.FileReader) {
this.cropperLoading = true;
const fileReader = new FileReader();
fileReader.addEventListener('load', () => {
this.imageUrl = fileReader.result as string;
}, false);
fileReader.readAsDataURL(files[0]);
} else {
alert('请使用最新版的 Google Chrome 浏览器。');
}
}
}
}
imgSelectChange() {
this.imageUrl = '';
}
cropperReady(ev: boolean) {
if (ev) {
this.cropper = this.pictureCroper.cropper;
this.loadedImage = this.pictureCroper.imageElement;
this.step = 1;
}
}
cropperError(ev: boolean) {
if (ev) {
this.cropper = null;
this.loadedImage = null;
this.step = 0;
}
}
cropperSelectAll() {
this.uploadForm.patchValue({ aspectRatio: '0' });
this.cropper?.setCropBoxData({
left: 0,
top: 0,
width: this.loadedImage.width,
height: this.loadedImage.height
});
}
submitForm() {
this.stopJitter = true;
for (const key in this.uploadForm.controls) {
if (this.uploadForm.controls.hasOwnProperty(key)) {
this.uploadForm.controls[key].markAsDirty();
this.uploadForm.controls[key].updateValueAndValidity();
}
}
const inputOrigin = this.imageUrl.length > 200 ? '' : this.imageUrl;
const cachePicture = this.cache.get<Picture>('outsidePicture');
if (this.uploadForm.valid && this.imageUrl) {
this.step = 2;
this.uploading = true;
const modeWidth = this.mode === 'common' ? this.resizeToWidth : this.resizeToWidth2;
const modeBase64 = this.cropper.getCroppedCanvas({
imageSmoothingEnabled: false,
imageSmoothingQuality: 'high',
}).toDataURL('image/jpeg');
this.http.post(this.uploadApi, {
base64: modeBase64,
width: modeWidth < this.cropper.getData().width ? modeWidth : this.cropper.getData().width,
user: this.authService.user.name || 'system',
keywords: this.uploadForm.value.keywords || '',
origin: inputOrigin || cachePicture?.picture.path || null,
outside: cachePicture?.outside,
site: this.uploadForm.value.site || 'all'
}).pipe(
catchError(() => {
this.uploading = false;
this.stopJitter = false;
alert('图片上传失败,请重新试2-3次,如再不行,请联系lmr。');
return throwError('Something bad happened; please try again later.');
})
).subscribe((res: any) => {
this.uploading = false;
this.uploaded = true;
this.rsPath = res.url;
this.step = 3;
this.stopJitter = false;
});
} else {
setTimeout(() => {
this.stopJitter = false;
}, 550);
}
}
oneMore() {
this.step = 1;
this.uploaded = false;
}
handleTags(tag: string) {
this.uploadForm.patchValue({ keywords: tag });
}
goManager() {
this.router.navigateByUrl('/picture-manager/picture-storehouse');
}
showIntro() {
this.shareService.showIntro().start();
}
ngOnInit(): void {
const cachePicture = this.cache.get<Picture>('outsidePicture');
if (cachePicture) {
this.cropperLoading = true;
this.imgSelect = 'imgSrc';
this.imageUrl = cachePicture.outside ?
cachePicture.picture.path : cachePicture.url;
}
if (!this.cookie.get('intro-picture-upload')) {
setTimeout(() => {
this.showIntro();
this.cookie.set('intro-picture-upload', 'yes', new Date('2088-12-12'), undefined, undefined, undefined, 'Lax');
}, 1500);
}
}
ngOnDestroy() {
if (this.cropper) {
this.cropper.destroy();
this.cropper = undefined;
}
}
}