2025-06-06 11:14:06 +08:00
|
|
|
|
<template>
|
|
|
|
|
<view class="page">
|
|
|
|
|
<u-navbar title="拼桌群聊" :border-bottom="false" :background="bgc" back-icon-color="#fff" title-color='#fff'
|
|
|
|
|
title-size='36' height='44' id="navbar">
|
|
|
|
|
</u-navbar>
|
|
|
|
|
<view class="tablexx">
|
|
|
|
|
<view class="top">
|
|
|
|
|
<view class="zhuti">
|
|
|
|
|
拼桌主题:
|
|
|
|
|
</view>
|
|
|
|
|
<!-- <button open-type="share"><image src="https://api.ccttiot.com/smartmeter/img/static/uOBU07kcJQjEVSNLyxPC" mode=""></image></button> -->
|
|
|
|
|
</view>
|
|
|
|
|
<view class="jieshao">
|
|
|
|
|
{{pinzhuoobj.topic}}
|
|
|
|
|
</view>
|
|
|
|
|
<view class="dangqian">
|
|
|
|
|
当前桌号:{{pinzhuoobj.boothName}}
|
|
|
|
|
</view>
|
|
|
|
|
<view class="pianhao">
|
|
|
|
|
<view class="">
|
|
|
|
|
<image style="height:26rpx;" src="https://api.ccttiot.com/smartmeter/img/static/uSFf09L8mtvqhjMOu0RV" mode=""></image>
|
|
|
|
|
{{pinzhuoobj.prefer == 1 ? '意向偏好男性' : pinzhuoobj.prefer == 2 ? '意向偏好女性' : '男女不限'}}
|
|
|
|
|
</view>
|
|
|
|
|
<view class="">
|
|
|
|
|
<image src="https://api.ccttiot.com/smartmeter/img/static/uL0SnLLV5kxVrM1dGGsQ" mode=""></image> 已加入{{pinzhuoobj.currentNum}}人 | 还可以加入{{Number(pinzhuoobj.limitNum == null ? 0 : pinzhuoobj.limitNum) - Number(pinzhuoobj.currentNum == null ? 0 : pinzhuoobj.currentNum)}}人
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="chat-container" :style="{ transform: `translateY(-${keyboardHeight}px)` }">
|
|
|
|
|
<scroll-view
|
|
|
|
|
scroll-y="true"
|
|
|
|
|
class="message-list"
|
|
|
|
|
:scroll-top="scrollTop"
|
|
|
|
|
:scroll-with-animation="true"
|
|
|
|
|
:scroll-anchoring="false"
|
|
|
|
|
:enhanced="true"
|
|
|
|
|
:bounces="false"
|
|
|
|
|
@scrolltoupper="loadMoreMessages"
|
|
|
|
|
refresher-enabled @refresherrefresh="onRefresh" :refresher-triggered="isRefreshing" refresher-default-style="white"
|
|
|
|
|
id="messageList">
|
2025-06-19 17:41:39 +08:00
|
|
|
|
<view style="width: 300rpx;color: #fff;text-align: center;background-color: #999;margin: auto;border-radius: 10rpx;opacity: .7;padding: 20rpx;box-sizing: border-box;">
|
|
|
|
|
倡导聊天过程文明善意~ 谨慎判断切勿私下交易,谨防网络诈骗,切勿违法乱纪!!!</view>
|
2025-06-06 11:14:06 +08:00
|
|
|
|
<view v-for="(messages, index) in messages" :key="index" class="message-item">
|
|
|
|
|
<view style="width: 100%;color: #666;text-align: center;font-size: 20rpx;margin-top: 20rpx;margin-bottom: 10rpx;">{{ messages.createTime }}</view>
|
|
|
|
|
<view v-if="messages.sendId == userId" class="message-self">
|
|
|
|
|
<view class="message-content" v-if="messages.type == 1">
|
|
|
|
|
{{ messages.content }}
|
|
|
|
|
<view class="message-status" v-if="messages.status">
|
|
|
|
|
<image v-if="messages.status === 'sending'" src="https://api.ccttiot.com/smartmeter/img/static/loading" class="status-icon sending"></image>
|
|
|
|
|
<image v-else-if="messages.status === 'failed'" src="https://api.ccttiot.com/smartmeter/img/static/failed" class="status-icon failed" @click="resendMessage(messages)"></image>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<image class="message-image" v-if="messages.type == 2" :src="messages.content" mode="widthFix" @click="previewImage(messages.content)"></image>
|
|
|
|
|
<video class="message-video" v-if="messages.type == 3" :src="messages.content" object-fit="contain" :id="'video-' + index"></video>
|
|
|
|
|
<image class="avatar" :src="messages.senderAvatar" v-if="messages.type != 4" mode=""></image>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-else class="message-other">
|
|
|
|
|
<image class="avatar" :src="messages.senderAvatar" v-if="messages.type != 4" mode=""></image>
|
|
|
|
|
<view v-if="messages.type == 4" style="width: 100%;color: #666;text-align: center;">{{ messages.content }}</view>
|
|
|
|
|
<view class="message-content" v-if="messages.type == 1">{{ messages.content }}</view>
|
|
|
|
|
<image class="message-image" v-if="messages.type == 2" :src="messages.content" mode="widthFix" @click="previewImage(messages.content)"></image>
|
|
|
|
|
<video class="message-video" v-if="messages.type == 3" :src="messages.content" object-fit="contain" :id="'video-' + index"></video>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</scroll-view>
|
|
|
|
|
<view class="bottom-area">
|
|
|
|
|
<view class="input-container">
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
v-model="inputContent"
|
|
|
|
|
placeholder="说点什么..."
|
|
|
|
|
class="input-box"
|
|
|
|
|
:adjust-position="false"
|
|
|
|
|
:cursor-spacing="20"
|
|
|
|
|
:hold-keyboard="true"
|
|
|
|
|
@confirm="sendMessage(1)"
|
|
|
|
|
@focus="onInputFocus"
|
|
|
|
|
@blur="onInputBlur"
|
|
|
|
|
/>
|
|
|
|
|
<button @click="sendMessage(1)" class="send-button">发送</button>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="function-icons">
|
|
|
|
|
<view class="icon-item" @click="showMediaActionSheet">
|
|
|
|
|
<image src="https://api.ccttiot.com/smartmeter/img/static/uGcE4EknnaOMxnqivQgL" mode="aspectFit"></image>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
bgc: {
|
|
|
|
|
backgroundColor: "#010000",
|
|
|
|
|
},
|
|
|
|
|
messages: [
|
2025-06-19 17:41:39 +08:00
|
|
|
|
{ content: '倡导聊天过程文明善意~ 谨慎判断,切勿私下交易,谨防网络诈骗', type: 4 },
|
2025-06-06 11:14:06 +08:00
|
|
|
|
],
|
|
|
|
|
inputContent: '',
|
|
|
|
|
scrollTop: 0,
|
|
|
|
|
keyboardHeight: 0,
|
|
|
|
|
isKeyboardShow: false,
|
|
|
|
|
pinzhuoobj:{},
|
|
|
|
|
teamId:'',
|
|
|
|
|
total:'',
|
|
|
|
|
pageNum:1,
|
|
|
|
|
isRefreshing: false,
|
|
|
|
|
userId:'',
|
|
|
|
|
oldScrollTop: 0,
|
|
|
|
|
socketTask: null,
|
|
|
|
|
isConnected: false,
|
|
|
|
|
sendingMessages: new Set(),
|
|
|
|
|
reconnectTimer: null,
|
|
|
|
|
reconnectCount: 0,
|
2025-06-19 17:41:39 +08:00
|
|
|
|
maxReconnectAttempts: 50,
|
2025-06-06 11:14:06 +08:00
|
|
|
|
token:''
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onLoad(option) {
|
|
|
|
|
this.userId = uni.getStorageSync('user').userId //获取登录用户id
|
|
|
|
|
if(option.teamId){
|
|
|
|
|
this.teamId = option.teamId
|
|
|
|
|
this.getxq()
|
|
|
|
|
}
|
|
|
|
|
this.getlist()
|
2025-06-19 17:41:39 +08:00
|
|
|
|
console.log('didididididdididi');
|
2025-06-06 11:14:06 +08:00
|
|
|
|
this.connectWebSocket()
|
|
|
|
|
this.gettoken()
|
|
|
|
|
|
|
|
|
|
// 监听键盘高度变化
|
|
|
|
|
uni.onKeyboardHeightChange(res => {
|
|
|
|
|
this.keyboardHeight = res.height;
|
|
|
|
|
this.isKeyboardShow = res.height > 0;
|
|
|
|
|
if (this.isKeyboardShow) {
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.scrollToBottom();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
onUnload() {
|
|
|
|
|
// 页面卸载时断开WebSocket连接
|
|
|
|
|
this.disconnectWebSocket();
|
|
|
|
|
uni.offKeyboardHeightChange();
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// 下拉刷新更多历史消息
|
|
|
|
|
onRefresh() {
|
|
|
|
|
if(this.messages.length < this.total){
|
|
|
|
|
this.isRefreshing = true
|
|
|
|
|
// 保存当前滚动位置
|
|
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
query.select('#messageList').boundingClientRect(data => {
|
|
|
|
|
this.oldScrollTop = data.top;
|
|
|
|
|
}).exec();
|
|
|
|
|
|
|
|
|
|
this.pageNum++
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.getlists()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.isRefreshing = false
|
|
|
|
|
}, 1000)
|
|
|
|
|
}else{
|
|
|
|
|
this.isRefreshing = true
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.isRefreshing = false
|
|
|
|
|
}, 1000)
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-06-19 17:41:39 +08:00
|
|
|
|
getlists(){
|
|
|
|
|
this.$u.get(`/app/chat/receiveList?pageNum=${this.pageNum}&pageSize=20&teamId=${this.teamId}`).then(res =>{
|
|
|
|
|
if(res.code == 200){
|
|
|
|
|
this.total = res.total
|
|
|
|
|
this.messages = [...res.rows.reverse(), ...this.messages] //将获取的信息进行倒转,最新的信息显示最下面
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
2025-06-06 11:14:06 +08:00
|
|
|
|
// 查询队伍聊天信息
|
|
|
|
|
getlist(){
|
|
|
|
|
this.$u.get(`/app/chat/receiveList?pageNum=${this.pageNum}&pageSize=20&teamId=${this.teamId}`).then(res =>{
|
|
|
|
|
if(res.code == 200){
|
|
|
|
|
this.total = res.total
|
|
|
|
|
if(this.pageNum == 1){
|
|
|
|
|
this.messages = res.rows.reverse()
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.scrollToBottom()
|
|
|
|
|
})
|
|
|
|
|
}else{
|
|
|
|
|
const oldLength = this.messages.length
|
|
|
|
|
this.messages = [...res.rows.reverse(), ...this.messages] //将获取的信息进行倒转,最新的信息显示最下面
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
// 计算新增内容的高度并设置滚动位置
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const query = uni.createSelectorQuery().in(this)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
query.selectAll('.message-item').boundingClientRect(items => {
|
|
|
|
|
if (items && items.length > oldLength) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
let newHeight = 0
|
2025-06-06 11:14:06 +08:00
|
|
|
|
for (let i = 0; i < items.length - oldLength; i++) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
newHeight += items[i].height
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.scrollTop = newHeight
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
}).exec()
|
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 查询拼桌信息
|
|
|
|
|
getxq(){
|
|
|
|
|
this.$u.get(`/app/team/getTeamInfo?id=${this.teamId}`).then(res =>{
|
|
|
|
|
if(res.code == 200){
|
|
|
|
|
this.pinzhuoobj = res.data
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 进行WebSocket连接
|
|
|
|
|
connectWebSocket() {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
if (this.socketTask) {
|
2025-06-06 11:14:06 +08:00
|
|
|
|
this.disconnectWebSocket()
|
|
|
|
|
}
|
|
|
|
|
const token = uni.getStorageSync('token')
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const wsUrl = `${this.$store.state.wsUrl}/ws/user?token=${token}`
|
2025-06-06 11:14:06 +08:00
|
|
|
|
this.socketTask = uni.connectSocket({
|
|
|
|
|
url: wsUrl,
|
|
|
|
|
success: () => {
|
|
|
|
|
console.log('WebSocket连接成功')
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
this.socketTask.onOpen(() => {
|
|
|
|
|
console.log('WebSocket连接已打开')
|
|
|
|
|
this.isConnected = true
|
|
|
|
|
this.reconnectCount = 0 // 重置重连次数
|
|
|
|
|
if (this.reconnectTimer) {
|
|
|
|
|
clearTimeout(this.reconnectTimer)
|
|
|
|
|
this.reconnectTimer = null
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
this.socketTask.onMessage((res) => {
|
|
|
|
|
const message = JSON.parse(res.data)
|
|
|
|
|
this.$nextTick(() => {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages.push(message)
|
|
|
|
|
console.log(message,this.messages,'asdasdasdas')
|
|
|
|
|
// this.scrollToBottom()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
this.socketTask.onClose(() => {
|
|
|
|
|
console.log('WebSocket连接已关闭')
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.isConnected = false
|
2025-06-06 11:14:06 +08:00
|
|
|
|
this.handleReconnect()
|
|
|
|
|
})
|
|
|
|
|
this.socketTask.onError((err) => {
|
|
|
|
|
console.error('WebSocket错误:', err)
|
|
|
|
|
this.isConnected = false
|
|
|
|
|
this.handleReconnect()
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
disconnectWebSocket() {
|
|
|
|
|
if (this.socketTask) {
|
|
|
|
|
this.socketTask.close()
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.socketTask = null
|
|
|
|
|
this.isConnected = false
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleReconnect() {
|
|
|
|
|
if (this.reconnectCount >= this.maxReconnectAttempts) {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '网络连接失败,请检查网络后重试',
|
|
|
|
|
icon: 'none',
|
|
|
|
|
duration: 2000
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!this.reconnectTimer) {
|
|
|
|
|
this.reconnectTimer = setTimeout(() => {
|
|
|
|
|
this.reconnectCount++
|
|
|
|
|
console.log(`尝试第${this.reconnectCount}次重连`);
|
|
|
|
|
this.connectWebSocket()
|
|
|
|
|
}, 3000) // 3秒后重试
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 点击发送信息
|
|
|
|
|
sendMessage(type) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
if(this.isConnected == false){
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '当前聊天未连接,请退出重试',
|
|
|
|
|
showCancel: false,
|
|
|
|
|
success: function(res) {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
|
|
|
|
} else if (res.cancel) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-06-06 11:14:06 +08:00
|
|
|
|
if (this.inputContent.trim() !== '') {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const tempId = Date.now().toString()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
const tempMessage = {
|
|
|
|
|
sendId: this.userId,
|
|
|
|
|
content: this.inputContent,
|
|
|
|
|
type: type,
|
|
|
|
|
status: 'sending',
|
|
|
|
|
tempId: tempId,
|
|
|
|
|
senderAvatar: uni.getStorageSync('user').avatar || 'https://api.ccttiot.com/smartmeter/img/static/default-avatar'
|
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.sendingMessages.add(tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.scrollToBottom()
|
|
|
|
|
})
|
|
|
|
|
let data = {
|
|
|
|
|
teamId: this.teamId,
|
|
|
|
|
content: this.inputContent,
|
|
|
|
|
type: type
|
|
|
|
|
}
|
|
|
|
|
this.$u.post(`/app/chat/sendMessage`, data).then(res => {
|
|
|
|
|
if (res.code == 200) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const index = this.messages.findIndex(msg => msg.tempId === tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
if (index !== -1) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'sent'
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.sendingMessages.delete(tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
} else {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const index = this.messages.findIndex(msg => msg.tempId === tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
if (index !== -1) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'failed'
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.sendingMessages.delete(tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: res.msg,
|
|
|
|
|
icon: 'none',
|
|
|
|
|
duration: 2000
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
}).catch(err => {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const index = this.messages.findIndex(msg => msg.tempId === tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
if (index !== -1) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'failed'
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.sendingMessages.delete(tempId)
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '发送失败,请重试',
|
|
|
|
|
showCancel: false,
|
|
|
|
|
success: function(res) {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
|
|
|
|
} else if (res.cancel) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
this.inputContent = ''
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
scrollToBottom() {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const query = uni.createSelectorQuery().in(this)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
query.select('#messageList').boundingClientRect(data => {
|
|
|
|
|
if (data) {
|
|
|
|
|
query.selectAll('.message-item').boundingClientRect(items => {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
let totalHeight = 0
|
2025-06-06 11:14:06 +08:00
|
|
|
|
items.forEach(item => {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
totalHeight += item.height
|
|
|
|
|
})
|
|
|
|
|
this.scrollTop = totalHeight
|
|
|
|
|
}).exec()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
}).exec()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
loadMoreMessages() {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
onInputFocus() {
|
|
|
|
|
this.scrollToBottom()
|
|
|
|
|
},
|
|
|
|
|
onInputBlur() {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.isKeyboardShow = false
|
|
|
|
|
this.keyboardHeight = 0
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
// 预览图片
|
|
|
|
|
previewImage(url) {
|
|
|
|
|
uni.previewImage({
|
|
|
|
|
urls: [url],
|
|
|
|
|
current: url,
|
|
|
|
|
indicator: 'number',
|
|
|
|
|
loop: false
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
// 播放视频
|
|
|
|
|
playVideo(index) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const videoContext = uni.createVideoContext('video-' + index, this)
|
|
|
|
|
videoContext.requestFullScreen()
|
|
|
|
|
videoContext.play()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
// 重发消息
|
|
|
|
|
resendMessage(message) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const index = this.messages.findIndex(msg => msg.tempId === message.tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
if (index !== -1) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'sending'
|
|
|
|
|
this.sendingMessages.add(message.tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
let data = {
|
|
|
|
|
teamId: this.teamId,
|
|
|
|
|
content: message.content,
|
|
|
|
|
type: message.type
|
2025-06-19 17:41:39 +08:00
|
|
|
|
}
|
2025-06-06 11:14:06 +08:00
|
|
|
|
this.$u.post(`/app/chat/sendMessage`, data).then(res => {
|
|
|
|
|
if (res.code == 200) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'sent'
|
|
|
|
|
this.sendingMessages.delete(message.tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
} else {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'failed'
|
|
|
|
|
this.sendingMessages.delete(message.tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: res.msg,
|
|
|
|
|
icon: 'none',
|
|
|
|
|
duration: 2000
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
}).catch(err => {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.messages[index].status = 'failed'
|
|
|
|
|
this.sendingMessages.delete(message.tempId)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '发送失败,请重试',
|
|
|
|
|
icon: 'none',
|
|
|
|
|
duration: 2000
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 获取七牛云token
|
|
|
|
|
gettoken(){
|
|
|
|
|
this.$u.get(`/common/qiniuToken`).then(res => {
|
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
this.token = res.data
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 显示媒体选择菜单
|
|
|
|
|
showMediaActionSheet() {
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
itemList: ['从相册选择', '拍摄视频'],
|
|
|
|
|
success: (res) => {
|
|
|
|
|
switch (res.tapIndex) {
|
|
|
|
|
case 0: // 从相册选择
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.chooseImage()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
break;
|
|
|
|
|
case 1: // 拍摄视频
|
2025-06-19 17:41:39 +08:00
|
|
|
|
this.takeVideo()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
// 选择图片
|
|
|
|
|
chooseImage() {
|
|
|
|
|
let _this = this
|
|
|
|
|
let math = 'static/' + _this.$u.guid(20)
|
|
|
|
|
uni.chooseImage({
|
|
|
|
|
count: 9,
|
|
|
|
|
type: 'all',
|
|
|
|
|
success(res) {
|
|
|
|
|
const tempFilePaths = res.tempFiles
|
|
|
|
|
wx.uploadFile({
|
|
|
|
|
url: 'https://up-z2.qiniup.com',
|
|
|
|
|
name: 'file',
|
|
|
|
|
filePath: tempFilePaths[0].path,
|
|
|
|
|
formData: {
|
|
|
|
|
token: _this.token, //后端返回的token
|
|
|
|
|
key: 'smartmeter/img/' + math
|
|
|
|
|
},
|
|
|
|
|
success: function(res) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
console.log(res, 'resres')
|
2025-06-06 11:14:06 +08:00
|
|
|
|
let str = JSON.parse(res.data)
|
|
|
|
|
_this.inputContent = 'https://api.ccttiot.com/' + str.key
|
|
|
|
|
console.log(_this.inputContent)
|
|
|
|
|
_this.sendMessage(2)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 拍摄视频
|
|
|
|
|
takeVideo() {
|
|
|
|
|
let _this = this;
|
2025-06-19 17:41:39 +08:00
|
|
|
|
let fileKey = 'static/video/' + _this.$u.guid(20) + '.mp4' // 视频文件后缀
|
2025-06-06 11:14:06 +08:00
|
|
|
|
uni.chooseVideo({
|
|
|
|
|
sourceType: ['camera'], // 只允许拍摄
|
|
|
|
|
maxDuration: 60, // 最长60秒
|
|
|
|
|
camera: 'back', // 默认后置摄像头
|
|
|
|
|
compressed: true, // 压缩视频
|
|
|
|
|
success(res) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
const tempFilePath = res.tempFilePath
|
2025-06-06 11:14:06 +08:00
|
|
|
|
// 显示上传loading
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
title: '视频上传中...',
|
|
|
|
|
mask: true
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
wx.uploadFile({
|
|
|
|
|
url: 'https://up-z2.qiniup.com',
|
|
|
|
|
name: 'file',
|
|
|
|
|
filePath: tempFilePath,
|
|
|
|
|
formData: {
|
|
|
|
|
token: _this.token, // 后端返回的token
|
|
|
|
|
key: 'smartmeter/video/' + fileKey // 修改存储路径为video目录
|
|
|
|
|
},
|
|
|
|
|
success: function(uploadRes) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
uni.hideLoading()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
let responseData = JSON.parse(uploadRes.data);
|
2025-06-19 17:41:39 +08:00
|
|
|
|
_this.inputContent = 'https://api.ccttiot.com/' + responseData.key
|
2025-06-06 11:14:06 +08:00
|
|
|
|
// 视频特殊处理:保存缩略图
|
|
|
|
|
if(res.thumbTempFilePath){
|
2025-06-19 17:41:39 +08:00
|
|
|
|
_this.uploadThumb(res.thumbTempFilePath)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
_this.sendMessage(3); // 类型改为3表示视频
|
|
|
|
|
},
|
|
|
|
|
fail(err) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
uni.hideLoading()
|
2025-06-06 11:14:06 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '上传失败',
|
|
|
|
|
icon: 'none'
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
|
|
|
|
console.error('视频上传失败:', err)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
fail(err) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
console.log('视频选择失败:', err)
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
},
|
|
|
|
|
// 上传视频缩略图
|
|
|
|
|
uploadThumb(thumbPath) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
let _this = this
|
|
|
|
|
let thumbKey = 'static/thumb/' + _this.$u.guid(20) + '.jpg'
|
2025-06-06 11:14:06 +08:00
|
|
|
|
wx.uploadFile({
|
|
|
|
|
url: 'https://up-z2.qiniup.com',
|
|
|
|
|
name: 'file',
|
|
|
|
|
filePath: thumbPath,
|
|
|
|
|
formData: {
|
|
|
|
|
token: _this.token,
|
|
|
|
|
key: thumbKey
|
|
|
|
|
},
|
|
|
|
|
success(res) {
|
2025-06-19 17:41:39 +08:00
|
|
|
|
console.log('缩略图上传成功')
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
2025-06-19 17:41:39 +08:00
|
|
|
|
})
|
2025-06-06 11:14:06 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
page {
|
|
|
|
|
background: #010000;
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
.page {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
.chat-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
height: calc(100vh - 350rpx - 70rpx);
|
|
|
|
|
background-color: #010000;
|
|
|
|
|
width: 750rpx;
|
|
|
|
|
position: relative;
|
|
|
|
|
top: 240rpx;
|
|
|
|
|
transition: transform 0.3s;
|
|
|
|
|
|
|
|
|
|
.message-list {
|
|
|
|
|
flex: 1;
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: calc(100% - 120rpx);
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
.message-item {
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
.avatar {
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
height: 60rpx;
|
|
|
|
|
background-color: #ccc;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
margin-left: 15rpx;
|
|
|
|
|
}
|
|
|
|
|
.message-self {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
|
|
|
|
.message-content {
|
|
|
|
|
background-color: #4D3F53;
|
|
|
|
|
color: white;
|
|
|
|
|
padding: 15rpx 20rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
max-width: 70%;
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
.message-status {
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: -40rpx;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.status-icon {
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
|
|
|
|
|
&.sending {
|
|
|
|
|
animation: rotate 1s linear infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&.failed {
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.message-image {
|
|
|
|
|
max-width: 400rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
}
|
|
|
|
|
.message-video {
|
|
|
|
|
max-width: 400rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message-other {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
|
|
|
|
.avatar {
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
height: 60rpx;
|
|
|
|
|
background-color: #ccc;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
margin-right: 15rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message-content {
|
|
|
|
|
background-color: #333;
|
|
|
|
|
color: white;
|
|
|
|
|
padding: 15rpx 20rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
max-width: 70%;
|
|
|
|
|
}
|
|
|
|
|
.message-image {
|
|
|
|
|
max-width: 400rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
}
|
|
|
|
|
.message-video {
|
|
|
|
|
max-width: 400rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.bottom-area {
|
|
|
|
|
background-color: #010000;
|
|
|
|
|
border-top: 1rpx solid #333;
|
|
|
|
|
|
|
|
|
|
.input-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
|
|
|
|
.input-box {
|
|
|
|
|
flex: 1;
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
background-color: #333;
|
|
|
|
|
color: white;
|
|
|
|
|
padding: 0 20rpx;
|
|
|
|
|
border-radius: 40rpx;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.send-button {
|
|
|
|
|
margin-left: 20rpx;
|
|
|
|
|
background-color: #FF8998;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 40rpx;
|
|
|
|
|
padding: 0 30rpx;
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
line-height: 80rpx;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.tablexx{
|
|
|
|
|
width: 730rpx;
|
|
|
|
|
height: 266rpx;
|
|
|
|
|
background: #010000;
|
|
|
|
|
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
|
|
|
|
border-image: linear-gradient(226deg, rgba(255, 137.00000703334808, 152.0000061392784, 0.1899999976158142), rgba(255, 137.00000703334808, 152.0000061392784, 0)) 2 2;
|
|
|
|
|
padding: 32rpx 36rpx;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 150rpx;
|
|
|
|
|
left: 50%;
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
z-index: 99;
|
|
|
|
|
.jieshao{
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
margin-top: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
.dangqian{
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
margin-top: 26rpx;
|
|
|
|
|
}
|
|
|
|
|
.pianhao{
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
view{
|
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #6E7191;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
image{
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.top{
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
button{
|
|
|
|
|
background-color: transparent;
|
|
|
|
|
margin: 0 !important;
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
line-height: 32rpx;
|
|
|
|
|
position: relative;
|
|
|
|
|
image{
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 10rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes rotate {
|
|
|
|
|
from {
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.function-icons {
|
|
|
|
|
display: flex;
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
border-top: 1rpx solid #333;
|
|
|
|
|
|
|
|
|
|
.icon-item {
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
height: 60rpx;
|
|
|
|
|
|
|
|
|
|
image {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|