1553 lines
37 KiB
Vue
1553 lines
37 KiB
Vue
<template>
|
||
<view class="maincontent contentBg">
|
||
|
||
<!-- 文字转语音 -->
|
||
<view v-if="Status.pageType==='Txt'">
|
||
<view>
|
||
<view class="importTxt fright" @click="importDoc">导入文档</view>
|
||
|
||
<view class="clear"></view>
|
||
</view>
|
||
<view class="text-content">
|
||
<view class="uni-textarea">
|
||
<textarea class="textarea" v-model="formData.txt" placeholder-class="placehoderClass"
|
||
placeholder="请输入要转换的文本" :auto-height="true" maxlength="100" cursor-color="#BBE600" />
|
||
</view>
|
||
<view class="line"></view>
|
||
<view class="footBtn">
|
||
<view class="fright convert" @click.stop="txtToAudio()">转换</view>
|
||
<view class="fright audioSett" @click.stop="formData.txt=''">清空</view>
|
||
<view class="clear"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 获取到的语音信息 -->
|
||
<view class="cEdit" :class="{'displayNone':(!AudioData.tempFilePath && Status.pageType!=='Txt')|| (AudioData.hexLength===0 && Status.pageType==='Txt')}">
|
||
<view class="audioRemark">
|
||
<view>
|
||
<view>
|
||
<input type="text" class="txtName" v-model="cEdit.name" placeholder="音频名称"
|
||
placeholder-class="placehoderClass" />
|
||
</view>
|
||
<view>
|
||
<text>{{cEdit.createTime}}</text>
|
||
<text>{{getFormatSeconds(cEdit.time,true)}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="btnSave" v-if="Status.pageType!=='Txt'" @click.stop="uploadLuYin">保存</view>
|
||
</view>
|
||
<view class="slide" v-if="Status.pageType!=='Txt'">
|
||
|
||
<view class="circle" :style="{'left':PlayProgress}"></view>
|
||
<view class="line"></view>
|
||
<view class="fleft">
|
||
{{getFormatSeconds(cEdit.currTime)}}
|
||
</view>
|
||
<view class="fright">
|
||
{{getFormatSeconds(cEdit.time)}}
|
||
|
||
</view>
|
||
<view class="clear"></view>
|
||
</view>
|
||
<view class="control" v-if="Status.pageType!=='Txt'">
|
||
<view class="playControl">
|
||
<view class="seek" @click.stop="seek(-10)">
|
||
<image class="img" src="/static/images/common/prev.png" mode="aspectFit"></image>
|
||
</view>
|
||
<view class="play" @click="playToggle()">
|
||
|
||
<image class="img"
|
||
:class="{'displayNone':Status.playState!=='ready' && Status.playState!=='pause'}"
|
||
src="/static/images/common/play.png" mode="aspectFit"></image>
|
||
|
||
|
||
<image class="img" :class="{'displayNone':!Status.playState || Status.playState!=='play'}"
|
||
src="/static/images/common/pause.png" mode="aspectFit"></image>
|
||
</view>
|
||
<view class="seek" @click.stop="seek(10)">
|
||
<image class="img" src="/static/images/common/next.png" mode="aspectFit"></image>
|
||
</view>
|
||
</view>
|
||
<view class="drop" v-if="Status.pageType!=='Txt'" @click.stop="drop()">
|
||
<uni-icons type="trash" size="30" color="#e03434"></uni-icons>
|
||
</view>
|
||
</view>
|
||
|
||
|
||
|
||
|
||
</view>
|
||
|
||
<view class="txtBtns" v-if="Status.pageType==='Txt'"
|
||
:class="{'displayNone':AudioData.hexLength===0}">
|
||
<view class="btnSave fright" @click.stop="SaveTTS()">保存</view>
|
||
<view class="audioSett fright" @click.stop="CancelTTS">取消</view>
|
||
<view class="clear"></view>
|
||
</view>
|
||
|
||
<!-- 录音的提示 -->
|
||
<view v-if="Status.pageType==='Record'">
|
||
<view class="tips" :class="{'displayNone':Status.isRecord || AudioData.tempFilePath}">
|
||
点击下方红色录制按钮开始录音,吐字清晰,语句流畅
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 录音、选择文件操作 -->
|
||
<view class="footer" v-if="Status.pageType!=='Txt'">
|
||
<view class="opt">
|
||
|
||
<view class="recording" :class="{'displayNone':Status.pageType!=='Record'}">
|
||
<view class="recordTitle">语音录制{{Status.RecordName}}</view>
|
||
<view class="recordName" :class="{'visibilityHidden':!formatSecondsToDHMS}">{{formatSecondsToDHMS?formatSecondsToDHMS:"00:00"}}</view>
|
||
</view>
|
||
<view class="btnRecord center" @click.stop="toggleRecord()"
|
||
:class="{'displayNone':Status.pageType!=='Record'}">
|
||
<view class="start" :class="{'active':Status.isRecord}"></view>
|
||
</view>
|
||
<view class="btnRemark" :class="{'displayNone':Status.pageType!=='Record'}">
|
||
{{Status.isRecord?'录制中':'录制'}}
|
||
</view>
|
||
|
||
|
||
<view class="btnCheckFile center" @click.stop="checkFile()"
|
||
:class="{'displayNone':Status.pageType!=='File'}">
|
||
<view class="polygon center">
|
||
<uni-icons type="plusempty" size="45" color="#ffffff99"></uni-icons>
|
||
</view>
|
||
</view>
|
||
|
||
|
||
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 自定义弹出层 -->
|
||
<MessagePopup :visible="Status.Pop.showPop" :type="Status.Pop.popType" :bgColor="Status.Pop.bgColor"
|
||
:borderColor="Status.Pop.borderColor" :textColor="Status.Pop.textColor"
|
||
:buttonBgColor="Status.Pop.buttonBgColor" :buttonTextColor="Status.Pop.buttonTextColor"
|
||
:iconUrl="Status.Pop.iconUrl" :message="Status.Pop.message" :buttonText="Status.Pop.buttonText"
|
||
@buttonClick="HidePop" :visiblePrompt="Status.Pop.visiblePrompt" :promptTitle="Status.Pop.promptTitle"
|
||
v-model="Status.Pop.modelValue" @closePop="closePop" :buttonCancelText="Status.Pop.buttonCancelText"
|
||
:showCancel="Status.Pop.showCancel" @cancelPop="closePop" :showSlot="Status.Pop.showSlot">
|
||
|
||
|
||
|
||
<view class="popup-prompt">
|
||
|
||
<input type="text" class="popup-prompt-input" placeholder="请输入名称" v-model="cEdit.name" />
|
||
</view>
|
||
|
||
|
||
|
||
</MessagePopup>
|
||
|
||
|
||
|
||
<global-loading ref="loading" />
|
||
|
||
<xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
var eventChannel = null;
|
||
var these = null;
|
||
var innerAudioContext = null;
|
||
var AudeoRecoder = null;
|
||
var audioTime = null;
|
||
var hexs = null;
|
||
import BleTool from '@/utils/BleHelper.js';
|
||
import request, {
|
||
baseURL
|
||
} from '@/utils/request';
|
||
import {
|
||
showLoading,
|
||
hideLoading,
|
||
updateLoading
|
||
} from '@/utils/loading.js';
|
||
import Common from '@/utils/Common.js';
|
||
|
||
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
Status: {
|
||
playState: '', //播放状态
|
||
pageType: '', //页面类型,用于区分录音、选择文件、文字转语音
|
||
pageValid: false, //页面状态,是否已销毁
|
||
recoderIntval: null, //录音的定时器
|
||
isRecord: false, //是否正在录音
|
||
RecordTime: null, //已录间的时长
|
||
Pop: { //弹出框的配置
|
||
showPop: false, //是否显示弹窗
|
||
popType: 'custom',
|
||
bgColor: '#383934bd',
|
||
borderColor: '#BBE600',
|
||
textColor: '#ffffffde',
|
||
buttonBgColor: '#BBE600',
|
||
buttonTextColor: '#232323DE',
|
||
iconUrl: '',
|
||
message: '您确定要这样做吗?',
|
||
buttonText: '确定',
|
||
clickEvt: '',
|
||
visiblePrompt: false,
|
||
promptTitle: '设备名称',
|
||
modelValue: '',
|
||
visibleClose: false,
|
||
okCallback: null,
|
||
buttonCancelText: '',
|
||
showCancel: false,
|
||
showSlot: false
|
||
},
|
||
},
|
||
cEdit: {
|
||
|
||
Id: "", //编号
|
||
name: "", //名称
|
||
createTime: "", //创建时间
|
||
localPath: "", //本地地址
|
||
webPath: "", //网络地址
|
||
statu: "", //状态,是否公开
|
||
isApply: "", //是否使用中
|
||
time: "", //音频总长度
|
||
currTime: '', //当前播放进度
|
||
type:''
|
||
},
|
||
AudioData: {
|
||
tempFilePath: '',
|
||
hexLength:0
|
||
},
|
||
uploadOptions: {
|
||
|
||
},
|
||
formData: {
|
||
txt: '只要你能吃苦,就有吃不完的苦'
|
||
}
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
formatSecondsToDHMS() {
|
||
let seconds = this.Status.RecordTime;
|
||
|
||
return this.getFormatSeconds(seconds);
|
||
|
||
},
|
||
PlayProgress() {
|
||
return this.cEdit.currTime / (this.cEdit.time === 0 ? 1 : this.cEdit.time) * 100 + '%';
|
||
}
|
||
},
|
||
onLoad(opt) {
|
||
eventChannel = this.getOpenerEventChannel();
|
||
these = this;
|
||
this.Status.pageType = opt.pageType;
|
||
let title = ""
|
||
if (opt.pageType === 'Record') {
|
||
title = "录制语音";
|
||
} else if (opt.pageType === 'Txt') {
|
||
title = '文字转语音';
|
||
} else {
|
||
title = "文件上传";
|
||
}
|
||
uni.setNavigationBarTitle({
|
||
title: title
|
||
});
|
||
},
|
||
onUnload() {
|
||
this.destoryAudioPlayer();
|
||
clearInterval(audioTime);
|
||
eventChannel.emit('RecordOver', {
|
||
data: '从音频页面返回,刷新数据'
|
||
});
|
||
},
|
||
onBackPress(e) {
|
||
if (this.Status.isRecord) { //如果正在录音,提示是否放弃
|
||
this.showMsg("正在录音,是否放弃?", false, true, () => {
|
||
these.Status.pageValid = true;
|
||
these.stopLuYin();
|
||
|
||
|
||
uni.navigateBack();
|
||
|
||
|
||
});
|
||
return true;
|
||
} else {
|
||
if (this.AudioData.tempFilePath) {
|
||
this.showMsg("录音没有保存是否放弃?", false, true, () => {
|
||
these.Status.pageValid = true;
|
||
this.dropTmpFile();
|
||
this.AudioData.tempFilePath = "";
|
||
AudeoRecoder = null;
|
||
uni.navigateBack();
|
||
});
|
||
return true;
|
||
}
|
||
|
||
}
|
||
|
||
},
|
||
methods: {
|
||
CancelTTS(){
|
||
this.cEdit.name='';
|
||
this.cEdit.Id="";
|
||
this.cEdit.createTime="";
|
||
this.cEdit.currTime="";
|
||
this.cEdit.isApply="";
|
||
this.cEdit.localPath="";
|
||
this.cEdit.statu="";
|
||
this.cEdit.time="";
|
||
this.cEdit.webPath="";
|
||
this.AudioData.hexLength=0;
|
||
this.cEdit.type=this.Status.pageType;
|
||
hexs=[];
|
||
},
|
||
SaveTTS() {
|
||
if (!this.cEdit.name) {
|
||
this.showMsg("请输入语音名称");
|
||
return;
|
||
}
|
||
|
||
this.cEdit.localPath = "";
|
||
this.cEdit.Id = Common.guid();
|
||
this.cEdit.createTime = Common.DateFormat(new Date(), "yyyy年MM月dd日");
|
||
this.cEdit.isApply = false;
|
||
this.cEdit.statu = false;
|
||
this.cEdit.type=this.Status.pageType;
|
||
this.cEdit.webPath = "";
|
||
|
||
let pro1 = new Promise((resolve, reject) => {
|
||
uni.setStorage({
|
||
key: Common.pcmStorageKey + "_" + this
|
||
.cEdit.Id,
|
||
data: hexs,
|
||
success() {
|
||
resolve();
|
||
},
|
||
fail(ex) {
|
||
reject(ex)
|
||
}
|
||
});
|
||
});
|
||
let pro2 = new Promise((resolve, reject) => {
|
||
let array = uni.getStorageSync(Common
|
||
.audioStorageKey);
|
||
if (!array) {
|
||
array = [this.cEdit];
|
||
} else {
|
||
array.unshift(this.cEdit);
|
||
}
|
||
uni.setStorage({
|
||
key: Common.audioStorageKey,
|
||
data: array,
|
||
success() {
|
||
resolve();
|
||
},
|
||
fail(ex) {
|
||
reject(ex)
|
||
}
|
||
});
|
||
});
|
||
Promise.allSettled([pro1, pro2]).then(res => {
|
||
if (res[0].status == 'fulfilled' && res[1]
|
||
.status == 'fulfilled') {
|
||
updateLoading(these, {
|
||
text: "操作成功"
|
||
});
|
||
this.AudioData.tempFilePath = "";
|
||
this.Status.isRecord = false;
|
||
|
||
uni.navigateBack();
|
||
return;
|
||
} else {
|
||
updateLoading(these, {
|
||
text: "操作没有成功"
|
||
});
|
||
|
||
}
|
||
this.timeOutCloseLoad();
|
||
|
||
}).catch(ex => {
|
||
updateLoading(these, {
|
||
text: "出现异常" + JSON.stringify(ex)
|
||
});
|
||
this.timeOutCloseLoad();
|
||
});
|
||
|
||
},
|
||
importDoc() {
|
||
this.checkFile();
|
||
},
|
||
txtToAudio() {
|
||
let msg = "";
|
||
if (!this.formData.txt) {
|
||
msg = '请输入语音内容';
|
||
}
|
||
if (this.formData.txt.length > 100) {
|
||
msg = "内容限制在100字以内";
|
||
}
|
||
if (msg) {
|
||
this.showMsg(msg);
|
||
return;
|
||
}
|
||
hexs = [];
|
||
this.AudioData.hexLength=0;
|
||
showLoading(this, {
|
||
text: '正在生成语音'
|
||
});
|
||
|
||
|
||
let closeWaiting = () => {
|
||
|
||
|
||
setTimeout(() => {
|
||
hideLoading(this);
|
||
}, 2000)
|
||
}
|
||
let task = () => {
|
||
return new Promise((succ, err) => {
|
||
request({
|
||
url: "/app/video/audioTTS",
|
||
method: 'GET',
|
||
data: {
|
||
text: this.formData.txt
|
||
}
|
||
}).then(res => {
|
||
if (res && res.code && res.code === 200) {
|
||
succ(res.data);
|
||
} else {
|
||
err(res);
|
||
|
||
}
|
||
|
||
}).catch(ex => {
|
||
console.error("出现异常", ex);
|
||
err(res);
|
||
|
||
|
||
});
|
||
})
|
||
}
|
||
|
||
|
||
task().then(res => {
|
||
|
||
try {
|
||
console.log("文本转语音成功", res);
|
||
hexs = res;
|
||
|
||
|
||
|
||
|
||
|
||
this.AudioData.hexLength =hexs.length;
|
||
this.AudioData.tempFilePath = "";
|
||
this.cEdit.localPath = "";
|
||
this.cEdit.time="";
|
||
this.playInit("");
|
||
|
||
|
||
updateLoading(this, {
|
||
text: '文本转语音成功'
|
||
});
|
||
|
||
|
||
|
||
|
||
|
||
|
||
} catch (error) {
|
||
console.error("出现错误,", error)
|
||
}
|
||
|
||
|
||
|
||
}).catch(ex => {
|
||
console.error("出现异常", ex);
|
||
updateLoading(this, {
|
||
text: '生成失败'
|
||
});
|
||
}).finally(closeWaiting);
|
||
},
|
||
timeOutCloseLoad() {
|
||
setTimeout(() => {
|
||
hideLoading(these);
|
||
}, 1200);
|
||
},
|
||
uploadLuYin() {
|
||
let key = Common.pcmStorageKey + "_" + this.cEdit.Id;
|
||
var store = uni.getStorageInfoSync();
|
||
var f = store.keys.includes(key);
|
||
if (f) {
|
||
|
||
return;
|
||
}
|
||
|
||
const token = uni.getStorageSync('token');
|
||
const clientid = uni.getStorageSync('clientID');
|
||
|
||
showLoading(this, {
|
||
text: "文件上传中"
|
||
});
|
||
|
||
|
||
console.log("token=", {
|
||
token: token,
|
||
clientid: clientid
|
||
});
|
||
|
||
setTimeout(() => {
|
||
|
||
uni.uploadFile({
|
||
url: baseURL + "/app/video/audio",
|
||
filePath: this.AudioData.tempFilePath,
|
||
name: 'file',
|
||
header: {
|
||
"Method": "POST",
|
||
"Content-Type": "multipart/form-data",
|
||
"Authorization": 'Bearer ' + token,
|
||
"clientid": clientid
|
||
},
|
||
timeout: 1200000,
|
||
fail: (ex) => {
|
||
updateLoading(these, {
|
||
text: "未知的原因上传失败"
|
||
});
|
||
this.timeOutCloseLoad();
|
||
},
|
||
success: (res) => {
|
||
// console.log("服务器响应=", res);
|
||
if (res && res.data) {
|
||
try {
|
||
res.data = JSON.parse(res.data);
|
||
if (res.data.code == 200) {
|
||
|
||
|
||
|
||
let pro1 = new Promise((resolve, reject) => {
|
||
uni.setStorage({
|
||
key: Common.pcmStorageKey + "_" + this
|
||
.cEdit.Id,
|
||
data: res.data.data,
|
||
success() {
|
||
resolve();
|
||
},
|
||
fail(ex) {
|
||
reject(ex)
|
||
}
|
||
});
|
||
});
|
||
let pro2 = new Promise((resolve, reject) => {
|
||
let array = uni.getStorageSync(Common
|
||
.audioStorageKey);
|
||
if (!array) {
|
||
array = [this.cEdit];
|
||
} else {
|
||
array.unshift(this.cEdit);
|
||
}
|
||
uni.setStorage({
|
||
key: Common.audioStorageKey,
|
||
data: array,
|
||
success() {
|
||
resolve();
|
||
},
|
||
fail(ex) {
|
||
reject(ex)
|
||
}
|
||
});
|
||
});
|
||
Promise.allSettled([pro1, pro2]).then(res => {
|
||
if (res[0].status == 'fulfilled' && res[1]
|
||
.status == 'fulfilled') {
|
||
updateLoading(these, {
|
||
text: "操作成功"
|
||
});
|
||
this.AudioData.tempFilePath = "";
|
||
this.Status.isRecord = false;
|
||
|
||
uni.navigateBack();
|
||
return;
|
||
} else {
|
||
updateLoading(these, {
|
||
text: "操作没有成功"
|
||
});
|
||
|
||
}
|
||
this.timeOutCloseLoad();
|
||
|
||
}).catch(ex => {
|
||
updateLoading(these, {
|
||
text: "出现异常" + JSON.stringify(ex)
|
||
});
|
||
this.timeOutCloseLoad();
|
||
});
|
||
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
console.error("出现异常,", error);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
updateLoading(these, {
|
||
text: "未知的异常上传失败"
|
||
});
|
||
this.timeOutCloseLoad();
|
||
},
|
||
complete() {
|
||
|
||
}
|
||
});
|
||
|
||
}, 10);
|
||
|
||
},
|
||
drop() {
|
||
this.showMsg("您确定删除该音频吗?", false, true, () => {
|
||
these.dropTmpFile();
|
||
this.cEdit = {
|
||
|
||
Id: "", //编号
|
||
name: "", //名称
|
||
createTime: "", //创建时间
|
||
localPath: "", //本地地址
|
||
webPath: "", //网络地址
|
||
statu: "", //状态,是否公开
|
||
isApply: "", //是否使用中
|
||
time: "", //音频总长度
|
||
currTime: '' //当前播放进度
|
||
};
|
||
this.Status.playState = "";
|
||
|
||
})
|
||
},
|
||
seek(intval) { //快进快退
|
||
let tmp = this.cEdit.currTime + intval;
|
||
console.log("tmp=" + tmp)
|
||
if (tmp < 0) {
|
||
|
||
this.cEdit.currTime = 0;
|
||
innerAudioContext.seekTo(0);
|
||
innerAudioContext.play();
|
||
} else if (tmp > this.cEdit.time) {
|
||
this.cEdit.currTime = this.cEdit.time;
|
||
innerAudioContext.seekTo(this.cEdit.time);
|
||
innerAudioContext.stop();
|
||
clearInterval(audioTime);
|
||
} else {
|
||
this.cEdit.currTime = tmp;
|
||
innerAudioContext.seekTo(tmp);
|
||
}
|
||
},
|
||
playToggle() {
|
||
if (this.Status.playState === '') {
|
||
this.showMsg("音频未就绪");
|
||
return;
|
||
}
|
||
if (innerAudioContext) {
|
||
if (this.Status.playState == 'play') {
|
||
innerAudioContext.pause();
|
||
|
||
} else {
|
||
innerAudioContext.play();
|
||
|
||
}
|
||
} else {
|
||
this.showMsg("播放器未就绪");
|
||
}
|
||
},
|
||
getFormatSeconds(seconds, Ms) {
|
||
if (!seconds) {
|
||
return "";
|
||
}
|
||
|
||
let totalSeconds = Math.floor(seconds);
|
||
let days = Math.floor(totalSeconds / 86400); // 1天=86400秒
|
||
let remainingSeconds = totalSeconds % 86400;
|
||
|
||
let hours = Math.floor(remainingSeconds / 3600);
|
||
let minutes = Math.floor((remainingSeconds % 3600) / 60);
|
||
let secs = remainingSeconds % 60;
|
||
|
||
// 补零处理
|
||
let paddedDays = String(days).padStart(2, '0');
|
||
let paddedHours = String(hours).padStart(2, '0');
|
||
let paddedMinutes = String(minutes).padStart(2, '0');
|
||
let paddedSecs = String(secs).padStart(2, '0');
|
||
if (Ms) {
|
||
return `${paddedMinutes}分${paddedSecs}秒`;
|
||
}
|
||
return `${paddedMinutes}:${paddedSecs}`;
|
||
},
|
||
createAudioPlayer() {
|
||
try {
|
||
console.log("准备创建播放器");
|
||
if (innerAudioContext) {
|
||
this.destoryAudioPlayer();
|
||
clearInterval(audioTime);
|
||
this.cEdit.currTime = 0;
|
||
}
|
||
|
||
innerAudioContext = plus.audio.createPlayer({
|
||
src: this.cEdit.localPath,
|
||
autoplay: false,
|
||
backgroundControl: false,
|
||
|
||
});
|
||
console.log('播放器创建成功');
|
||
|
||
|
||
innerAudioContext.addEventListener('canplay', () => {
|
||
console.log("准备就绪,可以播放了");
|
||
this.Status.playState = 'ready';
|
||
|
||
this.cEdit.time = innerAudioContext.getDuration();
|
||
this.cEdit.time =Math.ceil(this.cEdit.time);
|
||
console.log("音频长度:", this.cEdit.time);
|
||
});
|
||
console.log("canplay事件注册成功")
|
||
//开始播放
|
||
innerAudioContext.addEventListener("play", (res) => {
|
||
if (this.Status.playState === 'ready') {
|
||
this.cEdit.currTime = 0;
|
||
}
|
||
this.Status.playState = 'play';
|
||
audioTime = setInterval(() => {
|
||
this.cEdit.currTime += 1;
|
||
}, 1000);
|
||
console.log("播放中", res);
|
||
});
|
||
console.log("play事件注册成功")
|
||
//播放结束
|
||
innerAudioContext.addEventListener("ended", (res) => {
|
||
clearInterval(audioTime);
|
||
|
||
this.cEdit.currTime = 0;
|
||
this.Status.playState = 'ready';
|
||
console.log("播放结束", res);
|
||
});
|
||
console.log("ended事件注册成功")
|
||
//暂停播放
|
||
innerAudioContext.addEventListener("pause", (res) => {
|
||
clearInterval(audioTime);
|
||
audioTime = null;
|
||
this.Status.playState = 'pause';
|
||
console.log("暂停了", res);
|
||
});
|
||
console.log("pause事件注册成功")
|
||
innerAudioContext.addEventListener("seeked", (res) => {
|
||
console.log("seek完成了", res);
|
||
})
|
||
console.log("seeked事件注册成功")
|
||
|
||
innerAudioContext.addEventListener('error',ex=>{
|
||
console.log("出错了",ex)
|
||
});
|
||
console.log("error事件注册成功");
|
||
|
||
this.Status.playState = 'ready';
|
||
} catch (ex) {
|
||
console.error("出现错误", ex);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
},
|
||
destoryAudioPlayer() { //销毁播放器
|
||
if (innerAudioContext) {
|
||
innerAudioContext.close();
|
||
console.log("播放器已销毁");
|
||
}
|
||
},
|
||
handleUploadCallback(res) {
|
||
console.log("选择文件:", res);
|
||
if (res && res.data) {
|
||
if (this.Status.pageType === 'File') { //文件上传
|
||
if (res.data[0].type.indexOf('audio') > -1) {
|
||
this.cEdit.name = res.data[0].name;
|
||
this.playInit(res.data[0].tempFilePath);
|
||
} else {
|
||
this.showMsg("只能选择音频文件");
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (this.Status.pageType === 'Txt') { //文字转语音
|
||
|
||
let file = res.data[0];
|
||
|
||
let path = file.tempFilePath;
|
||
let type = file.type;
|
||
if (type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
|
||
this.parseWord(path); //docx
|
||
return;
|
||
}
|
||
if (type === 'text/plain') {
|
||
this.parseTxt(path); //txt
|
||
return;
|
||
}
|
||
if (type == "application/msword") { //doc
|
||
this.showPop({
|
||
showPop: true, //是否显示弹窗
|
||
popType: 'custom',
|
||
bgColor: '#383934bd',
|
||
borderColor: '#BBE600',
|
||
textColor: '#ffffffde',
|
||
buttonBgColor: '#BBE600',
|
||
buttonTextColor: '#232323DE',
|
||
iconUrl: '',
|
||
message: '打开文档后请手动复制文本内容',
|
||
buttonText: '打开',
|
||
clickEvt: '',
|
||
visiblePrompt: false,
|
||
promptTitle: '',
|
||
modelValue: '',
|
||
visibleClose: false,
|
||
okCallback: () => {
|
||
this.parseDoc(path);
|
||
},
|
||
showSlot: false,
|
||
buttonCancelText: '取消',
|
||
showCancel: true,
|
||
});
|
||
|
||
return;
|
||
}
|
||
this.showMsg("只能选择.txt、.docx、.doc文档");
|
||
return;
|
||
|
||
}
|
||
} else {
|
||
console.log("未选择任何文件");
|
||
}
|
||
},
|
||
parseTxt(txtPath) { //读取txt文件
|
||
showLoading(this, {
|
||
text: "文档读取中"
|
||
});
|
||
let promise = new Promise((resolve, reject) => {
|
||
plus.io.resolveLocalFileSystemURL(
|
||
txtPath,
|
||
(entry) => {
|
||
// 2. 获取文件对象
|
||
console.log("111111");
|
||
entry.file(
|
||
(file) => {
|
||
console.log("22222")
|
||
try {
|
||
let reader = new plus.io.FileReader();
|
||
reader.onloadend = function(e) {
|
||
|
||
// Get data
|
||
console.log("读取成功:", e.target.result);
|
||
resolve(e.target.result);
|
||
|
||
};
|
||
reader.onerror = function(ex) {
|
||
console.error("err=", ex)
|
||
reject("reader.onerror");
|
||
}
|
||
reader.readAsText(file);
|
||
|
||
|
||
} catch (err) {
|
||
console.error("err=", err);
|
||
reject(err.message)
|
||
}
|
||
|
||
|
||
|
||
},
|
||
(err) => {
|
||
console.error('获取文件对象失败:', err);
|
||
reject('获取文件对象失败')
|
||
}
|
||
);
|
||
},
|
||
(err) => {
|
||
console.error('解析文件路径失败:', err);
|
||
reject('解析文件路径失败')
|
||
}
|
||
);
|
||
});
|
||
|
||
promise.then(txt => {
|
||
this.formData.txt = txt;
|
||
updateLoading(this, {
|
||
text: '读取成功'
|
||
});
|
||
}).catch(ex => {
|
||
updateLoading(this, {
|
||
text: '无法读取文档'
|
||
});
|
||
}).finally(() => {
|
||
setTimeout(() => {
|
||
hideLoading(these);
|
||
}, 500)
|
||
})
|
||
|
||
},
|
||
parseDoc(filePath) {
|
||
uni.openDocument({
|
||
filePath: filePath,
|
||
fail(err) {
|
||
these.showMsg("无法打开文档");
|
||
}
|
||
});
|
||
},
|
||
parseWord(filePath) { //读取word文件
|
||
const token = uni.getStorageSync('token');
|
||
const clientid = uni.getStorageSync('clientID');
|
||
|
||
|
||
|
||
showLoading(this, {
|
||
text: "文档读取中"
|
||
});
|
||
let promise = new Promise((resolve, reject) => {
|
||
|
||
uni.uploadFile({
|
||
url: baseURL + "/app/video/extract",
|
||
|
||
filePath: filePath,
|
||
name: 'file',
|
||
header: {
|
||
"Method": "POST",
|
||
"Content-Type": "multipart/form-data",
|
||
"Authorization": 'Bearer ' + token,
|
||
"clientid": clientid
|
||
},
|
||
timeout: 600000,
|
||
fail: (ex) => {
|
||
reject('文件无法读取,请手动复制文本内容');
|
||
},
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
res = JSON.parse(res.data);
|
||
console.log("服务器响应=", res);
|
||
if (res && res.data) {
|
||
these.formData.txt = res.data;
|
||
updateLoading(this, {
|
||
text: '读取成功'
|
||
});
|
||
resolve();
|
||
return;
|
||
}
|
||
}
|
||
|
||
reject('文件无法读取,请手动复制文本内容');
|
||
},
|
||
complete() {
|
||
setTimeout(() => {
|
||
hideLoading(these);
|
||
}, 500);
|
||
}
|
||
});
|
||
|
||
});
|
||
|
||
promise.then(res => {}).catch(ex => {
|
||
updateLoading(these, {
|
||
text: ex
|
||
});
|
||
uni.openDocument({
|
||
filePath: filePath,
|
||
fail(err) {
|
||
console.error("无法打开文件", err);
|
||
}
|
||
});
|
||
});
|
||
},
|
||
checkFile() {
|
||
this.$refs.XeUpload.upload('file');
|
||
},
|
||
toggleRecord() {
|
||
if (this.Status.recoderIntval) {
|
||
this.stopLuYin();
|
||
} else {
|
||
this.startLuYin();
|
||
}
|
||
},
|
||
playInit(tempFilePath) {
|
||
let task = (path) => {
|
||
try {
|
||
console.log("path=", path);
|
||
this.AudioData.tempFilePath = path;
|
||
this.cEdit.localPath = path;
|
||
this.cEdit.Id = Common.guid();
|
||
this.cEdit.createTime = Common.DateFormat(new Date(), "yyyy年MM月dd日");
|
||
this.cEdit.isApply = false;
|
||
this.cEdit.statu = false;
|
||
this.cEdit.type=this.Status.pageType;
|
||
this.cEdit.webPath = "";
|
||
console.log("aaaaaaaaaaaaaaaaaaa");
|
||
if(path){
|
||
this.createAudioPlayer();
|
||
}
|
||
else{
|
||
this.cEdit.time="";
|
||
}
|
||
} catch (exx) {
|
||
console.error("exx=", exx)
|
||
}
|
||
|
||
}
|
||
|
||
//将文件移动到downloads目录,因为doc目录会丢失
|
||
Common.moveFileToDownloads(tempFilePath).then(res => {
|
||
console.log("文件移动成功", res);
|
||
task(res);
|
||
}).catch(ex => {
|
||
console.error("文件移动失败了", ex);
|
||
task(tempFilePath);
|
||
});
|
||
},
|
||
startLuYin() {
|
||
|
||
this.destoryAudioPlayer();
|
||
if (!AudeoRecoder) {
|
||
// #ifdef APP
|
||
try {
|
||
AudeoRecoder = uni.getRecorderManager();
|
||
|
||
AudeoRecoder.onStop(function(res) {
|
||
try {
|
||
console.log('录音停止:' + JSON.stringify(res));
|
||
these.AudioData = res;
|
||
these.cEdit.time = these.Status.RecordTime;
|
||
these.cEdit.name = "语音录制" + these.Status.RecordName;
|
||
if (these.Status.pageValid) {
|
||
these.dropTmpFile();
|
||
these.Status.pageValid = false;
|
||
AudeoRecoder = null;
|
||
|
||
} else {
|
||
|
||
these.playInit(these.AudioData.tempFilePath);
|
||
}
|
||
} catch (ex) {
|
||
console.error("ex=", ex);
|
||
}
|
||
|
||
|
||
});
|
||
} catch (ex) {
|
||
|
||
}
|
||
// #endif
|
||
}
|
||
|
||
|
||
|
||
let startTask = () => {
|
||
clearInterval(this.Status.recoderIntval);
|
||
this.Status.recoderIntval = null;
|
||
// #ifdef APP
|
||
try {
|
||
AudeoRecoder.start({
|
||
duration: 60000,
|
||
sampleRate: 44100,
|
||
format: 'wav',
|
||
frameSize: 16
|
||
|
||
});
|
||
} catch (error) {
|
||
//TODO handle the exception
|
||
}
|
||
|
||
|
||
// #endif
|
||
this.Status.RecordTime = 0;
|
||
this.Status.RecordName = Common.DateFormat(new Date(), "yyyyMMddHHmmss");
|
||
this.AudioData.tempFilePath = "";
|
||
this.Status.recoderIntval = setInterval(() => {
|
||
this.Status.RecordTime += 1;
|
||
if (this.Status.RecordTime >= 60) {
|
||
this.toggleRecord();
|
||
}
|
||
}, 1000);
|
||
this.Status.isRecord = !this.Status.isRecord;
|
||
}
|
||
|
||
|
||
if (this.AudioData.tempFilePath) {
|
||
this.showMsg("当前录音未保存,您要放弃该录音吗?", false, true, () => {
|
||
these.dropTmpFile();
|
||
startTask();
|
||
})
|
||
} else {
|
||
startTask()
|
||
}
|
||
|
||
},
|
||
stopLuYin() {
|
||
clearInterval(this.Status.recoderIntval);
|
||
this.Status.recoderIntval = null;
|
||
|
||
try {
|
||
AudeoRecoder.stop();
|
||
} catch (ex) {
|
||
if (!these.Status.pageValid) {
|
||
these.AudioData.tempFilePath = "_doc/" + this.Status.RecordName + ".mp3"
|
||
}
|
||
|
||
} finally {
|
||
this.Status.isRecord = !this.Status.isRecord;
|
||
}
|
||
|
||
},
|
||
dropTmpFile() {
|
||
//删除丢弃的文件
|
||
// #ifdef APP
|
||
if (!these.AudioData.tempFilePath) {
|
||
return;
|
||
}
|
||
try {
|
||
plus.io.resolveLocalFileSystemURL(these.AudioData.tempFilePath, (entry) => {
|
||
// 确认是文件类型
|
||
if (entry.isFile) {
|
||
entry.remove(
|
||
() => {
|
||
console.log('文件删除成功');
|
||
// 删除成功后的逻辑
|
||
these.AudioData.tempFilePath = "";
|
||
},
|
||
(err) => {
|
||
console.error('文件删除失败:', err.message);
|
||
}
|
||
);
|
||
} else {
|
||
console.error('路径指向的不是文件');
|
||
}
|
||
}, (err) => {
|
||
console.error('路径解析失败:', err.message);
|
||
|
||
});
|
||
} catch (error) {
|
||
|
||
}
|
||
// #endif
|
||
},
|
||
closePop: function() {
|
||
this.Status.Pop.showPop = false;
|
||
|
||
if (this.Status.Pop.cancelCallback) {
|
||
this.Status.Pop.cancelCallback();
|
||
}
|
||
},
|
||
HidePop: function() {
|
||
|
||
|
||
|
||
this.Status.Pop.showPop = false;
|
||
if (this.Status.Pop.okCallback) {
|
||
this.Status.Pop.okCallback();
|
||
}
|
||
},
|
||
showPop: function(option) {
|
||
hideLoading(this);
|
||
let def = {
|
||
showPop: true, //是否显示弹窗
|
||
popType: 'custom',
|
||
bgColor: '#383934bd',
|
||
borderColor: '#BBE600',
|
||
textColor: '#ffffffde',
|
||
buttonBgColor: '#BBE600',
|
||
buttonTextColor: '#232323DE',
|
||
iconUrl: '',
|
||
message: '',
|
||
buttonText: '确定',
|
||
clickEvt: '',
|
||
visiblePrompt: false,
|
||
promptTitle: '',
|
||
modelValue: '',
|
||
visibleClose: false,
|
||
okCallback: null,
|
||
showSlot: false,
|
||
buttonCancelText: '',
|
||
showCancel: false,
|
||
}
|
||
|
||
let keys = Object.keys(def);
|
||
|
||
for (let i = 0; i < keys.length; i++) {
|
||
let key = keys[i];
|
||
if (key in option) {
|
||
continue;
|
||
}
|
||
this.Status.Pop[key] = def[key];
|
||
}
|
||
if (option) {
|
||
keys = Object.keys(option);
|
||
for (let i = 0; i < keys.length; i++) {
|
||
let key = keys[i];
|
||
|
||
this.Status.Pop[key] = option[key];
|
||
}
|
||
}
|
||
|
||
if (!option.borderColor) {
|
||
option.borderColor = '#BBE600';
|
||
option.buttonBgColor = '#BBE600';
|
||
}
|
||
these.Status.Pop.showPop = true;
|
||
},
|
||
showMsg(msg, isSucc, showCancel, okCallback) {
|
||
if (showCancel === undefined) {
|
||
showCancel = false;
|
||
}
|
||
if (okCallback === undefined) {
|
||
okCallback = null;
|
||
}
|
||
let icoUrl = '/static/images/6155/DeviceDetail/uploadErr.png';
|
||
let borderColor = "#e034344d";
|
||
let buttonBgColor = "#E03434";
|
||
if (isSucc) {
|
||
icoUrl = '/static/images/common/success.png';
|
||
borderColor = "#BBE600";
|
||
buttonBgColor = "#BBE600";
|
||
}
|
||
this.showPop({
|
||
message: msg,
|
||
iconUrl: icoUrl,
|
||
borderColor: borderColor,
|
||
buttonBgColor: buttonBgColor,
|
||
buttonText: '确定',
|
||
okCallback: okCallback,
|
||
showCancel: showCancel,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.footer .opt {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-wrap: wrap;
|
||
align-content: center;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.footer .recordTitle {
|
||
color: rgba(255, 255, 255, 0.87);
|
||
|
||
font-family: PingFang SC;
|
||
font-size: 28rpx;
|
||
font-weight: 400;
|
||
line-height: 40rpx;
|
||
letter-spacing: 0.14rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.footer .recordName {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
|
||
font-family: PingFang SC;
|
||
font-size: 24rpx;
|
||
font-weight: 400;
|
||
line-height: 34rpx;
|
||
letter-spacing: 0.14px;
|
||
text-align: center;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.footer .btnRecord .start {
|
||
background: rgba(224, 52, 52, 1);
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.footer .btnRecord .start.active {
|
||
border-radius: 8rpx;
|
||
background: rgba(224, 52, 52, 1);
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.footer .btnRecord {
|
||
|
||
width: 110rpx;
|
||
height: 110rpx;
|
||
box-sizing: border-box;
|
||
border: 4rpx solid rgba(255, 255, 255, 0.6);
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.footer .btnRemark {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
margin-top: 20rpx;
|
||
font-family: PingFang SC;
|
||
font-size: 28rpx;
|
||
font-weight: 400;
|
||
line-height: 40rpx;
|
||
letter-spacing: 0.14px;
|
||
text-align: center;
|
||
|
||
}
|
||
|
||
.footer {
|
||
padding-top: 60rpx;
|
||
padding-bottom: 60rpx;
|
||
width: 100%;
|
||
|
||
height: auto;
|
||
position: fixed;
|
||
z-index: 99;
|
||
left: 0rpx;
|
||
bottom: 0rpx;
|
||
border-radius: 16rpx 16rpx 0px 0px;
|
||
background: rgba(26, 26, 26, 1);
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-wrap: nowrap;
|
||
align-content: center;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.popup-prompt {
|
||
width: 100%;
|
||
margin-top: 40rpx;
|
||
}
|
||
|
||
|
||
|
||
.popup-prompt-input {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
border: 1rpx solid #BBE60096;
|
||
border-radius: 10rpx;
|
||
padding: 0 20rpx;
|
||
margin-bottom: 30rpx;
|
||
font-size: 26rpx;
|
||
box-sizing: border-box;
|
||
text-align: left;
|
||
|
||
}
|
||
|
||
|
||
.tips {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
|
||
font-family: PingFang SC;
|
||
font-size: 28rpx;
|
||
font-weight: 400;
|
||
line-height: 40rpx;
|
||
letter-spacing: 0.14rpx;
|
||
text-align: left;
|
||
}
|
||
|
||
.polygon {
|
||
width: 300rpx;
|
||
height: 150rpx;
|
||
background-color: #3A3A3A;
|
||
border-radius: 10rpx;
|
||
color: rgba(255, 255, 255, 0.6);
|
||
;
|
||
}
|
||
|
||
.cEdit {
|
||
width: 100%;
|
||
height: auto;
|
||
border-radius: 8px;
|
||
background: rgba(26, 26, 26, 1);
|
||
box-sizing: border-box;
|
||
padding: 40rpx 30rpx
|
||
}
|
||
|
||
.btnSave {
|
||
width: 130rpx;
|
||
height: 55rpx;
|
||
line-height: 55rpx;
|
||
text-align: center;
|
||
color: rgba(23, 23, 23, 1);
|
||
font-family: PingFang SC;
|
||
font-size: 24rpx;
|
||
font-weight: 400;
|
||
letter-spacing: 12rpx;
|
||
background-color: #BBE600;
|
||
border-radius: 180rpx;
|
||
}
|
||
|
||
.txtName {
|
||
color: rgba(174, 214, 0, 1);
|
||
border-bottom: 1rpx solid rgba(174, 214, 0, 1);
|
||
font-family: PingFang SC;
|
||
font-size: 32rpx;
|
||
font-weight: 400;
|
||
line-height: 44rpx;
|
||
letter-spacing: 0.14px;
|
||
text-align: left;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.audioRemark {
|
||
display: flex;
|
||
flex-wrap: nowrap;
|
||
align-content: center;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.slide {
|
||
padding-top: 60rpx;
|
||
width: 100%;
|
||
position: relative;
|
||
}
|
||
|
||
.slide .line {
|
||
width: 100%;
|
||
height: 4rpx;
|
||
border-radius: 12rpx;
|
||
background: rgba(106, 106, 106, 1);
|
||
}
|
||
|
||
.slide .circle {
|
||
position: absolute;
|
||
margin-top: -4rpx;
|
||
width: 12rpx;
|
||
height: 12rpx;
|
||
background: rgba(234, 234, 234, 1);
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.control {
|
||
width: 100%;
|
||
padding: 40rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.control .playControl {
|
||
width: 100%;
|
||
position: absolute;
|
||
left: 0rpx;
|
||
bottom: 0rpx;
|
||
z-index: 1;
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: nowrap;
|
||
align-content: center;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.control .drop {
|
||
position: absolute;
|
||
z-index: 2;
|
||
bottom: 0rpx;
|
||
right: 0rpx;
|
||
}
|
||
|
||
.playControl .seek .img {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
}
|
||
|
||
.playControl .play .img {
|
||
width: 38rpx;
|
||
height: 44rpx;
|
||
margin: 0rpx 80rpx;
|
||
}
|
||
|
||
.input {
|
||
border-bottom: 1rpx solid #FFFFFF;
|
||
}
|
||
|
||
.placehoderClass {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
|
||
font-family: PingFang SC;
|
||
font-size: 32rpx;
|
||
font-weight: 400;
|
||
line-height: 44rpx;
|
||
letter-spacing: 0.14px;
|
||
}
|
||
|
||
.text-content {
|
||
border-radius: 16rpx;
|
||
background: rgba(26, 26, 26, 1);
|
||
width: 100%;
|
||
height: auto;
|
||
box-sizing: border-box;
|
||
padding: 20rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.importTxt {
|
||
color: rgba(174, 214, 0, 1);
|
||
|
||
font-family: PingFang SC;
|
||
font-size: 28rpx;
|
||
font-weight: 400;
|
||
height: 60rpx;
|
||
line-height: 60rpx;
|
||
letter-spacing: 0.14px;
|
||
|
||
}
|
||
|
||
.textarea {
|
||
min-height: 300rpx;
|
||
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.line {
|
||
width: 100%;
|
||
height: 0rpx;
|
||
border-bottom: 1rpx solid rgba(255, 255, 255, 0.36);
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.footBtn {
|
||
width: 100%;
|
||
|
||
}
|
||
|
||
.footBtn .convert {
|
||
/* 组合 99 */
|
||
width: 130rpx;
|
||
height: 55rpx;
|
||
line-height: 55rpx;
|
||
border-radius: 180px;
|
||
color: #232323;
|
||
background-color: #AED600;
|
||
text-align: center;
|
||
font-family: PingFang SC;
|
||
font-size: 24rpx;
|
||
font-weight: 400;
|
||
letter-spacing: 12rpx;
|
||
}
|
||
|
||
.footBtn .audioSett,
|
||
.audioSett{
|
||
margin-right: 50rpx;
|
||
color: #FFFFFFDE;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
|
||
font-family: PingFang SC;
|
||
font-size: 28rpx;
|
||
font-weight: 400;
|
||
line-height: 55rpx;
|
||
letter-spacing: 0px;
|
||
text-align: center;
|
||
}
|
||
|
||
.txtBtns{
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
padding:20rpx;
|
||
}
|
||
</style> |