This commit is contained in:
许允枞 2025-03-13 18:01:21 +08:00
parent 5614e9859b
commit 463f26d465
4 changed files with 276 additions and 137 deletions

View File

@ -16,7 +16,7 @@
<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">
</view>
<view v-if="info.conversation == 'Translator'" class="sm-text" @click="chooseLang">
{{ lang }}
@ -28,8 +28,8 @@
<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'}">
<scroll-view class="chat" id="scrollview" scroll-y="true" scroll-with-animation="true" :scroll-into-view="scrollToView">
<view class="chat-main" :style="{paddingBottom:inputh+'px'}" id="msglistview">
<view class="chat-ls" v-for="(item,index) in messagesList" :key="index" :id="'msg'+ index">
<view class="msg-m msg-right" v-if="item.isTrans">
<image class="user-img" :src="imagesUrl+userAvatar"></image>
@ -53,7 +53,7 @@
<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)"
<view class="msg-text" @longpress="clickSprinkImage(index)"
v-if="item.inputs.type == 'image' && info.conversation == 'Translator'">
<view class="po_i" v-if="show=='2'&&clickIdx==index">
@ -62,29 +62,31 @@
<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" @click="previewImage(item.answer)" v-if="item.showImage" class="msg-img"
<image :src="'data:image/png;base64,'+item.answer" @click="previewImage(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="msg-text" @longpress="clickSprink(index)" id="po_" v-else>
<view class="po_z" v-if="show=='1'&&clickIdx==index">
<view class="size_" @click="voiceTxt(item)">Voice</view>
</view>
{{ item.answer }}
<br/>
<!-- <text v-if="item.answerCh">{{ item.answerCh }}</text>-->
<!-- <text v-if="item.answerCh">{{ item.answerCh }}</text>-->
</view>
</view>
</view>
<span id="bottomId"></span>
<view id="bottomId" style="height: 1px;"></view>
</view>
</scroll-view>
<submit @inputs="inputs" @heights="heights" :title="this.info.title"></submit>
<u-picker :show="langShow" ref="langPicker" :defaultIndex="langIndex" :columns="columns" @confirm="langConfirm"
@cancel="langCancel"></u-picker>
<u-picker :show="sayLangShow" ref="langPicker" :defaultIndex="sayLangIndex" keyName="label" :columns="[sayLangColumns]"
<u-picker :show="sayLangShow" ref="langPicker" :defaultIndex="sayLangIndex" keyName="label"
:columns="[sayLangColumns]"
@confirm="sayLangConfirm"
@cancel="sayLangCancel"></u-picker>
</view>
@ -116,7 +118,7 @@ export default {
//
timer: null,//
show: '0',
sayLangIndex : [1],
sayLangIndex: [1],
langIndex: [11],
columns: [
['Arabic-阿拉伯语',
@ -251,7 +253,6 @@ export default {
this.userId = infoData.userId
this.userAvatar = infoData.userAvatar
this.getMessageByStore()
this.goBottom()
}
this.getRecordsToken()
@ -259,6 +260,23 @@ export default {
components: {
submit,
},
// onReady() {
// console.log('ready')
// // this.bottomId = 'bottom'; //
// this.scrollToView = 'bottomId';
// // this.$nextTick(() => {
// // setTimeout(() => {
// // uni.createSelectorQuery()
// // .select('#bottom')
// // .boundingClientRect((res) => {
// // if (res) {
// // this.scrollTop = res.top + 5500; // 50px
// // }
// // })
// // .exec();
// // }, 100);
// // });
// },
methods: {
async voiceTxt(item) {
let res = await request({
@ -275,37 +293,30 @@ export default {
},
//
previewImage(photoImg) {
console.log('预览图片')
photoImg = 'data:image/jpeg;base64,' + photoImg;
base64ToPath(photoImg).then((resInfo)=>{
photoImg = 'data:image/jpeg;base64,' + photoImg;
base64ToPath(photoImg).then((resInfo) => {
uni.getImageInfo({
src: resInfo,
success: function(res){
success: function (res) {
uni.previewImage({
urls:[res.path]
urls: [res.path]
});
},
fail: function(err){
fail: function (err) {
console.log(err)
}
})
}).catch((err)=>{
}).catch((err) => {
console.log(err)
})
},
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
},
@ -380,7 +391,6 @@ export default {
} else {
strStatus = "被永久拒绝权限"
}
},
startSocket() {
@ -389,81 +399,92 @@ export default {
this.msgInfo()
//
},
translatorChinese() {
//api
request({
url: 'chatHttpApi/getChatInfo',
method: 'post',
data: {
q: this.messagesList[this.messagesList.length - 1].answer,
lang: this.lang
}
}).then(res => {
this.$nextTick(() => {
let msgItem = {
"inputs": {
"type": "text"
},
"query": '',
"response_mode": 'streaming',
"conversation_id": uni.getStorageSync(this.info.conversation) || null,
"user": this.userId,
'token': this.info.token,
'answer': res.msg,
'answerCh': '',
'showImageTextIndex': '',
'showImage': '',
'imageText': '',
'time': '',
'type': '',
'filePath': '',
"lang": "Chinese",
'isTrans':false,
};
this.messagesList.push(msgItem);
// this.messagesList[this.messagesList.length - 1].answerCh = this.messagesList[this.messagesList.length - 1].answerCh + res.msg
})
})
async translatorChinese() {
// Promise await
return new Promise((resolve, reject) => {
// API
request({
url: 'chatHttpApi/getChatInfo',
method: 'post',
data: {
q: this.messagesList[this.messagesList.length - 1].answer,
lang: this.lang
}
}).then(res => {
this.$nextTick(() => {
let msgItem = {
"inputs": {
"type": "text"
},
"query": '',
"response_mode": 'streaming',
"conversation_id": uni.getStorageSync(this.info.conversation) || null,
"user": this.userId,
'token': this.info.token,
'answer': res.msg,
'answerCh': '',
'showImageTextIndex': '',
'showImage': '',
'imageText': '',
'time': '',
'type': '',
'filePath': '',
"lang": "Chinese",
'isTrans': false,
};
this.messagesList.push(msgItem);
// Promise resolve
resolve(); // await
});
}).catch(err => {
console.error('翻译失败:', err);
reject(err); //
});
});
},
msgInfo() {
async msgInfo() {
if (this.msgSocket) {
this.msgSocket.onMessage(res => {
this.msgSocket.onMessage(async 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
if (this.lang == 'Chinese' || this.sayLang == 'zh-CHS') {
}else {
this.translatorChinese()
const lastMsg = this.messagesList[this.messagesList.length - 1];
if (lastMsg.inputs.type != 'image') {
// 1.
lastMsg.answer += res.data;
// 2.
if (!(this.lang == 'Chinese' || this.sayLang == 'zh-CHS')) {
await this.translatorChinese(); // Promise
}
// 3.
this.postProcess();
} 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
const json = JSON.parse(res.data);
lastMsg.answer += json.answer;
lastMsg.imageText += json.tranContent;
this.postProcess();
}
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)
//
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()
this.messagesList[this.messagesList.length - 1].answer += res.data;
this.goBottom();
}
}
})
});
}
},
//
postProcess() {
this.goBottom();
uni.setStorageSync(this.storeList + '_' + this.info.conversation, this.messagesList);
},
//
getMessageByStore() {
let tempList = uni.getStorageSync(this.storeList + '_' + this.info.conversation) || []
@ -473,13 +494,7 @@ export default {
} else {
this.messagesList = tempList
}
// Vue.js Vue.nextTick
this.$nextTick(() => {
this.$forceUpdate()
//
this.scrollToView = this.scrollId;
})
this.goBottom()
},
//
getMessage() {
@ -513,11 +528,7 @@ export default {
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;
})
that.goBottom()
}
get();
@ -555,36 +566,13 @@ export default {
//
playVoice(e) {
console.log('地址',e)
console.log('地址', e)
// let innerAudioContext1 = uni.createInnerAudioContext();
// innerAudioContext1.autoplay = true;
// innerAudioContext1.playbackRate = 0.5;
innerAudioContext.src = this.imagesUrl + e;
console.log(innerAudioContext.src)
innerAudioContext.play()
// innerAudioContext.onPlay(() => {
// console.log('');
// });
// innerAudioContext.onError((err) => {
// console.log(':', err);
// });
// console.log('')
// innerAudioContext.src = `data:audio/mp3;base64,${e}`;
// // innerAudioContext.src = e;
// // console.log(innerAudioContext.src);
//
// // 3.
// innerAudioContext.onPlay(() => {
// console.log('');
// });
//
// innerAudioContext.onError((err) => {
// console.error(':', err);
// });
//
// // 4.
// innerAudioContext.play();
},
//
covers(e) {
@ -637,7 +625,7 @@ export default {
'type': '',
'filePath': inputData.filePath,
"lang": this.lang,
'isTrans':true,
'isTrans': true,
'url': inputData.url
};
if (this.info.conversation == 'Translator') {
@ -710,22 +698,34 @@ export default {
},
//
goBottom() {
// this.scrollToBottom()
this.scrollToView = '';
this.$nextTick(() => {
//
this.$nextTick(() => {
this.scrollToView = this.scrollId;
this.$forceUpdate()
this.$nextTick(() => {
//
this.scrollToView = '';
this.$forceUpdate()
})
})
},
//
scrollToBottom() {
this.$nextTick(() => {
setTimeout(() => {
this.scrollTop = 999999; //
}, 50); // DOM
});
//
scrollToBottom(e){
setTimeout(()=>{
let query = uni.createSelectorQuery().in(this);
query.select('#scrollview').boundingClientRect();
query.select('#msglistview').boundingClientRect();
query.exec((res) =>{
if(res[1].height > res[0].height){
this.scrollTop = this.rpxTopx(res[1].height - res[0].height)
}
})
},15)
},
// pxrpx
rpxTopx(px){
let deviceWidth = uni.getSystemInfoSync().windowWidth
let rpx = ( 750 / deviceWidth ) * Number(px)
return Math.floor(rpx)
},
}
}

View File

@ -10,7 +10,7 @@
</view>
<!-- 文本框 -->
<textarea auto-height="true" class="chat-send btn" :class="{displaynone:isrecord}" @input="inputs"
@focus="focus" v-model="msg"></textarea>
@focus="focus" v-model="msg" placeholder="Please enter content"></textarea>
<view class="record btn" :class="{displaynone:!isrecord}" @touchstart="touchstart" @touchend="touchend"
@touchmove="touchmove">
按住说话

129
dc-App/pages/my/Contact.vue Normal file
View File

@ -0,0 +1,129 @@
<template>
<view class="contact-container">
<u-card title="Contact Us" class="card">
<view class="info">
<u-icon name="map" size="28" color="#2E7D32" />
<text class="info-text">123 Main Street, New York, NY 10001</text>
</view>
<view class="info">
<u-icon name="phone" size="28" color="#2E7D32" />
<text class="info-text">+1 (123) 456-7890</text>
</view>
<view class="info">
<u-icon name="email" size="28" color="#2E7D32" />
<text class="info-text">contact@company.com</text>
</view>
</u-card>
<u-form labelPosition="top" :model="form" ref="formRef" class="">
<u-form-item label="Name" prop="name" borderBottom>
<u-input v-model="form.name" placeholder="Enter your name" font-size="18" />
</u-form-item>
<u-form-item label="Email" prop="email" borderBottom>
<u-input v-model="form.email" placeholder="Enter your email" font-size="18" />
</u-form-item>
<u-form-item label="Message" prop="message" borderBottom>
<u-textarea v-model="form.message" font-size="18" placeholder="Enter your message" ></u-textarea>
</u-form-item>
<view class="button-container">
<u-button @click="submitForm" class="submit-button" text="Submit"></u-button>
</view>
</u-form>
</view>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
email: '',
message: ''
},
rules: {
name: [
{
required: true,
message: '请输入姓名',
trigger: ['blur', 'change']
}
]
}
};
},
methods: {
submitForm() {
this.$refs.formRef.validate().then(res => {
uni.$u.toast('校验通过')
}).catch(errors => {
uni.$u.toast('校验失败')
})
if (!this.form.name || !this.form.email || !this.form.message) {
uni.showToast({ title: 'Please fill in all fields', icon: 'none' });
return;
}
//
if (!this.form.email.match(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/)) {
uni.showToast({ title: 'Invalid email address', icon: 'none' });
return;
}
uni.showToast({ title: 'Successfully', icon: 'success' });
this.form = { name: '', email: '', message: '' };
}
}
};
</script>
<style lang="scss" scoped>
.contact-container {
padding: 40rpx;
display: flex;
flex-direction: column;
//align-items: center;
//text-align: center;
height: 100vh;
font-size: 20rpx;
background-color: #FFFFFF;
}
.card {
width: 90%;
padding: 30rpx;
font-size: 22rpx;
background-color: #1B5E20;
color: #FFFFFF;
border-radius: 20rpx;
}
.info {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
color: #FFFFFF;
}
.info-text {
margin-left: 15rpx;
font-size: 22rpx;
color: #FFFFFF;
}
.form-container {
width: 90%;
//display: flex;
flex-direction: column;
align-items: center;
font-size: 22rpx;
}
.button-container {
display: flex;
justify-content: center;
width: 100%;
margin-top: 20rpx;
}
.submit-button {
font-size: 22rpx;
padding: 15rpx 30rpx;
background-color: #2E7D32;
color: #FFFFFF;
border-radius: 10rpx;
}
</style>

View File

@ -27,6 +27,12 @@
</view>
<view class="">History</view>
</view>
<view class="f_" @click="goMyRouter(5)">
<view class="icon_">
<image src="../../static/imgs/me2.png" mode=""></image>
</view>
<view class="">Contact Us</view>
</view>
<view class="f_" @click="goMyRouter(3)">
<view class="icon_">
<image src="../../static/imgs/me3.png" mode=""></image>
@ -107,8 +113,12 @@
}
}
});
}
if (num == 5) {
uni.navigateTo({
url: '/pages/my/Contact'
})
}
},
goback() {
uni.navigateBack()
@ -197,7 +207,7 @@
.f_ {
width: 25%;
font-weight: 500;
font-size: 12px;
font-size: 23rpx;
color: #333333;
text-align: center;
}