From 08ecd023c77d3ae23b777d5191ad0e6d027cf380 Mon Sep 17 00:00:00 2001 From: liumangmang Date: Mon, 9 Feb 2026 17:36:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=B9=B6=E5=A2=9E=E5=BC=BA=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=81=A5=E5=A3=AE=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- frontend/src/components/ProjectSidebar.vue | 33 ++++++++++++++++------ frontend/src/stores/projects.js | 21 ++++++++++++-- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/ProjectSidebar.vue b/frontend/src/components/ProjectSidebar.vue index ab92b5a..0d24ce3 100644 --- a/frontend/src/components/ProjectSidebar.vue +++ b/frontend/src/components/ProjectSidebar.vue @@ -63,13 +63,22 @@ function statusLabel(status) {
{{ p.name }}
{{ p.path }}
- +
+ + +
{{ statusLabel(p.status) }} @@ -156,8 +165,12 @@ function statusLabel(status) { border-left-color: var(--accent-blue); } .project-info { display: flex; align-items: center; gap: 0.5rem; } -.btn-edit { +.project-actions { + display: flex; + gap: 0.25rem; flex-shrink: 0; +} +.btn-icon { width: 1.5rem; height: 1.5rem; padding: 0; @@ -172,7 +185,9 @@ function statusLabel(status) { font-size: 0.75rem; opacity: 0.7; } -.btn-edit:hover { color: var(--accent-blue); background: var(--bg-secondary); opacity: 1; } +.btn-icon:hover { color: var(--accent-blue); background: var(--bg-secondary); opacity: 1; } +.btn-danger { color: #f97373; } +.btn-danger:hover { color: #f97373; background: rgba(248, 113, 113, 0.12); } .folder-icon { color: var(--accent-blue); font-size: 0.875rem; } .project-meta { flex: 1; min-width: 0; } .project-name { font-size: 0.875rem; font-weight: 500; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } diff --git a/frontend/src/stores/projects.js b/frontend/src/stores/projects.js index a485143..844258c 100644 --- a/frontend/src/stores/projects.js +++ b/frontend/src/stores/projects.js @@ -34,7 +34,10 @@ export const useProjectsStore = defineStore('projects', () => { const selectedFilePath = ref(null) const fileContent = ref(null) - const current = computed(() => list.value.find(p => p.id === currentId.value) || null) + const current = computed(() => { + if (!Array.isArray(list.value)) return null + return list.value.find(p => p.id === currentId.value) || null + }) const rawFileTree = computed(() => statusData.value?.fileTree || null) const currentFileTree = computed(() => { const tree = rawFileTree.value @@ -48,7 +51,7 @@ export const useProjectsStore = defineStore('projects', () => { error.value = null try { const res = await projectsApi.list() - list.value = res.data || [] + list.value = Array.isArray(res.data) ? res.data : [] if (list.value.length && !currentId.value) { currentId.value = list.value[0].id await refreshStatus() @@ -72,6 +75,19 @@ export const useProjectsStore = defineStore('projects', () => { return res.data } + async function deleteProject(id) { + if (!id) return + await projectsApi.delete(id) + // 重新加载列表并重置当前项目 + await loadProjects() + if (!list.value.length) { + currentId.value = null + statusData.value = null + selectedFilePath.value = null + fileContent.value = null + } + } + async function refreshStatus() { if (!currentId.value) return loading.value = true @@ -169,6 +185,7 @@ export const useProjectsStore = defineStore('projects', () => { loadProjects, addProject, updateProject, + deleteProject, refreshStatus, updateSvn, commit,