diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index dae4a07..309a801 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -121,11 +121,6 @@ export const modelApi = { return res }, - // Clear cache (e.g., when models changed on server) - clearCache() { - modelsCache = null - localStorage.removeItem('models_cache') - } } export const statsApi = { @@ -205,30 +200,6 @@ export const projectApi = { return request(`/projects/${projectId}`, { method: 'DELETE' }) }, - uploadFolder(data) { - const formData = new FormData() - formData.append('name', data.name || '') - formData.append('description', data.description || '') - for (const file of data.files) { - formData.append('files', file, file.webkitRelativePath) - } - return fetch(`${BASE}/projects/upload`, { - method: 'POST', - body: formData, - }).then(async res => { - let json - try { - json = await res.json() - } catch (_) { - throw new Error(`服务器错误 (${res.status}),请确认后端已重启`) - } - if (json.code !== 0) { - throw new Error(json.message || 'Request failed') - } - return json - }) - }, - listFiles(projectId, path = '') { return request(`/projects/${projectId}/files${buildQueryParams({ path })}`) }, @@ -261,11 +232,4 @@ export const projectApi = { body: { path: dirPath }, }) }, - - search(projectId, query, options = {}) { - return request(`/projects/${projectId}/search`, { - method: 'POST', - body: { query, ...options }, - }) - }, } diff --git a/frontend/src/components/ChatView.vue b/frontend/src/components/ChatView.vue index f3703af..c8f4818 100644 --- a/frontend/src/components/ChatView.vue +++ b/frontend/src/components/ChatView.vue @@ -93,7 +93,7 @@ const props = defineProps({ toolsEnabled: { type: Boolean, default: true }, }) -const emit = defineEmits(['sendMessage', 'deleteMessage', 'regenerateMessage', 'toggleSettings', 'toggleStats', 'loadMoreMessages', 'toggleTools']) +const emit = defineEmits(['sendMessage', 'deleteMessage', 'regenerateMessage', 'loadMoreMessages', 'toggleTools']) const scrollContainer = ref(null) const inputRef = ref(null) diff --git a/frontend/src/components/FileExplorer.vue b/frontend/src/components/FileExplorer.vue index b1fe634..acb1e27 100644 --- a/frontend/src/components/FileExplorer.vue +++ b/frontend/src/components/FileExplorer.vue @@ -60,25 +60,13 @@
- - -
- -
- - -
- -
- - -
- + +
+
+ + +
+ +
@@ -150,7 +131,6 @@ import { ref, computed, watch, onMounted, onUnmounted } from 'vue' import { projectApi } from '../api' import FileTreeItem from './FileTreeItem.vue' import { renderMarkdown } from '../utils/markdown' -import { highlightCode } from '../utils/highlight' import { normalizeFileTree } from '../utils/fileTree' const IMAGE_EXTS = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'ico']) @@ -169,10 +149,8 @@ const loadingTree = ref(false) // -- Viewer state -- const activeFile = ref(null) -const fileContent = ref('') const fileError = ref('') const loadingFile = ref(false) -const editing = ref(false) const editContent = ref('') const saving = ref(false) const editorRef = ref(null) @@ -195,18 +173,11 @@ const fileType = computed(() => { }) // -- Content rendering -- -const renderedContent = computed(() => { - if (!fileContent.value) return '' - if (isMarkdownFile.value) return renderMarkdown(fileContent.value) - // Wrap code in fenced code block — rendered by same markdown pipeline, same CSS - const lang = fileExt.value || '' - return renderMarkdown('```' + lang + '\n' + fileContent.value + '\n```') -}) - const editorHighlighted = computed(() => { if (!editContent.value) return '' + if (isMarkdownFile.value) return renderMarkdown(editContent.value) const lang = fileExt.value || '' - return highlightCode(editContent.value, lang) + return renderMarkdown('```' + lang + '\n' + editContent.value + '\n```') }) function syncScroll() { @@ -232,9 +203,8 @@ async function loadTree(path = '') { async function openFile(filepath) { activeFile.value = filepath - fileContent.value = '' fileError.value = '' - editing.value = false + editContent.value = '' imageUrl.value = '' loadingFile.value = true @@ -254,7 +224,7 @@ async function openFile(filepath) { try { const res = await projectApi.readFile(props.projectId, filepath) - fileContent.value = res.data.content + editContent.value = res.data.content } catch (e) { fileError.value = e.message || '加载文件失败' } finally { @@ -262,23 +232,11 @@ async function openFile(filepath) { } } -function startEdit() { - editContent.value = fileContent.value - editing.value = true -} - -function cancelEdit() { - editing.value = false - editContent.value = '' -} - async function saveFile() { if (!activeFile.value || saving.value) return saving.value = true try { await projectApi.writeFile(props.projectId, activeFile.value, editContent.value) - fileContent.value = editContent.value - editing.value = false } catch (e) { alert('保存失败: ' + e.message) } finally { @@ -293,7 +251,6 @@ function deleteFile() { projectApi.deleteFile(props.projectId, activeFile.value).then(() => { activeFile.value = null - fileContent.value = '' loadTree() }).catch(e => { alert('删除失败: ' + e.message) @@ -308,7 +265,6 @@ async function createNewFile() { await projectApi.writeFile(props.projectId, path, '') await loadTree() openFile(path) - startEdit() } catch (e) { alert('创建失败: ' + e.message) } @@ -330,14 +286,11 @@ function onEditorKeydown(e) { e.preventDefault() saveFile() } - if (e.key === 'Escape') { - cancelEdit() - } } // Ctrl+S global shortcut function onGlobalKeydown(e) { - if (e.key === 's' && (e.ctrlKey || e.metaKey) && editing.value) { + if (e.key === 's' && (e.ctrlKey || e.metaKey) && activeFile.value) { e.preventDefault() saveFile() } @@ -345,9 +298,8 @@ function onGlobalKeydown(e) { watch(() => props.projectId, () => { activeFile.value = null - fileContent.value = '' + editContent.value = '' imageUrl.value = '' - editing.value = false loadTree() }) @@ -536,10 +488,6 @@ onUnmounted(() => { resize: none; border: none; outline: none; - padding: 12px; - font-family: 'JetBrains Mono', 'Fira Code', monospace; - font-size: 13px; - line-height: 1.5; color: var(--text-primary); background: var(--bg-code); tab-size: 4; @@ -547,14 +495,12 @@ onUnmounted(() => { overflow: auto; } -.file-editor::-webkit-scrollbar, -.file-content-viewer::-webkit-scrollbar { +.file-editor::-webkit-scrollbar { width: 6px; height: 6px; } -.file-editor::-webkit-scrollbar-thumb, -.file-content-viewer::-webkit-scrollbar-thumb { +.file-editor::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 3px; } @@ -575,48 +521,55 @@ onUnmounted(() => { flex: 1; display: flex; position: relative; - margin: 8px; - border: 1px solid var(--border-light); - border-radius: 8px; - background: var(--bg-code); overflow: hidden; } -.editor-container pre.editor-highlight { +.editor-highlight { position: absolute; inset: 0; margin: 0; - padding: 12px; - font-family: 'JetBrains Mono', 'Fira Code', monospace; - font-size: 13px; - line-height: 1.5; + padding: 20px 24px; overflow: auto; pointer-events: none; color: var(--text-primary); - background: var(--bg-code); + background: transparent; + font-family: 'JetBrains Mono', 'Fira Code', monospace; + font-size: 14px; + line-height: 1.7; white-space: pre; tab-size: 4; } +/* Strip wrapper styles from markdown-rendered
 so text aligns with textarea */
