feat: 消息会话的调整和增加时间戳

This commit is contained in:
zoujing
2026-03-04 16:59:47 +08:00
parent 011c28d945
commit 3f2a4a506b
3 changed files with 82 additions and 10 deletions

View File

@@ -23,7 +23,7 @@
<ChatRoleMe v-if="msg.messageRole === MessageRole.ME" :msg="msg"> <ChatRoleMe v-if="msg.messageRole === MessageRole.ME" :msg="msg">
<template #header> <template #header>
<!-- 名字和时间 --> <!-- 名字和时间 -->
<ChatNameTime :showReverse="true" /> <ChatNameTime :showReverse="true" :msg="msg" />
</template> </template>
</ChatRoleMe> </ChatRoleMe>
@@ -31,7 +31,7 @@
<ChatRoleAI v-if="msg.messageRole === MessageRole.AI" :msg="msg"> <ChatRoleAI v-if="msg.messageRole === MessageRole.AI" :msg="msg">
<template #header> <template #header>
<!-- 名字和时间 --> <!-- 名字和时间 -->
<ChatNameTime :showReverse="false" /> <ChatNameTime :showReverse="false" :msg="msg" />
</template> </template>
<template #footer> <template #footer>
@@ -316,6 +316,7 @@ const loadConversationMessages = async (convId: string) => {
messageId: msg.messageId, messageId: msg.messageId,
messageRole: msg.messageSenderRole === 'user' ? MessageRole.ME : MessageRole.AI, messageRole: msg.messageSenderRole === 'user' ? MessageRole.ME : MessageRole.AI,
messageContent: msg.messageContent, messageContent: msg.messageContent,
timestamp: msg.timestamp,
finished: true, // 历史消息已完成 finished: true, // 历史消息已完成
})); }));
console.log("加载历史消息:", chatMsgList.value); console.log("加载历史消息:", chatMsgList.value);
@@ -348,7 +349,8 @@ const initWebSocket = async () => {
// 使用配置的WebSocket服务器地址 // 使用配置的WebSocket服务器地址
const token = getAccessToken(); const token = getAccessToken();
const wsUrl = `wss://onefeel.brother7.cn/ingress/agent/ws/chat?access_token=${token}`; // const wsUrl = `wss://onefeel.brother7.cn/ingress/agent/ws/chat?access_token=${token}`;
const wsUrl = `wss://onefeel.brother7.cn/ingress/nianxx/ws?token=${token}`;
// 初始化WebSocket管理器 // 初始化WebSocket管理器
webSocketManager = new WebSocketManager({ webSocketManager = new WebSocketManager({
wsUrl: wsUrl, wsUrl: wsUrl,
@@ -408,6 +410,17 @@ const initWebSocket = async () => {
// 处理WebSocket消息 // 处理WebSocket消息
const handleWebSocketMessage = (data: any) => { const handleWebSocketMessage = (data: any) => {
console.log("收到WebSocket消息:", data); console.log("收到WebSocket消息:", data);
if (data.type === 'notification' && data.event === 'connected') {
console.log("WebSocket连接已建立服务器消息:", data);
return;
}
if (data.type === 'heartbeat') {
console.log("收到心跳消息:", data);
return;
}
// 验证关键字段(若服务端传回 conversationId/agentId则校验是否属于当前会话 // 验证关键字段(若服务端传回 conversationId/agentId则校验是否属于当前会话
if (data.conversationId && data.conversationId !== conversationId.value) { if (data.conversationId && data.conversationId !== conversationId.value) {
console.warn("收到不属于当前会话的消息,忽略", data.conversationId); console.warn("收到不属于当前会话的消息,忽略", data.conversationId);
@@ -428,7 +441,7 @@ const handleWebSocketMessage = (data: any) => {
} }
// 优先使用 messageId 进行匹配 // 优先使用 messageId 进行匹配
const msgId = data.messageId || data.id || data.msgId; const msgId = data.messageId || data.reply_message_id || data.id || data.msgId;
let aiMsgIndex = -1; let aiMsgIndex = -1;
if (msgId && pendingMap.has(msgId)) { if (msgId && pendingMap.has(msgId)) {
aiMsgIndex = pendingMap.get(msgId); aiMsgIndex = pendingMap.get(msgId);
@@ -462,8 +475,14 @@ const handleWebSocketMessage = (data: any) => {
nextTick(() => scrollToBottom()); nextTick(() => scrollToBottom());
} }
/// 对于通知类消息,如果没有明确的完成状态,默认视为已完成,触发后续处理逻辑(例如心跳、连接建立等事件)
if (data.type === 'notification') {
data.finish = data.finish || true; // 确保 finish 字段存在
}
// 处理完成状态 // 处理完成状态
if (data.finish) { if (data.finish) {
chatMsgList.value[aiMsgIndex].timestamp = Date.now();
chatMsgList.value[aiMsgIndex].finished = data.finish; chatMsgList.value[aiMsgIndex].finished = data.finish;
const msg = chatMsgList.value[aiMsgIndex].messageContent; const msg = chatMsgList.value[aiMsgIndex].messageContent;
if (!msg || chatMsgList.value[aiMsgIndex].isLoading) { if (!msg || chatMsgList.value[aiMsgIndex].isLoading) {
@@ -554,6 +573,7 @@ const sendMessage = async (message: string, isInstruct: boolean = false) => {
messageId: IdUtils.generateMessageId(), messageId: IdUtils.generateMessageId(),
messageRole: MessageRole.ME, messageRole: MessageRole.ME,
messageContent: message, messageContent: message,
timestamp: Date.now(),
}; };
chatMsgList.value.push(newMsg); chatMsgList.value.push(newMsg);
inputMessage.value = ""; inputMessage.value = "";

View File

@@ -1,17 +1,65 @@
<template> <template>
<div class="flex items-start gap-2 pt-0.5 mb-2" :class="showReverse ? 'flex-row-reverse' : 'flex-row'"> <div class="flex items-start gap-2 pt-0.5 mb-2" :class="props.showReverse ? 'flex-row-reverse' : 'flex-row'">
<span class="text-xs text-[#4E5969]"> ZHINIAN</span> <span class="text-xs text-[#4E5969]">{{ props.msg?.messageRole === MessageRole.AI ? 'NIANXX' : '我' }}</span>
<span class="text-xs text-[#86909C]"> 20:30</span> <span class="text-xs text-[#86909C]">{{ formattedTime }}</span>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue'
import { ChatMessage, MessageRole } from '../model/ChatModel'
interface Props { interface Props {
showReverse: boolean msg?: ChatMessage
showReverse?: boolean
} }
withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
showReverse: false showReverse: false
}) })
const formattedTime = computed(() => {
const tsRaw = props.msg?.timestamp
if (tsRaw == null) return ''
let ts = Number(tsRaw)
if (isNaN(ts)) return ''
const pad = (n: number) => String(n).padStart(2, '0')
// Heuristic:
// - If ts < 1e9, treat as a duration in seconds and convert to dd-hh-mm (legacy)
// - If ts looks like an epoch (seconds or ms) format to YYYY年MM月DD日 HH:mm:ss
if (ts < 1e9) {
const totalSeconds = Math.floor(ts)
const days = Math.floor(totalSeconds / 86400)
const hours = Math.floor((totalSeconds % 86400) / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
return `${String(days).padStart(2, '0')}-${pad(hours)}-${pad(minutes)}`
}
// epoch handling: convert seconds -> ms when appropriate
if (ts < 1e12) ts = ts * 1000
const d = new Date(ts)
if (isNaN(d.getTime())) return ''
const Y = d.getFullYear()
const M = pad(d.getMonth() + 1)
const D = pad(d.getDate())
const h = pad(d.getHours())
const m = pad(d.getMinutes())
const s = pad(d.getSeconds())
// If the timestamp is the same calendar day as today, show only time HH:mm:ss
const now = new Date()
const sameDay = now.getFullYear() === d.getFullYear()
&& now.getMonth() === d.getMonth()
&& now.getDate() === d.getDate()
if (sameDay) {
return `${h}:${m}:${s}`
}
// otherwise show YYYY-MM-DD HH:mm:ss
return `${Y}-${M}-${D} ${h}:${m}:${s}`
})
</script> </script>

View File

@@ -24,6 +24,8 @@ export class ChatMessage {
toolCall?: any; toolCall?: any;
// 问题信息 // 问题信息
question?: string; question?: string;
// 时间戳
timestamp?: number;
constructor( constructor(
messageId: string, messageId: string,
@@ -32,7 +34,8 @@ export class ChatMessage {
isLoading: boolean = false, isLoading: boolean = false,
finished: boolean = false, finished: boolean = false,
toolCall?: any, toolCall?: any,
question?: any question?: any,
timestamp?: number
) { ) {
this.messageId = messageId; this.messageId = messageId;
this.messageRole = messageRole; this.messageRole = messageRole;
@@ -41,5 +44,6 @@ export class ChatMessage {
this.finished = finished; this.finished = finished;
this.toolCall = toolCall; this.toolCall = toolCall;
this.question = question; this.question = question;
this.timestamp = timestamp || Date.now();
} }
} }