|
@@ -0,0 +1,476 @@
|
|
|
|
+<template>
|
|
|
|
+ <view>
|
|
|
|
+ <view class="bgbox" v-if="voiceflag" @click="getClose"></view>
|
|
|
|
+ <view class="voice" v-if="voiceflag">
|
|
|
|
+ <image :src="closeimg" class="choseimg" @click="getClose"></image>
|
|
|
|
+ <view v-if="isShow">
|
|
|
|
+ <view v-if="sendLock" class="tip">
|
|
|
|
+ <view class="txt">试试这样说</view>
|
|
|
|
+ <view class="txt-bt">科技</view>
|
|
|
|
+ </view>
|
|
|
|
+ <view v-else>
|
|
|
|
+ <!-- @click="resultClick" -->
|
|
|
|
+ <view class="res-txt" >
|
|
|
|
+ <text :style="{
|
|
|
|
+ color: (resultText == '正在识别中2...' || resultText == '未检测到语音,请重试') ?
|
|
|
|
+ '#919098' :
|
|
|
|
+ '#2979ff'}">
|
|
|
|
+ {{resultText}}
|
|
|
|
+ </text>
|
|
|
|
+ <!-- <image v-if="resultText != '正在识别中.1..' && resultText != '未检测到语音,请重试'"
|
|
|
|
+ src="/static/img/xiaoshou.png" mode="widthFix"></image> -->
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+
|
|
|
|
+ <view v-else class="tip">
|
|
|
|
+ <view v-if="!sendLock" class="tipbox">{{voicetext}}</view>
|
|
|
|
+ <view v-html="text" class="txt" style="color: #8e8d9a;"></view>
|
|
|
|
+ <view v-if="!sendLock" class="prompt-loader">
|
|
|
|
+ <view class="em" :style="randomRgb()" v-for="(item,index) in 30" :key="index"></view>
|
|
|
|
+ </view>
|
|
|
|
+ <view v-else class="prompt-loader"></view>
|
|
|
|
+ </view>
|
|
|
|
+
|
|
|
|
+ <view class="btn" @longpress="handleRecordStart" @touchmove="handleTouchMove" @touchend="handleRecordStop">
|
|
|
|
+ <view class="btn-cont">
|
|
|
|
+ 长按开始语音搜索
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+ const recorderManager = uni.getRecorderManager();
|
|
|
|
+ //播放录音
|
|
|
|
+ const innerAudioContext = uni.createInnerAudioContext();
|
|
|
|
+ innerAudioContext.autoplay = true;
|
|
|
|
+ export default{
|
|
|
|
+ props:{
|
|
|
|
+ voiceflag:{
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default () {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ watch:{
|
|
|
|
+ sendLock(newVal, oldVal) {
|
|
|
|
+ var that=this;
|
|
|
|
+ recorderManager.onStop(res => {
|
|
|
|
+ if (newVal) return //上锁不发送
|
|
|
|
+ //解锁发送网络请求
|
|
|
|
+ setTimeout(function(res){
|
|
|
|
+ if(!that.voicetext&&!that.partialResult){
|
|
|
|
+ that.resultText='未检测到语音,请重试';
|
|
|
|
+ that.sendLock=true;
|
|
|
|
+ }else{
|
|
|
|
+ that.resultText=that.voicetext||that.partialResult;
|
|
|
|
+ // console.log(that.resultText,85)
|
|
|
|
+ // that.xmmc=that.xmmc+that.resultText;
|
|
|
|
+ setTimeout(function(){
|
|
|
|
+ that.$emit('getVoice',that.resultText)
|
|
|
|
+ // that.voiceflag=false;
|
|
|
|
+ that.sendLock=true;
|
|
|
|
+ },1200)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ },1000)
|
|
|
|
+ // console.log(res.tempFilePath, '获取录音文件')
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ data(){
|
|
|
|
+ return {
|
|
|
|
+ // speechimg:require('@/static/images/index/speech.png'),
|
|
|
|
+ xmmc:'',
|
|
|
|
+
|
|
|
|
+ closeimg:require("@/static/images/close.png"),
|
|
|
|
+ // voiceflag:true,
|
|
|
|
+ voiceToken: '',
|
|
|
|
+ timer: null,
|
|
|
|
+ text: '',
|
|
|
|
+ resultText: '正在识别中...',
|
|
|
|
+ startPoint: {},
|
|
|
|
+ sendLock: true,
|
|
|
|
+ isShow: true,
|
|
|
|
+ adioFileData: '',
|
|
|
|
+ adioSize: '',
|
|
|
|
+ resContent: '',
|
|
|
|
+ luyinStatus: true,
|
|
|
|
+ voicetext:'',
|
|
|
|
+ options: {}, // 语音转文字的设置
|
|
|
|
+ partialResult:'',//临时语音
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ // if(!this.xmmc){
|
|
|
|
+ // this.xmmc=this.name
|
|
|
|
+ // }
|
|
|
|
+ var that=this;
|
|
|
|
+ // #ifdef APP-PLUS
|
|
|
|
+ // 监听语音识别事件
|
|
|
|
+ plus.speech.addEventListener('start', this.ontStart, false);
|
|
|
|
+ plus.speech.addEventListener('volumeChange', this.onVolumeChange, false);
|
|
|
|
+ plus.speech.addEventListener('recognizing', this.onRecognizing, false);
|
|
|
|
+ plus.speech.addEventListener('recognition', this.onRecognition, false);
|
|
|
|
+ plus.speech.addEventListener('end', this.onEnd, false);
|
|
|
|
+ // #endif
|
|
|
|
+
|
|
|
|
+ recorderManager.onStop(function(res) {
|
|
|
|
+ //录音后的回调函数
|
|
|
|
+ // console.log('recorder stop' + JSON.stringify(res));
|
|
|
|
+ // console.log(res.tempFilePath);
|
|
|
|
+ that.voicePath = res.tempFilePath;
|
|
|
|
+ // self.voicePath =
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ onUnload() {
|
|
|
|
+ },
|
|
|
|
+ unmounted() {
|
|
|
|
+ },
|
|
|
|
+ methods:{
|
|
|
|
+ getClose(){
|
|
|
|
+ // this.voiceflag=false;
|
|
|
|
+ this.sendLock=true;
|
|
|
|
+ this.$emit('getClose')
|
|
|
|
+ },
|
|
|
|
+ onRecognizing(e){
|
|
|
|
+ this.partialResult=this.partialResult+e.partialResult;
|
|
|
|
+ },
|
|
|
|
+ // 录音转文字
|
|
|
|
+ handleVoice() {
|
|
|
|
+ // console.log('语音输入')
|
|
|
|
+ let _this = this;
|
|
|
|
+ this.options.engine = 'baidu'
|
|
|
|
+ // this.options.timeout = 60 * 1000; //超时时间
|
|
|
|
+ this.options.continue = true;//语音识别是否采用持续模式
|
|
|
|
+ this.options.punctuation = false; // 是否需要标点符号
|
|
|
|
+ this.options.userInterface = false; // 是否显示语音界面
|
|
|
|
+ plus.speech.startRecognize(this.options, (s) => {
|
|
|
|
+ console.log(s,1)
|
|
|
|
+ _this.voicetext+=s;
|
|
|
|
+ // plus.speech.stopRecognize(); // 关
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ //长按录音方法
|
|
|
|
+ handleRecordStart(e) {
|
|
|
|
+ this.voicetext='';
|
|
|
|
+ this.partialResult='';
|
|
|
|
+ this.startPoint = e.touches[0]; //记录长按时开始点信息,后面用于计算上划取消时手指滑动的距离。
|
|
|
|
+ recorderManager.start({duration: 60000}); //开始录音
|
|
|
|
+ this.handleVoice()
|
|
|
|
+ this.text = `<text style="color:#333">上划取消识别</text>`;
|
|
|
|
+ this.sendLock = false; //长按时不上锁。
|
|
|
|
+ this.isShow = false;
|
|
|
|
+ this.resultText = '正在识别中...';
|
|
|
|
+ // 按钮
|
|
|
|
+ },
|
|
|
|
+ //结束录音 (手指松开)时触发
|
|
|
|
+ handleRecordStop(e) {
|
|
|
|
+ var that=this;
|
|
|
|
+ this.isShow = true;
|
|
|
|
+ setTimeout(function(){
|
|
|
|
+ plus.speech.stopRecognize();
|
|
|
|
+ recorderManager.stop(); //结束录音
|
|
|
|
+ },1200)
|
|
|
|
+
|
|
|
|
+ },
|
|
|
|
+ //上划取消搜索
|
|
|
|
+ handleTouchMove(e) {
|
|
|
|
+ let moveLenght = e.touches[e.touches.length - 1].clientY - this.startPoint.clientY;
|
|
|
|
+ if (Math.abs(moveLenght) > 50) {
|
|
|
|
+ this.text = `松开手指,<text style="color:#333">取消搜索</text>`;
|
|
|
|
+ this.sendLock = true; //触发了上滑取消搜索,上锁
|
|
|
|
+ this.isShow = false;
|
|
|
|
+ } else {
|
|
|
|
+ this.text = `<text style="color:#333">上划取消搜索</text>`;
|
|
|
|
+ this.sendLock = false; //上划距离不足,可以搜索,不上锁
|
|
|
|
+ this.isShow = false;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ //获取录音结果子传父
|
|
|
|
+ resultClick() {
|
|
|
|
+ if (this.resultText == '正在识别中...' || this.resultText == '未检测到语音,请重试') return;
|
|
|
|
+ this.$emit('getVoice',this.resultText)
|
|
|
|
+ // this.voiceflag=false;
|
|
|
|
+ this.sendLock=true;
|
|
|
|
+ // this.$emit('voiceResult', this.resultText)
|
|
|
|
+ },
|
|
|
|
+ //弹窗关闭之后的操作,点击遮罩层或关闭按钮
|
|
|
|
+ // afterHide() {
|
|
|
|
+ // this.sendLock = true;
|
|
|
|
+ // this.$emit('closePopup');
|
|
|
|
+ // clearInterval(this.timer);
|
|
|
|
+ // this.resultText = '正在识别中...';
|
|
|
|
+ // },
|
|
|
|
+ randomRgb() {
|
|
|
|
+ let R = Math.floor(Math.random() * 130 + 110);
|
|
|
|
+ let G = Math.floor(Math.random() * 130 + 110);
|
|
|
|
+ let B = Math.floor(Math.random() * 130 + 110);
|
|
|
|
+ return {
|
|
|
|
+ background: `rgb(${R},${G},${B}, 1)`
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ // 语音转文字
|
|
|
|
+ getSeep(){
|
|
|
|
+ this.voicetext='';
|
|
|
|
+ this.partialResult='';
|
|
|
|
+ this.voiceflag=true;
|
|
|
|
+ },
|
|
|
|
+ onEnd() {
|
|
|
|
+ // let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
|
|
|
|
+ // let curRoute = routes[routes.length - 1].route //获取当前页面路由
|
|
|
|
+ // if(curRoute=='pages/work/shprogress'){
|
|
|
|
+
|
|
|
|
+ // }else{
|
|
|
|
+ // if(this.xmmc){
|
|
|
|
+ // this.getVoice()
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
+ // 搜索
|
|
|
|
+.listtopa{border: 6rpx solid #FD5001;border-radius: 32rpx;height:64rpx;box-sizing: border-box;padding:0 140rpx 0 32rpx ;position: relative;
|
|
|
|
+ input{}
|
|
|
|
+ image{width: 20rpx;height: 30rpx;margin-right: 16rpx;}
|
|
|
|
+ .btn{background: #FA5F03;border-radius: 32rpx;width: 120rpx;position: absolute;right: -2rpx;top: -2rpx;bottom:-2rpx;}
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .bgbox{z-index: 1900;}
|
|
|
|
+ .choseimg{width: 34rpx;height: 34rpx;position: absolute;left: 36rpx;top: 54rpx;}
|
|
|
|
+ .voice {
|
|
|
|
+ min-height: 500rpx;
|
|
|
|
+ padding: 100rpx 60rpx 0 60rpx;
|
|
|
|
+ position: relative;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ position: fixed;
|
|
|
|
+ left:0;right:0;bottom:0;z-index: 2000;
|
|
|
|
+ padding-bottom: 180rpx;
|
|
|
|
+ .res-txt {
|
|
|
|
+ text-align: center;
|
|
|
|
+ margin-top: 40rpx;
|
|
|
|
+ font-size: 36rpx;
|
|
|
|
+ color: #919098;
|
|
|
|
+
|
|
|
|
+ image {
|
|
|
|
+ display: block;
|
|
|
|
+ margin: auto;
|
|
|
|
+ margin-top: 10rpx;
|
|
|
|
+ width: 60rpx;
|
|
|
|
+ animation: bounce-down 2.6s linear infinite;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .tip {
|
|
|
|
+ margin-top: 15rpx;
|
|
|
|
+ text-align: center;
|
|
|
|
+
|
|
|
|
+ .txt {
|
|
|
|
+ font-size: 36rpx;
|
|
|
|
+ color: #151823;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .txt-bt {
|
|
|
|
+ margin-top: 20rpx;
|
|
|
|
+ color: #919098;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .btn {
|
|
|
|
+ width: 50%;
|
|
|
|
+ height: 80rpx;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ color: #fff;
|
|
|
|
+ border-radius: 50rpx;
|
|
|
|
+ background: #3484fd;
|
|
|
|
+ position: absolute;
|
|
|
|
+ bottom: 80rpx;
|
|
|
|
+ left: 50%;
|
|
|
|
+ transform: translateX(-50%);
|
|
|
|
+
|
|
|
|
+ .btn-cont {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @-webkit-keyframes bounce-down {
|
|
|
|
+ 25% {
|
|
|
|
+ -webkit-transform: translateY(-10px);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 50%,
|
|
|
|
+ 100% {
|
|
|
|
+ -webkit-transform: translateY(0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 75% {
|
|
|
|
+ -webkit-transform: translateY(13px);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .content{background-color: #f5f5f5;position: fixed;left: 0;right: 0;bottom: 0;z-index: 10000;height: 500rpx;}
|
|
|
|
+ /* 语音动画 */
|
|
|
|
+ .prompt-loader {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 35px;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ margin: 30rpx auto;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em {
|
|
|
|
+ height: 15%;
|
|
|
|
+ width: 2px;
|
|
|
|
+ float: left;
|
|
|
|
+ display: block;
|
|
|
|
+ background: #333333;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:last-child {
|
|
|
|
+ margin-right: 0px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(1) {
|
|
|
|
+ animation: load 1.3s 0.4s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(2) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(3) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(4) {
|
|
|
|
+ animation: load 1.3s 0.8s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(5) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(6) {
|
|
|
|
+ animation: load 1.3s 0.4s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(7) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(8) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(9) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(10) {
|
|
|
|
+ animation: load 1.3s 0.4s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(11) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(12) {
|
|
|
|
+ animation: load 1.3s 0.8s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(13) {
|
|
|
|
+ animation: load 1.3s 1s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(14) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(15) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(16) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(17) {
|
|
|
|
+ animation: load 1.3s 0.8s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(18) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(19) {
|
|
|
|
+ animation: load 1.3s 0.4s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(20) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(21) {
|
|
|
|
+ animation: load 1.3s 0.5s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(22) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(23) {
|
|
|
|
+ animation: load 1.3s 0.4s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(24) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(25) {
|
|
|
|
+ animation: load 1.3s 0.8s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(26) {
|
|
|
|
+ animation: load 1.3s 0.2s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(27) {
|
|
|
|
+ animation: load 1.3s 0.4s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(28) {
|
|
|
|
+ animation: load 1.3s 0.1s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(29) {
|
|
|
|
+ animation: load 1.3s 0.3s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .prompt-loader .em:nth-child(30) {
|
|
|
|
+ animation: load 1.3s 0.6s infinite linear;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @keyframes load {
|
|
|
|
+ 0% {
|
|
|
|
+ height: 15%;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 50% {
|
|
|
|
+ height: 100%;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 100% {
|
|
|
|
+ height: 15%;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+</style>
|