Files
xk-client-wx/store/chat/chat.js
2026-02-02 16:10:46 +08:00

350 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {getChatRegisterInfoApi, getMessagesByRoomIdApi} from "@/request/api/im";
/**
* 聊天消息管理器
* @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 = {
// 当前房间ID
currentRoomId: null,
lastMessageId: 0,
// 存储未读消息数 { roomId: count }
unreadCounts: {},
// 消息缓存 { roomId: [message1, message2, ...] }
messageCache: {},
// 房间消息存储 { roomId: [message1, message2, ...] }
roomMessages: {},
// 进入聊天室
enterRoom(roomId) {
this.currentRoomId = roomId;
uni.setStorageSync('currentRoomId', roomId);
// 重置当前房间的未读消息
this.resetUnreadCount(roomId);
},
// 离开聊天室
leaveRoom() {
this.currentRoomId = null;
uni.removeStorageSync('currentRoomId');
},
// 获取当前房间ID
getCurrentRoomId() {
return this.currentRoomId || uni.getStorageSync('currentRoomId');
},
// 增加未读消息数
increaseUnreadCount(roomId) {
// 如果当前不在该房间,才增加未读计数
if (this.getCurrentRoomId() !== roomId) {
this.unreadCounts[roomId] = (this.unreadCounts[roomId] || 0) + 1;
this.notifyUnreadChange();
}
},
// 重置未读消息数
resetUnreadCount(roomId) {
if (this.unreadCounts[roomId]) {
this.unreadCounts[roomId] = 0;
this.notifyUnreadChange();
}
},
// 获取未读消息数
getUnreadCount(roomId) {
return this.unreadCounts[roomId] || 0;
},
// 获取所有未读消息数
getAllUnreadCount() {
return Object.values(this.unreadCounts).reduce((sum, count) => sum + count, 0);
},
// 通知未读消息变化
notifyUnreadChange() {
uni.$emit('unread-message-update', {
total: this.getAllUnreadCount(),
byRoom: {...this.unreadCounts}
});
},
// 添加消息到房间
addMessageToRoom(roomId, message) {
if (!this.roomMessages[roomId]) {
this.roomMessages[roomId] = [];
}
this.roomMessages[roomId].push(message);
},
// 获取房间消息
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;
uni.$emit('load-room-message', 1);
return this.roomMessages[roomId] || [];
})
return this.roomMessages[roomId] || [];
},
checkMessage(message, type = 0) {
if (type === 1) {
// 直接返回数据库字段,不进行转换
return {
id: message.id,
sender_user_id: message.sender_user_id,
receiver_user_id: message.receiver_user_id,
message_type: message.message_type,
message_content: message.message_content,
duration: message.duration,
room_id: message.room_id,
created_at: message.created_at || message.send_time,
created_at_text: message.created_at_text || this.formatTime(message.send_time || message.created_at),
timestamp: message.send_time || message.created_at
};
}
return message.map((item, index) => {
// 直接返回数据库字段,不进行转换
const result = {
id: item.id,
sender_user_id: item.sender_user_id,
receiver_user_id: item.receiver_user_id,
message_type: item.message_type,
message_content: item.message_content,
duration: item.duration,
room_id: item.room_id,
created_at: item.created_at || item.send_time,
created_at_text: item.created_at_text || this.formatTime(item.send_time || item.created_at),
timestamp: item.send_time || item.created_at
};
// 对于挂号消息,仍然需要异步获取详细信息
if (item.message_type === 10) {
this.getChatRegisterInfo(result, index)
}
return result;
});
},
// 根据消息类型ID获取类型名称辅助函数不转换字段名
getMessageTypeName(typeId) {
const types = {
0: 'text',
1: 'image',
2: 'audio',
3: 'video',
4: 'prescription',
5: 'file',
6: 'video-call',
7: 'audio-call',
8: 'file',
9: 'system',
10: 'register',
11: 'patient-experience',
12: 'product-card',
13: 'end-consultation',
};
return types[typeId] || 'unknown';
},
// 按需解析消息内容(辅助函数)
getParsedContent(messageType, messageContent) {
// 对于需要 JSON 解析的消息类型4, 10, 11, 12, 13
if ([4, 10, 11, 12, 13].includes(messageType)) {
try {
return JSON.parse(messageContent);
} catch (e) {
console.error('解析消息内容失败:', e);
return messageContent;
}
}
return messageContent;
},
/**
* 获取挂号信息卡片
* @param item
* @param index
* @returns {*}
*/
getChatRegisterInfo(item, index) {
let that = this;
getChatRegisterInfoApi({
id: item.id
}).then((res) => {
that.roomMessages[that.currentRoomId][index].content = res.data.result;
})
},
// 格式化时间
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
})
},
// 处理收到的消息
handleIncomingMessage(message) {
const roomId = message.room_id;
const currentRoomId = this.getCurrentRoomId();
// 添加消息到房间
this.addMessageToRoom(roomId, this.checkMessage(message, 1));
// 如果当前在消息所属的房间,直接显示
if (currentRoomId === roomId) {
// 通知聊天页面显示消息
uni.$emit('new-room-message', this.checkMessage(message, 1));
} else {
// 不在当前房间,缓存消息并增加未读消息数
this.increaseUnreadCount(roomId);
// 触发顶部通知(传递原始消息,由 App.vue 处理通知显示)
uni.$emit('show-global-notification', message);
}
// 通知聊天列表页刷新
uni.$emit('chat-list-update');
},
/**
* 获取消息预览文本
* @param {Object} message 消息对象
* @returns {string} 预览文本
*/
getMessagePreview(message) {
const messageType = message.message_type;
const content = message.message_content;
switch (messageType) {
case 0: // 文本
return content;
case 1: // 图片
return '[图片]';
case 2: // 音频
return '[语音消息]';
case 3: // 视频
return '[视频]';
case 4: // 处方
return '[处方单]';
case 5: // 文件
return '[文件]';
case 6: // 视频通话
return '[视频通话]';
case 7: // 音频通话
return '[语音通话]';
case 9: // 系统消息
try {
const parsed = JSON.parse(content);
if (parsed.type === 'price_update') {
return parsed.message || '[价格更新]';
}
if (parsed.type === 'price_adjust') {
return parsed.message || '[价格调整]';
}
return '[系统消息]';
} catch (e) {
return '[系统消息]';
}
case 10: // 挂号
return '[挂号信息]';
case 11: // 患者就诊经历
return '[就诊信息]';
case 12: // 产品卡片
return '[商品推荐]';
case 13: // 结束问诊
return '[问诊已结束]';
default:
return '您有一条新消息';
}
}
};
export { ChatManager };