This commit is contained in:
2026-04-20 13:01:00 -04:00
parent bdad27d6ac
commit 505c7e612c
10 changed files with 307 additions and 205 deletions

View File

@@ -13,6 +13,8 @@ import {
TONE_REGISTER_OPTIONS,
type Participant
} from '../stores/settings';
import { useConversationStore } from '../stores/conversation';
import { useLogsStore } from '../stores/logs';
import { cn } from '../lib/utils';
import { listen } from '@tauri-apps/api/event';
import { useClipboard } from '../composables/useClipboard';
@@ -26,6 +28,8 @@ import {
} from '../lib/translation-service';
const settings = useSettingsStore();
const conversationStore = useConversationStore();
const logsStore = useLogsStore();
const { activeCopyId, copyWithFeedback } = useClipboard();
// UI States
@@ -72,7 +76,7 @@ const closeAllModalDropdowns = () => {
// Current active session
const activeSession = computed(() =>
settings.chatSessions.find(s => s.id === settings.activeSessionId) || null
conversationStore.chatSessions.find(s => s.id === conversationStore.activeSessionId) || null
);
const scrollToBottom = async (smooth = true) => {
@@ -86,7 +90,7 @@ const scrollToBottom = async (smooth = true) => {
};
// Watch for session switch
watch(() => settings.activeSessionId, async (newVal) => {
watch(() => conversationStore.activeSessionId, async (newVal) => {
if (newVal) {
// 切换会话时,先立即滚动到底部(非平滑),然后再等 DOM 渲染完成后尝试平滑滚动确保到位
await scrollToBottom(false);
@@ -95,9 +99,9 @@ watch(() => settings.activeSessionId, async (newVal) => {
});
const filteredSessions = computed(() => {
if (!searchQuery.value.trim()) return settings.chatSessions;
if (!searchQuery.value.trim()) return conversationStore.chatSessions;
const q = searchQuery.value.toLowerCase();
return settings.chatSessions.filter(s =>
return conversationStore.chatSessions.filter(s =>
s.title.toLowerCase().includes(q) ||
s.partner.name.toLowerCase().includes(q)
);
@@ -116,9 +120,9 @@ const myToneDropdownOpen = ref(false);
// Methods
const handleCreateSession = () => {
if (!newSessionPartner.value.name.trim()) return;
const id = settings.createSession({ ...newSessionMe.value }, { ...newSessionPartner.value });
const id = conversationStore.createSession({ ...newSessionMe.value }, { ...newSessionPartner.value });
isCreatingSession.value = false;
settings.activeSessionId = id;
conversationStore.activeSessionId = id;
};
let unlisten: (() => void) | null = null;
@@ -129,7 +133,7 @@ onMounted(async () => {
currentStreamingMessageId.value &&
event.payload.request_id === activeStreamRequestId.value
) {
settings.updateChatMessage(activeSession.value.id, currentStreamingMessageId.value, {
conversationStore.updateChatMessage(activeSession.value.id, currentStreamingMessageId.value, {
translated: (activeSession.value.messages.find(m => m.id === currentStreamingMessageId.value)?.translated || '') + event.payload.chunk
});
@@ -154,12 +158,12 @@ const translateMessage = async (sender: 'me' | 'partner', retranslateId?: string
if (!msg) return;
text = msg.original;
messageId = retranslateId;
settings.updateChatMessage(activeSession.value.id, messageId, { translated: '', evaluation: undefined });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { translated: '', evaluation: undefined });
} else {
text = sender === 'me' ? myInput.value.trim() : partnerInput.value.trim();
if (!text) return;
const newId = settings.addMessageToSession(activeSession.value.id, sender, text, '');
const newId = conversationStore.addMessageToSession(activeSession.value.id, sender, text, '');
if (!newId) return;
messageId = newId;
if (sender === 'me') myInput.value = ''; else partnerInput.value = '';
@@ -219,7 +223,7 @@ const translateMessage = async (sender: 'me' | 'partner', retranslateId?: string
apiAddress: settings.apiBaseUrl,
apiKey: settings.apiKey,
payload: requestBody,
logger: settings,
logger: logsStore,
logType: retranslateId ? 'conversation-retranslate' : 'conversation',
onStreamStart: (requestId) => {
activeStreamRequestId.value = requestId;
@@ -227,10 +231,10 @@ const translateMessage = async (sender: 'me' | 'partner', retranslateId?: string
});
if (!settings.enableStreaming) {
settings.updateChatMessage(activeSession.value.id, messageId, { translated: extractAssistantContent(response) });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { translated: extractAssistantContent(response) });
}
} catch (err: any) {
settings.updateChatMessage(activeSession.value.id, messageId, { translated: `Error: ${String(err)}` });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { translated: `Error: ${String(err)}` });
} finally {
isTranslating.value = false;
currentStreamingMessageId.value = null;
@@ -245,7 +249,7 @@ const translateMessage = async (sender: 'me' | 'partner', retranslateId?: string
const deleteMessage = (messageId: string) => {
if (!activeSession.value) return;
settings.deleteChatMessage(activeSession.value.id, messageId);
conversationStore.deleteChatMessage(activeSession.value.id, messageId);
};
const evaluateMessage = async (messageId: string, force = false) => {
@@ -261,7 +265,7 @@ const evaluateMessage = async (messageId: string, force = false) => {
if (!force && (msg.evaluation || msg.isEvaluating)) return;
settings.updateChatMessage(activeSession.value.id, messageId, { isEvaluating: true, evaluation: undefined });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { isEvaluating: true, evaluation: undefined });
const historyLimit = 10;
const recentMessages = activeSession.value.messages.filter(m => m.id !== messageId).slice(-historyLimit);
@@ -318,13 +322,13 @@ const evaluateMessage = async (messageId: string, force = false) => {
apiAddress: modelConfig.apiBaseUrl,
apiKey: modelConfig.apiKey,
payload: requestBody,
logger: settings,
logger: logsStore,
logType: 'conversation-eval',
});
settings.updateChatMessage(activeSession.value.id, messageId, { evaluation: extractAssistantContent(response) });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { evaluation: extractAssistantContent(response) });
} catch {
} finally {
settings.updateChatMessage(activeSession.value.id, messageId, { isEvaluating: false });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { isEvaluating: false });
}
};
@@ -350,7 +354,7 @@ const refineMessage = async (messageId: string) => {
const currentTranslation = msg.translated;
isAuditModalOpen.value = false; // 关闭弹窗开始润色
settings.updateChatMessage(activeSession.value.id, messageId, { isRefining: true, translated: '' });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { isRefining: true, translated: '' });
currentStreamingMessageId.value = messageId;
const historyLimit = 10;
@@ -407,7 +411,7 @@ const refineMessage = async (messageId: string) => {
apiAddress: modelConfig.apiBaseUrl,
apiKey: modelConfig.apiKey,
payload: requestBody,
logger: settings,
logger: logsStore,
logType: 'conversation-refine',
onStreamStart: (requestId) => {
activeStreamRequestId.value = requestId;
@@ -415,11 +419,11 @@ const refineMessage = async (messageId: string) => {
});
if (!settings.enableStreaming) {
settings.updateChatMessage(activeSession.value.id, messageId, { translated: extractAssistantContent(response) });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { translated: extractAssistantContent(response) });
}
} catch {
} finally {
settings.updateChatMessage(activeSession.value.id, messageId, { isRefining: false, evaluation: undefined });
conversationStore.updateChatMessage(activeSession.value.id, messageId, { isRefining: false, evaluation: undefined });
currentStreamingMessageId.value = null;
activeStreamRequestId.value = null;
@@ -477,10 +481,10 @@ onUnmounted(() => window.removeEventListener('click', handleGlobalClick));
<div
v-for="session in filteredSessions"
:key="session.id"
@click="settings.activeSessionId = session.id"
@click="conversationStore.activeSessionId = session.id"
:class="cn(
'w-full p-4 rounded-xl text-left transition-all border group relative cursor-pointer',
settings.activeSessionId === session.id
conversationStore.activeSessionId === session.id
? 'bg-blue-50 dark:bg-blue-900/20 border-blue-100 dark:border-blue-900/50 shadow-sm'
: 'hover:bg-slate-100 dark:hover:bg-slate-800/50 border-transparent'
)"
@@ -499,7 +503,7 @@ onUnmounted(() => window.removeEventListener('click', handleGlobalClick));
</p>
<button
@click.stop="settings.deleteSession(session.id)"
@click.stop="conversationStore.deleteSession(session.id)"
class="absolute right-2 bottom-2 p-1.5 rounded-md text-red-400 opacity-0 group-hover:opacity-100 hover:bg-red-50 dark:hover:bg-red-900/30 transition-all"
title="删除会话"
>