fix: 聊天(已实现图文消息对话)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -114,3 +114,5 @@ dist
|
|||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
/.hbuilderx/
|
||||||
|
/.idea/
|
||||||
|
|||||||
@@ -86,6 +86,9 @@
|
|||||||
},
|
},
|
||||||
"scope.camera": {
|
"scope.camera": {
|
||||||
"desc": "需要摄像头拍照和视频通话"
|
"desc": "需要摄像头拍照和视频通话"
|
||||||
|
},
|
||||||
|
"scope.writePhotosAlbum": {
|
||||||
|
"desc": "需要访问您的相册以选择图片"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -124,9 +124,9 @@
|
|||||||
<view class="img">
|
<view class="img">
|
||||||
<image :src="item.avatar" mode=""></image>
|
<image :src="item.avatar" mode=""></image>
|
||||||
</view>
|
</view>
|
||||||
<u-badge size="default" v-if="item.un_read_num>=0" :count="item.un_read_num"
|
<u-badge size="default" v-if="item.un_read_count>=0" :count="item.un_read_count"
|
||||||
:is-dot="item.un_read_num==0?true:false"
|
:is-dot="item.un_read_count==0?true:false"
|
||||||
type="error" :offset="item.un_read_num>0?[-4,-8]:[0,0]"></u-badge>
|
type="error" :offset="item.un_read_count>0?[-4,-8]:[0,0]"></u-badge>
|
||||||
</view>
|
</view>
|
||||||
<!-- 描述 -->
|
<!-- 描述 -->
|
||||||
<view class="info">
|
<view class="info">
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="preview">
|
<view class="preview">
|
||||||
<p>{{ item.last_message }}</p>
|
<p>{{ item.last_message }}</p>
|
||||||
<!-- <p v-if="item.un_read_num>0">您有{{item.un_read_num}}条新的消息</p>-->
|
<!-- <p v-if="item.un_read_count>0">您有{{item.un_read_count}}条新的消息</p>-->
|
||||||
</view>
|
</view>
|
||||||
<view class="preview" v-if="item.last_message===''">
|
<view class="preview" v-if="item.last_message===''">
|
||||||
暂无新消息
|
暂无新消息
|
||||||
@@ -151,6 +151,7 @@ import {
|
|||||||
getseesionInfo,
|
getseesionInfo,
|
||||||
getseesionRead
|
getseesionRead
|
||||||
} from '../../request/api/api'
|
} from '../../request/api/api'
|
||||||
|
import {getChatFriendsListApi} from "@/request/api/im";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@@ -158,108 +159,7 @@ export default {
|
|||||||
order: [],
|
order: [],
|
||||||
system: [],
|
system: [],
|
||||||
doctor: [],
|
doctor: [],
|
||||||
imChat: [
|
imChat: [],
|
||||||
{
|
|
||||||
id: 'doctor-39',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '李二狗',
|
|
||||||
avatar: 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg',
|
|
||||||
un_read_num: 99,
|
|
||||||
last_message: '多喝水即可',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-2',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王三三',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[图片]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-3',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王五五',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[图片]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-4',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[图片]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-5',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六1',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[音频]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-6',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六2',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[视频]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-7',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六3',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[文件]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-8',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[图片]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-9',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六1',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[音频]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-10',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六2',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[视频]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doctor-11',
|
|
||||||
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
|
|
||||||
nick_name: '王六六3',
|
|
||||||
avatar: '/static/xx/ysxx.png',
|
|
||||||
un_read_num: 0,
|
|
||||||
last_message: '[文件]',
|
|
||||||
last_message_time: '2021-07-05 09:05:05'
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
type: ""
|
type: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -357,6 +257,11 @@ export default {
|
|||||||
this.system = res.data.data.system
|
this.system = res.data.data.system
|
||||||
this.doctor = res.data.data.doctor_news
|
this.doctor = res.data.data.doctor_news
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
getMyChatFriendsList() {
|
||||||
|
getChatFriendsListApi().then((res) => {
|
||||||
|
this.imChat = res.data.result
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -367,6 +272,7 @@ export default {
|
|||||||
this.system = []
|
this.system = []
|
||||||
this.doctor = []
|
this.doctor = []
|
||||||
this.getInfo()
|
this.getInfo()
|
||||||
|
this.getMyChatFriendsList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -8,15 +8,23 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
js-base64:
|
||||||
|
specifier: ^3.7.7
|
||||||
|
version: 3.7.7
|
||||||
uview-ui:
|
uview-ui:
|
||||||
specifier: ^1.8.8
|
specifier: ^1.8.8
|
||||||
version: 1.8.8
|
version: 1.8.8
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
js-base64@3.7.7:
|
||||||
|
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
|
||||||
|
|
||||||
uview-ui@1.8.8:
|
uview-ui@1.8.8:
|
||||||
resolution: {integrity: sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg==, tarball: https://registry.npmmirror.com/uview-ui/-/uview-ui-1.8.8.tgz}
|
resolution: {integrity: sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg==, tarball: https://registry.npmmirror.com/uview-ui/-/uview-ui-1.8.8.tgz}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
|
js-base64@3.7.7: {}
|
||||||
|
|
||||||
uview-ui@1.8.8: {}
|
uview-ui@1.8.8: {}
|
||||||
|
|||||||
88
request/api/http.js
Normal file
88
request/api/http.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import http from './request'
|
||||||
|
|
||||||
|
const HttpUrlMap = [
|
||||||
|
'/oldApi',
|
||||||
|
'/newApi',
|
||||||
|
'/imApi',
|
||||||
|
'/xkApi',
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET请求(Json)
|
||||||
|
* @param url
|
||||||
|
* @param params
|
||||||
|
* @param type
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function get(url, params, type = 0) {
|
||||||
|
return await http(HttpUrlMap[type] + url, {
|
||||||
|
method: 'GET',
|
||||||
|
data: params,
|
||||||
|
// 传输方式是json
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* POST请求(Json)
|
||||||
|
* @param url
|
||||||
|
* @param params
|
||||||
|
* @param type
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function post(url, params, type = 0) {
|
||||||
|
return await http(HttpUrlMap[type] + url, {
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
// 传输方式是json
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传方法(仅支持 FormData 格式)
|
||||||
|
* @param {string} url - 接口路径
|
||||||
|
* @param {any} formData - 包含文件的 FormData 对象
|
||||||
|
* @param {int} [type=0] - 请求类型(用于映射 HttpUrlMap)
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export function uploadFile(url, formData, type = 3) {
|
||||||
|
const fullUrl = 'http://127.0.0.1:18001/api/mobile' + url;
|
||||||
|
|
||||||
|
console.log(fullUrl, 'sssssssssssss')
|
||||||
|
uni.uploadFile({
|
||||||
|
url: 'http://127.0.0.1:18001/api/mobile/chat-friends/upload-chat-file',
|
||||||
|
filePath: formData,
|
||||||
|
name: 'file',
|
||||||
|
header: {
|
||||||
|
"authorization": uni.getStorageSync('token')
|
||||||
|
},
|
||||||
|
formData,
|
||||||
|
success: (uploadFileRes) => {
|
||||||
|
return uploadFileRes;
|
||||||
|
},
|
||||||
|
fail: (res) => {
|
||||||
|
console.log(res, '上传失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// return;
|
||||||
|
// try {
|
||||||
|
// const response = await http(fullUrl, {
|
||||||
|
// method: 'POST',
|
||||||
|
// data: formData,
|
||||||
|
// // 注意:不手动设置 Content-Type,浏览器会自动添加 multipart/form-data 和 boundary
|
||||||
|
// headers: {
|
||||||
|
// // 如果需要额外 headers(如 token),可在此添加
|
||||||
|
// // 'Authorization': 'Bearer xxx',
|
||||||
|
// },
|
||||||
|
// }, 1);
|
||||||
|
//
|
||||||
|
// return response;
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('File upload failed:', error);
|
||||||
|
// throw error; // 抛出错误供调用者处理
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import http from './request'
|
import http from './request'
|
||||||
|
import {get, post, uploadFile} from './http'
|
||||||
// 发信息
|
// 发信息
|
||||||
// export async function sendMsg(params) {
|
// export async function sendMsg(params) {
|
||||||
// let data = await http('/v1/im/message-send', params)
|
// let data = await http('/v1/im/message-send', params)
|
||||||
@@ -14,4 +15,32 @@ export async function sendToUserApi(params) {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
}, 1)
|
}, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取房间聊天记录
|
||||||
|
* @param params
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function getMessagesByRoomIdApi(params) {
|
||||||
|
return await post('/chat-friends/messages-by-room-id', params, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取聊天好友列表
|
||||||
|
* @param params
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function getChatFriendsListApi(params) {
|
||||||
|
return await get('/chat-friends/list', params, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传聊天文件
|
||||||
|
* @param params
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export function upLoadChatFileApi(params) {
|
||||||
|
return console.log('aaaaaaaaaaaaaaaaaaa', uploadFile('/chat-friends/upload-chat-file', params))
|
||||||
|
return uploadFile('/chat-friends/upload-chat-file', params)
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ function request(url, params, method = 0) {
|
|||||||
}
|
}
|
||||||
if (url.split('/').indexOf('xkApi') !== -1) {
|
if (url.split('/').indexOf('xkApi') !== -1) {
|
||||||
// baseURL = "https://api.xiaokang88.com/member"
|
// baseURL = "https://api.xiaokang88.com/member"
|
||||||
baseURL = "https://127.0.0.1:18001/member"
|
baseURL = "http://127.0.0.1:18001/api/mobile"
|
||||||
}
|
}
|
||||||
url = url.replace('/oldApi', '');
|
url = url.replace('/oldApi', '');
|
||||||
url = url.replace('/newApi', '');
|
url = url.replace('/newApi', '');
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
import {getMessagesByRoomIdApi} from "@/request/api/im";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天消息管理器
|
* 聊天消息管理器
|
||||||
* @type {{currentRoomId: null, unreadCounts: {}, messageCache: {}, roomMessages: {}, enterRoom(*): void, leaveRoom(): void, getCurrentRoomId(): *, increaseUnreadCount(*): void, resetUnreadCount(*): void, getUnreadCount(*): *, getAllUnreadCount(): *, notifyUnreadChange(): void, cacheMessage(*, *): void, addMessageToRoom(*, *): void, getRoomMessages(*): *, handleIncomingMessage(*): void}}
|
* @type {{currentRoomId: null, lastMessageId: null, unreadCounts: {}, messageCache: {}, roomMessages: {}, enterRoom(*): void, leaveRoom(): void, getCurrentRoomId(): *, increaseUnreadCount(*): void, resetUnreadCount(*): void, getUnreadCount(*): *, getAllUnreadCount(): *, loadHistory(): *, getMessageType(): *, notifyUnreadChange(): void,, addMessageToRoom(*, *): void, getRoomMessages(*): *, handleIncomingMessage(*): void}}
|
||||||
*/
|
*/
|
||||||
const ChatManager = {
|
const ChatManager = {
|
||||||
// 当前房间ID
|
// 当前房间ID
|
||||||
currentRoomId: null,
|
currentRoomId: null,
|
||||||
|
|
||||||
|
lastMessageId: 0,
|
||||||
|
|
||||||
// 存储未读消息数 { roomId: count }
|
// 存储未读消息数 { roomId: count }
|
||||||
unreadCounts: {},
|
unreadCounts: {},
|
||||||
|
|
||||||
@@ -19,19 +23,9 @@ const ChatManager = {
|
|||||||
enterRoom(roomId) {
|
enterRoom(roomId) {
|
||||||
this.currentRoomId = roomId;
|
this.currentRoomId = roomId;
|
||||||
uni.setStorageSync('currentRoomId', roomId);
|
uni.setStorageSync('currentRoomId', roomId);
|
||||||
console.log(`进入房间: ${roomId}`);
|
console.log(`进入房间`);
|
||||||
|
|
||||||
// 重置当前房间的未读消息
|
// 重置当前房间的未读消息
|
||||||
this.resetUnreadCount(roomId);
|
this.resetUnreadCount(roomId);
|
||||||
|
|
||||||
// 如果有缓存消息,则触发事件,然后清除缓存
|
|
||||||
if (this.messageCache[roomId]) {
|
|
||||||
const cachedMessages = this.messageCache[roomId];
|
|
||||||
cachedMessages.forEach(message => {
|
|
||||||
this.addMessageToRoom(roomId, message);
|
|
||||||
});
|
|
||||||
delete this.messageCache[roomId];
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 离开聊天室
|
// 离开聊天室
|
||||||
@@ -83,25 +77,152 @@ const ChatManager = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// 缓存消息(当收到消息但不在该房间时)
|
|
||||||
cacheMessage(roomId, message) {
|
|
||||||
if (!this.messageCache[roomId]) {
|
|
||||||
this.messageCache[roomId] = [];
|
|
||||||
}
|
|
||||||
this.messageCache[roomId].push(message);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 添加消息到房间
|
// 添加消息到房间
|
||||||
addMessageToRoom(roomId, message) {
|
addMessageToRoom(roomId, message) {
|
||||||
if (!this.roomMessages[roomId]) {
|
if (!this.roomMessages[roomId]) {
|
||||||
this.roomMessages[roomId] = [];
|
this.roomMessages[roomId] = [];
|
||||||
}
|
}
|
||||||
this.roomMessages[roomId].push(message);
|
this.roomMessages[roomId].push(message);
|
||||||
|
console.log('addMessageToRoom', this.roomMessages[roomId])
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取房间消息
|
// 获取房间消息
|
||||||
getRoomMessages(roomId) {
|
getRoomMessages(roomId) {
|
||||||
|
let that = this;
|
||||||
|
this.roomMessages[roomId] = [];
|
||||||
|
getMessagesByRoomIdApi({
|
||||||
|
room_id: roomId,
|
||||||
|
last_message_id: 0,
|
||||||
|
}).then((res) => {
|
||||||
|
that.roomMessages[roomId] = that.checkMessage(res.data.result.list);
|
||||||
|
that.lastMessageId = res.data.result.last_message_id;
|
||||||
|
console.log(that.roomMessages[roomId], 'roomMessages')
|
||||||
|
|
||||||
|
uni.$emit('load-room-message', 1);
|
||||||
|
return this.roomMessages[roomId] || [];
|
||||||
|
})
|
||||||
return this.roomMessages[roomId] || [];
|
return this.roomMessages[roomId] || [];
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
checkMessage(message, type = 0) {
|
||||||
|
if (type === 1) {
|
||||||
|
return {
|
||||||
|
id: message.id,
|
||||||
|
sender: message.sender_user_id,
|
||||||
|
type: this.getMessageType(message.message_type),
|
||||||
|
content: message.content,
|
||||||
|
duration: message.duration,
|
||||||
|
time: this.formatTime(message.send_time),
|
||||||
|
timestamp: message.send_time
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return message.map(item => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
sender: item.sender_user_id,
|
||||||
|
type: this.getMessageType(item.message_type),
|
||||||
|
content: item?.message_content || item.content,
|
||||||
|
duration: item.duration,
|
||||||
|
time: item?.created_at_text || item.send_time,
|
||||||
|
timestamp: item?.created_at || item.send_time
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 根据消息类型ID获取类型名称
|
||||||
|
getMessageType(typeId) {
|
||||||
|
const types = {
|
||||||
|
0: 'text',
|
||||||
|
1: 'image',
|
||||||
|
2: 'audio',
|
||||||
|
3: 'video',
|
||||||
|
4: 'prescription',
|
||||||
|
5: 'file'
|
||||||
|
};
|
||||||
|
return types[typeId];
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化时间
|
||||||
|
formatTime(timestamp) {
|
||||||
|
let date;
|
||||||
|
|
||||||
|
// 处理不同输入类型
|
||||||
|
if (typeof timestamp === 'number') {
|
||||||
|
// 数字直接作为时间戳处理
|
||||||
|
date = new Date(timestamp);
|
||||||
|
} else if (timestamp instanceof Date) {
|
||||||
|
// Date对象直接使用
|
||||||
|
date = timestamp;
|
||||||
|
} else if (typeof timestamp === 'string') {
|
||||||
|
// 字符串类型:尝试转换为时间戳
|
||||||
|
const parsed = Date.parse(timestamp);
|
||||||
|
if (isNaN(parsed)) {
|
||||||
|
// 转换失败则使用当前时间
|
||||||
|
date = new Date();
|
||||||
|
} else {
|
||||||
|
date = new Date(parsed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 其他类型使用当前时间
|
||||||
|
date = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const diff = now - date; // 时间差(毫秒)
|
||||||
|
const seconds = Math.floor(diff / 1000);
|
||||||
|
|
||||||
|
// 定义星期几的名称
|
||||||
|
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
|
||||||
|
const currentWeekday = date.getDay(); // 0=周日,1=周一,...,6=周六
|
||||||
|
|
||||||
|
// 格式化时间函数 (补零)
|
||||||
|
const formatTime = (num) => num.toString().padStart(2, '0');
|
||||||
|
const formattedTime = `${formatTime(date.getHours())}:${formatTime(date.getMinutes())}`;
|
||||||
|
|
||||||
|
if (seconds < 60) {
|
||||||
|
return '刚刚';
|
||||||
|
} else if (seconds < 3600) {
|
||||||
|
return Math.floor(seconds / 60) + '分钟前';
|
||||||
|
} else if (seconds < 7200) { // 1-2小时
|
||||||
|
return Math.floor(seconds / 3600) + '小时前';
|
||||||
|
} else if (seconds < 86400) { // 2-24小时
|
||||||
|
return formattedTime;
|
||||||
|
} else if (seconds < 172800) { // 1-2天(昨天)
|
||||||
|
return `昨天 ${formattedTime}`;
|
||||||
|
} else if (seconds < 259200) { // 2-3天(前天)
|
||||||
|
return `前天 ${formattedTime}`;
|
||||||
|
} else if (seconds < 604800) { // 3-7天内(本周X)
|
||||||
|
return `周${weekdays[currentWeekday]} ${formattedTime}`;
|
||||||
|
} else if (seconds < 1209600) { // 7-14天(上周X)
|
||||||
|
return `上周${weekdays[currentWeekday]} ${formattedTime}`;
|
||||||
|
} else if (seconds < 2592000) { // 14天-1个月
|
||||||
|
return Math.floor(seconds / 86400) + '天前';
|
||||||
|
} else if (seconds < 31536000) { // 1个月-1年
|
||||||
|
return Math.floor(seconds / 2592000) + '个月前';
|
||||||
|
} else { // 超过1年
|
||||||
|
return `${date.getFullYear()}-${formatTime(date.getMonth() + 1)}-${formatTime(date.getDate())}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
loadHistory(roomId) {
|
||||||
|
let that = this;
|
||||||
|
getMessagesByRoomIdApi({
|
||||||
|
room_id: roomId,
|
||||||
|
last_message_id: that.lastMessageId,
|
||||||
|
}).then((res) => {
|
||||||
|
|
||||||
|
if (res.data.result.list?.length === 0) {
|
||||||
|
// 没有更多历史消息
|
||||||
|
uni.$emit('no-more-history');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
that.roomMessages[roomId] = [...that.checkMessage(res.data.result.list), ...that.roomMessages[roomId]];
|
||||||
|
that.lastMessageId = res.data.result.last_message_id;
|
||||||
|
|
||||||
|
uni.$emit('load-room-message');
|
||||||
|
return res.data.result.list
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 处理收到的消息
|
// 处理收到的消息
|
||||||
@@ -110,15 +231,14 @@ const ChatManager = {
|
|||||||
const currentRoomId = this.getCurrentRoomId();
|
const currentRoomId = this.getCurrentRoomId();
|
||||||
|
|
||||||
// 添加消息到房间
|
// 添加消息到房间
|
||||||
this.addMessageToRoom(roomId, message);
|
this.addMessageToRoom(roomId, this.checkMessage(message, 1));
|
||||||
|
|
||||||
// 如果当前在消息所属的房间,直接显示
|
// 如果当前在消息所属的房间,直接显示
|
||||||
if (currentRoomId === roomId) {
|
if (currentRoomId === roomId) {
|
||||||
// 通知聊天页面显示消息
|
// 通知聊天页面显示消息
|
||||||
uni.$emit('new-room-message', message);
|
uni.$emit('new-room-message', this.checkMessage(message, 1));
|
||||||
} else {
|
} else {
|
||||||
// 不在当前房间,缓存消息并增加未读消息数
|
// 不在当前房间,缓存消息并增加未读消息数
|
||||||
this.cacheMessage(roomId, message);
|
|
||||||
this.increaseUnreadCount(roomId);
|
this.increaseUnreadCount(roomId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
@scrolltoupper="loadHistory"
|
@scrolltoupper="loadHistory"
|
||||||
>
|
>
|
||||||
<view class="message-list">
|
<view class="message-list">
|
||||||
|
<view v-if="isEmpty" class="empty-state">
|
||||||
|
没有更多消息了~
|
||||||
|
</view>
|
||||||
<view v-for="(msg, index) in messages" :key="index" class="message-item">
|
<view v-for="(msg, index) in messages" :key="index" class="message-item">
|
||||||
<!-- 对方消息 -->
|
<!-- 对方消息 -->
|
||||||
<view v-if="msg.sender !== currentUserId" class="other-message">
|
<view v-if="msg.sender !== currentUserId" class="other-message">
|
||||||
@@ -218,7 +221,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { webSocketManager } from '@/utils/ws/websocket';
|
import { webSocketManager } from '@/utils/ws/websocket';
|
||||||
import { ChatManager } from '@/store/chat/chat.js';
|
import { ChatManager } from '@/store/chat/chat.js';
|
||||||
import {sendToUserApi} from "@/request/api/im";
|
import {sendToUserApi, upLoadChatFileApi} from "@/request/api/im";
|
||||||
import AudioPlayer from './components/AudioPlayer.vue';
|
import AudioPlayer from './components/AudioPlayer.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -248,10 +251,13 @@ export default {
|
|||||||
showRecordingModal: false,
|
showRecordingModal: false,
|
||||||
currentPlayingAudio: null,
|
currentPlayingAudio: null,
|
||||||
scrollTop: 0,
|
scrollTop: 0,
|
||||||
|
scrollViewHeight: 0,
|
||||||
|
oldScrollViewHeight: 0,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
hasMore: true,
|
hasMore: true,
|
||||||
loading: false, // 新增加载状态
|
loading: false, // 新增加载状态
|
||||||
|
isEmpty: false, // 历史消息是否为空
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad: function (option) {
|
onLoad: function (option) {
|
||||||
@@ -272,22 +278,14 @@ export default {
|
|||||||
|
|
||||||
// 从ChatManager获取房间消息
|
// 从ChatManager获取房间消息
|
||||||
this.messages = ChatManager.getRoomMessages(option.room_id);
|
this.messages = ChatManager.getRoomMessages(option.room_id);
|
||||||
|
|
||||||
// 如果没有消息,添加示例消息
|
|
||||||
if (this.messages.length === 0) {
|
|
||||||
this.addExampleMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: `与${this.doctorUserInfo.nick_name}医生的对话`,
|
title: `与${this.doctorUserInfo.nick_name}医生的对话`,
|
||||||
success: () => {
|
success: () => {
|
||||||
console.log('修改标题成功');
|
console.log('修改标题成功');
|
||||||
},
|
},
|
||||||
fail: () => {
|
fail: () => {
|
||||||
console.log('修改标题失败');
|
|
||||||
},
|
},
|
||||||
complete: () => {
|
complete: () => {
|
||||||
console.log('修改标题结束');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -307,10 +305,14 @@ export default {
|
|||||||
onShow() {
|
onShow() {
|
||||||
// 监听当前房间的新消息事件
|
// 监听当前房间的新消息事件
|
||||||
uni.$on('new-room-message', this.handleNewRoomMessage);
|
uni.$on('new-room-message', this.handleNewRoomMessage);
|
||||||
|
uni.$on('load-room-message', this.handLoadMessageList);
|
||||||
|
uni.$on('no-more-history', this.handNoMessageList);
|
||||||
},
|
},
|
||||||
onHide() {
|
onHide() {
|
||||||
// 移除消息监听
|
// 移除消息监听
|
||||||
uni.$off('new-room-message', this.handleNewRoomMessage);
|
uni.$off('new-room-message', this.handleNewRoomMessage);
|
||||||
|
uni.$off('load-room-message', this.handLoadMessageList);
|
||||||
|
uni.$off('no-more-history', this.handNoMessageList);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// 初始化录音管理器
|
// 初始化录音管理器
|
||||||
@@ -327,73 +329,32 @@ export default {
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 添加示例消息
|
// 添加示例消息
|
||||||
addExampleMessages() {
|
handNoMessageList() {
|
||||||
const exampleMessages = [
|
// 提示没有更多消息了
|
||||||
{
|
this.isEmpty = true;
|
||||||
id: '1',
|
this.hasMore = false;
|
||||||
sender: 'doctor-1',
|
},
|
||||||
type: 'text',
|
// 加载历史消息
|
||||||
content: '您好,请问有什么可以帮您的?',
|
handLoadMessageList(type = 0) {
|
||||||
time: '09:30',
|
this.loading = false;
|
||||||
timestamp: Date.now() - 3600000
|
this.messages = ChatManager.roomMessages[this.doctorUserInfo.room_id]
|
||||||
},
|
if (type === 1) {
|
||||||
{
|
this.scrollToBottom();
|
||||||
id: '2',
|
} else {
|
||||||
sender: 'user-252',
|
this.scrollToOldLastMessage();
|
||||||
type: 'text',
|
}
|
||||||
content: '我这两天有点发烧,还有咳嗽。',
|
},
|
||||||
time: '09:31',
|
|
||||||
timestamp: Date.now() - 3540000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
sender: 'doctor-1',
|
|
||||||
type: 'text',
|
|
||||||
content: '您有测量体温吗?最近有没有接触过感冒的人?',
|
|
||||||
time: '09:32',
|
|
||||||
timestamp: Date.now() - 3480000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
sender: 'user-252',
|
|
||||||
type: 'image',
|
|
||||||
content: 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg',
|
|
||||||
time: '09:33',
|
|
||||||
timestamp: Date.now() - 3420000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '5',
|
|
||||||
sender: 'doctor-1',
|
|
||||||
type: 'video',
|
|
||||||
content: 'https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4',
|
|
||||||
time: '09:35',
|
|
||||||
timestamp: Date.now() - 3300000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '6',
|
|
||||||
sender: 'user-252',
|
|
||||||
type: 'audio',
|
|
||||||
content: 'https://er-sycdn.kuwo.cn/f7c3be4ff67cc7b135e38e8365479e06/687d941e/resource/30106/trackmedia/M800004emQMs09Z1lz.mp3',
|
|
||||||
duration: 15,
|
|
||||||
time: '09:36',
|
|
||||||
timestamp: Date.now() - 3240000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '7',
|
|
||||||
sender: 'doctor-1',
|
|
||||||
type: 'audio',
|
|
||||||
content: 'https://er-sycdn.kuwo.cn/f7c3be4ff67cc7b135e38e8365479e06/687d941e/resource/30106/trackmedia/M800004emQMs09Z1lz.mp3',
|
|
||||||
duration: 8,
|
|
||||||
time: '09:37',
|
|
||||||
timestamp: Date.now() - 3180000
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 添加到ChatManager和本地消息列表
|
getScrollHeight() {
|
||||||
exampleMessages.forEach(msg => {
|
|
||||||
ChatManager.addMessageToRoom(this.doctorUserInfo.room_id, msg);
|
const query = uni.createSelectorQuery().in(this)
|
||||||
});
|
// query.select('.chat-messages').boundingClientRect(res => {
|
||||||
this.messages = [...exampleMessages];
|
query.select('.message-list').boundingClientRect(res => {
|
||||||
|
if (res) {
|
||||||
|
this.oldScrollViewHeight = this.scrollViewHeight
|
||||||
|
this.scrollViewHeight = res.height
|
||||||
|
}
|
||||||
|
}).exec()
|
||||||
},
|
},
|
||||||
|
|
||||||
// 处理WebSocket消息
|
// 处理WebSocket消息
|
||||||
@@ -404,77 +365,22 @@ export default {
|
|||||||
|
|
||||||
// 处理当前房间的新消息事件
|
// 处理当前房间的新消息事件
|
||||||
handleNewRoomMessage(message) {
|
handleNewRoomMessage(message) {
|
||||||
// 处理不同类型的消息
|
|
||||||
const msgType = this.getMessageType(message.message_type);
|
|
||||||
const newMsg = {
|
|
||||||
id: message.id,
|
|
||||||
sender: message.sender_user_id,
|
|
||||||
type: msgType,
|
|
||||||
content: message.content,
|
|
||||||
time: this.formatTime(message.send_time),
|
|
||||||
timestamp: message.send_time
|
|
||||||
};
|
|
||||||
|
|
||||||
// 对于音频和视频消息,可能有额外字段
|
|
||||||
if (msgType === 'audio' || msgType === 'video') {
|
|
||||||
newMsg.duration = message.duration || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加到消息列表
|
// 添加到消息列表
|
||||||
this.addMessage(newMsg);
|
console.log('handle', message)
|
||||||
},
|
this.addMessage(message);
|
||||||
|
this.scrollToBottom();
|
||||||
// 根据消息类型ID获取类型名称
|
|
||||||
getMessageType(typeId) {
|
|
||||||
const types = {
|
|
||||||
0: 'text',
|
|
||||||
1: 'image',
|
|
||||||
2: 'audio',
|
|
||||||
3: 'video',
|
|
||||||
4: 'file',
|
|
||||||
5: 'prescription'
|
|
||||||
};
|
|
||||||
return types[typeId] || 'text';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 添加消息到列表
|
// 添加消息到列表
|
||||||
addMessage(message) {
|
addMessage(message) {
|
||||||
// 避免重复添加
|
// 避免重复添加
|
||||||
if (!this.messages.some(m => m.id === message.id)) {
|
if (!this.messages.some(m => m.id === message.id)) {
|
||||||
|
console.log('push', message)
|
||||||
this.messages.push(message);
|
this.messages.push(message);
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 格式化时间
|
|
||||||
formatTime(timestamp) {
|
|
||||||
let date;
|
|
||||||
|
|
||||||
// 处理不同输入类型
|
|
||||||
if (typeof timestamp === 'number') {
|
|
||||||
// 数字直接作为时间戳处理
|
|
||||||
date = new Date(timestamp);
|
|
||||||
} else if (timestamp instanceof Date) {
|
|
||||||
// Date对象直接使用
|
|
||||||
date = timestamp;
|
|
||||||
} else if (typeof timestamp === 'string') {
|
|
||||||
// 字符串类型:尝试转换为时间戳
|
|
||||||
const parsed = Date.parse(timestamp);
|
|
||||||
if (isNaN(parsed)) {
|
|
||||||
// 转换失败则使用当前时间
|
|
||||||
date = new Date();
|
|
||||||
} else {
|
|
||||||
date = new Date(parsed);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 其他类型使用当前时间
|
|
||||||
date = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 格式化时间为 HH:MM
|
|
||||||
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 切换医生详情显示
|
// 切换医生详情显示
|
||||||
toggleDoctorDetail() {
|
toggleDoctorDetail() {
|
||||||
this.showDoctorDetail = !this.showDoctorDetail;
|
this.showDoctorDetail = !this.showDoctorDetail;
|
||||||
@@ -491,11 +397,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendMessage({
|
// 上传录音文件
|
||||||
type: 'audio',
|
this.uploadAudioFile(res.tempFilePath, Math.floor(res.duration / 1000));
|
||||||
content: 'https://er-sycdn.kuwo.cn/f7c3be4ff67cc7b135e38e8365479e06/687d941e/resource/30106/trackmedia/M800004emQMs09Z1lz.mp3',
|
|
||||||
duration: Math.floor(res.duration / 1000),
|
|
||||||
});
|
|
||||||
|
|
||||||
this.recording = false;
|
this.recording = false;
|
||||||
this.showRecordingModal = false;
|
this.showRecordingModal = false;
|
||||||
@@ -511,10 +414,43 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 上传音频文件并发送
|
||||||
|
async uploadAudioFile(tempFilePath, duration) {
|
||||||
|
uni.showLoading({ title: '上传中...', mask: true });
|
||||||
|
try {
|
||||||
|
uni.uploadFile({
|
||||||
|
url: 'http://127.0.0.1:18001/api/mobile/chat-friends/upload-chat-file',
|
||||||
|
filePath: tempFilePath,
|
||||||
|
name: 'file',
|
||||||
|
header: {
|
||||||
|
"authorization": uni.getStorageSync('token')
|
||||||
|
},
|
||||||
|
formData: tempFilePath,
|
||||||
|
success: (uploadFileRes) => {
|
||||||
|
|
||||||
|
this.sendMessage({
|
||||||
|
type: 'audio',
|
||||||
|
content: JSON.parse(uploadFileRes.data).result.url,
|
||||||
|
duration,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (res) => {
|
||||||
|
console.log(res, '上传失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('音频上传失败:', error);
|
||||||
|
uni.showToast({ title: '音频上传失败', icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
sendMessage(message) {
|
sendMessage(message) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const timeStr = this.formatTime(now);
|
const timeStr = ChatManager.formatTime(now);
|
||||||
|
|
||||||
// 构建完整消息对象
|
// 构建完整消息对象
|
||||||
const fullMessage = {
|
const fullMessage = {
|
||||||
@@ -551,9 +487,8 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
sendToUserApi(requestData).then(res => {
|
sendToUserApi(requestData).then(res => {
|
||||||
console.log('发送成功:', res);
|
|
||||||
// 添加到本地消息列表
|
// 添加到本地消息列表
|
||||||
this.messages.push(fullMessage);
|
// this.messages.push(fullMessage);
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error('发送失败:', error);
|
console.error('发送失败:', error);
|
||||||
@@ -582,7 +517,6 @@ export default {
|
|||||||
this.startRecording();
|
this.startRecording();
|
||||||
},
|
},
|
||||||
fail: (e) => {
|
fail: (e) => {
|
||||||
console.log('失败', e)
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '需要录音权限',
|
title: '需要录音权限',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -649,24 +583,47 @@ export default {
|
|||||||
this.showMoreActions = false;
|
this.showMoreActions = false;
|
||||||
|
|
||||||
if (type === 'image') {
|
if (type === 'image') {
|
||||||
|
console.log(type, 'sssssssssssssssssssss')
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 9,
|
count: 9,
|
||||||
sourceType: ['album', 'camera'],
|
sourceType: ['album', 'camera'],
|
||||||
success: res => {
|
success: res => {
|
||||||
res.tempFilePaths.forEach(path => {
|
res.tempFilePaths.forEach(file => {
|
||||||
this.sendMessage({
|
uni.uploadFile({
|
||||||
type: 'image',
|
url: 'http://127.0.0.1:18001/api/mobile/chat-friends/upload-chat-file',
|
||||||
content: path
|
filePath: file,
|
||||||
});
|
name: 'file',
|
||||||
|
header: {
|
||||||
|
"authorization": uni.getStorageSync('token')
|
||||||
|
},
|
||||||
|
formData: file,
|
||||||
|
success: (uploadFileRes) => {
|
||||||
|
|
||||||
|
this.sendMessage({
|
||||||
|
type: 'image',
|
||||||
|
content: JSON.parse(uploadFileRes.data).result.url
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (res) => {
|
||||||
|
console.log(res, '上传失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// upLoadChatFileApi
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
fail: (e) => {
|
||||||
|
console.log('错误', e)
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} else if (type === 'video') {
|
} else if (type === 'video') {
|
||||||
|
console.log(type, 'sssssssssssssssssssss')
|
||||||
uni.chooseVideo({
|
uni.chooseVideo({
|
||||||
sourceType: ['album', 'camera'],
|
sourceType: ['album', 'camera'],
|
||||||
compressed: true,
|
compressed: true,
|
||||||
maxDuration: 60,
|
maxDuration: 60,
|
||||||
success: res => {
|
success: res => {
|
||||||
|
console.log('vedio path', res)
|
||||||
|
// upLoadChatFileApi
|
||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
type: 'video',
|
type: 'video',
|
||||||
content: res.tempFilePath,
|
content: res.tempFilePath,
|
||||||
@@ -754,6 +711,14 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
scrollToOldLastMessage() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.getScrollHeight()
|
||||||
|
const newHeight = this.scrollViewHeight;
|
||||||
|
this.scrollTop = newHeight - this.oldScrollViewHeight; // 计算差值保持位置
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 加载历史消息
|
// 加载历史消息
|
||||||
async loadHistory() {
|
async loadHistory() {
|
||||||
if (!this.hasMore || this.loading) return;
|
if (!this.hasMore || this.loading) return;
|
||||||
@@ -761,31 +726,7 @@ export default {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
// 模拟加载历史消息
|
// 模拟加载历史消息
|
||||||
const newMessages = await new Promise(resolve => {
|
ChatManager.loadHistory(this.doctorUserInfo.room_id)
|
||||||
setTimeout(() => {
|
|
||||||
resolve([
|
|
||||||
{
|
|
||||||
id: 'h1',
|
|
||||||
sender: 'doctor-1',
|
|
||||||
type: 'text',
|
|
||||||
content: '这是更早的消息',
|
|
||||||
time: '09:20',
|
|
||||||
timestamp: Date.now() - 7200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'h2',
|
|
||||||
sender: 'user-252',
|
|
||||||
type: 'text',
|
|
||||||
content: '是的,这是历史消息',
|
|
||||||
time: '09:21',
|
|
||||||
timestamp: Date.now() - 7140000
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.messages = [...newMessages, ...this.messages];
|
|
||||||
this.hasMore = false; // 假设没有更多历史消息
|
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
@@ -800,6 +741,14 @@ $doctor-bg: #e6f2ff;
|
|||||||
$patient-bg: #e6f9ff;
|
$patient-bg: #e6f9ff;
|
||||||
$light-bg: #f5f9ff;
|
$light-bg: #f5f9ff;
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
// 文字水平居中,灰色
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: $light-bg;
|
||||||
|
}
|
||||||
.chat-container {
|
.chat-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -81,4 +81,9 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- 即使不需要渲染内容,也需要保留一个空的 template -->
|
||||||
|
<div v-if="false"></div>
|
||||||
|
</template>
|
||||||
@@ -107,7 +107,7 @@ export class WebSocketManager {
|
|||||||
handleMessage(data) {
|
handleMessage(data) {
|
||||||
// 如果对象中有clientId则给websocket发送
|
// 如果对象中有clientId则给websocket发送
|
||||||
if (data.clientId) {
|
if (data.clientId) {
|
||||||
const userId = '252'; // 实际项目中从存储获取
|
const userId = uni.getStorageSync('user_id'); // 实际项目中从存储获取
|
||||||
const bindMessage = {
|
const bindMessage = {
|
||||||
request_type: 'bind',
|
request_type: 'bind',
|
||||||
user_type: 'user',
|
user_type: 'user',
|
||||||
|
|||||||
123
yarn.lock
123
yarn.lock
@@ -2,12 +2,135 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@babel/helper-string-parser@^7.27.1":
|
||||||
|
version "7.27.1"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz"
|
||||||
|
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier@^7.27.1":
|
||||||
|
version "7.27.1"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz"
|
||||||
|
integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
|
||||||
|
|
||||||
|
"@babel/parser@^7.23.5":
|
||||||
|
version "7.28.0"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz"
|
||||||
|
integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.28.0"
|
||||||
|
|
||||||
|
"@babel/types@^7.28.0":
|
||||||
|
version "7.28.1"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz"
|
||||||
|
integrity sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-string-parser" "^7.27.1"
|
||||||
|
"@babel/helper-validator-identifier" "^7.27.1"
|
||||||
|
|
||||||
|
"@vue/compiler-sfc@2.7.16":
|
||||||
|
version "2.7.16"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz"
|
||||||
|
integrity sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.23.5"
|
||||||
|
postcss "^8.4.14"
|
||||||
|
source-map "^0.6.1"
|
||||||
|
optionalDependencies:
|
||||||
|
prettier "^1.18.2 || ^2.0.0"
|
||||||
|
|
||||||
|
"@vue/composition-api@^1.0.0-rc.1", "@vue/composition-api@^1.4.1":
|
||||||
|
version "1.4.1"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/composition-api/-/composition-api-1.4.1.tgz"
|
||||||
|
integrity sha512-ZTat9ru/rwecveRnFzlO2mduOBpGfnBdXn+WtBcFLV9UsL/D+6nX47RWuLiVdNxNDX0qphGZRC+JDjwt+YTnRA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.3.1"
|
||||||
|
|
||||||
|
"@vue/devtools-api@^6.6.3":
|
||||||
|
version "6.6.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz"
|
||||||
|
integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
|
||||||
|
|
||||||
|
csstype@^3.1.0:
|
||||||
|
version "3.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
|
||||||
|
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
|
||||||
|
|
||||||
js-base64@^3.7.7:
|
js-base64@^3.7.7:
|
||||||
version "3.7.7"
|
version "3.7.7"
|
||||||
resolved "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz"
|
resolved "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz"
|
||||||
integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==
|
integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==
|
||||||
|
|
||||||
|
nanoid@^3.3.11:
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz"
|
||||||
|
integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
|
||||||
|
|
||||||
|
picocolors@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
|
||||||
|
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
||||||
|
|
||||||
|
pinia@^2.0.14:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz"
|
||||||
|
integrity sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==
|
||||||
|
dependencies:
|
||||||
|
"@vue/devtools-api" "^6.6.3"
|
||||||
|
vue-demi "^0.14.10"
|
||||||
|
|
||||||
|
postcss@^8.4.14:
|
||||||
|
version "8.5.6"
|
||||||
|
resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz"
|
||||||
|
integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==
|
||||||
|
dependencies:
|
||||||
|
nanoid "^3.3.11"
|
||||||
|
picocolors "^1.1.1"
|
||||||
|
source-map-js "^1.2.1"
|
||||||
|
|
||||||
|
"prettier@^1.18.2 || ^2.0.0":
|
||||||
|
version "2.8.8"
|
||||||
|
resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz"
|
||||||
|
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
|
||||||
|
|
||||||
|
source-map-js@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
|
||||||
|
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||||
|
|
||||||
|
source-map@^0.6.1:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||||
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
tslib@^2.3.1:
|
||||||
|
version "2.8.1"
|
||||||
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
||||||
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
|
|
||||||
uview-ui@^1.8.8:
|
uview-ui@^1.8.8:
|
||||||
version "1.8.8"
|
version "1.8.8"
|
||||||
resolved "https://registry.npmmirror.com/uview-ui/-/uview-ui-1.8.8.tgz"
|
resolved "https://registry.npmmirror.com/uview-ui/-/uview-ui-1.8.8.tgz"
|
||||||
integrity sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg==
|
integrity sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg==
|
||||||
|
|
||||||
|
vue-demi@^0.14.10:
|
||||||
|
version "0.14.10"
|
||||||
|
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz"
|
||||||
|
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
||||||
|
|
||||||
|
vue-demi@^0.14.5:
|
||||||
|
version "0.14.5"
|
||||||
|
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz"
|
||||||
|
integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
|
||||||
|
|
||||||
|
vue@^2.0.0, "vue@^2.7.0 || ^3.5.11", "vue@^3.0.0-0 || ^2.6.0", "vue@>= 2.5 < 3":
|
||||||
|
version "2.7.16"
|
||||||
|
resolved "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz"
|
||||||
|
integrity sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-sfc" "2.7.16"
|
||||||
|
csstype "^3.1.0"
|
||||||
|
|
||||||
|
vuex@^3.6.2:
|
||||||
|
version "3.6.2"
|
||||||
|
resolved "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz"
|
||||||
|
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==
|
||||||
|
|||||||
Reference in New Issue
Block a user