From 3bff9b3b937b5154bb81b103657f4a9b7241a39d Mon Sep 17 00:00:00 2001 From: "WIN-JHFT4D3SIVT\\caoxiaozhu" Date: Mon, 6 Apr 2026 23:48:52 +0800 Subject: [PATCH] feat(frontend): add four-quadrant kanban task management system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add KanbanPanel component with four-quadrant task layout - Add KanbanDetail component for task configuration modal - Add "待办" (Todo) module to sidebar collapsed icon rail - Click TODAY'S STATUS card or sidebar icon to open kanban drawer - Click quadrant check icon to open detail modal with Teleport to body - Apply blur effect to sidebar and chat area when detail modal is open - Import ListTodo icon from lucide-vue-next - Update sidebar labels to English for consistency --- frontend/src/components/chat/KanbanDetail.vue | 496 ++++++++++++++++++ frontend/src/components/chat/KanbanPanel.vue | 336 ++++++++++++ frontend/src/pages/chat/chatPage.css | 59 ++- .../pages/chat/composables/useSidebarPlan.ts | 11 +- frontend/src/pages/chat/index.vue | 69 ++- 5 files changed, 954 insertions(+), 17 deletions(-) create mode 100644 frontend/src/components/chat/KanbanDetail.vue create mode 100644 frontend/src/components/chat/KanbanPanel.vue diff --git a/frontend/src/components/chat/KanbanDetail.vue b/frontend/src/components/chat/KanbanDetail.vue new file mode 100644 index 0000000..ba2fca6 --- /dev/null +++ b/frontend/src/components/chat/KanbanDetail.vue @@ -0,0 +1,496 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/components/chat/KanbanPanel.vue b/frontend/src/components/chat/KanbanPanel.vue new file mode 100644 index 0000000..a0eac11 --- /dev/null +++ b/frontend/src/components/chat/KanbanPanel.vue @@ -0,0 +1,336 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/chat/chatPage.css b/frontend/src/pages/chat/chatPage.css index 33a29a9..b2c0cbf 100644 --- a/frontend/src/pages/chat/chatPage.css +++ b/frontend/src/pages/chat/chatPage.css @@ -14,6 +14,12 @@ overflow: visible; } +.chat-view.blur-when-modal .conv-sidebar, +.chat-view.blur-when-modal .chat-area { + filter: blur(8px); + pointer-events: none; +} + .sidebar-runtime-panel { flex: 1; padding: 12px 14px; @@ -444,6 +450,50 @@ pointer-events: auto; } +/* Kanban Drawer (四象限任务管理) */ +.kanban-drawer-shell { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 32; +} + +.kanban-drawer-shell.open { + pointer-events: auto; +} + +.kanban-drawer-backdrop { + position: absolute; + inset: 0; + border: none; + background: rgba(2, 6, 14, 0.52); + backdrop-filter: blur(4px); +} + +.kanban-drawer { + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 100%; + max-width: 900px; + transform: translateX(100%); + transition: transform var(--transition-mid); +} + +.kanban-drawer.open { + transform: translateX(0); +} + +.kanban-drawer :deep(.kanban-panel) { + height: 100%; + padding: 12px 12px 12px 0; +} + +.kanban-drawer :deep(.kanban-frame) { + height: 100%; +} + .knowledge-hud-backdrop { position: absolute; inset: 0; @@ -610,6 +660,11 @@ margin-bottom: 10px; } +.jarvis-sidebar-scroll .section-label { + margin-bottom: 8px; + padding: 0 12px; +} + .conv-sidebar-header .section-label { margin-bottom: 0; } @@ -2345,8 +2400,8 @@ .jarvis-progress-core span { font-family: var(--font-mono); - font-size: 9px; - letter-spacing: 0.12em; + font-size: 7px; + letter-spacing: 0.1em; color: rgba(155, 231, 255, 0.54); } diff --git a/frontend/src/pages/chat/composables/useSidebarPlan.ts b/frontend/src/pages/chat/composables/useSidebarPlan.ts index 3df2e92..35fd21c 100644 --- a/frontend/src/pages/chat/composables/useSidebarPlan.ts +++ b/frontend/src/pages/chat/composables/useSidebarPlan.ts @@ -1,5 +1,5 @@ import { computed, onMounted, ref, watch } from 'vue' -import { CornerDownLeft, Database, Sparkles, Sun } from 'lucide-vue-next' +import { CornerDownLeft, Database, Sparkles, Sun, ListTodo } from 'lucide-vue-next' import { scheduleCenterApi, type ScheduleCenterDateResponse, type ScheduleCenterDaySummary } from '@/api/scheduleCenter' export interface SidebarFocusItem { @@ -13,6 +13,7 @@ export const sidebarCollapsedModules = [ { id: 'calendar', label: '日历', icon: Sun }, { id: 'status', label: '计划', icon: Database }, { id: 'focus', label: '重点', icon: Sparkles }, + { id: 'kanban', label: '待办', icon: ListTodo }, { id: 'review', label: '复盘', icon: CornerDownLeft }, ] @@ -111,10 +112,10 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn )) const sidebarStatusBreakdown = computed(() => [ - { key: 'done', label: '已完成', value: todayPlanCounters.value.done, tone: 'done' }, - { key: 'doing', label: '进行中', value: todayPlanCounters.value.doing, tone: 'doing' }, - { key: 'pending', label: '未开始', value: todayPlanCounters.value.pending, tone: 'pending' }, - { key: 'total', label: '今日合计', value: todayPlanCounters.value.total, tone: 'total' }, + { key: 'done', label: 'Completed', value: todayPlanCounters.value.done, tone: 'done' }, + { key: 'doing', label: 'In Progress', value: todayPlanCounters.value.doing, tone: 'doing' }, + { key: 'pending', label: 'Pending', value: todayPlanCounters.value.pending, tone: 'pending' }, + { key: 'total', label: 'Total', value: todayPlanCounters.value.total, tone: 'total' }, ]) // 模拟数据 - 用于测试滑动条 diff --git a/frontend/src/pages/chat/index.vue b/frontend/src/pages/chat/index.vue index 046f296..dd99650 100644 --- a/frontend/src/pages/chat/index.vue +++ b/frontend/src/pages/chat/index.vue @@ -15,6 +15,8 @@ import KnowledgeHudPanel from '@/components/chat/KnowledgeHudPanel.vue' import KnowledgeSlidePanel from '@/components/chat/KnowledgeSlidePanel.vue' import KnowledgeHUDPreview from '@/components/chat/KnowledgeHUDPreview.vue' import OrchestrationPanel from '@/components/chat/OrchestrationPanel.vue' +import KanbanPanel from '@/components/chat/KanbanPanel.vue' +import KanbanDetail from '@/components/chat/KanbanDetail.vue' import TelemetrySparkline from '@/components/chat/TelemetrySparkline.vue' import NavShortcutRow from '@/components/navigation/NavShortcutRow.vue' import DailyDigestCard from '@/components/memory/DailyDigestCard.vue' @@ -78,12 +80,28 @@ const { // --- Local UI state --- const sidebarCollapsed = ref(false) const orchestrationDrawerOpen = ref(false) +const kanbanDrawerOpen = ref(false) +const kanbanDetailOpen = ref(false) +const kanbanDetailQuadrant = ref<{ id: string; title: string; color: string } | null>(null) const knowledgeHudOpen = ref(false) const selectedFolder = ref(null) const previewDoc = ref(null) function openOrchestrationDrawer() { orchestrationDrawerOpen.value = true } function closeOrchestrationDrawer() { orchestrationDrawerOpen.value = false } +function openKanbanDrawer() { kanbanDrawerOpen.value = true } +function closeKanbanDrawer() { kanbanDrawerOpen.value = false } +function openKanbanDetail(quadrantId: string) { + const quadrantMap: Record = { + 'urgent-important': { title: '重要且紧急', color: '#f56565' }, + 'not-urgent-important': { title: '重要不紧急', color: '#ecc94b' }, + 'urgent-not-important': { title: '紧急不重要', color: '#42b9f5' }, + 'not-urgent-not-important': { title: '不重要不紧急', color: '#97c950' }, + } + kanbanDetailQuadrant.value = { id: quadrantId, ...quadrantMap[quadrantId] } + kanbanDetailOpen.value = true +} +function closeKanbanDetail() { kanbanDetailOpen.value = false } function openKnowledgeHud() { selectedFolder.value = null previewDoc.value = null @@ -208,7 +226,7 @@ function renderMarkdown(content: string) {