+.editor-highlight :deep(pre),
+.editor-highlight :deep(code) {
+  margin: 0;
+  padding: 0;
+  background: transparent !important;
+  border: none;
+  border-radius: 0;
+  font-size: inherit;
+  font-family: inherit;
+  line-height: inherit;
+  white-space: inherit;
+  tab-size: inherit;
+  word-wrap: normal;
+}
+
 .editor-container .file-editor {
   position: relative;
   z-index: 1;
   flex: 1;
   border: none;
+  font-family: 'JetBrains Mono', 'Fira Code', monospace;
+  font-size: 14px;
+  line-height: 1.7;
+  padding: 20px 24px;
   color: transparent;
   caret-color: var(--text-primary);
   background: transparent;
 }
 
-.file-content-viewer {
-  flex: 1;
-  overflow: auto;
-  padding: 20px 24px;
-  font-size: 14px;
-  line-height: 1.7;
-  color: var(--text-primary);
-}
-
 /* -- Image viewer -- */
 .image-viewer {
   flex: 1;
diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue
index 46c86e2..fe9d283 100644
--- a/frontend/src/components/Sidebar.vue
+++ b/frontend/src/components/Sidebar.vue
@@ -76,6 +76,9 @@
           
             
           
+          
+            
+          
           {{ groupedData.standalone.length }}
           
           
+