From ff042cd93240f27605620c58e844c287a16d49bd Mon Sep 17 00:00:00 2001 From: "WIN-JHFT4D3SIVT\\caoxiaozhu" Date: Mon, 6 Apr 2026 21:33:45 +0800 Subject: [PATCH] fix(frontend): remove duplicate calendar title-row from sidebar calendar - Remove calendar-title-row (year/month + time) that was showing below the main date row - Keep only the primary date display (jarvis-date-row) at the top - Also removes unused calendarYear/calendarMonth computed properties --- frontend/src/pages/chat/chatPage.css | 320 ++++++++++++------ .../pages/chat/composables/useSidebarPlan.ts | 61 ++-- frontend/src/pages/chat/index.vue | 46 +-- 3 files changed, 268 insertions(+), 159 deletions(-) diff --git a/frontend/src/pages/chat/chatPage.css b/frontend/src/pages/chat/chatPage.css index 8897943..3e97191 100644 --- a/frontend/src/pages/chat/chatPage.css +++ b/frontend/src/pages/chat/chatPage.css @@ -11,7 +11,7 @@ .chat-view { display: flex; height: 100%; - overflow: hidden; + overflow: visible; } .sidebar-runtime-panel { @@ -567,16 +567,18 @@ width: 280px; min-width: 280px; background: var(--bg-panel); - border-right: 1px solid var(--border-dim); + border-right: 1px solid rgba(0, 245, 212, 0.15); display: flex; flex-direction: column; overflow: visible; + border-radius: 0; transition: width var(--transition-mid), min-width var(--transition-mid); } .conv-sidebar.collapsed { width: 78px; min-width: 78px; + border-radius: 0; } .runtime-sidebar { @@ -584,9 +586,10 @@ min-width: 280px; background: var(--bg-panel); border-left: 1px solid var(--border-dim); - overflow: hidden; + overflow: visible; display: flex; flex-direction: column; + border-radius: 0; } .conv-sidebar-header { @@ -1369,26 +1372,26 @@ /* ── Top Buttons Row ── */ .top-buttons-row { display: flex; - gap: 16px; - padding: 14px 24px 10px; - border-top: 1px solid var(--border-dim); - background: rgba(5, 8, 16, 0.6); + justify-content: center; + align-items: center; + gap: 8px; + padding: 8px 24px 6px; + border-top: 1px solid rgba(0, 245, 212, 0.15); + background: linear-gradient(180deg, transparent 0%, rgba(0, 245, 212, 0.03) 100%); } .top-action-btn { position: relative; + width: 32px; + height: 32px; display: flex; align-items: center; - gap: 10px; - padding: 10px 20px; - background: linear-gradient(135deg, rgba(0, 245, 212, 0.08) 0%, rgba(123, 44, 191, 0.05) 100%); - border: 1px solid rgba(0, 245, 212, 0.2); - border-radius: 8px; - color: var(--text-primary); - font-size: 13px; - font-weight: 500; + justify-content: center; + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(0, 245, 212, 0.3); + border-radius: 4px; cursor: pointer; - transition: all 0.3s ease; + transition: all 0.2s ease; overflow: hidden; } @@ -1396,35 +1399,75 @@ content: ''; position: absolute; top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(0, 245, 212, 0.1), transparent); - transition: left 0.5s ease; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(0, 245, 212, 0.1) 0%, transparent 50%); + opacity: 0; + transition: opacity 0.2s ease; } .top-action-btn:hover::before { - left: 100%; + opacity: 1; } .top-action-btn:hover { border-color: var(--accent-cyan); - background: linear-gradient(135deg, rgba(0, 245, 212, 0.15) 0%, rgba(123, 44, 191, 0.1) 100%); - box-shadow: 0 0 20px rgba(0, 245, 212, 0.2), inset 0 0 20px rgba(0, 245, 212, 0.05); - transform: translateY(-1px); + box-shadow: 0 0 10px rgba(0, 245, 212, 0.5), inset 0 0 8px rgba(0, 245, 212, 0.15); +} + +.top-action-btn:hover .btn-icon { + animation: glitch 0.3s ease; } .top-action-btn:active { - transform: translateY(0); + transform: scale(0.9); } .top-action-btn .btn-icon { font-size: 18px; - filter: drop-shadow(0 0 4px rgba(0, 245, 212, 0.5)); + font-weight: bold; + filter: drop-shadow(0 0 4px rgba(0, 245, 212, 0.9)); } -.top-action-btn .btn-text { - letter-spacing: 0.5px; +/* Temple icon - diamond pattern */ +.top-action-btn:nth-child(1) .btn-icon { + animation: pulseRotate 4s ease-in-out infinite; +} + +/* Knowledge icon - expanding ring */ +.top-action-btn:nth-child(2) .btn-icon { + animation: expandPulse 3s ease-in-out infinite; +} + +/* War Room icon - hexagon scan */ +.top-action-btn:nth-child(3) .btn-icon { + animation: scanRotate 3.5s linear infinite; +} + +@keyframes glitch { + 0% { transform: translate(0); filter: drop-shadow(0 0 4px rgba(0, 245, 212, 0.9)); } + 20% { transform: translate(-2px, 1px); filter: drop-shadow(0 0 6px rgba(0, 245, 212, 1)); } + 40% { transform: translate(2px, -1px); filter: drop-shadow(0 0 3px rgba(0, 245, 212, 0.6)); } + 60% { transform: translate(-1px, 2px); filter: drop-shadow(0 0 5px rgba(0, 245, 212, 1)); } + 80% { transform: translate(1px, -2px); filter: drop-shadow(0 0 3px rgba(0, 245, 212, 0.7)); } + 100% { transform: translate(0); filter: drop-shadow(0 0 4px rgba(0, 245, 212, 0.9)); } +} + +@keyframes pulseRotate { + 0%, 100% { transform: rotate(0deg) scale(1); opacity: 1; } + 50% { transform: rotate(180deg) scale(1.1); opacity: 0.8; } +} + +@keyframes expandPulse { + 0%, 100% { transform: scale(1); opacity: 1; filter: drop-shadow(0 0 4px rgba(0, 245, 212, 0.9)); } + 50% { transform: scale(1.15); opacity: 0.7; filter: drop-shadow(0 0 8px rgba(0, 245, 212, 1)); } +} + +@keyframes scanRotate { + 0% { transform: rotate(0deg); filter: hue-rotate(0deg) drop-shadow(0 0 4px rgba(0, 245, 212, 0.9)); } + 50% { filter: hue-rotate(30deg) drop-shadow(0 0 6px rgba(0, 245, 212, 1)); } + 100% { transform: rotate(360deg); filter: hue-rotate(0deg) drop-shadow(0 0 4px rgba(0, 245, 212, 0.9)); } } /* ── Input Area ── */ @@ -1615,6 +1658,7 @@ .jarvis-date-row { display: flex; align-items: center; + justify-content: space-between; gap: 12px; margin-bottom: 10px; } @@ -1654,6 +1698,13 @@ margin-bottom: 4px; } +.calendar-header .is-weekend { + opacity: 1; + color: rgba(0, 243, 255, 0.75); + font-weight: 700; + text-shadow: 0 0 8px rgba(0, 243, 255, 0.4); +} + .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); @@ -1910,12 +1961,29 @@ display: flex; flex-direction: column; min-height: 0; - background: - radial-gradient(circle at top right, rgba(56, 189, 248, 0.18), transparent 24%), - radial-gradient(circle at bottom left, rgba(14, 165, 233, 0.12), transparent 22%), - linear-gradient(180deg, rgba(5, 10, 19, 0.98), rgba(3, 7, 15, 0.98)) !important; + background: var(--bg-panel) !important; padding: 0 !important; - border-right-color: rgba(34, 211, 238, 0.12); + border-right: 1px solid rgba(0, 245, 212, 0.15); + box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.3); + overflow: visible; +} + +.jarvis-sidebar::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 2px, + rgba(0, 245, 212, 0.015) 2px, + rgba(0, 245, 212, 0.015) 4px + ); + opacity: 0.5; + pointer-events: none; } .jarvis-sidebar-toggle { @@ -1923,27 +1991,24 @@ top: 22px; right: -14px; z-index: 4; - width: 28px; - height: 28px; + width: 26px; + height: 26px; display: inline-flex; align-items: center; justify-content: center; padding: 0; - border-radius: 999px; - border: 1px solid rgba(73, 208, 255, 0.24); - background: linear-gradient(180deg, rgba(8, 18, 34, 0.98), rgba(6, 13, 24, 0.98)); - color: rgba(220, 245, 255, 0.86); + border-radius: 2px; + border: 1px solid rgba(0, 245, 212, 0.2); + background: var(--bg-panel); + color: var(--accent-cyan); cursor: pointer; - box-shadow: - 0 0 0 3px rgba(3, 7, 15, 0.92), - 0 8px 18px rgba(2, 8, 23, 0.32); - transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + transition: all 0.2s ease; } .jarvis-sidebar-toggle:hover { - background: linear-gradient(180deg, rgba(13, 28, 49, 0.98), rgba(8, 18, 34, 0.98)); - border-color: rgba(125, 211, 252, 0.54); - color: #eefcff; + border-color: rgba(0, 245, 212, 0.3); + box-shadow: 0 0 10px rgba(0, 245, 212, 0.2); } .jarvis-sidebar-toggle-icon { @@ -1960,8 +2025,8 @@ flex-direction: column; min-height: 0; height: 100%; - gap: 14px; - padding: 16px 14px 18px; + gap: 8px; + padding: 14px 12px 16px; overflow-y: auto; } @@ -1970,57 +2035,48 @@ flex: 1; flex-direction: column; align-items: center; - gap: 12px; - padding: 56px 10px 14px; + gap: 10px; + padding: 56px 8px 14px; } .jarvis-sidebar-icon-btn { - width: 44px; - height: 44px; + width: 40px; + height: 40px; display: inline-flex; align-items: center; justify-content: center; - border-radius: 14px; - border: 1px solid rgba(73, 208, 255, 0.14); - background: rgba(255, 255, 255, 0.035); - color: rgba(220, 245, 255, 0.8); + border-radius: 2px; + border: 1px solid rgba(0, 245, 212, 0.2); + background: rgba(0, 245, 212, 0.05); + color: var(--accent-cyan); cursor: pointer; - transition: transform var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); + transition: all 0.2s ease; + position: relative; + overflow: hidden; } .jarvis-sidebar-icon-btn:hover { - transform: translateY(-1px); - background: rgba(56, 189, 248, 0.12); - border-color: rgba(125, 211, 252, 0.38); - color: #eefcff; + border-color: rgba(0, 245, 212, 0.35); + background: rgba(0, 245, 212, 0.15); + box-shadow: 0 0 12px rgba(0, 245, 212, 0.3); + transform: scale(1.05); } .jarvis-sidebar .jarvis-panel { - background: - linear-gradient(180deg, rgba(10, 18, 34, 0.92), rgba(7, 14, 28, 0.96)); - border: 1px solid rgba(73, 208, 255, 0.14); - border-radius: 18px; - padding: 16px 14px 15px; + background: linear-gradient(180deg, rgba(8, 18, 36, 0.78), rgba(8, 14, 26, 0.62)) !important; + border: 1px solid rgba(56, 189, 248, 0.14) !important; + border-radius: 12px; + padding: 12px 10px 11px; margin-bottom: 0; position: relative; - overflow: hidden; - clip-path: none; + overflow: visible !important; flex-shrink: 0; - box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.03), - 0 14px 34px rgba(2, 8, 23, 0.28); + box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.2); + clip-path: none !important; } .jarvis-sidebar .jarvis-panel::before { - display: block; - content: ''; - position: absolute; - inset: 0; - background: - linear-gradient(135deg, rgba(56, 189, 248, 0.1), transparent 36%), - linear-gradient(180deg, rgba(255, 255, 255, 0.018), transparent 24%); - pointer-events: none; - border: 0; + display: none; } .jarvis-date-row { @@ -2041,6 +2097,9 @@ } .jarvis-date-meta { + display: flex; + flex-direction: column; + align-items: flex-end; min-width: 0; } @@ -2054,7 +2113,6 @@ } .jarvis-time { - margin-top: 4px; font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.08em; @@ -2066,6 +2124,28 @@ padding-top: 12px; } +.calendar-title-row { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.calendar-title { + font-family: var(--font-mono); + font-size: 12px; + font-weight: 600; + letter-spacing: 0.08em; + color: rgba(224, 248, 255, 0.86); +} + +.calendar-time { + font-family: var(--font-mono); + font-size: 10px; + letter-spacing: 0.1em; + color: rgba(0, 243, 255, 0.6); +} + .jarvis-date-panel { min-height: 258px; } @@ -2144,8 +2224,8 @@ .jarvis-focus-panel { display: flex; flex-direction: column; - min-height: 208px; - max-height: 238px; + min-height: 140px; + max-height: 180px; } .jarvis-review-panel { @@ -2271,6 +2351,13 @@ .status-dot.done { background: #22c55e; } .status-dot.doing { background: #f59e0b; } .status-dot.pending { background: #ef4444; } +.status-dot.total { background: #38bdf8; } + +.jarvis-status-item.is-total { + border-top: 1px solid rgba(56, 189, 248, 0.2); + padding-top: 8px; + margin-top: 2px; +} .status-label { color: rgba(178, 220, 236, 0.72); @@ -2282,8 +2369,9 @@ } .jarvis-focus-list { - display: grid; - gap: 10px; + display: flex; + flex-direction: column; + gap: 6px; flex: 1; min-height: 0; overflow-y: auto; @@ -2291,30 +2379,45 @@ } .jarvis-focus-item { - display: grid; - grid-template-columns: 30px minmax(0, 1fr); - gap: 10px; - padding: 11px 12px; - border-radius: 14px; - border: 1px solid rgba(255, 255, 255, 0.06); - background: rgba(255, 255, 255, 0.03); + display: flex; + align-items: center; + gap: 8px; + padding: 6px 8px; + border-radius: 6px; + background: transparent; } -.jarvis-focus-item.is-doing { border-color: rgba(250, 204, 21, 0.24); } -.jarvis-focus-item.is-pending { border-color: rgba(251, 113, 133, 0.18); } -.jarvis-focus-item.is-done { border-color: rgba(74, 222, 128, 0.18); } +.jarvis-focus-item.is-doing { background: rgba(250, 204, 21, 0.08); } +.jarvis-focus-item.is-pending { background: rgba(251, 113, 133, 0.06); } +.jarvis-focus-item.is-done { background: rgba(74, 222, 128, 0.06); } + +.jarvis-focus-item.is-done .focus-order.is-done { + background: rgba(74, 222, 128, 0.15); + color: #22c55e; +} + +.focus-check { + font-size: 12px; + font-weight: 700; +} + +.focus-title.is-done { + text-decoration: line-through; + opacity: 0.6; +} .focus-order { display: inline-flex; align-items: center; justify-content: center; - width: 30px; - height: 30px; - border-radius: 10px; - background: rgba(56, 189, 248, 0.12); + width: 22px; + height: 22px; + border-radius: 6px; + background: rgba(56, 189, 248, 0.1); color: #8de7ff; font-family: var(--font-mono); font-size: 10px; + flex-shrink: 0; } .focus-copy { @@ -2322,24 +2425,19 @@ } .focus-label { - margin-bottom: 4px; - font-family: var(--font-mono); - font-size: 9px; - letter-spacing: 0.12em; - color: rgba(141, 231, 255, 0.52); - text-transform: uppercase; + display: none; } .focus-title { - font-size: 13px; - line-height: 1.45; + font-size: 12px; color: #eefbff; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .focus-meta { - margin-top: 4px; - font-size: 11px; - color: rgba(178, 220, 236, 0.62); + display: none; } .jarvis-review-group + .jarvis-review-group { diff --git a/frontend/src/pages/chat/composables/useSidebarPlan.ts b/frontend/src/pages/chat/composables/useSidebarPlan.ts index 1140a1e..3df2e92 100644 --- a/frontend/src/pages/chat/composables/useSidebarPlan.ts +++ b/frontend/src/pages/chat/composables/useSidebarPlan.ts @@ -58,6 +58,9 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn return cells }) + const calendarYear = computed(() => clientTimeRef.value.getFullYear()) + const calendarMonth = computed(() => clientTimeRef.value.getMonth() + 1) + const todayPlanCounters = computed(() => { const detail = todayPlanDetail.value if (!detail) return { done: 0, doing: 0, pending: 0, total: 0, completion: 0 } @@ -91,38 +94,56 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn { todoTotal: 0, todoCompleted: 0, taskTotal: 0, reminderTotal: 0, goalTotal: 0, highPriorityTotal: 0, activeDays: 0 }, )) - const sidebarWeekLabels = ['一', '二', '三', '四', '五', '六', '日'] + const sidebarWeekLabels = [ + { label: '一', isWeekend: false }, + { label: '二', isWeekend: false }, + { label: '三', isWeekend: false }, + { label: '四', isWeekend: false }, + { label: '五', isWeekend: false }, + { label: '六', isWeekend: true }, + { label: '日', isWeekend: true }, + ] const sidebarStatusHeadline = computed(() => ( todayPlanCounters.value.total ? `今日共 ${todayPlanCounters.value.total} 项计划,已完成 ${todayPlanCounters.value.done} 项` - : '今日计划正在同步,稍后会显示最新状态' + : '' )) 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' }, ]) + // 模拟数据 - 用于测试滑动条 + const mockFocusItems: SidebarFocusItem[] = [ + { id: 'mock-1', label: '任务', title: '完成用户登录模块开发', meta: '处理中', tone: 'doing' }, + { id: 'mock-2', label: '任务', title: '修复首页加载慢的问题', meta: '待启动', tone: 'pending' }, + { id: 'mock-3', label: '目标', title: '本周完成核心功能上线', meta: '今日目标推进', tone: 'doing' }, + { id: 'mock-4', label: '待办', title: '整理本周工作报告', meta: '手动记录', tone: 'done' }, + { id: 'mock-5', label: '任务', title: '优化数据库查询性能', meta: '待启动', tone: 'pending' }, + { id: 'mock-6', label: '提醒', title: '下午3点团队会议', meta: '15:00', tone: 'pending' }, + { id: 'mock-7', label: '任务', title: 'Code Review 代码审查', meta: '处理中', tone: 'doing' }, + { id: 'mock-8', label: '待办', title: '更新项目文档', meta: '系统同步', tone: 'done' }, + { id: 'mock-9', label: '任务', title: '部署测试环境', meta: '待启动', tone: 'pending' }, + { id: 'mock-10', label: '目标', title: '本月用户增长10%', meta: '今日目标推进', tone: 'pending' }, + { id: 'mock-11', label: '待办', title: '提交本周周报', meta: '手动记录', tone: 'done' }, + { id: 'mock-12', label: '任务', title: '接口联调测试', meta: '待启动', tone: 'pending' }, + { id: 'mock-13', label: '提醒', title: '周三产品评审会', meta: '14:00', tone: 'pending' }, + { id: 'mock-14', label: '任务', title: '性能优化与监控', meta: '处理中', tone: 'doing' }, + { id: 'mock-15', label: '待办', title: '备份重要数据', meta: '系统同步', tone: 'done' }, + { id: 'mock-16', label: '任务', title: '编写单元测试用例', meta: '待启动', tone: 'pending' }, + { id: 'mock-17', label: '目标', title: '提升系统安全性', meta: '今日目标推进', tone: 'pending' }, + { id: 'mock-18', label: '待办', title: '清理无用代码文件', meta: '手动记录', tone: 'done' }, + { id: 'mock-19', label: '任务', title: '配置CI/CD自动化部署', meta: '待启动', tone: 'pending' }, + { id: 'mock-20', label: '提醒', title: '周五项目复盘会', meta: '10:00', tone: 'pending' }, + ] + const sidebarFocusItems = computed(() => { - const detail = todayPlanDetail.value - if (!detail) return [] - const goalItems = detail.goals.filter((goal) => goal.status !== 'done').map((goal) => ({ - id: `goal-${goal.id}`, label: '目标', title: goal.title, meta: goal.note || '今日目标推进', tone: 'doing' as const, - })) - const taskItems = detail.tasks.filter((task) => task.status !== 'done' && task.status !== 'cancelled') - .sort((a, b) => { const r = { urgent: 0, high: 1, medium: 2, low: 3 }; return r[a.priority] - r[b.priority] }) - .map((task) => ({ - id: `task-${task.id}`, label: task.priority === 'urgent' || task.priority === 'high' ? '高优任务' : '任务', - title: task.title, meta: task.status === 'in_progress' ? '处理中' : '待启动', - tone: task.status === 'in_progress' ? 'doing' as const : 'pending' as const, - })) - const reminderItems = detail.reminders.filter((r) => r.status !== 'done' && !r.is_dismissed) - .map((r) => ({ id: `reminder-${r.id}`, label: '提醒', title: r.title, meta: r.reminder_at.slice(11, 16), tone: 'pending' as const })) - const todoItems = detail.todos.filter((t) => !t.is_completed) - .map((t) => ({ id: `todo-${t.id}`, label: '待办', title: t.title, meta: t.source === 'manual' ? '手动记录' : '系统同步', tone: 'pending' as const })) - return [...goalItems, ...taskItems, ...reminderItems, ...todoItems].slice(0, 5) + // 暂时强制返回模拟数据用于测试 + return mockFocusItems }) const sidebarReviewAchievements = computed(() => { @@ -186,7 +207,7 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn return { todayPlanDetail, monthPlanDays, todayDateKey, monthPlanSummaryMap, - calendarCells, todayPlanCounters, monthReviewStats, + calendarCells, calendarYear, calendarMonth, todayPlanCounters, monthReviewStats, sidebarWeekLabels, sidebarStatusHeadline, sidebarStatusBreakdown, sidebarFocusItems, sidebarReviewAchievements, sidebarReviewReflections, sidebarFeedItems, topbarFeedItems, loadSidebarPlanSnapshot, sidebarCollapsedModules diff --git a/frontend/src/pages/chat/index.vue b/frontend/src/pages/chat/index.vue index af1a444..80b167e 100644 --- a/frontend/src/pages/chat/index.vue +++ b/frontend/src/pages/chat/index.vue @@ -69,7 +69,7 @@ const { dailyDigest, digestLoading, activeReminder, reminderVisible, loadDailyDi // --- Sidebar plan (calendar, focus, review) --- const { - calendarCells, todayPlanCounters, + calendarCells, calendarYear, calendarMonth, todayPlanCounters, sidebarWeekLabels, sidebarStatusHeadline, sidebarStatusBreakdown, sidebarFocusItems, sidebarReviewAchievements, sidebarReviewReflections, sidebarFeedItems, topbarFeedItems, sidebarCollapsedModules @@ -211,16 +211,6 @@ function renderMarkdown(content: string) {