Commit 6b4e0b80 authored by 李维's avatar 李维

feat: 修改表单结构

parent ee8a8474
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, 100%-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>h5-template-generator</title> <title>h5-template-generator</title>
<link href="./index.css" rel="stylesheet" > <link href="./index.css" rel="stylesheet">
<script type="text/javascript" src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/jquery-1.12.3.min.js"></script> <script type="text/javascript"
src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> <script type="text/javascript" src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script>
<script type="text/javascript" src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/vue.min.js"></script> <script type="text/javascript" src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/vue.min.js"></script>
<!-- 引入样式 --> <!-- 引入样式 -->
<link href="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/element-ui/theme-chalk/index.css" rel="stylesheet"> <link href="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/element-ui/theme-chalk/index.css" rel="stylesheet">
<!-- 引入组件库 --> <!-- 引入组件库 -->
<script src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/element-ui/index.js"></script> <script src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/element-ui/index.js"></script>
<style>
.el-upload-dragger {
width: 100%;
height: 100%;
border: none;
}
</style>
</head> </head>
<body>
<div class="edit-data"> <body>
<el-card class="data-card" v-for="item, index in data" :key="index"> <div class="edit-data">
<div slot="header" class="clearfix"> <el-card class="data-card">
<span>题目{{index + 1}}</span> <el-form inline label-width="120px">
<el-button style="float: right; padding: 3px 0" type="text" @click="deleteConf(index)">删除</el-button> <el-divider content-position="left">基础信息</el-divider>
</div> <el-form-item label="Form ID">
<div> <el-input v-model="data.form_id" placeholder="Form ID" @blur="save" style="width: 120px;"></el-input>
<el-form label-width="90px"> </el-form-item>
<el-form-item label="题干图片"> <el-form-item label="Form Name">
<div class="image-uploader"> <el-input v-model="data.form_name" placeholder="Form Name" @blur="save" style="width: 320px;"></el-input>
</el-form-item>
<el-form-item label="Item Number">
<el-input v-model="data.item_number" placeholder="Item Number" @blur="save" style="width: 120px;"></el-input>
</el-form-item>
<el-form-item label="IMS ID">
<el-input v-model="data.ims_id" placeholder="Ims ID" @blur="save"></el-input>
</el-form-item>
<el-form-item label="Item Type">
<el-input v-model="data.item_type" placeholder="Item Type" @blur="save"></el-input>
</el-form-item>
<el-form-item label="Word Count">
<el-input v-model="data.word_count" placeholder="Word Count" @blur="save"></el-input>
</el-form-item>
</el-form>
<el-form label-width="90px">
<el-divider content-position="left">题干</el-divider>
<el-form-item label="文字">
<el-input type="textarea" v-model="data.passage_text.text" placeholder="请输入题干英文" @change="save"></el-input>
</el-form-item>
<el-form-item label="图片">
<div class="image-uploader">
<el-upload
:action="uploadUrl"
:data="uploadData"
:show-file-list="false"
:on-success="(res, file) => handleImageSuccess(res, file, data.passage_text.image)"
:before-upload="beforeImageUpload"
drag>
<div v-if="data.passage_text.image.url" class="image-preview">
<img :src="data.passage_text.image.url" class="uploaded-image">
<div class="image-actions">
<i class="el-icon-zoom-in" @click.stop="previewImage(data.passage_text.image.url)"></i>
<i class="el-icon-delete" @click.stop="removeImage(data.passage_text.image)"></i>
</div>
</div>
<i v-else class="el-icon-plus upload-icon"></i>
</el-upload>
</div>
</el-form-item>
<el-form-item label="音频">
<div class="audio-uploader">
<el-upload
:action="uploadUrl"
:data="uploadData"
:on-success="(res, file) => handleAudioSuccess(res, file, data.passage_text.audio)"
:before-upload="beforeAudioUpload"
:show-file-list="false"
drag>
<el-button size="small" type="primary">{{ data.passage_text.audio.url ? '重新上传' : '上传' }}</el-button>
&nbsp;&nbsp;&nbsp;&nbsp;
<span v-if="data.passage_text.audio.url" class="filename">{{ data.passage_text.audio.name }}</span>
</el-upload>
</div>
<audio v-if="data.passage_text.audio.url" :src="data.passage_text.audio.url" controls></audio>
</el-form-item>
<el-divider content-position="left">副题干</el-divider>
<el-form-item label="文字">
<el-input type="textarea" v-model="data.stem.text" placeholder="请输入题干英文" @change="save"></el-input>
</el-form-item>
<el-form-item label="图片">
<div class="image-uploader">
<el-upload
:action="uploadUrl"
:data="uploadData"
:show-file-list="false"
:on-success="(res, file) => handleImageSuccess(res, file, data.stem.image)"
:before-upload="beforeImageUpload"
drag>
<div v-if="data.stem.image.url" class="image-preview">
<img :src="data.stem.image.url" class="uploaded-image">
<div class="image-actions">
<i class="el-icon-zoom-in" @click.stop="previewImage(data.stem.image.url)"></i>
<i class="el-icon-delete" @click.stop="removeImage(data.stem.image)"></i>
</div>
</div>
<i v-else class="el-icon-plus upload-icon"></i>
</el-upload>
</div>
</el-form-item>
<el-form-item label="音频">
<div class="audio-uploader">
<el-upload
:action="uploadUrl"
:data="uploadData"
:on-success="(res, file) => handleAudioSuccess(res, file, data.stem.audio)"
:before-upload="beforeAudioUpload"
:show-file-list="false"
drag>
<el-button size="small" type="primary">{{ data.stem.audio.url ? '重新上传' : '上传' }}</el-button>
&nbsp;&nbsp;&nbsp;&nbsp;
<span v-if="data.stem.audio.url" class="filename">{{ data.stem.audio.name }}</span>
</el-upload>
</div>
<audio v-if="data.stem.audio.url" :src="data.stem.audio.url" controls></audio>
</el-form-item>
<el-form v-for="(option, optionIndex) in data.options" :key="optionIndex" :label="'选项' + (optionIndex + 1)" label-width="120px">
<el-divider content-position="left">选项{{ optionIndex + 1 }}</el-divider>
<el-form-item label="文字">
<el-input style="width: 60%; margin-bottom: 10px;" v-model="option.text" placeholder="请输入选项英文" @change="save"></el-input>
</el-form-item>
<el-form-item label="图片">
<div class="image-uploader" style="display: inline-block;">
<el-upload <el-upload
:action="uploadUrl" :action="uploadUrl"
:data="uploadData" :data="uploadData"
:show-file-list="false" :show-file-list="false"
:on-success="(res, file) => handleImageSuccess(res, file, index)" :on-success="(res, file) => handleOptionImageSuccess(res, file, option.image)"
:before-upload="beforeImageUpload"> :before-upload="beforeImageUpload"
<div v-if="data[index].image_url" class="image-preview"> drag>
<img :src="data[index].image_url" class="uploaded-image"> <div v-if="option.image.url" class="image-preview">
<img :src="option.image.url" class="uploaded-image">
<div class="image-actions"> <div class="image-actions">
<i class="el-icon-zoom-in" @click.stop="previewImage(data[index].image_url)"></i> <i class="el-icon-zoom-in" @click.stop="previewImage(option.image.url)"></i>
<i class="el-icon-delete" @click.stop="removeImage(index)"></i> <i class="el-icon-delete" @click.stop="removeOptionImage(option.image)"></i>
</div> </div>
</div> </div>
<i v-else class="el-icon-plus upload-icon"></i> <i v-else class="el-icon-plus upload-icon"></i>
</el-upload> </el-upload>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="题干"> <el-form-item label="音频">
<el-input type="textarea" v-model="data[index].question" placeholder="请输入题干英文" @change="save"></el-input>
</el-form-item>
<!-- 新增音频上传和预览部分 -->
<el-form-item label="题干音频">
<div class="audio-uploader"> <div class="audio-uploader">
<el-upload <el-upload
:action="uploadUrl" :action="uploadUrl"
:data="uploadData" :data="uploadData"
:on-success="(res, file) => handleAudioSuccess(res, file, index)" :on-success="(res, file) => handleAudioSuccess(res, file, option.audio)"
:before-upload="beforeAudioUpload" :before-upload="beforeAudioUpload"
:show-file-list="false"> :show-file-list="false"
<el-button size="small" type="primary">{{ data[index].audio_url ? '重新上传' : '上传' }}</el-button> drag>
<el-button size="small" type="primary">{{ option.audio.url ? '重新上传' : '上传' }}音频</el-button>
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
<span v-if="data[index].audio_url" class="filename" @click.stop="togglePlay(index)">{{ data[index].audio_name }}(点击播放)</span> <span v-if="option.audio.url" class="filename">{{ option.audio.name }}</span>
<audio :ref="'audio' + index" :src="data[index].audio_url" @ended.stop="audioEnded(index)" style="display: none;"></audio>
</el-upload> </el-upload>
</div> </div>
<div>
<audio v-if="option.audio.url" :src="option.audio.url" controls></audio>
</div>
</el-form-item> </el-form-item>
<el-form-item v-for="(option, optionIndex) in data[index].options" :key="optionIndex" :label="'选项' + (optionIndex + 1)"> <el-form-item label="">
<el-row style="border: 1px solid #E4E7ED; padding: 10px;"> <el-checkbox v-model="option.is_correct" @change="save">正确</el-checkbox>
<el-col :span="6"> <el-button style="float: right;" icon="el-icon-delete" size="small" type="danger" @click.stop="deleteOption(optionIndex)">删除选项</el-button>
<div class="image-uploader" style="display: inline-block;">
<el-upload
:action="uploadUrl"
:data="uploadData"
:show-file-list="false"
:on-success="(res, file) => handleOptionImageSuccess(res, file, index, optionIndex)"
:before-upload="beforeImageUpload">
<div v-if="data[index].options[optionIndex].image_url" class="image-preview">
<img :src="data[index].options[optionIndex].image_url" class="uploaded-image">
<div class="image-actions">
<i class="el-icon-zoom-in" @click.stop="previewImage(data[index].options[optionIndex].image_url)"></i>
<i class="el-icon-delete" @click.stop="removeOptionImage(index, optionIndex)"></i>
</div>
</div>
<i v-else class="el-icon-plus upload-icon"></i>
</el-upload>
</div>
</el-col>
<el-col :span="18">
<el-input style="width: 60%;" v-model="data[index].options[optionIndex].text" placeholder="请输入选项英文" @change="save">
</el-input><br>
<div class="audio-uploader">
<el-upload
:action="uploadUrl"
:data="uploadData"
:on-success="(res, file) => handleOptionAudioSuccess(res, file, index, optionIndex)"
:before-upload="beforeAudioUpload"
:show-file-list="false">
<el-button size="small" type="primary">{{ data[index].options[optionIndex].audio_url ? '重新上传' : '上传' }}音频</el-button>
&nbsp;&nbsp;&nbsp;&nbsp;
<span v-if="data[index].options[optionIndex].audio_url" class="filename" @click.stop="toggleOptionPlay(index, optionIndex)">{{ data[index].options[optionIndex].audio_name }}(点击播放)</span>
<audio :ref="'audio' + index + '-' + optionIndex" :src="data[index].options[optionIndex].audio_url" @ended.stop="audioOptionEnded(index, optionIndex)" style="display: none;"></audio>
</el-upload>
</div>
<el-checkbox v-model="data[index].options[optionIndex].is_correct" @change="save">正确</el-checkbox>
<el-button style="float: right;" icon="el-icon-delete" size="small" type="primary" @click.stop="deleteOption(index, optionIndex)">删除选项</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click.stop="addOption(index)">增加选项</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> <el-button size="small" type="ghost" @click.stop="addOption()" style="height: 80px; width: 100%; margin: 20px 0;"><i class="el-icon-plus"></i> 增加选项</el-button>
</el-card>
<el-card shadow="hover" class="data-card">
<div style="cursor: pointer; display: flex; justify-content: center; align-items: center; height: 80px;"
@click="addConfig">
<el-button class="btn" type="text" size="mini" icon="el-icon-plus">新加</el-button>
</div>
</el-card> </el-card>
</div> </div>
</body> </body>
<script src="./index.js"></script> <script src="./index.js"></script>
</html> </html>
\ No newline at end of file
...@@ -16,8 +16,42 @@ new Vue({ ...@@ -16,8 +16,42 @@ new Vue({
el: '.edit-data', el: '.edit-data',
created() { created() {
window.courseware.getData((data) => { window.courseware.getData((data) => {
this.data = data || []; this.data = data || {
form_id: '',
form_name: '',
item_number: '',
item_type: '',
ims_id: '',
word_count: '',
passage_text: {
text: '',
audio: {
url: '',
name: '',
size: '',
duration: ''
},
image: {
url: '',
},
},
stem: {
text: '',
audio: {
url: '',
name: '',
size: '',
duration: ''
},
image: {
url: '',
},
},
options: []
};
}, key); }, key);
console.log("========== data ==========")
console.log(this.data)
window['air'].getUploadCallback = (url, data) => { window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url; this.uploadUrl = url;
this.uploadData = data; this.uploadData = data;
...@@ -31,55 +65,18 @@ new Vue({ ...@@ -31,55 +65,18 @@ new Vue({
} }
}, },
methods: { methods: {
handleAudioSuccess(res, file, index) { handleAudioSuccess(res, file, obj) {
// 假设上传接口返回的音频URL在 res.url 中 // 假设上传接口返回的音频URL在 res.url 中
this.data[index].audio_url = res.url; obj.url = res.url;
this.data[index].audio_name = file.name; obj.name = file.name;
// 计算文件大小 // 计算文件大小
const size = file.size; obj.size = file.size;
if (size < 1024) {
this.data[index].audio_size = size + 'B';
} else if (size < 1024 * 1024) {
this.data[index].audio_size = (size / 1024).toFixed(2) + 'KB';
} else {
this.data[index].audio_size = (size / (1024 * 1024)).toFixed(2) + 'MB';
}
// 获取音频时长 // 获取音频时长
const audio = new Audio(res.url); const audio = new Audio(res.url);
audio.addEventListener('loadedmetadata', () => { audio.addEventListener('loadedmetadata', () => {
const duration = audio.duration; obj.duration = audio.duration;
const minutes = Math.floor(duration / 60); this.save();
const seconds = Math.floor(duration % 60);
this.data[index].audio_duration = `${minutes}:${seconds.toString().padStart(2, '0')}`;
});
this.save();
},
handleOptionAudioSuccess(res, file, index, optionIndex) {
// 假设上传接口返回的音频URL在 res.url 中
this.data[index].options[optionIndex].audio_url = res.url;
this.data[index].options[optionIndex].audio_name = file.name;
// 计算文件大小
const size = file.size;
if (size < 1024) {
this.data[index].options[optionIndex].audio_size = size + 'B';
} else if (size < 1024 * 1024) {
this.data[index].options[optionIndex].audio_size = (size / 1024).toFixed(2) + 'KB';
} else {
this.data[index].options[optionIndex].audio_size = (size / (1024 * 1024)).toFixed(2) + 'MB';
}
// 获取音频时长
const audio = new Audio(res.url);
audio.addEventListener('loadedmetadata', () => {
const duration = audio.duration;
const minutes = Math.floor(duration / 60);
const seconds = Math.floor(duration % 60);
this.data[index].options[optionIndex].audio_duration = `${minutes}:${seconds.toString().padStart(2, '0')}`;
}); });
this.save(); this.save();
...@@ -87,10 +84,10 @@ new Vue({ ...@@ -87,10 +84,10 @@ new Vue({
// 播放/暂停音频 // 播放/暂停音频
togglePlay(index) { togglePlay(index) {
const audio = this.$refs['audio' + index][0]; const audio = this.$refs['audio'][0];
if (this.data[index].isPlaying) { if (this.data.isPlaying) {
audio.pause(); audio.pause();
this.data[index].isPlaying = false; this.data.isPlaying = false;
} else { } else {
// 先停止其他正在播放的音频 // 先停止其他正在播放的音频
this.data.forEach((item, i) => { this.data.forEach((item, i) => {
...@@ -100,7 +97,7 @@ new Vue({ ...@@ -100,7 +97,7 @@ new Vue({
} }
}); });
audio.play(); audio.play();
this.data[index].isPlaying = true; this.data.isPlaying = true;
} }
}, },
...@@ -128,7 +125,7 @@ new Vue({ ...@@ -128,7 +125,7 @@ new Vue({
}, },
audioOptionEnded(index, optionIndex) { audioOptionEnded(index, optionIndex) {
this.data[index].options[optionIndex].isPlaying = false; this.data.options[optionIndex].isPlaying = false;
}, },
beforeAudioUpload(file) { beforeAudioUpload(file) {
...@@ -152,46 +149,34 @@ new Vue({ ...@@ -152,46 +149,34 @@ new Vue({
this.$message.success("实时保存成功"); this.$message.success("实时保存成功");
}, key); }, key);
}, },
deleteConf(index) { addOption() {
this.data.splice(index, 1); this.data.options.push({
this.save();
},
addConfig() {
this.data.push({
question: '',
audio_url: '',
image_url: '',
audio_name: '',
audio_size: '',
audio_duration: '',
isPlaying: false,
options: [],
});
this.save();
},
addOption(index) {
this.data[index].options.push({
image_url: '',
audio_url: '',
audio_name: '',
text: '', text: '',
audio: {
url: '',
name: '',
size: '',
duration: ''
},
image: {
url: '',
},
is_correct: false, is_correct: false,
}); });
this.save(); this.save();
}, },
deleteOption(index, optionIndex) { deleteOption(optionIndex) {
this.data[index].options.splice(optionIndex, 1); this.data.options.splice(optionIndex, 1);
this.save(); this.save();
}, },
// 图片上传成功的回调 // 图片上传成功的回调
handleImageSuccess(res, file, index) { handleImageSuccess(res, file, obj) {
// 假设上传接口返回的图片URL在 res.url 中 // 假设上传接口返回的图片URL在 res.url 中
console.log(res, file, index); obj.url = res.url;
this.data[index].image_url = res.url;
this.save(); this.save();
}, },
handleOptionImageSuccess(res, file, index, optionIndex) { handleOptionImageSuccess(res, file, obj) {
this.data[index].options[optionIndex].image_url = res.url; obj.url = res.url;
this.save(); this.save();
}, },
...@@ -227,13 +212,13 @@ new Vue({ ...@@ -227,13 +212,13 @@ new Vue({
confirmButtonText: '关闭' confirmButtonText: '关闭'
}); });
}, },
removeImage(index) { removeImage(obj) {
this.$confirm('确定要删除这张图片吗?', '提示', { this.$confirm('确定要删除这张图片吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.data[index].image_url = ''; obj.url = '';
this.save(); this.save();
this.$message({ this.$message({
type: 'success', type: 'success',
...@@ -241,8 +226,8 @@ new Vue({ ...@@ -241,8 +226,8 @@ new Vue({
}); });
}).catch(() => { }); }).catch(() => { });
}, },
removeOptionImage(index, optionIndex) { removeOptionImage(obj) {
this.data[index].options[optionIndex].image_url = ''; obj.url = '';
this.save(); this.save();
} }
}, },
......
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