You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

601 lines
13 KiB

<template>
<view class="input-content-com" :class="pointDown ? 'input-content-com-bg': ''" :textInfo="textInfo"
:change:textInfo="renderjs.getTextInfo" :taskId="taskId" :change:taskId="renderjs.getTaskId" :params="params"
:change:params="renderjs.getParams">
<view class="voice-content" v-if="pointDown">
<template v-if="speech">
<view class="voice-text font-family-SM">
{{msg}}
</view>
<!-- <view class="voice-time font-family-SM">
录音还有{{closeTime}}S结束
</view> -->
<view class="voice-icon">
<view class="time-box">
<span class="start-taste-line">
<hr class="hr1" />
<hr class="hr2" />
<hr class="hr3" />
<hr class="hr4" />
<hr class="hr5" />
<hr class="hr6" />
<hr class="hr7" />
<hr class="hr8" />
<hr class="hr9" />
<hr class="hr10" />
</span>
</view>
</view>
</template>
<u-loading-icon class="voice-loading" color="#000" size="40" v-else></u-loading-icon>
</view>
<view class="input-wrapper" :class="{ 'input-wrapper-expanded': isExpanded }">
<view class="topContent">
<image style="width: 50rpx;height: 50rpx;margin-left:16.67rpx ;" src="/static/voice.png"
@click="handleChange"></image>
<!-- <uni-icons class="uni-icon" type="mic" size="30" @click="handleChange"></uni-icons> -->
<!-- <input ref="inputRef" v-show="!showVoice" class="uni-input"
:placeholder="disabled ? '请等待回复结束' : '请输入内容'" :value="inputValue"
@confirm="$emit('confirm', $event)" @input="onKeyInput" :disabled="disabled" /> -->
<input ref="inputRef" v-show="!showVoice" class="uni-input"
:placeholder="disabled ? '请等待回复结束' : '请输入内容'" :value="inputValue" @confirm="setTextInfo"
@input="onKeyInput" :disabled="disabled" />
<view class="voice-btn" v-show="showVoice" @touchstart="handleStart" @touchend="handleEnd"
@touchcancel="handleCancel">
{{pointDown ? '松开 结束' : '按住 说话'}}
</view>
<image v-if=" showUpload &&!inputValue &&!hideUpload"
style="width: 50rpx;height: 50rpx;margin-right: 16.67rpx" src="/static/add.png"
@click="isExpanded = !isExpanded"></image>
<!-- <uni-icons v-if=" showUpload &&!inputValue" class="uni-icon" type="plus" size="30"
@click="isExpanded = !isExpanded" :disabled="disabled"></uni-icons> -->
<button v-if=" showUpload &&inputValue" class="sendBtn" @click="setTextInfo"
:disabled="disabled">发送</button>
</view>
<view v-if="isExpanded" class="expanded">
<view @click="chooseImage" class="expandedItem">
<uni-icons class="camera-icon" type="image" size="28"></uni-icons>
<view>照片</view>
</view>
<!-- <view class="expandedItem" style="margin-top: 6px">
<image src="../../static/video.png" class="video"></image>
<view>视频</view>
</view> -->
</view>
</view>
<yimo-AudioTrans ref="yimoAudioTransRefs" :options="options" @countDown="countDown" @result="resultMsg"
@onStop="onStop" @onOpen="onOpen" @change="change"></yimo-AudioTrans>
</view>
</template>
<script>
import {
recordRequest
} from '@/libs/util/permission-request.js'
export default {
props: {
disabled: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
},
showUpload: {
type: Boolean,
default: true
},
hideUpload: {
type: Boolean,
default: false
},
taskId: {
type: String,
default: ''
},
params: {
type: Object,
default: () => {
return {}
}
},
},
computed: {
inputValue: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
}
}
},
data() {
return {
msg: '',
options: {
receordingDuration: 60,
APPID: '5fd31b2b',
API_SECRET: '041f2472806b54a66cf70cfcb33b7e1d',
API_KEY: '9bdeee3a806337a56abaff2c12b2c817'
},
isExpanded: false,
showVoice: false,
speech: false, // 是否正在录音中
closeTime: 60, // 录音倒计时
pointDown: false, // 用户是否手指按住屏幕,避免因为申请权限导致触发结束事件监听不到
wsStatus: "CLOSED",
timer: null,
speeching: false,
closeing: false,
textInfo: '',
};
},
mounted() {},
onLoad() {},
onShow() {
console.log('SHOW')
},
onHide() {
console.log('HIDE')
},
methods: {
setTextInfo() {
this.textInfo = this.inputValue
setTimeout(() => {
this.textInfo = ''
}, 10)
},
handleChange() {
if (this.disabled) {
return
}
this.showVoice = !this.showVoice
},
handleStart() {
this.pointDown = true
if (this.speech) return
clearTimeout(this.timer)
this.timer = setTimeout(() => {
if (this.pointDown) {
this.msg = ''
this.closeTime = 60
// #ifdef H5
this.start()
// #endif
// #ifdef APP-PLUS
try {
recordRequest().then(res => {
if (this.pointDown) {
console.log('链接')
this.start()
}
})
} catch (e) {
//TODO handle the exception
}
// #endif
console.log('开始')
}
}, 150)
},
handleEnd() {
if (this.wsStatus === 'OPEN') {
this.end()
}
if (this.wsStatus === 'CLOSED' || this.wsStatus === 'CONNECTING') {
this.pointDown = false
}
console.log('结束')
},
handleCancel() {
this.pointDown = false
console.log('取消')
},
onKeyInput(event) {
this.inputValue = event.detail.value;
},
chooseImage() {
this.$emit('imageChoose')
this.isExpanded = false
// uni.chooseImage({
// count: 6, //默认9
// sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
// sourceType: ["album", 'camera'], //从相册选择
// success: (res) => {
// },
// });
},
handleVoice() {},
start() {
if (this.speeching) return
this.speeching = true
this.$refs.yimoAudioTransRefs.start();
},
end() {
this.$refs.yimoAudioTransRefs.end();
},
countDown(e) {
console.log(this.pointDown, this.wsStatus)
if (!this.pointDown && this.wsStatus === 'OPEN') {
this.end()
}
this.closeTime = e
console.log('countDown', e);
},
onStop(e) {
console.log('onStop', e);
},
onOpen(e) {
console.log('onOpen', e);
},
change(e) {
this.wsStatus = e.status
console.log('change', e);
if (e.status === 'OPEN' && e.msg === '开始录音') {
this.speeching = false
this.speech = true
}
if (e.status === 'CLOSED' && e.msg === '录音已关闭') {
this.end()
this.speech = false
this.closeing = false
this.pointDown = false
if (this.msg !== '') {
this.inputValue = this.inputValue + this.msg
this.showVoice = false
// this.$nextTick(() => {
// this.$refs.inputRef.focus()
// })
} else {
this.$.toast('未检测到声源,录写已关闭')
}
}
if (e.status === 'CLOSING' && e.msg === '关闭连接中') {
this.closeing = true
// this.speeching = false
// this.speech = true
}
},
resultMsg(e) {
this.msg = e.replace(' ', '')
console.log('resultMsg', e);
},
propsConfirm(
text
) {
this.$emit('confirm',
text
)
},
dataSend(ev) {
this.$emit('dataSend',
ev,
)
},
dataSend(ev) {
this.$emit('dataSend',
ev,
)
},
sseClose() {
this.$emit('sseTimeout')
}
}
};
</script>
<script module="renderjs" lang="renderjs">
import $ from "../common/globalJs/globalJs.js";
import {
fetchEventSource
} from "@microsoft/fetch-event-source";
export default {
data() {
taskId: '';
params: {};
},
mounted() {},
methods: {
getTaskId(taskId) {
this.taskId = taskId
},
getParams(params) {
this.params = params
},
getTextInfo(info) {
if (info) {
this.newSSE(info, '1')
}
},
newSSE(voiceText, answerId = '') {
console.log('输入框SSE触发', voiceText)
this.$ownerInstance.callMethod('propsConfirm',
voiceText
);
// const ctrl = new AbortController();
fetchEventSource($.chatUrl + "/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: ["text/event-stream", "application/json"],
},
body: JSON.stringify({
voiceText,
deptId: this.params.deptId && this.params.deptId != 'undefined' ? this.params
.deptId : "",
id: this.params.id || "",
multiType: "",
sceneFlag: "",
stream: true,
type: this.taskId ? '1' : '0',
userId: this.params.userId || "",
taskId: this.taskId || "",
sectionId: this.params.sectionId || '',
sectionType: this.params.sectionType || ''
}),
// signal: ctrl.signal,
openWhenHidden: true,
onopen: () => {},
onmessage: (ev) => {
//发送数据到逻辑层
this.$ownerInstance.callMethod('dataSend', ev);
},
onclose: () => {
this.$ownerInstance.callMethod('sseClose');
this.expandedFlag = false
if (this.isExpanded) {
this.isExpanded = !this.isExpanded;
}
},
onerror(error) {
console.log("error", error);
throw error;
},
});
},
}
}
</script>
<style lang="scss">
@keyframes radius-animation {
100% {
height: 10px;
border-radius: 50%;
filter: contrast(2);
}
}
.input-content-com-bg {
&::before {
position: absolute;
content: '';
display: block;
width: 100%;
height: calc(100vh - 100rpx);
left: 0;
bottom: 100rpx;
z-index: 9998;
background: rgba(255, 255, 255, .5);
}
}
.input-content-com {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
margin: 20rpx auto 0 auto;
.voice-loading {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-20px, -20px);
}
.voice-content {
min-height: 100px;
max-height: 600rpx;
width: 80%;
position: absolute;
left: 0;
bottom: 0;
transform: translate(10%, -150px);
z-index: 9999;
background: #0cad53;
border-radius: 10px;
font-size: 16px;
padding: 8px 8px 8px 8px;
&::after {
position: absolute;
content: '';
display: block;
width: 0;
height: 0;
border-width: 10px;
border-style: solid;
border-color: #0cad53 transparent transparent transparent;
left: 50%;
bottom: 2px;
z-index: 9999;
transform: translate(-50%, 100%);
}
.voice-time {
position: absolute;
bottom: 4px;
left: 15px;
color: red;
}
.voice-text {
overflow: auto;
height: auto;
margin-bottom: 20px;
}
.voice-icon {
position: absolute;
right: 15px;
bottom: 10px;
}
.time-box .start-taste-line hr {
background-color: #f0f2f7; //声波颜色
width: 2px;
height: 3px;
margin: 0 0.03rem;
display: inline-block;
border: none;
}
hr {
animation: note 0.5s ease-in-out;
animation-iteration-count: infinite;
animation-direction: alternate;
}
.hr1 {
animation-delay: -1s;
}
.hr2 {
animation-delay: -0.9s;
}
.hr3 {
animation-delay: -0.8s;
}
.hr4 {
animation-delay: -0.7s;
}
.hr5 {
animation-delay: -0.6s;
}
.hr6 {
animation-delay: -0.5s;
}
.hr7 {
animation-delay: -0.4s;
}
.hr8 {
animation-delay: -0.3s;
}
.hr9 {
animation-delay: -0.2s;
}
.hr10 {
animation-delay: -0.1s;
}
@keyframes note {
from {
transform: scaleY(1);
}
to {
transform: scaleY(4);
}
}
}
.uni-input {
width: 575rpx;
height: 75rpx;
// height: 66rpx;
line-height: 56rpx;
font-size: 30rpx;
padding: 0rpx 10rpx;
margin: 0 15rpx;
flex: 1;
background-color: #fff;
border-radius: 4px;
}
.voice-btn {
font-size: 30rpx;
line-height: 75rpx;
flex: 1;
text-align: center;
background: #fff;
border-radius: 4px;
margin: 0 15rpx;
}
.input-wrapper {
box-shadow: 0px -1.39px 2.78px 0.69px rgba(0, 0, 0, 0.1);
display: flex;
width: 100%;
padding: 20.83rpx 0;
// margin: 20rpx auto 0 auto;
// height: 80rpx;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
// border-top: 1px solid #e2e4e9;
bottom: 1px solid #e2e4e9;
// padding: 15rpx 20rpx;
background: #F5F7FA;
.topContent {
display: flex;
width: 100%;
align-items: center;
}
.expanded {
width: 100%;
height: 250rpx;
background-color: #F5F7FA;
display: flex;
padding-left: 37.5rpx;
padding-top: 54.17rpx;
border-top: 1px solid rgba(0, 0, 0, 0.1);
margin-top: 20.83rpx;
// padding: 5px;
.expandedItem {
width: 106rpx;
height: 106rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
.camera-icon {
margin-top: 5px;
}
}
.video {
width: 60rpx;
height: 60rpx;
}
}
.sendBtn {
background: #2663BF;
color: #fff;
font-size: 32rpx;
padding: 14rpx 20rpx;
border-radius: 0;
margin-right: 16.67rpx
}
}
}
</style>