Commit 050d85cb authored by liujiaxin's avatar liujiaxin

add form

parent cefb9793
......@@ -16,42 +16,42 @@ const compressing = require("compressing");
//Windows系统上'Windows_NT'
let sysType = os.type();
Date.prototype.Format = function (fmt) {
Date.prototype.Format = function(fmt) {
var o = {
"M+": this.getMonth() + 1,
"d+": this.getDate(),
"h+": this.getHours(),
"m+": this.getMinutes(),
"s+": this.getSeconds(),
"q+": Math.floor((this.getMonth() + 3) / 3),
"S": this.getMilliseconds()
"M+" : this.getMonth() + 1,
"d+" : this.getDate(),
"h+" : this.getHours(),
"m+" : this.getMinutes(),
"s+" : this.getSeconds(),
"q+" : Math.floor((this.getMonth() + 3) / 3),
"S" : this.getMilliseconds()
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
function clean(zipPath) {
if (fs.existsSync(zipPath)) {
function clean(zipPath){
if(fs.existsSync(zipPath)){
fs.unlinkSync(zipPath);
}
}
const runSpawn = async function () {
const runSpawn = async function (){
await new Promise(function (resolve, reject) {
await new Promise(function(resolve,reject){
let pkg = require("../package.json");
let ls;
if (sysType === "Windows_NT") {
if(sysType==="Windows_NT"){
//ng build --prod --build--optimizer --base-href /ng-one/
ls = spawn("cmd.exe", ['/c', 'ng', 'build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/']);
} else {
ls = spawn("ng", ['build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/']);
ls = spawn("cmd.exe", ['/c', 'ng', 'build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/'] );
}else{
ls = spawn("ng", ['build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/'] );
}
ls.stdout.on('data', (data) => {
......@@ -66,29 +66,28 @@ const runSpawn = async function () {
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
//要压缩的目录
let zippath = path.resolve(__dirname, "../dist", pkg.name);
let zippath = path.resolve(__dirname,"../dist", pkg.name);
//压缩包的存放目录
let date = new Date();
// let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss");
let zipname = 'form';
let zipdir = path.resolve(__dirname, "../publish/" + zipname + ".zip");
let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss");
let zipdir = path.resolve(__dirname,"../publish/"+zipname+".zip");
clean(zipdir); //删除原有的包
const tarStream = new compressing.zip.Stream();
fs.readdir(zippath, function (err, files) {
if (err) {
fs.readdir(zippath,function(err,files){
if(err){
console.log("======文件打开异常======");
console.log(err);
reject();
}
for (let i = 0; i < files.length; i++) {
tarStream.addEntry(zippath + "/" + files[i]);
for(let i=0;i<files.length;i++){
tarStream.addEntry(zippath+"/"+files[i]);
}
let writeStream = fs.createWriteStream(zipdir);
tarStream.pipe(writeStream);
writeStream.on('close', () => {
console.log(`模板 ${pkg.name} 打包已完成!`);
resolve();
console.log(`模板 ${pkg.name} 打包已完成!`);
resolve();
})
});
......@@ -104,7 +103,7 @@ const runSpawn = async function () {
// }
// projects = process.argv[2];
let exec = async function () {
let exec = async function(){
//压缩模板
await runSpawn();
}
......
This diff is collapsed.
......@@ -24,6 +24,7 @@ import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.com
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons';
import { LrcEditorComponent } from './common/lrc-editor/lrc-editor.component';
registerLocaleData(zh);
......@@ -41,7 +42,8 @@ registerLocaleData(zh);
UploadVideoComponent,
CustomHotZoneComponent,
PlayerContentWrapperComponent
PlayerContentWrapperComponent,
LrcEditorComponent,
],
imports: [
......
This diff is collapsed.
......@@ -32,33 +32,92 @@
<nz-divider style="margin-top: 10px;"></nz-divider>
<div style="margin-top: -20px; margin-bottom: 5px; width: 100%;">
<div style="margin-top: -20px; margin-bottom: 5px">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)">
<label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label>
<label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label>
</nz-radio-group>
</div>
<div *ngIf="customTypeGroupArr">
<nz-radio-group [ngModel]="it.gIdx" (ngModelChange)="customRadioChange($event, it)" style="display: flex; align-items: center; justify-content: center; flex-wrap: wrap;">
<div *ngFor="let group of customTypeGroupArr; let gIdx = index" style="display: flex; ">
<label nz-radio nzValue="{{gIdx}}">{{group.name}}</label>
</div>
</nz-radio-group>
</div>
<div *ngIf="!customTypeGroupArr">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)" style="display: flex; align-items: center; justify-content: center">
<label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label>
<label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label>
</nz-radio-group>
</div>
<div *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="it.itemType == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
<div *ngIf="customTypeGroupArr && customTypeGroupArr[it.gIdx]">
<div *ngIf="customTypeGroupArr[it.gIdx].pic">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].text" style="margin-top: 5px">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].anima" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].audio" style="display: flex;align-items: center; margin-top: 5px">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
</div>
<div style="width: 100%; margin-top: 5px;">
<app-audio-recorder
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
<div *ngIf="!customTypeGroupArr">
<div *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="it.itemType == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="isHasAudio"
style="width: 100%; margin-top: 5px; display: flex; align-items: center; justify-items: center;">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<div *ngIf="it.itemType == 'rect' && isHasAnima" align="center" style="margin-bottom: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
</div>
</div>
</div>
......@@ -83,12 +142,29 @@
<div class="save-box">
<button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
<button style="margin-left: 200px" class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
(click)="saveClick()" >
<i nz-icon nzType="save"></i>
Save
</button>
<div style="height: 40px; display: flex; justify-items: center;" >
<label style="margin-left: 40px" nz-checkbox [(ngModel)]="bgItem.isShowDebugLine">显示辅助框</label>
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyHotZoneData()"> 复制基础数据 </button>
<div style="margin-left: 10px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div>
<!--<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="pasteHotZoneData()" > 粘贴数据 </button>-->
</div>
</div>
......@@ -98,3 +174,50 @@
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label>
<!--龙骨面板-->
<nz-modal [(nzVisible)]="animaPanelVisible" nzTitle="配置资源文件" (nzOnCancel)="animaPanelCancel()" (nzOnOk)="animaPanelOk()" nzOkText="保存">
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
</nz-modal>
......@@ -81,19 +81,21 @@
}
}
h5 {
margin-top: 1rem;
.anima-upload-btn {
padding: 10px;
}
@font-face
{
font-family: 'BRLNSR_1';
src: url("/assets/font/BRLNSR_1.TTF") ;
h5 {
margin-top: 1rem;
}
//
//@font-face
//{
// font-family: 'BRLNSR_1';
// src: url("/assets/font/BRLNSR_1.TTF") ;
//}
......@@ -107,104 +109,3 @@ h5 {
//@import '../../../style/common_mixin';
//
//.p-image-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");
// @include k-img-bg();
// }
// }
//}
//
//.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 {
// 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: #27b43f;
// border-radius: 0.5rem;
// }
//}
//
//
//:host ::ng-deep .ant-upload {
// display: block;
//}
import { EventEmitter } from '@angular/core';
export class AudioDelegate {
audioObj = new Audio();
public audioPlayTimestamp = new EventEmitter();
public audioDataLoaded = new EventEmitter();
public audioPlayBarPosition = new EventEmitter();
public audioPlayEnd = new EventEmitter();
syncAudioCurrentTimeId: number = null;
private arrayBuffer = null;
formatter = new Intl.NumberFormat('en', {
minimumIntegerDigits: 2,
minimumFractionDigits: 3,
maximumFractionDigits: 3,
useGrouping: false,
});
constructor() {
this.audioObj.onloadeddata = this.onAudioDataLoaded.bind(this);
this.audioObj.onplay = this.onAudioPlay.bind(this);
this.audioObj.onpause = this.onAudioPause.bind(this);
this.audioObj.ontimeupdate = this.onAudioTimeUpdate.bind(this);
this.audioObj.onratechange = this.onAudioRateChange.bind(this);
this.audioObj.onended = this.onAudioEnded.bind(this);
this.audioObj.onerror = () => {
};
}
set playbackRate(val) {
this.audioObj.playbackRate = val;
}
set src(val) {
this.audioObj.src = val;
}
get src() {
return this.audioObj.src;
}
convertTagToTime(tag) {
tag = tag.replace('[', '');
tag = tag.replace(']', '');
const parts = tag.split(':');
let h = 0;
let m = 0;
let s = 0;
if (parts.length === 3) {
h = parseInt(parts[0], 10);
m = parseInt(parts[1], 10);
s = parseInt(parts[2], 10);
} else if (parts.length === 2) {
m = parseInt(parts[0], 10);
s = parseFloat(parts[1] );
}
return h * 60 * 60 + m * 60 + s;
}
convertTimeToTag(time, withBracket = true): string {
if (time === undefined) {
return '';
}
const hh = Math.floor(time / 60 / 60)
.toString()
.padStart(2, '0');
const mm = Math.floor(time / 60)
.toString()
.padStart(2, '0');
const ss = this.formatter.format(time % 60);
return withBracket ? `[${hh}:${mm}:${ss}]` : `${hh}:${mm}:${ss}`;
}
setSource(ab) {
this.arrayBuffer = ab;
const blob = new Blob([ab], { type: 'audio/wav' });
this.audioObj.src = URL.createObjectURL(blob);
}
getDataBuffer() {
return this.arrayBuffer;
}
getBufferClip(start, end) {
return this.arrayBuffer.slice(start * this.arrayBuffer.length, end * this.arrayBuffer.length);
}
load() {
this.audioObj.load();
}
syncAudioCurrentTime() {
this.audioPlayTimestamp.emit({
timeFormat: this.convertTimeToTag(this.audioObj.currentTime, false),
time: this.audioObj.currentTime
});
this.syncAudioCurrentTimeId = requestAnimationFrame(() => {
this.syncAudioCurrentTime();
});
}
onAudioDataLoaded(evt) {
console.log('onAudioDataLoaded', evt);
this.audioDataLoaded.emit(this.arrayBuffer);
}
onAudioPlay() {
this.syncAudioCurrentTimeId = requestAnimationFrame(() => {
this.syncAudioCurrentTime();
});
console.log('onAudioPlay');
}
onAudioPause() {
console.log('onAudioPause');
cancelAnimationFrame(this.syncAudioCurrentTimeId);
}
onAudioEnded() {
console.log('onAudioEnded');
this.audioPlayEnd.emit()
cancelAnimationFrame(this.syncAudioCurrentTimeId);
}
onAudioTimeUpdate() {
// console.log('onAudioTimeUpdate', this.convertTimeToTag(this.audioObj.currentTime));
// this.audioPlayTimestamp.emit(this.convertTimeToTag(this.audioObj.currentTime));
}
onAudioRateChange() {
console.log('onAudioRateChange');
}
get isPlaying() {
return !!(this.audioObj.currentTime > 0
&& !this.audioObj.paused
&& !this.audioObj.ended
&& this.audioObj.readyState > 2);
}
currentTimeFormatted(time?) {
let t = this.audioObj.currentTime;
if (typeof time !== 'undefined') {
t = time;
}
return this.convertTimeToTag(t);
}
get currentTime() {
return this.audioObj.currentTime;
}
set currentTime(val) {
this.audioPlayBarPosition.emit({
time: val
});
this.audioObj.currentTime = val;
}
get duration() {
return this.audioObj.duration;
}
get durationFormatted() {
return this.convertTimeToTag(this.audioObj.duration, false);
}
get currentSrc() {
return this.audioObj.currentSrc;
}
pause() {
this.audioObj.pause();
}
async play() {
return this.audioObj.play();
}
}
import { EventEmitter } from '@angular/core';
export class DragElement {
onMove = new EventEmitter();
canMove = false;
dragEl = null;
relX = 0;
private readonly bindMove: any;
private readonly maxWidth: any;
private readonly bindDown: any;
private readonly bindUp: any;
constructor(el, maxWidth) {
this.dragEl = el;
this.maxWidth = maxWidth;
this.bindMove = this.move.bind(this);
this.bindDown = this.down.bind(this);
this.bindUp = this.up.bind(this);
this.dragEl.addEventListener('mousedown', this.bindDown, false);
document.addEventListener('mouseup', this.bindUp, false);
}
dispose() {
this.dragEl.removeEventListener('mousedown', this.bindDown, false);
}
down(e) {
document.addEventListener('mousemove', this.bindMove, false);
// relX = e.pageX - this.timeLine.offsetWidth || 0;
// const left = parseInt(el.offsetWidth|| 0)
const matrix = new DOMMatrix(this.dragEl.style.transform);
this.relX = e.pageX - matrix.m41 || 0;
this.canMove = true;
}
up(e) {
this.canMove = false;
document.removeEventListener('mousemove', this.bindMove, false);
}
move(e) {
if (!this.canMove) {
return;
}
const matrix = new DOMMatrix(this.dragEl.style.transform);
const w = matrix.m41;
if (w > this.maxWidth) {
this.dragEl.style.transform = `translateX(${this.maxWidth}px)`;
return;
}
if (w < 0 ) {
this.dragEl.style.transform = `translateX(0px)`;
return;
}
// this.dragEl.style.transform = `translateX(${(e.pageX - this.relX)}px)`;
this.onMove.emit({
position: e.pageX - this.relX,
});
}
}
<div class="cmp-lrc-editor" >
<div id="step2" class="step" >
<nz-spin [nzSpinning]="isLoadingAudioBuffer" style="width: 100%;height: 100%;">
<div class="content">
<div class="center" >
<div style="display: flex; line-height: 36px;">
<span style="margin-right: 20px">{{currentAudioTime}}/{{currentAudioDuration}}</span>
&nbsp;
<app-audio-recorder [audioUrl]="LRCData.audio_url"
(audioUploaded)="onAudioUploaded($event)"></app-audio-recorder>
&nbsp;
<button nz-button nzSize="default"
nzType="primary"
nz-tooltip nzTooltipTitle="上剪头播放暂停,下箭头打点,左右剪头微调"
(click)="togglePlayAudio($event)">
<ng-container *ngIf="isPlaying"><i nz-icon nzType="pause" nzTheme="outline"></i>暂停(上箭头)</ng-container>
<ng-container *ngIf="!isPlaying"><i nz-icon nzType="caret-right" nzTheme="outline"></i>播放(上箭头)</ng-container>
</button>
&nbsp;
<button nz-button nzSize="default"
nzType="primary"
nz-tooltip nzTooltipTitle="上剪头播放暂停,下箭头打点,左右剪头微调"
id="enterbtn"
(click)="setTimestampPoint()">打点(下箭头)</button>
&nbsp;
<button nz-button nzSize="default"
nzType="danger"
(click)="saveUserData()"><i nz-icon nzType="cloud-upload" nzTheme="outline"></i>保存</button>
</div>
<div style="display: flex; line-height: 36px;">
<span>播放速度:</span>&nbsp;
<span style="width: 150px;">
<nz-slider [(ngModel)]="playbackRate"
(ngModelChange)="changePlaybackRate($event)"
[nzMax]="2" [nzMin]="0.25" [nzStep]="0.25"></nz-slider>
</span>
<label style="margin-right: 20px;margin-left: 20px">文字大小: <nz-input-number [(ngModel)]="LRCData.fontSize" [nzMin]="1" [nzMax]="100" [nzStep]="1"></nz-input-number></label>
<label style="">行高: <nz-input-number [(ngModel)]="LRCData.lineHeight" [nzMin]="1" [nzMax]="100" [nzStep]="1"></nz-input-number></label>
<input type="file" onclick="this.value=null;" accept=".lrc" style="display: none" #uploadBtn>
<button [disabled]="!LRCData.audio_url" nz-button nzType="link" (click)="uploadLRC()">上传LRC文件</button>
<nz-select [(ngModel)]="lrcFileEncoding" (ngModelChange)="changeLrcFileEncoding($event)">
<nz-option nzValue="UTF-8" nzLabel="UTF-8"></nz-option>
<nz-option nzValue="GB18030" nzLabel="GB18030"></nz-option>
</nz-select>
</div>
<!-- <span>{{currentAudioTime}}/{{currentAudioDuration}}</span>-->
<!-- <nz-radio-group (ngModelChange)="changeMode($event)" [(ngModel)]="LRCData.mode" class="mode">-->
<!-- <label nz-radio [nzValue]="MODE.TEXT">文本模式</label>-->
<!-- <label nz-radio [nzValue]="MODE.IMAGE">图片模式</label>-->
<!-- </nz-radio-group>-->
<!-- <span style="width: 150px;">-->
<!-- <nz-slider [(ngModel)]="playbackRate"-->
<!-- (ngModelChange)="changePlaybackRate($event)"-->
<!-- [nzMax]="2" [nzMin]="0.25" [nzStep]="0.25"></nz-slider>-->
<!-- </span>-->
</div>
<div class="timestamp-container">
<ng-template #insertLineContentTemplate>
<div>
<p>Content</p>
<p>Content</p>
</div>
</ng-template>
<div class="timestamp-line"
(click)="selectTimePoint(i)"
[ngClass]="{selected: selectHighlightTimePointIndex === i}"
*ngFor="let item of timePointData; let i = index">
<div class="time-tag" [ngClass]="{warn: item.warn}">{{item.timeFormatted}}</div>
<div class="add-line" style="margin-right: 4px;">
<button nz-tooltip nzTooltipTitle="向后插入一行" nz-button nzType="danger" nzSize="small" nzShape="circle"
(click)="insertTimePoint(i)">
<i nz-icon nzType="plus" nzTheme="outline"></i>
</button>
</div>
<div class="time-content">
<!-- <app-upload-image-with-preview-->
<!-- [picUrl]="item.data"-->
<!-- (imageUploaded)="onImageUploadSuccess($event)"-->
<!-- ></app-upload-image-with-preview>-->
<input nz-input [(ngModel)]="item.data" />
</div>
<div class="line-break">
<label nz-checkbox nz-tooltip nzTitle="添加换行" [(ngModel)]="item.newLine"></label>
</div>
<div class="time-del">
<button nz-button nzType="primary" nzSize="small" nzShape="circle" (click)="removeTimePoint(i)">
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</div>
</div>
</div>
</div>
</nz-spin>
</div>
<div class="wave-player" [ngStyle]="{visibility: LRCData.audio_url ? 'visible' : 'hidden'}" >
<canvas #waveEl autofocus></canvas>
<div class="time-line" #timeLineEl>
<div class="ctrl-bar">
</div>
<div class="play-bar"></div>
</div>
<div class="point-line">
<div *ngFor="let item of timePointData; let i = index"
[ngStyle]="{transform: item.position, zIndex: selectHighlightTimePointIndex === i ? 1 : 0}">
<div class="arrow-up"
nzTrigger="click"
nzTitle="⇽⇾左右方向键可以微调该时间点"
nzPlacement="bottom"
nz-tooltip
[ngClass]="{selected: selectHighlightTimePointIndex === i}">
<div class="ctrl-bar" (click)="selectTimePoint(i)"></div>
</div>
</div>
</div>
<!-- [nzDisabled]="isScaleTimeLine"-->
<nz-slider nzRange style="flex: 1" [nzTipFormatter]="formatter" [nzStep]="0.01" [nzMax]="timeRangeObj.max" [nzMin]="timeRangeObj.min"
(nzOnAfterChange)="timeRangeAfterChange($event)"
[(ngModel)]="timeRangeSelector"></nz-slider>
<div style="width: 100%;
position: relative;
height: 30px;
display: flex;
flex-direction: row-reverse;">
<!-- *ngIf="!isScaleTimeLine"-->
<!-- *ngIf="isScaleTimeLine"-->
<button [disabled]="!isScaleTimeLine" style="margin-right: 8px;" nz-button nzSize="small"
(click)="restoreTimeLine()"
nzType="primary">
返回</button>
<button style="margin-right: 8px;" nz-button nzSize="small"
(click)="scaleTimeLine()"
nzType="primary">
缩放时间轴</button>
</div>
</div>
</div>
@import '../../style/common_mixin.css';
:host ::ng-deep .cmp-lrc-editor .ant-spin-container {
width: 100%;
height: 100%;
}
.cmp-lrc-editor{
width: 100%;
.step{
width: 100%;
height: 500px;
position: relative;
.content{
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
}
.flex1{
flex: 1;
}
.wave-player{
display: inline-block;
position: relative;
width: 100%;
canvas{
width: 100%;
height: 100px;
}
}
.time-line{
height: 100%;
position: absolute;
border: 0;
top: 0;
opacity: 0.5;
width: 0px;
z-index: 1;
}
.line-break{
margin: 0 4px 0 8px;
}
.time-tag.warn{
background: firebrick;
}
.time-tag:after {
content: "\27A4";
}
.timestamp-container{
width: 100%;
flex: 1;
overflow: auto;
}
.timestamp-line.selected{
background: green;
}
.timestamp-line{
display: flex;
margin: 2px 0;
height: 36px;
line-height: 36px;
.time-tag{
flex: 0;
margin-right: 4px;
}
.time-content{
flex: 1;
}
.time-del{
margin-left: 4px;
flex: 0;
}
}
.ctrl-bar{
height: 100%;
width: 0px;
transform: translateX(50%);
position: absolute;
cursor: ew-resize;
user-select: none;
padding: 0 2px;
box-shadow: 0.5px 0 0 blue;
}
.point-line{
position: relative;
height: 5px;
.arrow-up.selected{
border-bottom-color: #faad14;
}
.arrow-up {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
position: absolute;
border-bottom: 5px solid black;
//transform: translateX(-100%);
.ctrl-bar{
bottom: 0;
transform: translateX(-100%);
box-shadow: 0.5px 0 0 blue;
height: 100px;
position: absolute;
}
}
}
}
This diff is collapsed.
......@@ -6,30 +6,3 @@
height: 100%;
}
.radioPaire {
float: left;
margin: 3px;
border-style: dashed;
border-color: #000;
border-width: 1px;
}
.border {
border-radius: 20px;
border-style: dashed;
padding: 20px;
margin: 20px;
/*width: 500px; */
/*//border-radius: 20px;*/
/*//border-width: 2px;*/
/*//border-color: #000000;*/
}
.border-lite {
border: 2px dashed #ddd;
border-radius: 0.5rem;
padding: 10px;
margin: 10px;
}
<div class="model-content">
<div style="padding: 10px;">
<div style="width: 300px;" align='center'>
<span>图1: </span>
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')">
</app-upload-image-with-preview>
</div>
<div style="width: 300px; margin-top: 5px;" align='center'>
<span>图2: </span>
<app-upload-image-with-preview
[picUrl]="item.pic_url_2"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url_2')">
</app-upload-image-with-preview>
</div>
<nz-divider nzText="配置歌词"></nz-divider>
<div style="width: 300px; margin-top: 15px;">
<span>文本: </span>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
</div>
<app-lrc-editor [LRCData]="item.lrcData" (editFinished)="getLRC($event)">
</app-lrc-editor>
<nz-divider nzText="配置伴奏音频"></nz-divider>
<div style="padding: 0 20px;">
<app-audio-recorder
style="margin-top: 5px"
[audioUrl]="item.accompany_audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'accompany_audio_url', item)"
></app-audio-recorder>
</div>
<nz-divider nzText="显示配置"></nz-divider>
<div *ngIf="item.lrcData" style="padding: 20px">
<app-custom-hot-zone
[bgItem]="bgItem"
[hotZoneItemArr]="hotZoneItemArr"
[customTypeGroupArr]="customTypeGroupArr"
(save)="saveHotZone($event)"
>
</app-custom-hot-zone>
<div style="margin-top: 30px;">
<div style="display: flex; flex-wrap: wrap">
<div *ngFor="let it of picArr; let i = index" style="padding: 10px">
<div style="width: 230px; height: 240px; border: 1px solid #ccc; border-radius: 10px; padding: 5px; display: flex; align-items: center; flex-direction: column">
<div style="width: 230px; height: 40px; position: absolute;" align="right">
<button style="margin-top: 5px; margin-right: 5px" nz-button nzSize="small" nzType="danger" (click)="deletePic(i)">
<i nz-icon nzType="close" nzTheme="outline"></i>
</button>
</div>
<h3 align="center" style="margin-top: 5px">item-{{i + 1}}</h3>
<div style="width: 90%">
<app-upload-image-with-preview
[picUrl]="it.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url', it)"
></app-upload-image-with-preview>
</div>
<input type="text" nz-input [(ngModel)]="it.text" (blur)="save()" style="width: 80%;margin-top: 5px">
<app-audio-recorder
style="margin-top: 5px"
[audioUrl]="it.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url', it)"
></app-audio-recorder>
</div>
</div>
<div style="padding: 10px">
<button style="width: 230px; height: 240px; padding: 5px;" nz-button nzType="dashed" (click)="addPic()">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>添加底部item
</button>
</div>
</div>
<div style="margin-top: 5px">
<span>音频: </span>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
</div>
</div>
<!--<div style="position: absolute; left: 200px; top: 100px; width: 800px;">-->
<!--<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">-->
<!--<app-upload-image-with-preview-->
<!--[picUrl]="item.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="item.audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"-->
<!--&gt;</app-audio-recorder>-->
<!--<app-custom-hot-zone></app-custom-hot-zone>-->
<!--<app-upload-video></app-upload-video>-->
<!--<app-lesson-title-config></app-lesson-title-config>-->
<!--</div>-->
</div>
import { Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef } from '@angular/core';
import { JsonPipe } from '@angular/common';
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core';
import {NzMessageService} from "ng-zorro-antd";
@Component({
......@@ -10,38 +11,58 @@ import { JsonPipe } from '@angular/common';
export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用
saveKey = "test_001";
saveKey = 'cocos_karaoke';
// 储存对象
item;
constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
}
bgItem = {};
hotZoneItemArr = [];
animaArr = [];
picArr;
customTypeGroupArr = [
{
name: '基础资源',
rect: true,
anima: true,
audio: true,
pic: true,
text: true,
},
{
name: '图片',
pic: true
},
{
name: '歌词区域',
rect: true,
},
{
name: '播放按钮',
rect: true,
},
{
name: '模式切换按钮',
rect: true,
}
]
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef, private message: NzMessageService) {
createShell() {
this.item.wordList.push({
word: '',
audio: '',
backWord: '',
backWordAudio: '',
});
this.save();
}
removeShell(idx) {
this.item.wordList.splice(idx, 1);
this.save();
}
ngOnInit() {
this.item = {};
// 获取存储的数据
(<any>window).courseware.getData((data) => {
(<any> window).courseware.getData((data) => {
// console.log(1, data);
if (data) {
this.item = data;
// console.log(2, data);
}
this.init();
......@@ -50,16 +71,26 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
this.refresh();
}, this.saveKey);
}
ngOnChanges() {
}
ngOnDestroy() {
}
init() {
this.bgItem = this.item.bgItem || {};
this.hotZoneItemArr = this.item.hotZoneItemArr || [];
this.animaArr = this.item.animaArr || [];
this.picArr = this.item.picArr || [];
this.refreshAnimaArr();
}
......@@ -67,39 +98,93 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key) {
onImageUploadSuccess(e, key, it) {
this.item[key] = e.url;
this.save();
it[key] = e.url;
this.save();
}
/**
* 储存音频数据
* @param e
*/
onAudioUploadSuccess(e, key) {
this.item[key] = e.url;
onAudioUploadSuccess(e, key, it) {
it[key] = e.url;
this.save();
}
onWordAudioUploadSuccess(e, idx) {
this.item.wordList[idx].audio = e.url;
saveHotZone(e) {
console.log('e: ', e);
const {bgItem, hotZoneItemArr} = e;
this.bgItem = bgItem;
this.hotZoneItemArr = hotZoneItemArr;
this.item.bgItem = bgItem;
this.item.hotZoneItemArr = hotZoneItemArr;
this.refreshAnimaArr();
this.save();
this.message.create(
'success',
'保存成功'
);
}
onBackWordAudioUploadSuccess(e, idx) {
this.item.wordList[idx].backWordAudio = e.url;
refreshAnimaArr() {
const tmpArr = [];
this.hotZoneItemArr.forEach((item) => {
let data = this.animaArr.find((anima) => {
return anima.id === item.id;
});
if (!data) {
data = this.createAnimaData(item);
}
tmpArr.push(data);
});
this.animaArr = tmpArr;
}
createAnimaData(hotZoneItem) {
const animaData = {};
animaData['id'] = hotZoneItem.id;
return animaData;
}
addPic() {
this.picArr.push({
pic_url: '',
audio_url: '',
text: ''
});
this.item.picArr = this.picArr;
this.save();
}
deletePic(i) {
this.picArr.splice(i, 1);
this.item.picArr = this.picArr;
this.save();
}
/**
* 储存数据
*/
save() {
(<any>window).courseware.setData(this.item, null, this.saveKey);
console.log('this.item: ', this.item);
console.log('this.item json: ', JSON.stringify(this.item) );
(<any> window).courseware.setData(this.item, null, this.saveKey);
this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
}
/**
......@@ -110,5 +195,10 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
this.appRef.tick();
}, 1);
}
getLRC(evt) {
this.item.lrcData = evt;
this.save();
}
}
}
\ No newline at end of file
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
This diff is collapsed.
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