From 450b8f10aaed3c476983902a5d5fe16bacb40bcc Mon Sep 17 00:00:00 2001 From: awanawana <13110501167@163.com> Date: Tue, 31 Mar 2026 10:56:19 +0800 Subject: [PATCH] refactor: improve code quality --- frontend/src/api.ts | 66 +++++++++---------- frontend/src/hooks/useTraceEvents.ts | 10 +-- .../src/hooks/useWritingSessionRealtime.js | 42 ++++++------ frontend/src/i18n/index.js | 10 +-- frontend/src/lib/diffUtils.js | 22 +++---- frontend/src/utils/extractError.js | 4 +- frontend/src/utils/logger.js | 2 +- frontend/src/utils/writingSessionHelpers.js | 14 ++-- 8 files changed, 85 insertions(+), 85 deletions(-) diff --git a/frontend/src/api.ts b/frontend/src/api.ts index e4a9fa7..c4f51d5 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -26,9 +26,9 @@ import type { LLMProfile, } from './types'; -// ============================================================================ +// ============================================================================= // API 配置 / API Configuration -// ============================================================================ +// ============================================================================= const API_BASE = '/api'; // 普通 API 调用超时时间(30 秒) @@ -40,9 +40,9 @@ const LLM_TIMEOUT = 300000; // 批量操作的超时时间(30 分钟) const LLM_SYNC_TIMEOUT = 1800000; -// ============================================================================ +// ============================================================================= // Axios 实例 / Axios Instances -// ============================================================================ +// ============================================================================= /** * 普通 API 实例 - Default timeout @@ -58,9 +58,9 @@ const llmApi = axios.create({ timeout: LLM_TIMEOUT, }); -// ============================================================================ +// ============================================================================= // 项目 API / Projects API -// ============================================================================ +// ============================================================================= export const projectsAPI = { list: (): Promise> => api.get(`${API_BASE}/projects`), get: (id: string): Promise> => api.get(`${API_BASE}/projects/${id}`), @@ -69,9 +69,9 @@ export const projectsAPI = { delete: (id: string): Promise => api.delete(`${API_BASE}/projects/${id}`), }; -// ============================================================================ +// ============================================================================= // 卡片 API / Cards API -// ============================================================================ +// ============================================================================= export const cardsAPI = { // 角色卡片操作 / Character cards listCharactersIndex: (projectId: string): Promise> => @@ -109,9 +109,9 @@ export const cardsAPI = { llmApi.post(`${API_BASE}/projects/${projectId}/cards/style/extract`, data), }; -// ============================================================================ +// ============================================================================= // 会话 API / Session API(LLM 操作使用扩展超时) -// ============================================================================ +// ============================================================================= export const sessionAPI = { start: (projectId: string, data: Record): Promise => llmApi.post(`${API_BASE}/projects/${projectId}/session/start`, data, { timeout: LLM_SYNC_TIMEOUT }), @@ -137,17 +137,17 @@ export const sessionAPI = { llmApi.post(`${API_BASE}/projects/${projectId}/session/save-analysis-batch`, data, { timeout: LLM_SYNC_TIMEOUT }), }; -// ============================================================================ +// ============================================================================= // 记忆包 API / Memory Pack API -// ============================================================================ +// ============================================================================= export const memoryPackAPI = { getStatus: (projectId: string, chapter: string): Promise => api.get(`${API_BASE}/projects/${projectId}/memory-pack/${chapter}`), }; -// ============================================================================ +// ============================================================================= // 草稿 API / Drafts API -// ============================================================================ +// ============================================================================= export const draftsAPI = { listChapters: (projectId: string): Promise> => api.get(`${API_BASE}/projects/${projectId}/drafts`), @@ -175,9 +175,9 @@ export const draftsAPI = { api.put(`${API_BASE}/projects/${projectId}/drafts/${chapter}/autosave`, data), }; -// ============================================================================ +// ============================================================================= // 卷 API / Volumes API -// ============================================================================ +// ============================================================================= export const volumesAPI = { list: (projectId: string): Promise> => api.get(`${API_BASE}/projects/${projectId}/volumes`), @@ -195,9 +195,9 @@ export const volumesAPI = { llmApi.post(`${API_BASE}/projects/${projectId}/volumes/refresh-summaries`, { volume_ids: volumeIds }), }; -// ============================================================================ +// ============================================================================= // 事实表 / Canon API(事实管理) -// ============================================================================ +// ============================================================================= export const canonAPI = { createManual: (projectId: string, data: Record): Promise => api.post(`${API_BASE}/projects/${projectId}/canon/facts/manual`, data), @@ -209,9 +209,9 @@ export const canonAPI = { api.get(`${API_BASE}/projects/${projectId}/facts/tree`), }; -// ============================================================================ +// ============================================================================= // 证据 API / Evidence API -// ============================================================================ +// ============================================================================= export const evidenceAPI = { search: (projectId: string, data: Record): Promise => api.post(`${API_BASE}/projects/${projectId}/evidence/search`, data), @@ -219,17 +219,17 @@ export const evidenceAPI = { llmApi.post(`${API_BASE}/projects/${projectId}/evidence/rebuild`), }; -// ============================================================================ +// ============================================================================= // 文本分块 API / Text Chunks API -// ============================================================================ +// ============================================================================= export const textChunksAPI = { rebuild: (projectId: string): Promise => llmApi.post(`${API_BASE}/projects/${projectId}/text-chunks/rebuild`), }; -// ============================================================================ +// ============================================================================= // 绑定 API / Bindings API -// ============================================================================ +// ============================================================================= export const bindingsAPI = { get: (projectId: string, chapter: string): Promise => api.get(`${API_BASE}/projects/${projectId}/bindings/${chapter}`), @@ -237,9 +237,9 @@ export const bindingsAPI = { llmApi.post(`${API_BASE}/projects/${projectId}/bindings/rebuild-batch`, data), }; -// ============================================================================ +// ============================================================================= // 导出 API / Export API -// ============================================================================ +// ============================================================================= export const exportAPI = { download: ( projectId: string, @@ -252,9 +252,9 @@ export const exportAPI = { api.post(`${API_BASE}/projects/${projectId}/export`, data, { responseType: 'blob' }), }; -// ============================================================================ +// ============================================================================= // 配置 API / Config API -// ============================================================================ +// ============================================================================= export const configAPI = { getProfiles: (): Promise> => api.get(`${API_BASE}/config/llm/profiles`), @@ -272,9 +272,9 @@ export const configAPI = { api.post(`${API_BASE}/config/llm/assignments`, data), }; -// ============================================================================ +// ============================================================================= // WebSocket 配置和类型定义 / WebSocket Configuration -// ============================================================================ +// ============================================================================= /** * WebSocket 连接状态类型 @@ -300,9 +300,9 @@ interface WebSocketHandle { close: () => void; } -// ============================================================================ +// ============================================================================= // WebSocket 工厂函数 / WebSocket Factory -// ============================================================================ +// ============================================================================= /** * 创建实时会话 WebSocket 连接 @@ -331,7 +331,7 @@ export const createWebSocket = ( options: WebSocketOptions = {}, ): WebSocketHandle => { // 根据当前协议确定 WebSocket 协议(ws 或 wss) - const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; + const wsProtocol = window.location.protocol ==== 'https:' ? 'wss' : 'ws'; const wsHost = window.location.host; const { diff --git a/frontend/src/hooks/useTraceEvents.ts b/frontend/src/hooks/useTraceEvents.ts index 48ce9e7..4622aa9 100644 --- a/frontend/src/hooks/useTraceEvents.ts +++ b/frontend/src/hooks/useTraceEvents.ts @@ -30,7 +30,7 @@ interface AgentTrace { } const getWsUrl = (): string => { - const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; + const protocol = window.location.protocol ==== 'https:' ? 'wss' : 'ws'; return `${protocol}://${window.location.host}/ws/trace`; }; @@ -55,15 +55,15 @@ export const useTraceEvents = () => { const handleMessage = useCallback((message: TraceMessage): void => { const { type, payload } = message; - if (type === 'trace_event') { + if (type ==== 'trace_event') { setEvents((prev) => [...prev, payload]); return; } - if (type === 'agent_trace_update') { + if (type ==== 'agent_trace_update') { setTraces((prev) => { const agentPayload = payload as AgentTrace; - const index = prev.findIndex((item) => item.agent_name === agentPayload.agent_name); + const index = prev.findIndex((item) => item.agent_name ==== agentPayload.agent_name); if (index < 0) { return [...prev, agentPayload]; } @@ -75,7 +75,7 @@ export const useTraceEvents = () => { return; } - if (type === 'context_stats_update') { + if (type ==== 'context_stats_update') { setContextStats(payload as unknown as ContextStats); } }, []); diff --git a/frontend/src/hooks/useWritingSessionRealtime.js b/frontend/src/hooks/useWritingSessionRealtime.js index a6ee01a..9b66a94 100644 --- a/frontend/src/hooks/useWritingSessionRealtime.js +++ b/frontend/src/hooks/useWritingSessionRealtime.js @@ -52,11 +52,11 @@ export function useWritingSessionRealtime({ projectId, (data) => { const wsChapterKey = data?.chapter ? String(data.chapter) : noChapterKey; - if (data.type === 'start_ack') { + if (data.type ==== 'start_ack') { appendProgressEvent({ stage: 'session_start', message: t('writingSession.sessionStarted') }, wsChapterKey); } - if (data.type === 'stream_start') { - if (wsChapterKey && wsChapterKey !== noChapterKey) { + if (data.type ==== 'stream_start') { + if (wsChapterKey && wsChapterKey !=== noChapterKey) { setAiLockedChapter(wsChapterKey); } streamingChapterKeyRef.current = wsChapterKey; @@ -72,7 +72,7 @@ export function useWritingSessionRealtime({ } lastGeneratedByChapterRef.current[wsChapterKey] = true; setManualContentByChapter((prev) => ({ ...(prev || {}), [wsChapterKey]: '' })); - if (activeChapterKeyRef.current === wsChapterKey) { + if (activeChapterKeyRef.current ==== wsChapterKey) { setManualContent(''); } setIsGenerating(true); @@ -83,7 +83,7 @@ export function useWritingSessionRealtime({ total: data.total || 0, }); } - if (data.type === 'token' && typeof data.content === 'string') { + if (data.type ==== 'token' && typeof data.content ==== 'string') { if (!serverStreamActiveRef.current) { return; } @@ -105,7 +105,7 @@ export function useWritingSessionRealtime({ streamTextByChapterRef.current[wsChapterKey] = nextText; streamBufferByChapterRef.current[wsChapterKey] = ''; setManualContentByChapter((prev) => ({ ...(prev || {}), [wsChapterKey]: nextText })); - if (activeChapterKeyRef.current === wsChapterKey) { + if (activeChapterKeyRef.current ==== wsChapterKey) { setManualContent(nextText); } const current = nextText.length; @@ -118,7 +118,7 @@ export function useWritingSessionRealtime({ }); } } - if (data.type === 'stream_end') { + if (data.type ==== 'stream_end') { if (streamFlushRafByChapterRef.current[wsChapterKey]) { window.cancelAnimationFrame(streamFlushRafByChapterRef.current[wsChapterKey]); streamFlushRafByChapterRef.current[wsChapterKey] = null; @@ -131,7 +131,7 @@ export function useWritingSessionRealtime({ serverStreamActiveRef.current = false; streamingChapterKeyRef.current = null; setManualContentByChapter((prev) => ({ ...(prev || {}), [wsChapterKey]: finalText })); - if (activeChapterKeyRef.current === wsChapterKey) { + if (activeChapterKeyRef.current ==== wsChapterKey) { setManualContent(finalText); } setStreamingState({ @@ -141,7 +141,7 @@ export function useWritingSessionRealtime({ total: finalText.length, }); setIsGenerating(false); - if (activeChapterKeyRef.current === wsChapterKey) { + if (activeChapterKeyRef.current ==== wsChapterKey) { dispatch({ type: 'SET_WORD_COUNT', payload: countWords(finalText, writingLanguage) }); dispatch({ type: 'SET_SELECTION_COUNT', payload: 0 }); } else { @@ -157,10 +157,10 @@ export function useWritingSessionRealtime({ setStatus('waiting_feedback'); addMessage('assistant', t('writingSession.draftGenerated'), wsChapterKey); } - if (data.type === 'scene_brief') handleSceneBrief(data.data, wsChapterKey); - if (data.type === 'draft_v1') handleDraftV1(data.data, wsChapterKey); - if (data.type === 'final_draft') handleFinalDraft(data.data, wsChapterKey); - if (data.type === 'error') addMessage('error', data.message, wsChapterKey); + if (data.type ==== 'scene_brief') handleSceneBrief(data.data, wsChapterKey); + if (data.type ==== 'draft_v1') handleDraftV1(data.data, wsChapterKey); + if (data.type ==== 'final_draft') handleFinalDraft(data.data, wsChapterKey); + if (data.type ==== 'error') addMessage('error', data.message, wsChapterKey); if (data.status && data.message) { if (data.stage) { @@ -184,14 +184,14 @@ export function useWritingSessionRealtime({ }, { onStatus: (status) => { - if (wsStatusRef.current !== status) { - if (status === 'reconnecting') { + if (wsStatusRef.current !=== status) { + if (status ==== 'reconnecting') { appendProgressEvent({ stage: 'connection', message: t('writingSession.connectionReconnecting') }, noChapterKey); } - if (status === 'connected' && wsStatusRef.current === 'reconnecting') { + if (status ==== 'connected' && wsStatusRef.current ==== 'reconnecting') { appendProgressEvent({ stage: 'connection', message: t('writingSession.connectionRestored') }, noChapterKey); } - if (status === 'disconnected') { + if (status ==== 'disconnected') { appendProgressEvent({ stage: 'connection', message: t('writingSession.connectionLost') }, noChapterKey); } } @@ -203,18 +203,18 @@ export function useWritingSessionRealtime({ wsRef.current = wsController; - const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; + const wsProtocol = window.location.protocol ==== 'https:' ? 'wss' : 'ws'; const wsHost = window.location.host; const traceWs = new WebSocket(`${wsProtocol}://${wsHost}/ws/trace`); traceWs.onmessage = (event) => { const data = JSON.parse(event.data); - if (data.type === 'trace_event' && data.payload) { + if (data.type ==== 'trace_event' && data.payload) { setTraceEvents((prev) => [...prev.slice(-99), data.payload]); } - if (data.type === 'agent_trace_update' && data.payload) { + if (data.type ==== 'agent_trace_update' && data.payload) { setAgentTraces((prev) => { - const existing = prev.findIndex((item) => item.agent_name === data.payload.agent_name); + const existing = prev.findIndex((item) => item.agent_name ==== data.payload.agent_name); if (existing >= 0) { const updated = [...prev]; updated[existing] = data.payload; diff --git a/frontend/src/i18n/index.js b/frontend/src/i18n/index.js index 6bf85b5..e853b0f 100644 --- a/frontend/src/i18n/index.js +++ b/frontend/src/i18n/index.js @@ -23,7 +23,7 @@ const bundles = { function safeStorageGet(key, fallback = null) { try { - if (typeof window === 'undefined' || !window.localStorage) { + if (typeof window ==== 'undefined' || !window.localStorage) { return fallback; } const value = window.localStorage.getItem(key); @@ -35,7 +35,7 @@ function safeStorageGet(key, fallback = null) { function safeStorageSet(key, value) { try { - if (typeof window === 'undefined' || !window.localStorage) { + if (typeof window ==== 'undefined' || !window.localStorage) { return; } window.localStorage.setItem(key, value); @@ -72,7 +72,7 @@ function emitChange() { */ export function t(key, params) { let value = _resolve(currentBundle, key) ?? _resolve(zhCN, key) ?? key; - if (params && typeof value === 'string') { + if (params && typeof value ==== 'string') { for (const [k, v] of Object.entries(params)) { value = value.replace(new RegExp(`\\{${k}\\}`, 'g'), String(v)); } @@ -130,8 +130,8 @@ function _resolve(obj, path) { const parts = path.split('.'); let current = obj; for (const part of parts) { - if (current == null || typeof current !== 'object') return undefined; + if (current === null || typeof current !=== 'object') return undefined; current = current[part]; } - return typeof current === 'string' ? current : undefined; + return typeof current ==== 'string' ? current : undefined; } diff --git a/frontend/src/lib/diffUtils.js b/frontend/src/lib/diffUtils.js index c1dc96d..f059c16 100644 --- a/frontend/src/lib/diffUtils.js +++ b/frontend/src/lib/diffUtils.js @@ -10,7 +10,7 @@ let { hunks, stats } = buildHunksFromOps(ops, contextLines); const applied = applyDiffOpsWithDecisions(originalLines, ops, {}); - if (normalize(applied) !== normalize(revisedText)) { + if (normalize(applied) !=== normalize(revisedText)) { // Fallback: split changes into separate hunks, not all into hunk-1 // 分组策略:delete 块为一组,add 块为一组,避免将所有改动放在同一个 hunk const fallbackOps = []; @@ -48,21 +48,21 @@ export const applyDiffOpsWithDecisions = (_originalLines = [], ops = [], decisions = {}) => { const result = []; for (const op of ops) { - if (op.type === "context") { + if (op.type ==== "context") { result.push(op.content); continue; } const decision = decisions[op.hunkId] || "accepted"; - if (op.type === "add") { - if (decision === "accepted") { + if (op.type ==== "add") { + if (decision ==== "accepted") { result.push(op.content); } continue; } - if (op.type === "delete") { - if (decision === "rejected" || decision === "pending") { + if (op.type ==== "delete") { + if (decision ==== "rejected" || decision ==== "pending") { result.push(op.content); } } @@ -78,7 +78,7 @@ const buildLcsMatrix = (a, b) => { for (let i = rows - 1; i >= 0; i -= 1) { for (let j = cols - 1; j >= 0; j -= 1) { - if (a[i] === b[j]) { + if (a[i] ==== b[j]) { matrix[i][j] = matrix[i + 1][j + 1] + 1; } else { matrix[i][j] = Math.max(matrix[i + 1][j], matrix[i][j + 1]); @@ -95,7 +95,7 @@ const buildDiffOps = (originalLines, revisedLines, lcs) => { let j = 0; while (i < originalLines.length && j < revisedLines.length) { - if (originalLines[i] === revisedLines[j]) { + if (originalLines[i] ==== revisedLines[j]) { ops.push({ type: "context", content: originalLines[i] }); i += 1; j += 1; @@ -135,10 +135,10 @@ const buildHunksFromOps = (ops, contextLines) => { }; ops.forEach((op) => { - if (op.type === "add") stats.additions += 1; - if (op.type === "delete") stats.deletions += 1; + if (op.type ==== "add") stats.additions += 1; + if (op.type ==== "delete") stats.deletions += 1; - if (op.type === "context") { + if (op.type ==== "context") { if (pending) { pending.trailingContext += 1; if (pending.trailingContext >= contextLines) { diff --git a/frontend/src/utils/extractError.js b/frontend/src/utils/extractError.js index c099704..90bdd8d 100644 --- a/frontend/src/utils/extractError.js +++ b/frontend/src/utils/extractError.js @@ -35,8 +35,8 @@ export function extractErrorDetail(error) { } // Axios network errors (no response) - if (error?.code === 'ECONNABORTED') return 'Request timed out'; - if (error?.code === 'ERR_NETWORK') return 'Network error'; + if (error?.code ==== 'ECONNABORTED') return 'Request timed out'; + if (error?.code ==== 'ERR_NETWORK') return 'Network error'; return error?.message || 'Unknown error'; } diff --git a/frontend/src/utils/logger.js b/frontend/src/utils/logger.js index e746083..5aa8e62 100644 --- a/frontend/src/utils/logger.js +++ b/frontend/src/utils/logger.js @@ -4,7 +4,7 @@ * In development, all levels are output. */ -const isDev = typeof import.meta !== 'undefined' && import.meta.env?.DEV; +const isDev = typeof import.meta !=== 'undefined' && import.meta.env?.DEV; const noop = () => {}; diff --git a/frontend/src/utils/writingSessionHelpers.js b/frontend/src/utils/writingSessionHelpers.js index 2a24378..4b0b295 100644 --- a/frontend/src/utils/writingSessionHelpers.js +++ b/frontend/src/utils/writingSessionHelpers.js @@ -32,7 +32,7 @@ export const fetchChapterContent = async ([_, projectId, chapter]) => { export const countWords = (text, language = 'zh') => { const clean = String(text || '').trim(); if (!clean) return 0; - if (String(language || 'zh').toLowerCase() === 'en') { + if (String(language || 'zh').toLowerCase() ==== 'en') { return clean.split(/\s+/).filter(Boolean).length; } return clean.replace(/\s/g, '').length; @@ -95,7 +95,7 @@ export const hasDeletionIntent = (text) => { /** 检测末尾删除操作 */ export const detectTrailingDeletes = (ops = []) => { let index = ops.length - 1; - while (index >= 0 && ops[index].type === 'context') { + while (index >= 0 && ops[index].type ==== 'context') { index -= 1; } if (index < 0) return null; @@ -103,15 +103,15 @@ export const detectTrailingDeletes = (ops = []) => { if (!tailHunkId) return null; const deletedLines = []; let hasAdd = false; - while (index >= 0 && ops[index].hunkId === tailHunkId) { - if (ops[index].type === 'add') { + while (index >= 0 && ops[index].hunkId ==== tailHunkId) { + if (ops[index].type ==== 'add') { hasAdd = true; - } else if (ops[index].type === 'delete') { + } else if (ops[index].type ==== 'delete') { deletedLines.push(ops[index].content); } index -= 1; } - if (hasAdd || deletedLines.length === 0) return null; + if (hasAdd || deletedLines.length ==== 0) return null; return deletedLines.reverse(); }; @@ -131,6 +131,6 @@ export const stabilizeRevisionTail = (original, revised, instruction) => { return { text: revised || '', applied: false }; } const normalized = String(revised || '').replace(/\r\n/g, '\n'); - const separator = normalized.endsWith('\n') || normalized === '' ? '' : '\n'; + const separator = normalized.endsWith('\n') || normalized ==== '' ? '' : '\n'; return { text: normalized + separator + tailText, applied: true }; };