Commit 48cfaa5d authored by liujiangnan's avatar liujiangnan

feat: 音频表单

parent 9d944887
.edit-data{ .edit-data{
padding: 10px; padding: 10px;
} }
.el-card {
display: inline-block;
margin: 3px;
}
.data-card {
position: relative;
height: 320px;
width: 300px;
vertical-align: top;
}
.data-card .el-card__body {
padding: 15px 20px 0px;
}
.audio-uploader {
text-align: center;
margin-bottom: 10px;
}
.audio-uploader .el-upload {
width: 100%;
}
.audio-uploader .el-upload-dragger {
width: 100%;
height: auto;
padding: 10px;
}
audio {
width: 100%;
margin: 10px 0;
}
.el-form-item {
margin-bottom: 15px;
}
.delete-btn-wrapper {
position: absolute;
bottom: 10px;
left: 0;
right: 0;
text-align: center;
}
/* 音频信息显示样式 */
.audio-info {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
padding: 8px 12px;
background: #f5f7fa;
border-radius: 4px;
}
.audio-file-info {
flex: 1;
overflow: hidden;
margin-right: 10px;
}
.audio-file-info .filename {
display: block;
font-size: 14px;
color: #606266;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.audio-file-info .file-meta {
font-size: 12px;
color: #909399;
}
.audio-play-btn {
font-size: 20px;
color: #409EFF;
cursor: pointer;
transition: all 0.3s;
}
.audio-play-btn:hover {
color: #66b1ff;
}
.audio-play-btn.is-playing {
animation: rotating 2s linear infinite;
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
\ No newline at end of file
<!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, initial-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"
<script type="text/javascript" src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> src="//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="//staging-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>
</head> </head>
<body> <body>
<div class="edit-data"> <div class="edit-data">
<!-- 简单的例子,一个输入框+一个按钮,保存输入框的信息 --> <el-card v-for="item, index in data" :key="index" class="data-card">
test: <input type="text" name="test" /> <div>
<input id="save" type="button" value="保存" > <el-form label-width="40px">
<el-form-item label="英文">
<el-input v-model="data[index].text_en" placeholder="请输入英文" @change="save"></el-input>
</el-form-item>
<el-form-item label="中文">
<el-input v-model="data[index].text_cn" placeholder="请输入中文" @change="save"></el-input>
</el-form-item>
<!-- 新增音频上传和预览部分 -->
<el-form-item label="音频">
<div class="audio-uploader">
<el-upload
:action="uploadUrl"
:data="uploadData"
:on-success="(res, file) => handleAudioSuccess(res, file, index)"
:before-upload="beforeAudioUpload"
:show-file-list="false">
<el-button size="small" type="primary">点击上传音频</el-button>
</el-upload>
<div v-if="data[index].audio_url" class="audio-info">
<div class="audio-file-info">
<span class="filename">{{ data[index].audio_name }}</span>
</div>
<i class="el-icon-service audio-play-btn"
:class="{ 'is-playing': data[index].isPlaying }"
@click="togglePlay(index)"></i>
<audio
:ref="'audio' + index"
:src="data[index].audio_url"
@ended="audioEnded(index)"
style="display: none;">
</audio>
</div>
</div>
</el-form-item>
</el-form>
<div class="delete-btn-wrapper">
<el-button type="text" @click="deleteConf(index)">删除</el-button>
</div>
</div>
</el-card>
<el-card shadow="hover" class="data-card">
<div style="cursor: pointer; display: flex; justify-content: center; align-items: center; height: 300px;"
@click="addConfig">
<el-button class="btn" type="text" size="mini" icon="el-icon-plus">新建</el-button>
</div>
</el-card>
</div> </div>
</body> </body>
<script src="./index.js"></script> <script src="./index.js"></script>
</html> </html>
\ No newline at end of file
...@@ -10,26 +10,115 @@ var uploadData = window.courseware.uploadData(); //上传文件必须要的参 ...@@ -10,26 +10,115 @@ var uploadData = window.courseware.uploadData(); //上传文件必须要的参
*/ */
//对应模板的名称,这个可以不写,但是最好是能写上,同时开发多个模板的情况下如果不写这个,本地缓存可能会存在混乱 //对应模板的名称,这个可以不写,但是最好是能写上,同时开发多个模板的情况下如果不写这个,本地缓存可能会存在混乱
var key = "h5_test"; var key = "gs_words";
$(function(){ new Vue({
window.courseware.getData(function(data){ el: '.edit-data',
//数据加载完,才算页面加载完成 created() {
//获取数据 window.courseware.getData((data) => {
if(data&&data.test){ this.data = data || [];
$("[name='test']").val(data.test); }, key);
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
},
data() {
return {
data: [],
uploadUrl: window.courseware.uploadUrl(),
uploadData: window.courseware.uploadData(),
} }
},
methods: {
handleAudioSuccess(res, file, index) {
// 假设上传接口返回的音频URL在 res.url 中
this.data[index].audio_url = res.url;
this.data[index].audio_name = file.name;
//绑定点击事件 // 计算文件大小
$('#save').on('click',function(){ const size = file.size;
var test = $("[name='test']").val(); 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';
}
//保存新增或修改的数据 // 获取音频时长
window.courseware.setData({test: test},function(){ const audio = new Audio(res.url);
//保存数据也是异步的 audio.addEventListener('loadedmetadata', () => {
alert("保存成功!"); const duration = audio.duration;
},key); const minutes = Math.floor(duration / 60);
const seconds = Math.floor(duration % 60);
this.data[index].audio_duration = `${minutes}:${seconds.toString().padStart(2, '0')}`;
});
this.save();
},
// 播放/暂停音频
togglePlay(index) {
const audio = this.$refs['audio' + index][0];
if (this.data[index].isPlaying) {
audio.pause();
this.data[index].isPlaying = false;
} else {
// 先停止其他正在播放的音频
this.data.forEach((item, i) => {
if (i !== index && item.isPlaying) {
this.$refs['audio' + i][0].pause();
item.isPlaying = false;
}
});
audio.play();
this.data[index].isPlaying = true;
}
},
// 音频播放结束
audioEnded(index) {
this.data[index].isPlaying = false;
},
beforeAudioUpload(file) {
const isAudio = file.type.startsWith('audio/');
const isLt20M = file.size / 1024 / 1024 < 20;
}) if (!isAudio) {
},key); this.$message.error('只能上传音频文件!');
}) return false;
\ No newline at end of file }
if (!isLt20M) {
this.$message.error('音频大小不能超过 20MB!');
return false;
}
return true;
},
save() {
// 保存新增或修改的数据
window.courseware.setData(this.data, () => {
//保存数据也是异步的
this.$message.success("实时保存成功");
}, key);
},
deleteConf(index) {
this.data.splice(index, 1);
this.save();
},
addConfig() {
this.data.push({
text_en: '',
text_cn: '',
audio_url: '',
audio_name: '',
audio_size: '',
audio_duration: '',
isPlaying: false,
});
this.save();
},
},
computed: {
}
});
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