From 139e0d59edaaf51da1ecd6072013ce8d8a7a5ddf Mon Sep 17 00:00:00 2001 From: yanweidong Date: Sun, 26 Jul 2026 00:09:33 +0800 Subject: [PATCH] feat(desktop): open project documents by type --- apps/desktop/scripts/visual-check.mjs | 9 ++++++-- apps/desktop/src-tauri/tauri.conf.json | 2 +- apps/desktop/src/App.tsx | 29 +++++++++++++++++--------- apps/desktop/src/api.ts | 18 ++++++++++++++++ apps/desktop/src/styles.css | 2 ++ 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/apps/desktop/scripts/visual-check.mjs b/apps/desktop/scripts/visual-check.mjs index 794025c..7c2b7c3 100644 --- a/apps/desktop/scripts/visual-check.mjs +++ b/apps/desktop/scripts/visual-check.mjs @@ -32,6 +32,7 @@ await page.route('http://localhost:9150/api/v1/**', async (route) => { if (path === '/api/v1/auth/me') return route.fulfill({ json: user }) if (path === '/api/v1/projects') return route.fulfill({ json: [workspace.project] }) if (path === `/api/v1/projects/${projectId}/workspace`) return route.fulfill({ json: workspace }) + if (path === `/api/v1/projects/${projectId}/documents/doc-1`) return route.fulfill({ json: { ...workspace.documents[0], revision: 1, markdown: '# 版本规划\n\n记录交付安排。', hasBlob: false, size: 32, createdAt: '2026-07-22T10:00:00Z' } }) if (path === '/api/v1/ai-experts') return route.fulfill({ json: [expert] }) if (path === '/api/v1/dataset-sources') return route.fulfill({ json: [datasetSource] }) if (path === '/api/v1/dataset-items') return route.fulfill({ json: { items: [datasetItem], total: 1, limit: 50, offset: 0 } }) @@ -65,6 +66,10 @@ await page.getByRole('option', { name: '森林项目' }).click() await page.waitForSelector('.channel-rail') await page.locator('.channel-rail button[title="资料"]').click() const documents = await page.locator('.detail-row').count() +await page.locator('.document-row').first().click() +await page.waitForSelector('.markdown-editor-page') +const markdownEditing = await page.locator('.markdown-editor-page').count() +await page.locator('.markdown-editor-page .content-heading .arco-btn').click() const documentActions = await page.locator('.document-actions .arco-btn').count() await page.locator('.document-actions .arco-btn').nth(1).click() await page.waitForSelector('.markdown-editor-page') @@ -99,9 +104,9 @@ if (home.pending !== 1 || home.completed !== 0) failures.push(`all-project task if (taskModal !== 1) failures.push('task editor did not open') if (exploreSources !== 2 || exploreDetail !== 1) failures.push(`explore reader did not render: ${JSON.stringify({ exploreSources, exploreDetail })}`) if (documents !== 1) failures.push(`expected one document, got ${documents}`) -if (documentActions !== 2 || markdownEditor !== 1) failures.push(`document actions did not render: ${JSON.stringify({ documentActions, markdownEditor })}`) +if (documentActions !== 2 || markdownEditor !== 1 || markdownEditing !== 1) failures.push(`document actions did not render: ${JSON.stringify({ documentActions, markdownEditor, markdownEditing })}`) if (experts !== 1 || aiSwitches !== 2 || aiHistory !== 1) failures.push(`AI session pages did not render: ${JSON.stringify({ experts, aiSwitches, aiHistory })}`) if (profileMenu !== 1) failures.push('profile menu did not open') if (errors.length) failures.push(`console errors: ${errors.join('; ')}`) -console.log(JSON.stringify({ home, documents, documentActions, markdownEditor, markdownLayout, experts, aiSwitches, aiHistory, taskModal, exploreSources, exploreDetail, profileMenu, errors }, null, 2)) +console.log(JSON.stringify({ home, documents, documentActions, markdownEditor, markdownEditing, markdownLayout, experts, aiSwitches, aiHistory, taskModal, exploreSources, exploreDetail, profileMenu, errors }, null, 2)) if (failures.length) throw new Error(failures.join('\n')) diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index d8b67a4..586f5c8 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -25,7 +25,7 @@ } ], "security": { - "csp": "default-src 'self'; img-src 'self' asset: https: data:; style-src 'self' 'unsafe-inline'; connect-src http: https:" + "csp": "default-src 'self' blob:; img-src 'self' asset: https: data:; style-src 'self' 'unsafe-inline'; connect-src http: https:" } }, "bundle": { diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 3eab0a5..a7aaf31 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -6,10 +6,10 @@ import { IconSun, IconUpload, IconUser, } from '@arco-design/web-react/icon' import { - ApiError, createAISession, createMarkdownDocument, createProject, fetchProjectWorkspace, fetchProjects, getCurrentUser, - listAIExperts, listDatasetItems, listDatasetSources, login, setApiBaseUrl, updateCurrentUser, updateTask, + ApiError, createAISession, createMarkdownDocument, createProject, fetchDocumentBlob, fetchProjectWorkspace, fetchProjects, getCurrentUser, getDocument, + listAIExperts, listDatasetItems, listDatasetSources, login, setApiBaseUrl, updateCurrentUser, updateDocument, updateTask, uploadDocument, - type ApiSession, type CurrentUser, type DatasetItem, type DatasetSource, type Expert, type Project, type Workspace, type WorkspaceTask, + type ApiSession, type CurrentUser, type DatasetItem, type DatasetSource, type DocumentDetail, type Expert, type Project, type Workspace, type WorkspaceDocument, type WorkspaceTask, } from './api' const { Text, Title } = Typography @@ -115,7 +115,7 @@ export function App() { {error ? setError('')} /> : null} -
{workspaceMode === 'explore' ? : !projectId ? setProjectModalOpen(true)} /> : visibleWorkspaces.length ? { await uploadDocument(session, projectId, file); await loadWorkspaces() }} onCreateMarkdown={async (input) => { await createMarkdownDocument(session, projectId, input); await loadWorkspaces() }} onCreateAISession={async (input) => { await createAISession(session, projectId, input); await loadWorkspaces() }} /> : }
+
{workspaceMode === 'explore' ? : !projectId ? setProjectModalOpen(true)} /> : visibleWorkspaces.length ? { await uploadDocument(session, projectId, file); await loadWorkspaces() }} onCreateMarkdown={async (input) => { await createMarkdownDocument(session, projectId, input); await loadWorkspaces() }} onLoadMarkdown={(documentId) => getDocument(session, projectId, documentId)} onUpdateMarkdown={async (input) => { await updateDocument(session, projectId, input.id, input); await loadWorkspaces() }} onOpenExternalDocument={async (documentId) => { const preview = window.open('', '_blank'); const blob = await fetchDocumentBlob(session, projectId, documentId); const url = URL.createObjectURL(blob); if (preview) { preview.opener = null; preview.location.href = url } else { const link = document.createElement('a'); link.href = url; link.target = '_blank'; link.rel = 'noopener noreferrer'; link.click() } window.setTimeout(() => URL.revokeObjectURL(url), 60_000) }} onCreateAISession={async (input) => { await createAISession(session, projectId, input); await loadWorkspaces() }} /> : }
{projectId && workspaceMode === 'workbench' ?