Commit a4d93283 authored by limingzhe's avatar limingzhe

add upload-video

parent d8b62a10
......@@ -21,6 +21,9 @@ import { registerLocaleData } from '@angular/common';
import zh from '@angular/common/locales/zh';
import {UploadImageWithPreviewComponent} from "./common/upload-image-with-preview/upload-image-with-preview.component";
import {BackgroundImagePipe} from "./pipes/background-image.pipe";
import {UploadVideoComponent} from "./common/upload-video/upload-video.component";
import {ResourcePipe} from "./pipes/resource.pipe";
import {TimePipe} from "./pipes/time.pipe";
registerLocaleData(zh);
@NgModule({
......@@ -32,6 +35,9 @@ registerLocaleData(zh);
AudioRecorderComponent,
UploadImageWithPreviewComponent,
BackgroundImagePipe,
ResourcePipe,
TimePipe,
UploadVideoComponent,
PlayerContentWrapperComponent
],
......
<div class="up-video" style="display: flex;">
<!--<nz-upload class="" [nzDisabled]="!showUploadBtn"-->
<!--[nzShowUploadList]="false"-->
<!--[nzBeforeUpload]="beforeUpload"-->
<!--nzAccept = ".mp4"-->
<!--style="margin-right: 1rem">-->
<nz-upload class="p-image-uploader" [nzDisabled]="uploading"
[nzShowUploadList]="false"
nzAccept = ".mp4"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="handleChange($event)"
style="margin-right: 1rem">
<button type="button" nz-button nzType="default" *ngIf="showUploadBtn" [disabled]="uploading"
[nzLoading]="uploading" >
<i nz-icon type="plus" theme="outline"></i>
<span>{{ uploading ? 'Uploading' : 'Select Video' }}</span>
<!--<span>Select Video</span>-->
</button>
</nz-upload>
<!--<button nz-button nzType="primary" *ngIf="showUploadBtn"-->
<!--style="margin-right: 1rem"-->
<!--type="button"-->
<!--[nzLoading]="uploading"-->
<!--(click)="handleUpload()"-->
<!--[disabled]="!videoFile || uploading">-->
<!--<i nz-icon type="upload" theme="outline"></i>-->
<!--<span>{{ uploading ? 'Uploading' : 'Start Upload' }}</span>-->
<!--</button>-->
<!--
<button type="button"
(click)="extraCover()"
nz-button nzType="default"
[disabled]=" !(videoUrl && videoUrl.constructor.name === 'String')">设置封面</button>
-->
<!--
<nz-divider></nz-divider>
<div [style.display]="!uploading?'none':''" style="position:relative">
<div style="width: calc( 100% - 20px);">
<nz-progress [nzPercent]="progress">
</nz-progress>
</div>
<i (click)="cancelUpload()" class="anticon anticon-close-circle" style="position: absolute;top: 50%;right: 0;transform: translateY(-50%);cursor: pointer"></i>
</div>
-->
</div>
<div class="p-box d-flex align-items-center p-video-uploader" style="top: 20px;">
<div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading">
<i nz-icon type="upload" theme="outline"></i>
<div class="m-3"></div>
<span>Click here to upload video</span>
<div class="mt-5 p-progress-bar" *ngIf="uploading">
<div class="p-progress-bg" [style.width]="progress*0.2+'rem'"></div>
<div class="p-progress-value">{{progress}}%</div>
</div>
</div>
<div class="p-upload-progress-bg dddd " *ngIf="uploading"
[ngClass]="{'smart-bar': showUploadBtn}" >
<div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text">
<fa name="cloud-upload"></fa>
Uploading...
</div>
</div>
<div class="p-upload-check-bg" *ngIf="checking">
<div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text">
<fa name="cloud-upload"></fa>
<i nz-icon type="loading" theme="outline"></i>Checking...
</div>
</div>
<div class="p-preview" *ngIf="!showUploadBtn && !uploading && videoUrl " >
<!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>-->
<video [src]="safeVideoUrl(videoUrl)" controls #videoNode (loadedmetadata)="videoLoadedMetaData()"></video>
</div>
</div>
<div [style.display]="!checkVideoExists?'none':''">
<span><i nz-icon type="loading" theme="outline"></i> checking file to upload</span>
</div>
@import '../../style/common_mixin';
.p-video-uploader {
position: relative;
display: block;
width: 100%;
height: 0;
padding-bottom: 56.25%;
.p-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 2px dashed #ddd;
//border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.p-upload-icon {
text-align: center;
margin: auto;
.anticon-upload {
color: #888;
font-size: 5rem;
}
.p-progress-bar {
position: relative;
width: 20rem;
height: 1.5rem;
border: 1px solid #ccc;
border-radius: 1rem;
.p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-value {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-shadow: 0 0 4px #000;
color: white;
text-align: center;
font-size: 0.9rem;
line-height: 1.5rem;
}
}
}
.p-preview {
width: 100%;
height: 100%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
video{
max-height: 100%;
max-width: 100%;
}
}
}
}
.p-btn-delete {
position: absolute;
right: -0.5rem;
top: -0.5rem;
width: 2rem;
height: 2rem;
border: 0.2rem solid white;
border-radius: 50%;
font-size: 1.2rem;
background-color: #fb781a;
color: white;
text-align: center;
}
.p-upload-progress-bg, .p-upload-check-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #1890ff;
//border-radius: 0.5rem 0 0 0.5rem;
}
}
.p-upload-progress-bg.smart-bar{
height: 50px!important;
margin-top: 20px!important;
}
.p-upload-check-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #17a2b8;
//border-radius: 0.5rem 0 0 0.5rem;
}
}
//:host ::ng-deep .ant-upload {
// display: block;
//}
import {Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SecurityContext, ViewChild} from '@angular/core';
import {NzMessageService, UploadFile} from 'ng-zorro-antd';
import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
@Component({
selector: 'app-upload-video',
templateUrl: './upload-video.component.html',
styleUrls: ['./upload-video.component.scss']
})
export class UploadVideoComponent implements OnChanges, OnDestroy {
uploading = false;
checking = false;
checkVideoExists = false;
uploadClicked = false;
@Input()
videoFile = null;
uploaderInst = null;
progress = 0;
// @Input()
// setCovering = false;
@Input()
videoUrl = '';
@ViewChild('videoNode')
videoNode: ElementRef;
// @Input()
// extractCoverFunc = null;
@Output()
videoUploaded = new EventEmitter();
@Output()
videoUploadFailure = new EventEmitter();
@Output()
extractVideoCover = new EventEmitter();
@Input()
showUploadBtn = true;
@Input()
item: any;
// videoItem = null;
uploadUrl = (<any> window).courseware.uploadUrl();
uploadData = (<any> window).courseware.uploadData();
constructor(private nzMessageService: NzMessageService,
private sanitization: DomSanitizer
// private cwService: _coursewareService,
// private resService: ResourceService
) {
this.uploading = false;
this.videoFile = null;
}
ngOnChanges() {
// if (!this.videoFile || this.showUploadBtn) {
// return;
// }
// this.beforeUpload(this.videoFile);
// this.handleUpload();
}
ngOnDestroy(): void {
URL.revokeObjectURL(this.videoUrl);
}
safeVideoUrl(url) {
console.log(url)
return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`;
}
videoLoadedMetaData() {
}
handleChange(info: { type: string, file: UploadFile, event: any }): void {
console.log('info:' , info);
switch (info.type) {
case 'start':
// this.beforeUpload(info.file);
if (!this.checkSelectFile(info.file)) {
return;
}
this.uploading = true;
this.progress = 0;
break;
case 'success':
this.uploadSuccess(info.file);
// this.beforeUpload(info.file);
// this.uploadSuccess(info.file);
break;
case 'progress':
this.progress = parseInt(info.event.percent, 10);
this.doProgress(this.progress);
break;
}
}
checkSelectFile(file) {
if (!file.lastModified) {
return false;
}
const delta = 500;
const isOverSize = (file.size / 1024 / 1024) < delta;
if (!isOverSize) {
this.nzMessageService.error(`video must smaller than ${delta}MB!`);
return false;
}
return true;
}
checkHashFinish = (hash) => {
this.checking = false;
this.uploading = true;
}
uploadSuccess = (file) => {
this.nzMessageService.info('Upload Success');
// this.updateStatus(false);
this.uploading = false;
this.videoFile = null;
// this.updateSource(url);
this.videoUrl = file.response.url;
// console.log(this.picUrl)
// this.uploadFinished(url);
// if (!inOSS) {
const vid = document.createElement('video');
vid.addEventListener('loadedmetadata', () => {
const height = vid.videoHeight;
const width = vid.videoWidth;
let duration = vid.duration;
if (duration) {
duration = duration * 1000;
}
file['height'] = height;
file['width'] = width;
file['duration'] = duration;
vid.preload = 'none';
vid.src = '';
vid.remove();
this.videoUploaded.emit(file.response);
// this.resService.updateVideo(id, {width, height, duration}).then( () => {
// this.videoUploaded.emit({res_id: id, id, name, hash, url});
// });
});
vid.src = file.response.url;
// } else {
// this.videoUploaded.emit(file.response);
// }
}
uploadFailure = (err, file) => {
this.uploading = false;
if (err.name && err.name === 'cancel') {
return;
}
console.log(err);
this.nzMessageService.error('Upload Error ' + err.message);
this.videoUploadFailure.emit(file);
}
doProgress = (p) => {
if (p > 1) {
p = 1;
}
if (p < 0) {
p = 0;
}
// console.log(Math.floor(p * 100));
this.progress = Math.floor(p * 100);
}
}
import {Pipe, PipeTransform} from '@angular/core';
// import {ElectronUtil} from '../util/ElectronUtil';
declare const APP_PATH;
// const isInElectron = localStorage.getItem('electron');
@Pipe({
name: 'resource'
})
export class ResourcePipe implements PipeTransform {
transform(pic_url: any, coursewareSid?: string): string {
// return pic_url;
if (pic_url && typeof pic_url === 'object') {
return pic_url;
}
// console.log('resource', pic_url)
return `${pic_url}?t=${Math.random()}`;
// let ret = value ? `/api/resource/${value}/file` : '';
// let ret = res_id ? `/resource/audio/${res_id}` : '';
// if (isInElectron && ElectronUtil.hasCached(coursewareSid, res_id)) {
// ret = `file://${APP_PATH}/courseware_cache/${coursewareSid}/${res_id}`;
// }
// return ret;
}
}
import {Pipe, PipeTransform} from '@angular/core';
import * as _ from 'lodash';
@Pipe({
name: 'time'
})
export class TimePipe implements PipeTransform {
transform(value: any, args?: any): any {
let ret = '00:00';
if (_.isNumber(value) && value > 0) {
const minutes = Math.floor(value / 60);
const seconds = Math.floor(value % 60);
ret = _.padStart(minutes, 2, '0') + ':' + _.padStart(seconds, 2, '0');
}
return ret;
}
}
......@@ -8,81 +8,81 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<script>
<script>
window.courseware = (function(){
if(window.parent.net){
window.net = window.parent.net;
var id = window.frameElement.getAttribute("dataid");
return {
getData: function(callback){
net.getData("getCoursewareData",id,function(res){
if(res){
res = JSON.parse(res);
if(res.msg==="success"){
let callData = null;
if(res.data&&res.data!='null'){
callData = JSON.parse(res.data);
}
callback&&callback(callData);
}else{
alert('数据加载失败!');
window.courseware = (function(){
if(window.parent.net){
window.net = window.parent.net;
var id = window.frameElement.getAttribute("dataid");
return {
getData: function(callback, key=''){
net.getData("getCoursewareData",id,function(res){
if(res){
res = JSON.parse(res);
if(res.msg==="success"){
let callData = null;
if(res.data&&res.data!='null'){
callData = JSON.parse(res.data);
}
callback&&callback(callData);
}else{
alert('数据加载失败!');
}
});
},
setData: function(data,callback){
let str = JSON.stringify(data);
net.getData("setCoursewareData",{id: id,data: str},function(res){
if(res){
res = JSON.parse(res);
if(res.msg==="success"){
callback&&callback();
}else{
alert('数据保存失败!');
}
}else{
alert('数据加载失败!');
}
});
},
setData: function(data,callback, key=''){
let str = JSON.stringify(data);
net.getData("setCoursewareData",{id: id,data: str},function(res){
if(res){
res = JSON.parse(res);
if(res.msg==="success"){
callback&&callback();
}else{
alert('数据保存失败!');
}
});
},
uploadUrl: function(){
return net.getUploadFileURL();
},
uploadData: function(){
return net.getAjaxData("uploadFile","");
}
}
} else {
return {
getData: function(callback){
let data = localStorage.getItem("courseware_data");
if(data){
data = JSON.parse(data);
}else{
alert('数据保存失败!');
}
callback&&callback(data);
},
setData: function(data,callback){
console.log("******local********");
localStorage.setItem("courseware_data",JSON.stringify(data));
callback&&callback();
},
uploadUrl: function(){
return 'http://localhost:3000/api/test';
},
uploadData: function(){
return {};
});
},
uploadUrl: function(){
return net.getUploadFileURL();
},
uploadData: function(){
return net.getAjaxData("uploadFile","");
}
}
} else {
return {
getData: function(callback, key=''){
let data = localStorage.getItem("courseware_data_" + key);
if(data){
data = JSON.parse(data);
}
callback&&callback(data);
},
setData: function(data,callback, key=''){
console.log("******local********");
localStorage.setItem("courseware_data_" + key,JSON.stringify(data));
callback&&callback();
},
uploadUrl: function(){
return 'http://localhost:3000/api/test';
},
uploadData: function(){
return {};
}
}
})();
</script>
}
})();
</script>
</head>
<body>
<app-root></app-root>
</body>
<app-root></app-root>
</body>
</html>
......@@ -89,7 +89,10 @@
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"no-trailing-whitespace": false,
"variable-name": false
"variable-name": false,
"no-unused-expression": false,
"align": false
},
"rulesDirectory": [
"codelyzer"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment