Commit a4b98f66 authored by 范雪寒's avatar 范雪寒

feat: form

parent 3d36cbfc
...@@ -128,5 +128,8 @@ ...@@ -128,5 +128,8 @@
} }
} }
}, },
"defaultProject": "ng-template-generator" "defaultProject": "ng-template-generator",
} "cli": {
"analytics": false
}
}
\ No newline at end of file
This diff is collapsed.
...@@ -55,4 +55,4 @@ ...@@ -55,4 +55,4 @@
"tslint": "~5.18.0", "tslint": "~5.18.0",
"typescript": "~3.7.5" "typescript": "~3.7.5"
} }
} }
\ No newline at end of file
import { ApplicationRef, ChangeDetectorRef, ElementRef, ViewChild } from "@angular/core";
import { MetaFormCreator } from "./mataFormCreator";
export class ComponentBase {
// 储存数据用
saveKey = "";
// 储存对象
item: any = {};
ngOnChanges() { }
ngOnDestroy() { }
constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) { }
ngOnInit() {
// 获取存储的数据
(<any>window).courseware.getData((data) => {
if (data) {
this.item = data;
this.itemStr = JSON.stringify(this.item, null, 4).trim();
}
this.init();
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}, this.saveKey);
}
@ViewChild("itemTextarea", { static: true }) itemTextarea: ElementRef;
copyData() {
this.itemTextarea.nativeElement.select();
document.execCommand("copy");
}
/**
* 储存图片数据
* @param e
*/
onAssetUploadSuccess(e: any, ...key: Array<string>) {
let item = this.item;
for (let i = 0; i < key.length; i++) {
if (i + 1 == key.length) {
item[key[i]] = e.url;
this.save();
return;
}
item = item[key[i]];
}
}
save() {
(<any>window).courseware.setData(this.item, null, this.saveKey);
this.itemStr = JSON.stringify(this.item, null, 4).trim();
this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
}
itemStr = "";
load() {
this.itemStr = this.itemTextarea.nativeElement.value;
if (this.isJSON(this.itemStr)) {
this.item = JSON.parse(this.itemStr);
this.init();
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}
}
isJSON(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
if (typeof obj == 'object' && obj) {
return true;
}
return false;
} catch (e) {
return false;
}
}
return false;
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
init() { }
}
...@@ -33,3 +33,30 @@ ...@@ -33,3 +33,30 @@
padding: 10px; padding: 10px;
margin: 10px; margin: 10px;
} }
.button-right {
border-style: dotted;
border-color: rgb(42, 142, 72);
width: 100px;
height: 50px;
color: rgb(42, 142, 72);
background-color: white;
}
.button-wrong {
border-style: dotted;
border-color: rgb(180, 0, 0);
width: 100px;
height: 50px;
color: rgb(180, 0, 0);
background-color: white;
}
.button-disable {
border-style: dotted;
border-color: black;
width: 100px;
height: 50px;
color: black;
background-color: white;
}
\ No newline at end of file
<div class="model-content"> <div class="model-content">
<div style="padding: 10px;"> <div style="padding: 10px;">
<div class="border" style="width: 1000px;">
<div style="width: 300px;" align='center'> <textarea style="width: 955px; height: 300px;" (blur)="load()" #itemTextarea>{{itemStr}}</textarea>
<span>图1: </span> <button (click)="copyData();">Copy</button>
<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> </div>
<div style="width: 300px; margin-top: 15px;"> <div class="border" style="width: 1000px;">
<span>文本: </span> <span style="font-size: 20px;">标题: </span>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()"> <input type="text" nz-input [(ngModel)]="item.title" (blur)="save()">
<span style="font-size: 20px;">题目说明: </span>
<input type="text" nz-input [(ngModel)]="item.questionText" (blur)="save()">
<span style="font-size: 20px;">题目说明音频: </span>
<app-audio-recorder [audioUrl]="item.questionTextAudio"
(audioUploaded)="onAssetUploadSuccess($event, 'questionTextAudio')"></app-audio-recorder>
</div> </div>
<div class="border" style="width: 1000px;">
<div *ngFor="let question of item.questions; let i = index">
<div class="border" style="width: 950px;">
<span style="font-size: 20px;">小题{{i + 1}}: </span>
<div style="margin-top: 5px"> <div *ngFor="let option of question.options; let j = index">
<span>音频: </span> <div class="border" style="width: 900px;">
<app-audio-recorder <span style="font-size: 20px;">选项类型: </span>
[audioUrl]="item.audio_url" <div *ngIf="option.type=='img'">
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" <button class="button-right">图片</button>
></app-audio-recorder> &nbsp;
</div> <button class="button-disable" (click)="option.type='txt'; save();">文字</button>
</div>
<div *ngIf="option.type=='txt'">
<button class="button-disable" (click)="option.type='img'; save();">图片</button>
&nbsp;
<button class="button-right">文字</button>
</div>
<div *ngIf="option.type=='img'">
图片:
<div style="width: 300px;">
<app-upload-image-with-preview [picUrl]="option.image"
(imageUploaded)="onAssetUploadSuccess($event, 'questions', i, 'options', j, 'image')">
</app-upload-image-with-preview>
</div>
</div>
<span>音频: </span>
<app-audio-recorder [audioUrl]="option.audio"
(audioUploaded)="onAssetUploadSuccess($event, 'questions', i, 'options', j, 'audio')">
</app-audio-recorder>
<span>文本: </span>
<input type="text" nz-input [(ngModel)]="option.text" (blur)="save()">
<br>
<br>
<button style="width: 850px; height: 30px; color: red;" (click)="removeoption(i, j)">删除题目</button>
</div>
</div>
</div> <div class="border" style="width: 900px;">
<button style="width: 850px; height: 100px;" (click)="addoption(i)">增加选项</button>
</div>
<button style="width: 900px; height: 30px; color: red;" (click)="removequestion(i)">删除题目</button>
</div>
</div>
</div> <div class="border" style="width: 950px;">
<button style="width: 900px; height: 100px;" (click)="addquestion()">增加题目</button>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef } from '@angular/core'; import { Component, OnDestroy, OnChanges, OnInit, ApplicationRef, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core';
import { JsonPipe } from '@angular/common'; import { ComponentBase } from './ComponentBase';
import { MetaFormCreator } from './mataFormCreator';
@Component({ @Component({
selector: 'app-form', selector: 'app-form',
templateUrl: './form.component.html', templateUrl: './form.component.html',
styleUrls: ['./form.component.css'] styleUrls: ['./form.component.css']
}) })
export class FormComponent implements OnInit, OnChanges, OnDestroy { export class FormComponent extends ComponentBase implements OnInit, OnChanges, OnDestroy {
// 储存数据用 // 储存数据用
saveKey = "test_001"; saveKey = "dqq";
// 储存对象
item;
constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) { item = {
title: "",
questionText: "",
questionTextAudio: "",
questions: []
};
init(): void {
console.log(new MetaFormCreator().create());
} }
createShell() { removeoption(i, j) {
this.item.wordList.push({ this.item.questions[i].options.splice(j, 1);
word: '',
audio: '',
backWord: '',
backWordAudio: '',
});
this.save(); this.save();
} }
removeShell(idx) { addoption(i) {
this.item.wordList.splice(idx, 1); this.item.questions[i].options.push({
this.save(); type: "img",
} image: "",
audio: "",
ngOnInit() { text: "",
});
this.item = {};
// 获取存储的数据
(<any>window).courseware.getData((data) => {
if (data) {
this.item = data;
}
this.init();
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}, this.saveKey);
}
ngOnChanges() {
}
ngOnDestroy() {
}
init() {
}
/**
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
}
/**
* 储存音频数据
* @param e
*/
onAudioUploadSuccess(e, key) {
this.item[key] = e.url;
this.save(); this.save();
} }
onWordAudioUploadSuccess(e, idx) { removequestion(i) {
this.item.wordList[idx].audio = e.url; this.item.questions.splice(i, 1);
this.save(); this.save();
} }
onBackWordAudioUploadSuccess(e, idx) { addquestion() {
this.item.wordList[idx].backWordAudio = e.url; this.item.questions.push({
options: []
});
this.save(); this.save();
} }
/**
* 储存数据
*/
save() {
(<any>window).courseware.setData(this.item, null, this.saveKey);
this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
} }
\ No newline at end of file
export class MetaFormCreator {
constructor() { }
create() {
const data = {
onlineFlg: false, // 联机flg true联机版 false单机版
title: "标题文本", // 标题文本
questionText: "题目说明题目说明题目说明题目说明题目说明题目说明题目说明题目说明题目说明题目说明", // 题目说明
questionTextAudio: "http://staging-teach.cdn.ireadabc.com/b1019dcdb1f089ba9a65b71a1f52f67a.mp3", // 题目说明的语音
questions: [ // 题目,数组
{
questionAudio: "http://staging-teach.cdn.ireadabc.com/727a5af2f7ed99edb4a49d1126ecc9ca.mp3", // 题目音频
duration: 120, // 游戏倒计时(秒)
options: [ // 选项
{
type: "img",// 选项类型 img图片 txt文本
image: "http://staging-teach.cdn.ireadabc.com/03531e7ca2278b291da7d27bc1d60868.png", // 图片地址
audio: "http://staging-teach.cdn.ireadabc.com/727a5af2f7ed99edb4a49d1126ecc9ca.mp3", // 选项音频
text: "", // 选项类型为图片时,此选项没啥用
right: true // 这个选项是否是正确的
},
{
type: "text",// 选项类型 img图片 txt文本
image: "", // 选项类型为文本时,此选项没啥用
text: "asasdf", // 选项文本
audio: "http://staging-teach.cdn.ireadabc.com/727a5af2f7ed99edb4a49d1126ecc9ca.mp3",
right: true
},
{
image: "http://staging-teach.cdn.ireadabc.com/35bfd1d1342e1f2ea3db408afd072343.jpg",
audio: "",
type: "img",
text: "",
right: false
},
{
image: "",
audio: "",
type: "text",
text: "oliolioliooo",
right: false
}
]
},
{
questionAudio: "http://staging-teach.cdn.ireadabc.com/727a5af2f7ed99edb4a49d1126ecc9ca.mp3",
duration: 120, // 游戏倒计时(秒)
options: [
{
image: "http://staging-teach.cdn.ireadabc.com/03531e7ca2278b291da7d27bc1d60868.png",
audio: "http://staging-teach.cdn.ireadabc.com/727a5af2f7ed99edb4a49d1126ecc9ca.mp3",
type: "img",
text: "",
right: true
},
{
image: "",
audio: "http://staging-teach.cdn.ireadabc.com/727a5af2f7ed99edb4a49d1126ecc9ca.mp3",
type: "text",
text: "olio",
right: true
},
{
image: "http://staging-teach.cdn.ireadabc.com/35bfd1d1342e1f2ea3db408afd072343.jpg",
audio: "",
type: "img",
text: "",
right: false
},
{
image: "",
audio: "",
type: "text",
text: "oliolioliooo",
right: false
}
]
}
]
};
return this.createHtml(data, 'item', []);
}
createHtml(data: any, itemKey: string, idxList = []) {
let result = '';
for (const key in data) {
if (typeof data[key] == 'boolean') {
result += this.createBooleanHtml(itemKey, key);
}
if (typeof data[key] == 'number') {
result += this.createNumberHtml(itemKey, key);
}
if (typeof data[key] === 'string') {
if (key.includes('img') || key.includes('image')) {
result += this.createImageHtml(itemKey, key);
} else if (key.includes('Audio') || key.includes('audio')) {
result += this.createAudioHtml(itemKey, key);
} else {
result += this.createTextHtml(itemKey, key);
}
}
if (typeof data[key] == 'object') {
if (data[key] instanceof Array) {
result += this.createArrayHtml(itemKey, key, data[key], idxList);
}
}
}
return result;
}
createArrayHtml(itemName: string, key: string, data: any, idxList) {
let itemKey = key;
if (key[key.length - 1] == 's') {
itemKey = key.substring(0, key.length - 1);
}
const idxStrList = ['i', 'j', 'k', 'l'];
let idxStr = '';
for (let i = 0; i < idxStrList.length; i++) {
const str = idxStrList[i];
if (!idxList.includes(str)) {
idxStr = str;
break;
}
}
const subresult = this.createHtml(data[0], `${itemName}.${key}[${idxStr}]`, [...idxList, idxStr]);
return `
<div class="border" style="width: 800px;">
<div *ngFor="let ${itemKey} of ${itemName}.${key}; let ${idxStr} = index">
<div class="border" style="width: 700px;">
${subresult}
<button style="width: 650px; height: 30px; color: red;" (click)="remove${itemKey}(${idxStr})">删除</button>
</div>
</div>
<div class="border" style="width: 700px;">
<button style="width: 650px; height: 100px;" (click)="add${itemKey}()">增加</button>
</div>
</div>`
}
createNumberHtml(itemName: string, key: string) {
let dot = '.';
if (itemName == '') {
dot = '';
}
return `
<span>数字: </span>
<input type="number" nz-input [(ngModel)]="${itemName}${dot}${key}" (blur)="save()">`
}
createTextHtml(itemName: string, key: string) {
let dot = '.';
if (itemName == '') {
dot = '';
}
return `
<span>文本: </span>
<input type="text" nz-input [(ngModel)]="${itemName}${dot}${key}" (blur)="save()">`
}
createAudioHtml(itemName: string, key: string) {
let dot = '.';
if (itemName == '') {
dot = '';
}
let keyList = '';
itemName.split('.').forEach(key => {
keyList += `'${key}',`;
});
return `
<span>音频: </span>
<app-audio-recorder
[audioUrl]="${itemName}${dot}${key}"
(audioUploaded)="onAssetUploadSuccess($event, ${keyList}'${key}')"
></app-audio-recorder>`
}
createImageHtml(itemName: string, key: string) {
let dot = '.';
if (itemName == '') {
dot = '';
}
let keyList = '';
itemName.split('.').forEach(key => {
keyList += `'${key}',`;
});
return `<span>图片: </span>
<app-upload-image-with-preview
[picUrl]="${itemName}${dot}${key}"
(imageUploaded)="onAssetUploadSuccess($event, ${keyList}'${key}')">
</app-upload-image-with-preview>`;
}
createBooleanHtml(itemName: string, key: string) {
let dot = '.';
if (itemName == '') {
dot = '';
}
return `
<span style="font-size: 20px;">答案:</span>
<div *ngIf="${itemName}${dot}${key}==true">
<button class="button-right">正确</button>
&nbsp;
<button class="button-disable" (click)="${itemName}${dot}${key} = false;save();">错误</button>
</div>
<div *ngIf="${itemName}${dot}${key}==false">
<button class="button-disable" (click)="${itemName}${dot}${key} = true;save();">正确</button>
&nbsp;
<button class="button-wrong">错误</button>
</div>
<br>`
}
}
\ No newline at end of file
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