2025-03-01 10:26:49 +08:00
|
|
|
|
<template>
|
2025-03-07 17:57:49 +08:00
|
|
|
|
<!-- 聊天界面展示https://www.bilibili.com/video/BV1hT4y1P75N?p=22 搭建1和2 -->
|
|
|
|
|
<view class="content" @click="clickContent">
|
|
|
|
|
<view class="top_po">
|
|
|
|
|
<view class="" @click="goback()">
|
|
|
|
|
<u-icon name="arrow-left" color="#fff" size="20"></u-icon>
|
|
|
|
|
</view>
|
|
|
|
|
<view style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
|
|
|
|
<!-- 标题居中 -->
|
|
|
|
|
<text style="flex: 1; text-align: center;">{{ info.title }}</text>
|
|
|
|
|
|
|
|
|
|
<!-- 右侧内容 -->
|
|
|
|
|
<view style="display: flex; align-items: center;">
|
|
|
|
|
<view v-if="info.conversation == 'Translator'" class="sm-text" @click="chooseSayLang">
|
|
|
|
|
{{ sayLangStr }}
|
|
|
|
|
<u-icon style="margin-top: 6rpx; margin-left: 5rpx;" name="arrow-down" color="#fff" size="12"></u-icon>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="info.conversation == 'Translator'" style="margin: 0 15rpx">
|
|
|
|
|
<u-icon name="arrow-rightward" color="#fff" size="20"></u-icon>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="info.conversation == 'Translator'" class="sm-text" @click="chooseLang">
|
|
|
|
|
{{ lang }}
|
|
|
|
|
<u-icon style="margin-top: 6rpx; margin-left: 5rpx;" name="arrow-down" color="#fff" size="12"></u-icon>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="right_top"></view>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- 聊天内容 -->
|
|
|
|
|
<scroll-view class="chat" scroll-y="true" scroll-with-animation="true" :scroll-into-view="scrollToView">
|
|
|
|
|
<view class="chat-main" :style="{paddingBottom:inputh+'px'}">
|
|
|
|
|
<view class="chat-ls" v-for="(item,index) in messagesList" :key="index" :id="'msg'+ index">
|
|
|
|
|
<view class="msg-m msg-right">
|
|
|
|
|
<image class="user-img" :src="imagesUrl+userAvatar"></image>
|
|
|
|
|
<view class="message" v-if="item.inputs.type == 'text'">
|
|
|
|
|
<!-- 文字 -->
|
|
|
|
|
<view class="msg-text">
|
|
|
|
|
<text>{{ item.query }}</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="message" v-if="item.inputs.type == 'image'">
|
|
|
|
|
<image :src="'data:image/png;base64,'+item.query" class="msg-img" mode="widthFix"></image>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="message" v-if="item.inputs.type == 'voice'" @tap="playVoice(item.filePath)">
|
|
|
|
|
<!-- 音频 -->
|
|
|
|
|
<view class="msg-text voice" :style="{width:item.time*4+'rpx'}">
|
|
|
|
|
<image src="/static/chat/sy.png" class="voice-img"></image>
|
|
|
|
|
{{ item.time }}″
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="msg-m msg-left" v-if="item.answer">
|
|
|
|
|
|
|
|
|
|
<image class="user-img" :src="info.icon"></image>
|
|
|
|
|
<view class="msg-text" @click="clickSprinkImage(index)"
|
|
|
|
|
v-if="item.inputs.type == 'image' && info.conversation == 'Translator'">
|
|
|
|
|
|
|
|
|
|
<view class="po_i" v-if="show=='2'&&clickIdx==index">
|
|
|
|
|
<view class="size_" @click="showTxt(item)">text</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="po_i" v-if="!item.showImage&&clickIdx==index">
|
|
|
|
|
<view class="size_" @click="showImageFunction (item)">image</view>
|
|
|
|
|
</view>
|
|
|
|
|
<image :src="'data:image/png;base64,'+item.answer" v-if="item.showImage" class="msg-img"
|
|
|
|
|
mode="widthFix"></image>
|
|
|
|
|
<text v-else>{{ item.imageText }}</text>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="msg-text" @click="clickSprink(index)" id="po_" v-else>
|
|
|
|
|
<view class="po_z" v-if="show=='1'&&clickIdx==index">
|
|
|
|
|
<view class="size_" @click="voiceTxt(item.answer)">Voice</view>
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
{{ item.answer }}
|
|
|
|
|
<br/>
|
|
|
|
|
<text v-if="item.answerCh">{{ item.answerCh }}</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<span id="bottomId"></span>
|
|
|
|
|
</view>
|
|
|
|
|
</scroll-view>
|
|
|
|
|
<submit @inputs="inputs" @heights="heights" :title="this.info.title"></submit>
|
|
|
|
|
<u-picker :show="langShow" ref="langPicker" :defaultIndex="[11]" :columns="columns" @confirm="langConfirm"
|
|
|
|
|
@cancel="langCancel"></u-picker>
|
|
|
|
|
<u-picker :show="sayLangShow" ref="langPicker" :defaultIndex="[1]" keyName="label" :columns="[sayLangColumns]"
|
|
|
|
|
@confirm="sayLangConfirm"
|
|
|
|
|
@cancel="sayLangCancel"></u-picker>
|
|
|
|
|
</view>
|
2025-03-01 10:26:49 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-03-07 17:57:49 +08:00
|
|
|
|
import dateTime from './newChat/dateTime.js';
|
|
|
|
|
import submit from './newChat/submit.vue';
|
|
|
|
|
import config from '@/config'
|
|
|
|
|
import {
|
|
|
|
|
startMsgSocket,
|
|
|
|
|
msgSocketConnect,
|
|
|
|
|
sendMsg,
|
|
|
|
|
closeMsgSocket
|
|
|
|
|
} from './msgSocket'
|
|
|
|
|
import requestChat from '../../utils/requestChat'
|
|
|
|
|
import permision from "@/js_sdk/wa-permission/permission.js"
|
|
|
|
|
import request from '../../utils/request'
|
|
|
|
|
//音频播放
|
|
|
|
|
const innerAudioContext = uni.createInnerAudioContext();
|
|
|
|
|
// 录音
|
|
|
|
|
const recorderManager = uni.getRecorderManager();
|
|
|
|
|
export default {
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
audioSrc: '', // 用于存储音频的 URL
|
|
|
|
|
clickIdx: null,
|
|
|
|
|
//是否长按事件
|
|
|
|
|
timer: null,//长按计时器
|
|
|
|
|
show: '0',
|
|
|
|
|
columns: [
|
|
|
|
|
['Arabic-阿拉伯语',
|
|
|
|
|
'German-德语',
|
|
|
|
|
'English-英语',
|
|
|
|
|
'Spanish-西班牙语',
|
|
|
|
|
'French-法语',
|
|
|
|
|
'Hindi-印地语',
|
|
|
|
|
'Indonesian-印度尼西亚语',
|
|
|
|
|
'Italian-意大利语',
|
|
|
|
|
'Japanese-日语',
|
|
|
|
|
'Korean-韩语',
|
|
|
|
|
'Russian-俄语',
|
|
|
|
|
"Chinese-简体中文"
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
sayLangColumns: [
|
|
|
|
|
{
|
|
|
|
|
value: "zh-CHS",
|
|
|
|
|
label: "Mandarin (China)-普通话(中国)"
|
|
|
|
|
},
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en',
|
|
|
|
|
// label: 'Arabic-阿拉伯语',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'in',
|
|
|
|
|
// label: 'Bahasa (Indonesia)-巴哈萨语(印度尼西亚)',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'yue',
|
|
|
|
|
// label: 'Cantonese-粤语',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'ca',
|
|
|
|
|
// label: 'Catalan-加泰隆语',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'cs',
|
|
|
|
|
// label: 'Czech-捷克语',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'da',
|
|
|
|
|
// label: 'Danish-丹麦语',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'nl',
|
|
|
|
|
// label: 'Dutch-荷兰语',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'nl-BEL',
|
|
|
|
|
// label: 'Dutch (Belgium)-荷兰语(比利时',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en-AUS',
|
|
|
|
|
// label: 'English (Australia)-英语(澳大利亚)',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en-GBR',
|
|
|
|
|
// label: 'English (GB)-英语(英国)',
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en-IND',
|
|
|
|
|
// label: 'English (India)-英语(印度)'
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en-IRL',
|
|
|
|
|
// label: 'English (Ireland)-英语(爱尔兰)'
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en-SCT',
|
|
|
|
|
// label: 'English (Scotland)-英语(苏格兰)'
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// value: 'en-ZAF',
|
|
|
|
|
// label: 'English (South Africa)-英语(南非)'
|
|
|
|
|
// },
|
|
|
|
|
{
|
|
|
|
|
value: 'en',
|
|
|
|
|
label: 'English (US)-英语'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
value: 'ja',
|
|
|
|
|
label: 'Japanese (US)-日语)'
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
langShow: false,
|
|
|
|
|
sayLangShow: false,
|
|
|
|
|
sayLang: 'en',
|
|
|
|
|
sayLangStr: 'English',
|
|
|
|
|
lang: 'Chinese',
|
|
|
|
|
imagesUrl: config.imagesUrl,
|
|
|
|
|
msgSocket: null,
|
|
|
|
|
// 反转数据接收
|
|
|
|
|
messagesList: [],
|
|
|
|
|
imgMsg: [],
|
|
|
|
|
scrollToView: '',
|
|
|
|
|
showImageTextIndex: null,
|
|
|
|
|
showImage: true,
|
|
|
|
|
oldTime: new Date(),
|
|
|
|
|
inputh: '60',
|
|
|
|
|
info: {},
|
|
|
|
|
userId: null,
|
|
|
|
|
userAvatar: null,
|
|
|
|
|
firstId: null,
|
|
|
|
|
limit: 20,
|
|
|
|
|
socketId: null,
|
|
|
|
|
// 请求参数
|
|
|
|
|
ajax: {
|
|
|
|
|
rows: 20, //每页数量
|
|
|
|
|
page: 1, //页码
|
|
|
|
|
flag: true, // 请求开关
|
|
|
|
|
sendFlag: false
|
|
|
|
|
},
|
|
|
|
|
scrollId: 'bottomId',
|
|
|
|
|
storeList: 'msgHisList'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onLoad(option) {
|
|
|
|
|
if (option) {
|
|
|
|
|
let infoData = JSON.parse(option.data)
|
|
|
|
|
let tempInfo = {
|
|
|
|
|
icon: infoData.icon,
|
|
|
|
|
token: infoData.token,
|
|
|
|
|
conversation: infoData.conversation,
|
|
|
|
|
userId: infoData.userId,
|
|
|
|
|
userAvatar: infoData.userAvatar,
|
|
|
|
|
title: infoData.title
|
|
|
|
|
}
|
|
|
|
|
uni.setStorageSync('userId', infoData.userId)
|
|
|
|
|
this.info = tempInfo
|
|
|
|
|
this.userId = infoData.userId
|
|
|
|
|
this.userAvatar = infoData.userAvatar
|
|
|
|
|
this.getMessageByStore()
|
|
|
|
|
}
|
|
|
|
|
this.getRecordsToken()
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
components: {
|
|
|
|
|
submit,
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
async voiceTxt(text) {
|
|
|
|
|
let res = await request({
|
|
|
|
|
url: 'youDaoApi/tts',
|
|
|
|
|
method: 'post',
|
|
|
|
|
data: {
|
|
|
|
|
q: text,
|
|
|
|
|
voiceName: this.lang,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
this.playBase64Mp3(res.data)
|
|
|
|
|
this.show = false
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
showTxt(item) {
|
|
|
|
|
item.showImage = false
|
|
|
|
|
// this.showImageTextIndex = index
|
|
|
|
|
// console.log('触发',this.showImageTextIndex)
|
|
|
|
|
// this.showImage = false
|
|
|
|
|
this.show = false
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
showImageFunction(item) {
|
|
|
|
|
item.showImage = true
|
|
|
|
|
// this.showImageTextIndex = index
|
|
|
|
|
// console.log('触发',this.showImageTextIndex)
|
|
|
|
|
// this.showImage = false
|
|
|
|
|
this.show = false
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
// 播放 base64 编码的 MP3 文件
|
|
|
|
|
playBase64Mp3(base64Data) {
|
|
|
|
|
innerAudioContext.src = config.baseUrl + base64Data; // 不推荐,仅用于演示
|
|
|
|
|
innerAudioContext.play();
|
|
|
|
|
// 注意:如果你使用的是音频组件,确保在模板中正确绑定和使用它
|
|
|
|
|
},
|
|
|
|
|
clickContent(index) {
|
|
|
|
|
if (this.info.conversation == 'Translator') {
|
|
|
|
|
// 非长按
|
|
|
|
|
this.show = '0'
|
|
|
|
|
this.clickIdx = null
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
//点击事件
|
|
|
|
|
clickSprink(index) {
|
|
|
|
|
if (this.info.conversation == 'Translator') {
|
|
|
|
|
// 非长按
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.show = '1'
|
|
|
|
|
this.clickIdx = index
|
|
|
|
|
}, 10); // 延时200毫秒,即0.2秒
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
//点击事件
|
|
|
|
|
clickSprinkImage(index) {
|
|
|
|
|
if (this.info.conversation == 'Translator') {
|
|
|
|
|
// 非长按
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.show = '2'
|
|
|
|
|
this.clickIdx = index
|
|
|
|
|
}, 10); // 延时200毫秒,即0.2秒
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 回调参数为包含columnIndex、value、values
|
|
|
|
|
langConfirm(e) {
|
|
|
|
|
this.lang = e.value[0].split('-')[0]
|
|
|
|
|
this.langShow = false
|
|
|
|
|
},
|
|
|
|
|
langCancel() {
|
|
|
|
|
this.langShow = false
|
|
|
|
|
},
|
|
|
|
|
// 回调参数为包含columnIndex、value、values
|
|
|
|
|
sayLangConfirm(e) {
|
|
|
|
|
this.sayLangStr = e.value[0].label.split('-')[0]
|
|
|
|
|
this.sayLang = e.value[0].value
|
|
|
|
|
this.sayLangShow = false
|
|
|
|
|
},
|
|
|
|
|
sayLangCancel() {
|
|
|
|
|
this.sayLangShow = false
|
|
|
|
|
},
|
|
|
|
|
chooseLang() {
|
|
|
|
|
//选择语言
|
|
|
|
|
this.langShow = true
|
|
|
|
|
},
|
|
|
|
|
chooseSayLang() {
|
|
|
|
|
//选择录音语言
|
|
|
|
|
this.sayLangShow = true
|
|
|
|
|
},
|
|
|
|
|
async getRecordsToken() {
|
|
|
|
|
var result = await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
|
|
|
|
|
console.log(result, 124);
|
|
|
|
|
var strStatus
|
|
|
|
|
if (result == 1) {
|
|
|
|
|
strStatus = "已获得授权"
|
|
|
|
|
} else if (result == 0) {
|
|
|
|
|
strStatus = "未获得授权"
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
strStatus = "被永久拒绝权限"
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
startSocket() {
|
|
|
|
|
this.socketId = this.userId + "_" + Date.now()
|
|
|
|
|
this.msgSocket = startMsgSocket(this.socketId)
|
|
|
|
|
this.msgInfo()
|
|
|
|
|
//追加心跳机制
|
|
|
|
|
},
|
|
|
|
|
msgInfo() {
|
|
|
|
|
if (this.msgSocket) {
|
|
|
|
|
this.msgSocket.onMessage(res => {
|
|
|
|
|
if (this.info.conversation == 'Translator') {
|
|
|
|
|
if (this.messagesList[this.messagesList.length - 1].inputs.type != 'image') {
|
|
|
|
|
this.messagesList[this.messagesList.length - 1].answer = this.messagesList[this
|
|
|
|
|
.messagesList.length - 1].answer + res.data
|
|
|
|
|
//调用api翻译成中文
|
|
|
|
|
request({
|
|
|
|
|
url: 'chatHttpApi/getChatInfo',
|
|
|
|
|
method: 'post',
|
|
|
|
|
data: {
|
|
|
|
|
q: this.messagesList[this.messagesList.length - 1].answer,
|
|
|
|
|
lang: this.lang
|
|
|
|
|
}
|
|
|
|
|
}).then(res => {
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.messagesList[this.messagesList.length - 1].answerCh = this.messagesList[this.messagesList.length - 1].answerCh + res.msg
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
//将res.data 转为json
|
|
|
|
|
let json = JSON.parse(res.data)
|
|
|
|
|
this.messagesList[this.messagesList.length - 1].answer = this.messagesList[this
|
|
|
|
|
.messagesList.length - 1].answer + json.answer
|
|
|
|
|
this.messagesList[this.messagesList.length - 1].imageText = this.messagesList[this
|
|
|
|
|
.messagesList.length - 1].imageText + json.tranContent
|
|
|
|
|
}
|
|
|
|
|
this.goBottom()
|
|
|
|
|
uni.setStorageSync(this.storeList + '_' + this.info.conversation, this.messagesList)
|
|
|
|
|
} else {
|
|
|
|
|
if (res.data.indexOf("conversation_id") > -1) {
|
|
|
|
|
uni.setStorageSync(this.info.conversation, JSON.parse(res.data).conversation_id);
|
|
|
|
|
} else if (res.data.indexOf("workflow_finished") > -1) {
|
|
|
|
|
//代表结束
|
|
|
|
|
uni.setStorageSync(this.storeList + '_' + this.info.conversation, this.messagesList)
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
this.messagesList[this.messagesList.length - 1].answer = this.messagesList[this
|
|
|
|
|
.messagesList.length - 1].answer + res.data
|
|
|
|
|
this.goBottom()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
//缓存中获取历史消息
|
|
|
|
|
getMessageByStore() {
|
|
|
|
|
let tempList = uni.getStorageSync(this.storeList + '_' + this.info.conversation) || []
|
|
|
|
|
if (tempList && tempList.length > 30) {
|
|
|
|
|
//截取最新的30条
|
|
|
|
|
this.messagesList = tempList.slice(-30);
|
|
|
|
|
} else {
|
|
|
|
|
this.messagesList = tempList
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 数据挂载后执行,不懂的请自行阅读 Vue.js 文档对 Vue.nextTick 函数说明。
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.$forceUpdate()
|
|
|
|
|
// 设置当前滚动的位置
|
|
|
|
|
this.scrollToView = this.scrollId;
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 获取历史消息
|
|
|
|
|
getMessage() {
|
|
|
|
|
|
|
|
|
|
if (!uni.getStorageSync(this.info.conversation)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
console.log(uni.getStorageSync(this.info.conversation), 136);
|
|
|
|
|
let url = 'v1/messages?user=' + this.userId + '&conversation_id=' + uni.getStorageSync(this.info
|
|
|
|
|
.conversation) + '&limit=' + this.limit
|
|
|
|
|
if (this.firstId) {
|
|
|
|
|
url = url + "&first_id=" + this.firstId
|
|
|
|
|
}
|
|
|
|
|
let that = this
|
|
|
|
|
let get = async () => {
|
|
|
|
|
that.ajax.flag = false;
|
|
|
|
|
let res = await requestChat({
|
|
|
|
|
url: url,
|
|
|
|
|
method: 'get',
|
|
|
|
|
token: that.info.token
|
|
|
|
|
})
|
|
|
|
|
let data = res.data
|
|
|
|
|
// 获取待滚动元素选择器,解决插入数据后,滚动条定位时使用。取当前消息数据的第一条信息元素
|
|
|
|
|
console.log(res, 144);
|
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
that.firstId = data[i].id
|
|
|
|
|
}
|
|
|
|
|
that.messagesList.push(data[i])
|
|
|
|
|
}
|
|
|
|
|
that.$set(that.messagesList, that.messagesList.length - 1, that.messagesList[that.messagesList
|
|
|
|
|
.length - 1])
|
|
|
|
|
// 数据挂载后执行,不懂的请自行阅读 Vue.js 文档对 Vue.nextTick 函数说明。
|
|
|
|
|
that.$nextTick(() => {
|
|
|
|
|
that.$forceUpdate()
|
|
|
|
|
// 设置当前滚动的位置
|
|
|
|
|
that.scrollToView = this.scrollId;
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
get();
|
|
|
|
|
},
|
|
|
|
|
goback() {
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
},
|
|
|
|
|
changeTime(date) {
|
|
|
|
|
return dateTime.dateTime1(date);
|
|
|
|
|
},
|
|
|
|
|
// 进行图片的预览
|
|
|
|
|
previewImg(e) {
|
|
|
|
|
let index = 0;
|
|
|
|
|
for (let i = 0; i < this.imgMsg.length; i++) {
|
|
|
|
|
if (this.imgMsg[i] == e) {
|
|
|
|
|
index = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
console.log("index", index)
|
|
|
|
|
// 预览图片
|
|
|
|
|
uni.previewImage({
|
|
|
|
|
current: index,
|
|
|
|
|
urls: this.imgMsg,
|
|
|
|
|
longPressActions: {
|
|
|
|
|
itemList: ['发送给朋友', '保存图片', '收藏'],
|
|
|
|
|
success: function (data) {
|
|
|
|
|
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
|
|
|
|
|
},
|
|
|
|
|
fail: function (err) {
|
|
|
|
|
console.log(err.errMsg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
//音频播放
|
|
|
|
|
playVoice(e) {
|
|
|
|
|
console.log(e);
|
|
|
|
|
innerAudioContext.src = e;
|
|
|
|
|
|
|
|
|
|
innerAudioContext.play(() => {
|
|
|
|
|
console.log('开始播放');
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
//地图定位
|
|
|
|
|
covers(e) {
|
|
|
|
|
let map = [{
|
|
|
|
|
latitude: e.latitude,
|
|
|
|
|
longitude: e.longitude,
|
|
|
|
|
iconPath: '/static/chat/sy.png'
|
|
|
|
|
}]
|
|
|
|
|
return (map);
|
|
|
|
|
},
|
|
|
|
|
//跳转地图信息
|
|
|
|
|
openLocation(e) {
|
|
|
|
|
uni.openLocation({
|
|
|
|
|
latitude: e.latitude,
|
|
|
|
|
longitude: e.longitude,
|
|
|
|
|
name: e.name,
|
|
|
|
|
address: e.address,
|
|
|
|
|
success: function () {
|
|
|
|
|
console.log('success');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
//接受输入内容
|
|
|
|
|
inputs(inputData) {
|
|
|
|
|
console.log(inputData, 220);
|
|
|
|
|
let that = this;
|
|
|
|
|
if (this.msgSocket) {
|
|
|
|
|
closeMsgSocket(this.msgSocket);
|
|
|
|
|
this.msgSocket = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.startSocket()
|
|
|
|
|
let typeStr = "text"
|
|
|
|
|
let msgItem = {
|
|
|
|
|
"inputs": {
|
|
|
|
|
"type": typeStr
|
|
|
|
|
},
|
|
|
|
|
"query": inputData.message,
|
|
|
|
|
"response_mode": 'streaming',
|
|
|
|
|
"conversation_id": uni.getStorageSync(this.info.conversation) || null,
|
|
|
|
|
"user": this.userId,
|
|
|
|
|
'token': this.info.token,
|
|
|
|
|
'answer': '',
|
|
|
|
|
'answerCh': '',
|
|
|
|
|
'showImageTextIndex': '',
|
|
|
|
|
'showImage': '',
|
|
|
|
|
'imageText': '',
|
|
|
|
|
'time': inputData.time,
|
|
|
|
|
'type': '',
|
|
|
|
|
'filePath': inputData.filePath,
|
|
|
|
|
};
|
|
|
|
|
if (this.info.conversation == 'Translator') {
|
|
|
|
|
msgItem.response_mode = 'blocking'
|
|
|
|
|
msgItem.inputs.lang = this.lang
|
|
|
|
|
}
|
|
|
|
|
if (inputData.type == 0) {
|
|
|
|
|
msgItem.inputs.type = "text"
|
|
|
|
|
} else if (inputData.type == 1) {
|
|
|
|
|
typeStr = "image"
|
|
|
|
|
msgItem.inputs.type = "image"
|
|
|
|
|
msgItem.showImage = true
|
|
|
|
|
msgItem.query = inputData.base64
|
|
|
|
|
} else if (inputData.type == 2) {
|
|
|
|
|
typeStr = "voice"
|
|
|
|
|
msgItem.inputs.type = "voice"
|
|
|
|
|
msgItem.query = inputData.base64
|
|
|
|
|
}
|
|
|
|
|
this.messagesList.push(msgItem);
|
|
|
|
|
// 数据挂载后执行,不懂的请自行阅读 Vue.js 文档对 Vue.nextTick 函数说明。
|
|
|
|
|
this.goBottom()
|
|
|
|
|
//时间间隔处理
|
|
|
|
|
let requestData = {
|
|
|
|
|
"inputs": {
|
|
|
|
|
"type": typeStr
|
|
|
|
|
},
|
|
|
|
|
"query": inputData.message,
|
|
|
|
|
"response_mode": 'streaming',
|
|
|
|
|
"conversation_id": uni.getStorageSync(this.info.conversation) || null,
|
|
|
|
|
"user": this.userId,
|
|
|
|
|
'token': this.info.token,
|
|
|
|
|
'answer': '',
|
|
|
|
|
'socketId': this.socketId,
|
|
|
|
|
};
|
|
|
|
|
if (this.info.conversation == 'Translator') {
|
|
|
|
|
requestData.response_mode = 'blocking'
|
|
|
|
|
requestData.inputs.lang = this.lang
|
|
|
|
|
requestData.inputs.sayLang = this.sayLang
|
|
|
|
|
} else if (this.info.conversation == 'Trip') {
|
2025-03-10 15:10:08 +08:00
|
|
|
|
if (requestData.inputs.type == 'image') {
|
|
|
|
|
requestData.query = "描述图片"
|
|
|
|
|
// requestData.inputs = {}
|
|
|
|
|
requestData.files = [
|
|
|
|
|
{
|
|
|
|
|
"type": "image",
|
|
|
|
|
// "type": "image/jpeg",
|
|
|
|
|
"transfer_method": "local_file",
|
|
|
|
|
"url": '',
|
|
|
|
|
"upload_file_id": inputData.message
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
sendMsg(that.msgSocket, JSON.stringify(requestData))
|
|
|
|
|
requestData.query = inputData.base64
|
|
|
|
|
}, 500)
|
|
|
|
|
|
|
|
|
|
return
|
2025-03-07 17:57:49 +08:00
|
|
|
|
}
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
sendMsg(that.msgSocket, JSON.stringify(requestData))
|
|
|
|
|
|
|
|
|
|
}, 500)
|
|
|
|
|
},
|
|
|
|
|
//输入框高度
|
|
|
|
|
heights(e) {
|
|
|
|
|
console.log("高度:", e)
|
|
|
|
|
this.inputh = e;
|
|
|
|
|
this.goBottom();
|
|
|
|
|
},
|
|
|
|
|
// 滚动到底部
|
|
|
|
|
goBottom() {
|
|
|
|
|
this.scrollToView = '';
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
|
|
|
|
// 设置当前滚动的位置
|
|
|
|
|
this.scrollToView = this.scrollId;
|
|
|
|
|
this.$forceUpdate()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-01 10:26:49 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss">
|
2025-03-07 17:57:49 +08:00
|
|
|
|
page {
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#po_ {
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.po_z {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: -60px;
|
|
|
|
|
left: 0px;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
background: #3d3d3d;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.po_i {
|
|
|
|
|
position: absolute;
|
2025-03-10 15:10:08 +08:00
|
|
|
|
|
2025-03-07 17:57:49 +08:00
|
|
|
|
left: 0px;
|
2025-03-10 15:10:08 +08:00
|
|
|
|
top: -55px;
|
2025-03-07 17:57:49 +08:00
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
background: #3d3d3d;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.size_ {
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
height: 100%;
|
|
|
|
|
background-color: rgba(244, 244, 244, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.top_po {
|
|
|
|
|
position: fixed;
|
|
|
|
|
z-index: 9999;
|
|
|
|
|
width: 750rpx;
|
|
|
|
|
height: 180rpx;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
padding-top: 80rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
padding-left: 30rpx;
|
|
|
|
|
padding-right: 30rpx;
|
|
|
|
|
left: 0px;
|
|
|
|
|
top: 0px;
|
|
|
|
|
background: #32714f;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.right_top {
|
|
|
|
|
width: 20px;
|
|
|
|
|
height: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat {
|
|
|
|
|
height: 90%;
|
|
|
|
|
margin-top: 180rpx;
|
|
|
|
|
margin-bottom: 30rpx;
|
|
|
|
|
|
|
|
|
|
.chat-main {
|
|
|
|
|
padding-left: 32rpx;
|
|
|
|
|
padding-right: 32rpx;
|
|
|
|
|
padding-top: 20rpx;
|
|
|
|
|
// padding-bottom: 120rpx; //获取动态高度
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-ls {
|
|
|
|
|
.chat-time {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: rgba(39, 40, 50, 0.3);
|
|
|
|
|
line-height: 34rpx;
|
|
|
|
|
padding: 10rpx 0rpx;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msg-m {
|
|
|
|
|
display: flex;
|
|
|
|
|
padding: 20rpx 0;
|
|
|
|
|
|
|
|
|
|
.user-img {
|
|
|
|
|
flex: none;
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message {
|
|
|
|
|
flex: none;
|
|
|
|
|
max-width: 480rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msg-text {
|
|
|
|
|
max-width: 540rpx;
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: rgba(39, 40, 50, 1);
|
|
|
|
|
line-height: 44rpx;
|
|
|
|
|
padding: 18rpx 24rpx;
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
word-wrap: break-word;
|
2025-03-10 15:10:08 +08:00
|
|
|
|
position: relative;
|
2025-03-07 17:57:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msg-img {
|
|
|
|
|
max-width: 400rpx;
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msg-map {
|
|
|
|
|
background: #fff;
|
|
|
|
|
width: 464rpx;
|
|
|
|
|
height: 284rpx;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
.map-name {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: rgba(39, 40, 50, 1);
|
|
|
|
|
line-height: 44rpx;
|
|
|
|
|
padding: 18rpx 24rpx 0 24rpx;
|
|
|
|
|
//下面四行是单行文字的样式
|
|
|
|
|
display: -webkit-box;
|
|
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
-webkit-line-clamp: 1;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.map-address {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: rgba(39, 40, 50, 0.4);
|
|
|
|
|
padding: 0 24rpx;
|
|
|
|
|
//下面四行是单行文字的样式
|
|
|
|
|
display: -webkit-box;
|
|
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
-webkit-line-clamp: 1;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.map {
|
|
|
|
|
padding-top: 8rpx;
|
|
|
|
|
width: 464rpx;
|
|
|
|
|
height: 190rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.voice {
|
|
|
|
|
// width: 200rpx;
|
|
|
|
|
min-width: 100rpx;
|
|
|
|
|
max-width: 400rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.voice-img {
|
|
|
|
|
width: 28rpx;
|
|
|
|
|
height: 36rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msg-left {
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
|
|
|
|
.msg-text {
|
|
|
|
|
max-width: 540rpx;
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
border-radius: 0rpx 20rpx 20rpx 20rpx;
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.ms-img {
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msh-map {
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
border-radius: 0rpx 20rpx 20rpx 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.voice {
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.voice-img {
|
|
|
|
|
float: left;
|
|
|
|
|
transform: rotate(180deg);
|
|
|
|
|
width: 28rpx;
|
|
|
|
|
height: 36rpx;
|
|
|
|
|
padding-bottom: 4rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msg-right {
|
|
|
|
|
flex-direction: row-reverse;
|
|
|
|
|
|
|
|
|
|
.msg-text {
|
|
|
|
|
max-width: 540rpx;
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
background-color: rgba(255, 228, 49, 0.8);
|
|
|
|
|
border-radius: 20rpx 0rpx 20rpx 20rpx;
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.ms-img {
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.msh-map {
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
border-radius: 20rpx 0rpx 20rpx 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.voice {
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.voice-img {
|
|
|
|
|
float: right;
|
|
|
|
|
padding: 4rpx;
|
|
|
|
|
width: 28rpx;
|
|
|
|
|
height: 36rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.sm-text {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
margin-left: 5px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
line-height: 29px;
|
|
|
|
|
}
|
2025-03-03 14:31:40 +08:00
|
|
|
|
</style>
|