在家开发了btn按钮样式
This commit is contained in:
+2
-2
@@ -4,10 +4,10 @@ ENV = 'development'
|
||||
|
||||
|
||||
|
||||
#VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
|
||||
VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
|
||||
|
||||
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
#VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
|
||||
# VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
|
||||
# VITE_APP_BASE_API_Url = 'http://192.168.247.200'
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
position: relative;
|
||||
}
|
||||
/* 1. 定义通用的向右移出动画(核心:添加时长,解决秒没) */
|
||||
@keyframes moveRightOut {
|
||||
@@ -24,29 +25,44 @@
|
||||
left: -400rpx; /* 目标位置:向左移出400rpx */
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. 定义通用的向左移出动画(适配 btn-box-1) */
|
||||
@keyframes moveBottomOut {
|
||||
0% {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.page-1 {
|
||||
background-color: red;
|
||||
&.init {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
&.voice_to_text{
|
||||
.btn-box-1 {
|
||||
position: absolute; /* 定位是动画生效的前提 */
|
||||
left: 0; /* 初始位置 */
|
||||
/* 核心动画配置:时长+曲线+保留最终状态 */
|
||||
animation: moveLeftOut 0.5s ease-out forwards;
|
||||
animation: moveLeftOut 0.3s ease-out forwards;
|
||||
/* 清除冲突样式 */
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.btn-box-2 {
|
||||
position: absolute; /* 定位是动画生效的前提 */
|
||||
right: 0; /* 初始位置 */
|
||||
/* 核心动画配置:时长+曲线+保留最终状态 */
|
||||
animation: moveRightOut 0.5s ease-out forwards;
|
||||
animation: moveRightOut 0.3s ease-out forwards;
|
||||
/* 清除冲突样式 */
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
.circle-bg-box{
|
||||
animation: moveBottomOut 0.3s ease-out forwards;
|
||||
}
|
||||
}
|
||||
// 两侧按钮
|
||||
.btns-box {
|
||||
@@ -93,4 +109,159 @@
|
||||
line-height: 46px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-2{
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
display: none;
|
||||
z-index: 12000;
|
||||
justify-content: space-around;
|
||||
margin-bottom:234rpx;;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden; // 初始不可见且不占交互位置
|
||||
&.voice_to_text {
|
||||
display: flex !important;
|
||||
visibility: visible; // 激活后可见
|
||||
animation: fadeIn 0.4s ease-out 0.1s forwards;
|
||||
}
|
||||
.transVoiceIng {
|
||||
width: 154rpx;
|
||||
height: 154rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 12010;
|
||||
|
||||
&.cancel-btn {
|
||||
background: url(@/static/images/course/cancel-btn.png) no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
&.trans-btn {
|
||||
background: url(@/static/images/course/trans-btn.png) no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
.send-btn {
|
||||
position: relative;
|
||||
width: 262rpx;
|
||||
height: 154rpx;
|
||||
line-height: 154rpx;
|
||||
overflow: hidden;
|
||||
background-color: #d8d8d8;
|
||||
border-radius: 77rpx;
|
||||
font-size: 33rpx;
|
||||
z-index: 12010;
|
||||
}
|
||||
}
|
||||
.talk-dialog-box{
|
||||
position: absolute;
|
||||
bottom: 520rpx ;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.talk-dialog-div {
|
||||
width: 506rpx;
|
||||
min-height: 234rpx;
|
||||
background-color: #06f;
|
||||
border-radius: 32rpx;
|
||||
transition: width 0.3s ease;
|
||||
// 滑动到离开变红
|
||||
&.is-out {
|
||||
background-color: #ff3e49;
|
||||
|
||||
&::after {
|
||||
background-color: #ff3e49;
|
||||
}
|
||||
}
|
||||
// 滑动到转文字变宽
|
||||
&.is-translate {
|
||||
width: 706rpx;
|
||||
.gif-box {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
||||
background-color: #06f;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
bottom: -22rpx;
|
||||
left: 50%;
|
||||
margin-left: -22rpx;
|
||||
transition: left 0.3s ease-out; // 时长0.3秒,ease-out缓动(结束时变慢,更自然)
|
||||
}
|
||||
// 控制下边箭头指向发送
|
||||
&.init::after {
|
||||
left: 78% !important;
|
||||
}
|
||||
&.failed {
|
||||
width: 506rpx;
|
||||
height: 114rpx;
|
||||
min-height: 114rpx;
|
||||
background-color: #ff3e49;
|
||||
&::after {
|
||||
background-color: #ff3e49;
|
||||
}
|
||||
// 激活错误提示框
|
||||
.error-tip-div{
|
||||
display: flex !important;
|
||||
visibility: visible; // 激活后可见
|
||||
// animation: fadeIn 0.4s ease-out 0.1s forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
.talk-dialog {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
.text-div {
|
||||
overflow-y: scroll;
|
||||
max-height: 434rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
.gif-box {
|
||||
position: absolute;
|
||||
width: 200rpx;
|
||||
height: 80rpx;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.error-tip-div{
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
display: none;
|
||||
visibility: hidden; // 初始不可见且不占交互位置
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #ffffff;
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
.img{
|
||||
margin-right: 10rpx;
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,15 +11,21 @@ export const icKeyboardSvg = () : string => {
|
||||
`;
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
export const icMicSvg = () : string => {
|
||||
export const iconMicSvg = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1772357429950" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1775" width="200" height="200"><path d="M513.788813 938.289925c-113.566274 0-220.223734-44.167967-300.444149-124.388381-80.220415-80.220415-124.388382-186.877876-124.388382-300.44415s44.167967-220.227983 124.388382-300.448398c165.543834-165.548083 435.348714-165.548083 600.892548 0 165.548083 165.548083 165.548083 435.348714 0 600.892548-80.220415 80.220415-186.877876 124.388382-300.44415 124.388381z m0-785.973112c-92.538158 0-185.072066 35.453344-255.379651 105.756681-68.2001 68.204349-105.75668 158.63927-105.756681 255.3839s37.556581 187.175303 105.756681 255.379652c68.204349 68.2001 158.936697 106.054108 255.379651 105.75668 96.74888 0 187.179552-37.556581 255.379652-105.75668 140.912598-140.912598 140.912598-369.850954 0-510.759303-70.303336-70.307585-162.841494-105.75668-255.379652-105.756681z" fill="#515151" p-id="1776"></path><path d="M318.672199 341.705826h46.313693c11.047303 0 19.545228 8.497925 19.545228 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.738589c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695436v-46.738589c0-10.622407 8.497925-19.120332 19.120332-19.120332zM488.630705 341.705826h46.313693c11.047303 0 19.545228 8.497925 19.545229 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.73859c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695436v-46.738589c0-10.622407 8.497925-19.120332 19.120332-19.120332zM658.589212 341.705826h46.313693c11.047303 0 19.545228 8.497925 19.545228 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.738589c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695436v-46.738589c0-10.622407 8.497925-19.120332 19.120332-19.120332zM318.672199 469.174705h46.313693c10.622407 0 19.120332 8.497925 19.120332 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332H318.672199c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695435v-46.73859c0-10.622407 8.497925-19.120332 19.120332-19.120332zM488.630705 469.174705h46.313693c10.622407 0 19.120332 8.497925 19.120332 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.313693c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695435v-46.73859c0-10.622407 8.497925-19.120332 19.120332-19.120332zM658.589212 469.174705h46.313693c10.622407 0 19.120332 8.497925 19.120332 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.313693c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695435v-46.73859c0-10.622407 8.497925-19.120332 19.120332-19.120332zM458.887967 660.378025h106.224066c17.420747 0 31.86722 14.446473 31.86722 31.86722s-14.446473 31.86722-31.86722 31.86722h-106.224066c-17.420747 0-31.86722-14.446473-31.86722-31.86722s14.446473-31.86722 31.86722-31.86722z" fill="#515151" p-id="1777"></path></svg>
|
||||
`;
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
export const icSendSvg = () : string => {
|
||||
export const iconSendSvg = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1772375437715" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="44211" width="200" height="200"><path d="M512 56.888889c251.363556 0 455.111111 203.747556 455.111111 455.111111s-203.747556 455.111111-455.111111 455.111111S56.888889 763.363556 56.888889 512 260.636444 56.888889 512 56.888889z m-28.444444 324.664889V711.111111a28.444444 28.444444 0 0 0 56.888888 0V381.553778l150.556445 150.556444a28.444444 28.444444 0 0 0 40.220444-40.220444l-199.111111-199.111111a28.444444 28.444444 0 0 0-40.220444 0l-199.111111 199.111111a28.444444 28.444444 0 0 0 40.220444 40.220444L483.555556 381.553778z" fill="#0066FF" p-id="44212"></path></svg>
|
||||
`;
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
export const iconRecognizeErrorSvg = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1772464917665" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5331" width="64" height="64"><path d="M512 4.12672c280.49408 0 507.87328 227.3792 507.87328 507.87328 0 280.49408-227.3792 507.87328-507.87328 507.87328C231.50592 1019.87328 4.12672 792.49408 4.12672 512 4.12672 231.50592 231.50592 4.12672 512 4.12672zM512 685.96736c-42.47552 0-76.91264 34.42688-76.91264 76.91264 0 42.47552 34.43712 76.91264 76.91264 76.91264 42.47552 0 76.91264-34.43712 76.91264-76.91264C588.91264 720.39424 554.47552 685.96736 512 685.96736zM509.78816 625.83808c36.58752 0 66.24256-29.66528 66.24256-66.24256l0-309.1456c0-36.58752-29.65504-66.24256-66.24256-66.24256-36.58752 0-66.24256 29.66528-66.24256 66.24256l0 309.1456C443.5456 596.18304 473.20064 625.83808 509.78816 625.83808z" fill="#ffffff" p-id="5332"></path></svg>
|
||||
`;
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ export type StatusType = 'default' | 'voice_recording' | 'text_input' | 'voice_t
|
||||
* 语音转文字的子状态(仅当主状态为 voice_to_text 时生效)
|
||||
*/
|
||||
export type VoiceToTextSubStatus =
|
||||
| '' // 纯空
|
||||
| 'init' // 初始化(刚进入语音转文字页面)
|
||||
| 'loading' // 转换中(正在处理语音→文字)
|
||||
| 'success' // 转换完成(成功得到文字结果)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<view>
|
||||
<view class="talk-btns" :class="{action:isRecording, inputMode:!isInputVisible}">
|
||||
<view class="touch-btn" @click="disabled_click">
|
||||
<button v-if="!isTextOnlyMode && isInputVisible" class="voice-btn" @touchstart="startRecord" @touchend="stopRecord()" @touchmove="handleMove"
|
||||
@touchcancel="stopRecord()" :plain="true">
|
||||
<button v-if="!isTextOnlyMode && isInputVisible" class="voice-btn" @touchstart="startRecord"
|
||||
@touchend="stopRecord()" @touchmove="handleMove" @touchcancel="stopRecord()" :plain="true">
|
||||
<text class="voice-text">{{ isRecording ? '松开发送' : '按住说话' }}</text>
|
||||
</button>
|
||||
<input v-if="!isVoiceOnlyMode && !isInputVisible" class="input-box" ref="inputRef" v-model="inputText"
|
||||
@@ -15,43 +15,54 @@
|
||||
<image class="talk-right-icon" :src="talkRightIcon" mode="widthFix" @click="changeBtn"></image>
|
||||
</view>
|
||||
</view>
|
||||
<!-- :class="{ 'is-out': isOutStatus === '02', 'is-translate': isOutStatus === '03', voice_to_text_status: status === 'voice_to_text'}" -->
|
||||
<uni-popup ref="popupRef" class="popup">
|
||||
<view class="overlay-box">
|
||||
<view class="fl1"></view>
|
||||
<view class="talk-dialog"
|
||||
:class="{ 'is-out': isOutStatus === '02', 'is-translate': isOutStatus === '03' }">
|
||||
<image :src="voiceWhiteBtn" mode="" class="gif-box"></image>
|
||||
<uv-textarea ref="inputRef" v-model="textAreaText" :maxlength="255" @click.stop
|
||||
customStyle="background: #ffffff00; padding-bottom: 50rpx; color: #fff; caret-color: #fff"
|
||||
text-style="color: #fff" border="none" placeholderStyle="color:#999999;font-size:26rpx;"
|
||||
placeholder=""></uv-textarea>
|
||||
<view class="talk-dialog-box">
|
||||
<view class="talk-dialog-div" :class="dialogDynamicClasses">
|
||||
<view class="talk-dialog" >
|
||||
<image :src="voiceWhiteBtn" mode="" class="gif-box"></image>
|
||||
<uv-textarea ref="inputRef" v-model="textAreaText" :maxlength="255" @click.stop
|
||||
customStyle="background: #ffffff00; padding-bottom: 50rpx; color: #fff; caret-color: #fff"
|
||||
text-style="color: #fff" border="none" placeholderStyle="color:#999999;font-size:26rpx;"
|
||||
placeholder=""></uv-textarea>
|
||||
<view class="error-tip-div">
|
||||
<image :src="iconRecognizeErrorSvg()" mode="aspectFill" class="img"></image>
|
||||
<view class="">
|
||||
未识别到文字
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="page-1"
|
||||
:class="[
|
||||
status === 'voice_to_text' ? `${voice_to_text_status}` : ''
|
||||
]">
|
||||
<!-- 第一形态两侧按钮 -->
|
||||
<!-- 第一形态两侧按钮 -->
|
||||
<view class="page-1" :class="[ status]">
|
||||
|
||||
<view class="btns-box">
|
||||
<!-- 左侧取消按钮 -->
|
||||
<image class="btn-box btn-box-1" :src="isOutStatus == '02' ? cancelActiveBtn : cancelBtn" mode="heightFix" @click="closePopup()"></image>
|
||||
<image class="btn-box btn-box-1" :src="isOutStatus == '02' ? cancelActiveBtn : cancelBtn"
|
||||
mode="heightFix" @click="closePopup()"></image>
|
||||
<!-- 右侧转文字按钮 -->
|
||||
<image class="btn-box btn-box-2" :src="isOutStatus == '03' ? translateActiveBtn : translateBtn" mode="heightFix"></image>
|
||||
<image class="btn-box btn-box-2" :src="isOutStatus == '03' ? translateActiveBtn : translateBtn"
|
||||
mode="heightFix"></image>
|
||||
</view>
|
||||
<!-- 下方按钮 -->
|
||||
<view class="circle-bg-box">
|
||||
<view class="tips-box">松开发送</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<!-- <view class="page-2">
|
||||
<view class="cancel-btn transVoiceIng" @click="closeModel()"></view>
|
||||
<view class="trans-btn transVoiceIng" @click="sendVoice()" v-show="props.answerMethod !== '02'"></view>
|
||||
<view class="send-btn" @click="sendText()">发送</view>
|
||||
</view> -->
|
||||
|
||||
|
||||
<!-- 第二形态 -->
|
||||
<view class="page-2" :class="[ status, voice_to_text_status]">
|
||||
<!-- 左侧XX -->
|
||||
<view class="transVoiceIng cancel-btn" @click="closePopup()"></view>
|
||||
<!-- 中间发送原语音 -->
|
||||
<view class="transVoiceIng trans-btn" @click="testFun()"></view>
|
||||
<!-- 右侧发送按钮(椭圆) -->
|
||||
<view class="send-btn">发送</view>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
@@ -59,8 +70,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
// 导出图片
|
||||
import { cancelBtn, cancelActiveBtn, translateBtn, translateActiveBtn, voiceWhiteBtn, icKeyboardSvg, icMicSvg,icSendSvg } from './touch-btn.images';
|
||||
import { StatusType,VoiceToTextSubStatus } from './touch-btn.types';
|
||||
import { cancelBtn, cancelActiveBtn, translateBtn, translateActiveBtn, voiceWhiteBtn, icKeyboardSvg, iconMicSvg, iconSendSvg, iconRecognizeErrorSvg } from './touch-btn.images';
|
||||
import { StatusType, VoiceToTextSubStatus } from './touch-btn.types';
|
||||
import { wsUrl, bottomAreaTopBoundary, horizontalSplitX, initWebSocket } from './touch-btn';
|
||||
import { ref, computed, onMounted, nextTick, watch, reactive } from 'vue';
|
||||
import common from '@/common/common';
|
||||
@@ -118,12 +129,20 @@
|
||||
}
|
||||
});
|
||||
const textAreaText = computed({
|
||||
get() {
|
||||
return allText.value + tempText.value;
|
||||
},
|
||||
set(newValue) {
|
||||
allText.value = newValue;
|
||||
}
|
||||
get() {
|
||||
return allText.value + tempText.value;
|
||||
},
|
||||
set(newValue) {
|
||||
allText.value = newValue;
|
||||
}
|
||||
});
|
||||
const dialogDynamicClasses = computed(() => {
|
||||
const classes = [];
|
||||
isOutStatus.value === '02' && classes.push('is-out')
|
||||
isOutStatus.value === '03' && classes.push('is-translate')
|
||||
voice_to_text_status.value !== '' && classes.push(voice_to_text_status.value)
|
||||
|
||||
return classes;
|
||||
});
|
||||
const allText = ref('');
|
||||
const tempText = ref('');
|
||||
@@ -140,9 +159,9 @@
|
||||
const isVoiceOnlyMode = computed(() => props.mode === 'voice-only');
|
||||
const isTextOnlyMode = computed(() => props.mode === 'text-only');
|
||||
const talkRightIcon = computed(() => {
|
||||
if(isInputVisible.value) return icKeyboardSvg();
|
||||
if(inputText.value) return icSendSvg();
|
||||
return icMicSvg();
|
||||
if (isInputVisible.value) return icKeyboardSvg();
|
||||
if (inputText.value) return iconSendSvg();
|
||||
return iconMicSvg();
|
||||
});
|
||||
// 计算是否超出按下盒子位置01代表下方盒子,02代表左上03代表右上
|
||||
const isOutStatus = computed(() => {
|
||||
@@ -156,7 +175,9 @@
|
||||
touchPos.x = pageX;
|
||||
touchPos.y = pageY;
|
||||
};
|
||||
|
||||
const testFun = () => {
|
||||
voice_to_text_status.value = 'failed'
|
||||
}
|
||||
// 开启语音
|
||||
const startRecord = async (obj : { touches : any[]; }) => {
|
||||
try {
|
||||
@@ -172,13 +193,14 @@
|
||||
// 标记录音开始
|
||||
isRecording.value = true;
|
||||
status.value = 'voice_recording'
|
||||
voice_to_text_status.value = ''
|
||||
tempText.value = '';
|
||||
allText.value = '';
|
||||
initWebSocket(wsUrl).then(socketTask => {
|
||||
ws.value = socketTask
|
||||
wsStatus.value = true;
|
||||
console.log('WS连接成功');
|
||||
ws.value.onMessage((res: { data: Uint8Array | ArrayBuffer; }) => {
|
||||
ws.value.onMessage((res : { data : Uint8Array | ArrayBuffer; }) => {
|
||||
try {
|
||||
const { msgType, body } = ProtocolCodec.unpack(res.data);
|
||||
if (msgType === MessageType.TEXT_MESSAGE) {
|
||||
@@ -208,9 +230,9 @@
|
||||
recordStartTime.value = Date.now();
|
||||
// 弹出录音界面
|
||||
popupRef.value.open();
|
||||
startAudioRecord({
|
||||
startAudioRecord({
|
||||
onFrame: (pcmData : any) => {
|
||||
if(wsStatus.value) {
|
||||
if (wsStatus.value) {
|
||||
console.log('已连接', pcmData.length);
|
||||
ws.value.send({
|
||||
data: ProtocolCodec.pack(MessageType.AUDIO_DATA, pcmData)
|
||||
@@ -232,32 +254,32 @@
|
||||
});
|
||||
}, 140)
|
||||
};
|
||||
|
||||
|
||||
// 结束录音
|
||||
const closePopup = () => {
|
||||
const closePopup = () => {
|
||||
popupRef.value.close();
|
||||
}
|
||||
const stopRecord = async () => {
|
||||
clearTimeout(pressTimer.value);
|
||||
if (!isRecording.value) return; // 未处于录音状态
|
||||
if(isOutStatus.value === '03') { // 转换文字状态
|
||||
if (isOutStatus.value === '03') { // 转换文字状态
|
||||
console.log('已发送', '03转文字');
|
||||
switchFromVoiceToText()
|
||||
|
||||
|
||||
}
|
||||
const recordDurationMs = Date.now() - recordStartTime.value;
|
||||
if(isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
|
||||
if (isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
|
||||
// 核心:计算录音总时长(毫秒转秒,保留1位小数)
|
||||
if (recordDurationMs < 600) {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 600-recordDurationMs)
|
||||
}, 600 - recordDurationMs)
|
||||
})
|
||||
}
|
||||
}
|
||||
isRecording.value = false;
|
||||
if(isOutStatus.value === '02' && ws.value) { // 取消的时候自己主动关闭websocket,其他的时候需要等待后端的消息关闭
|
||||
if (isOutStatus.value === '02' && ws.value) { // 取消的时候自己主动关闭websocket,其他的时候需要等待后端的消息关闭
|
||||
ws.value.close({
|
||||
code: 1000,
|
||||
reason: '挂断',
|
||||
@@ -268,32 +290,32 @@
|
||||
});
|
||||
}
|
||||
stopAudioRecord(); // 关掉录音
|
||||
if(isOutStatus.value !== '03') { // 转文字时候不关遮罩层
|
||||
if (isOutStatus.value !== '03') { // 转文字时候不关遮罩层
|
||||
popupRef.value.close();
|
||||
if(isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
|
||||
if(recordDurationMs <= 1200) {
|
||||
if (isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
|
||||
if (recordDurationMs <= 1200) {
|
||||
setTimeout(() => {
|
||||
uni.showToast({
|
||||
title: '说话时间太短,没有听清!',
|
||||
icon: 'none'
|
||||
});
|
||||
}, 200)
|
||||
return
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
// 从录音状态切换成转文字状态
|
||||
const switchFromVoiceToText = () => {
|
||||
status.value = 'voice_to_text'
|
||||
ws.value && ws.value.send({data: ProtocolCodec.pack(MessageType.CONTROL_CMD, { type: ControlCode.FRNOT_TO_SERVER_OVER, ossID:'', text:'' })});
|
||||
ws.value && ws.value.send({ data: ProtocolCodec.pack(MessageType.CONTROL_CMD, { type: ControlCode.FRNOT_TO_SERVER_OVER, ossID: '', text: '' }) });
|
||||
voice_to_text_status.value = 'init'
|
||||
// 执行动画
|
||||
11
|
||||
}
|
||||
|
||||
|
||||
// 发送文本
|
||||
const showKeyboard = () => {
|
||||
if (isInputVisible.value) {
|
||||
@@ -324,7 +346,7 @@
|
||||
console.log('调用结束语音回答');
|
||||
stopRecord();
|
||||
};
|
||||
|
||||
|
||||
// 外部调用,清理输入框数据
|
||||
const clearinputText = (text = '') => {
|
||||
const old_text = inputText.value;
|
||||
@@ -332,7 +354,6 @@
|
||||
return old_text;
|
||||
};
|
||||
defineExpose({ clearinputText, give_up });
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -340,91 +361,34 @@
|
||||
@import "./style/popup.scss";
|
||||
|
||||
|
||||
.talk-dialog {
|
||||
width: 506rpx;
|
||||
min-height: 234rpx;
|
||||
margin: 0 auto 160rpx auto;
|
||||
background-color: #06f;
|
||||
border-radius: 32rpx;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: width 0.3s ease;
|
||||
|
||||
.text-div {
|
||||
overflow-y: scroll;
|
||||
max-height: 434rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
.white-bg-box {
|
||||
height: 365rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 58rpx 36rpx;
|
||||
|
||||
&.is-translate {
|
||||
width: 706rpx;
|
||||
|
||||
.gif-box {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-out {
|
||||
background-color: #ff3e49;
|
||||
|
||||
&::after {
|
||||
background-color: #ff3e49;
|
||||
}
|
||||
}
|
||||
|
||||
.gif-box {
|
||||
position: absolute;
|
||||
width: 200rpx;
|
||||
height: 80rpx;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
||||
background-color: #06f;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
bottom: -22rpx;
|
||||
left: 50%;
|
||||
margin-left: -22rpx;
|
||||
}
|
||||
.box-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 46rpx;
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
|
||||
.white-bg-box {
|
||||
height: 365rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 58rpx 36rpx;
|
||||
.box-btns {
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
|
||||
.box-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 46rpx;
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
|
||||
.box-btns {
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
|
||||
.is-active {
|
||||
color: #06f;
|
||||
}
|
||||
.is-active {
|
||||
color: #06f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
::v-deep .uv-input__content__field-wrapper__field {
|
||||
padding-right: 60rpx;
|
||||
|
||||
Reference in New Issue
Block a user