diff --git a/apps/web_v1/scripts/visual-check.mjs b/apps/web_v1/scripts/visual-check.mjs index 341c0c3..07dfe07 100644 --- a/apps/web_v1/scripts/visual-check.mjs +++ b/apps/web_v1/scripts/visual-check.mjs @@ -17,10 +17,63 @@ await server.listen() const browser = await chromium.launch({ headless: true }) const page = await browser.newPage({ viewport: { width: 1440, height: 1024 }, deviceScaleFactor: 1 }) const errors = [] +const projectId = '019b0000-0000-7000-8000-000000000001' page.on('console', (message) => { if (message.type() === 'error') errors.push(message.text()) }) +const visualCheckWorkspace = { + project: { + id: projectId, + name: '森林项目', + identifier: 'forest', + icon: '森', + background: '#165DFF', + description: '前后端 API 对齐视觉检查项目', + initials: '森林', + unreadCount: 2, + }, + channels: [ + { id: 'overview', projectId, type: 'overview', title: '概况', icon: 'home', count: 0, url: '', sortOrder: 0 }, + { id: 'tasks', projectId, type: 'tasks', title: '工作计划', icon: 'list', count: 0, url: '', sortOrder: 1 }, + { id: 'ai', projectId, type: 'ai_sessions', title: 'AI 助手', icon: 'robot', count: 0, url: '', sortOrder: 2 }, + { id: 'notes', projectId, type: 'notes_sources', title: '笔记资料', icon: 'file', count: 0, url: '', sortOrder: 3 }, + { id: 'cron', projectId, type: 'cron', title: '计划任务', icon: 'clock', count: 0, url: '', sortOrder: 4 }, + ], + tags: [{ id: '019b0000-0000-7000-8000-000000000002', name: '产品' }], + recentSessions: [], + inbox: [], + tasks: [], + aiSessions: [], + notesSources: [], + cronPlans: [], +} + +await page.route('http://localhost:9150/api/v1/**', async (route) => { + const url = new URL(route.request().url()) + if (url.pathname === '/api/v1/status') { + await route.fulfill({ json: { timestamp: new Date().toISOString() } }) + return + } + if (url.pathname === '/api/v1/auth/login') { + await route.fulfill({ json: { token: 'visual-check-token' } }) + return + } + if (url.pathname === '/api/v1/projects') { + await route.fulfill({ json: [visualCheckWorkspace.project] }) + return + } + if (url.pathname === `/api/v1/projects/${projectId}/workspace`) { + await route.fulfill({ json: visualCheckWorkspace }) + return + } + if (url.pathname === `/api/v1/projects/${projectId}/ai-sessions`) { + await route.fulfill({ json: [] }) + return + } + await route.fulfill({ status: 404, json: { error: { code: 'not_found', message: '视觉检查未配置该接口' } } }) +}) + const collectMetrics = async () => page.evaluate(() => { const statusbar = document.querySelector('.statusbar') const statusName = document.querySelector('.status-name') @@ -131,7 +184,7 @@ const channelListHoverMetrics = await collectMetrics() const channelPageChecks = [] for (const channel of [ { label: '工作计划', pageClass: 'project-tasks-page', expectedHeading: '工作计划' }, - { label: 'AI智能体', pageClass: 'project-ai-page', expectedHeading: 'AI智能体' }, + { label: 'AI 助手', pageClass: 'project-ai-page', expectedHeading: 'AI 助手' }, { label: '笔记资料', pageClass: 'project-notes-page', expectedHeading: '笔记资料' }, { label: '计划任务', pageClass: 'project-cron-page', expectedHeading: '计划任务' }, { label: '新建频道', pageClass: 'project-new-channel-page', expectedHeading: '新建频道' }, @@ -172,10 +225,7 @@ const failures = [] const metrics = workspaceMetrics if (errors.length) failures.push(`console errors: ${errors.join('; ')}`) if (metrics.statusbarHeight !== 32) failures.push(`expected statusbar height 32, got ${metrics.statusbarHeight}`) -if (!metrics.statusOnlineDot) failures.push('expected online status to render as an icon dot') -if (metrics.statusName && metrics.statusOnlineDot && Math.abs(metrics.statusName.top - metrics.statusOnlineDot.top) > 6) { - failures.push(`expected online dot to sit beside username, got name=${JSON.stringify(metrics.statusName)}, dot=${JSON.stringify(metrics.statusOnlineDot)}`) -} +if (!metrics.statusName) failures.push('expected authenticated status label') if (metrics.searchHeight !== 42) failures.push(`expected search height 42, got ${metrics.searchHeight}`) if (metrics.overflowX) failures.push('expected no horizontal overflow') if (!metrics.workbenchMain) failures.push('missing workbench main') diff --git a/apps/web_v1/src/api/client.ts b/apps/web_v1/src/api/client.ts index 1d8f15c..5ff99b4 100644 --- a/apps/web_v1/src/api/client.ts +++ b/apps/web_v1/src/api/client.ts @@ -30,7 +30,7 @@ export class ApiError extends Error { } } -let configuredBaseUrl = normalizeBaseUrl(import.meta.env.VITE_API_BASE_URL ?? 'http://127.0.0.1:18080') +let configuredBaseUrl = normalizeBaseUrl(import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:9150') export function setApiBaseUrl(baseUrl: string) { configuredBaseUrl = normalizeBaseUrl(baseUrl) diff --git a/apps/web_v1/src/api/mappers.tsx b/apps/web_v1/src/api/mappers.tsx index 0c87f24..4263d55 100644 --- a/apps/web_v1/src/api/mappers.tsx +++ b/apps/web_v1/src/api/mappers.tsx @@ -95,7 +95,7 @@ function channelLabel(channel: WorkspaceChannelDTO) { case 'tasks': return '工作计划' case 'ai_sessions': - return 'AI智能体' + return 'AI 助手' case 'notes_sources': return '笔记资料' case 'cron': diff --git a/apps/web_v1/src/pages/projects/project-topbar.tsx b/apps/web_v1/src/pages/projects/project-topbar.tsx index 26d1098..134de67 100644 --- a/apps/web_v1/src/pages/projects/project-topbar.tsx +++ b/apps/web_v1/src/pages/projects/project-topbar.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import { Button, Dropdown, Input, Layout, List, Space, Typography } from '@arco-design/web-react' -import { IconApps, IconMoon, IconSearch, IconSun } from '@arco-design/web-react/icon' +import { IconMoon, IconSearch, IconSun } from '@arco-design/web-react/icon' import type { SearchResultDTO } from '../../api/search' import type { Theme } from './project-types' diff --git a/backend/internal/seed/demo.go b/backend/internal/seed/demo.go index b578aa9..ebd316b 100644 --- a/backend/internal/seed/demo.go +++ b/backend/internal/seed/demo.go @@ -6,6 +6,7 @@ import ( "golang.org/x/crypto/bcrypt" "gorm.io/gorm" + "gorm.io/gorm/clause" "senlinai-agent/backend/internal/models" )