From d6395d3c640228ab2f931abc223f1a17d74d2db4 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Tue, 21 Jul 2026 01:00:27 +0800 Subject: [PATCH] feat: reorganize project task planning UI --- apps/senlinai-acro-react/src/App.css | 92 +++++++++++ apps/senlinai-acro-react/src/api/mappers.tsx | 2 + apps/senlinai-acro-react/src/api/projects.ts | 2 + apps/senlinai-acro-react/src/app/App.tsx | 1 - .../pages/projects/project-action-modals.tsx | 9 +- .../pages/projects/project-channel-page.tsx | 4 +- .../src/pages/projects/project-notes.tsx | 15 -- .../src/pages/projects/project-sidebar.tsx | 65 +------- .../src/pages/projects/project-tasks.tsx | 144 +++++++++++------- .../src/pages/projects/project-types.ts | 2 + .../src/pages/workspace-body.tsx | 21 ++- .../src/pages/workspace-home.tsx | 2 +- backend/internal/logic/projects/service.go | 63 ++++++-- 13 files changed, 251 insertions(+), 171 deletions(-) diff --git a/apps/senlinai-acro-react/src/App.css b/apps/senlinai-acro-react/src/App.css index 6d814d2..f02eb9f 100644 --- a/apps/senlinai-acro-react/src/App.css +++ b/apps/senlinai-acro-react/src/App.css @@ -1044,6 +1044,98 @@ padding: 10px; } +.task-tag-section .arco-card-body { + padding: 12px; +} + +.task-plan-card-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 12px; +} + +.task-plan-card { + min-height: 138px; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 10px; + border: 1px solid var(--senlin-border); + border-radius: 6px; + background: var(--senlin-surface); + color: var(--senlin-text); + padding: 14px; + text-align: left; + cursor: pointer; + transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease; +} + +.task-plan-card:hover { + border-color: color-mix(in srgb, var(--senlin-primary) 42%, var(--senlin-border)); + box-shadow: 0 8px 22px color-mix(in srgb, var(--senlin-primary) 12%, transparent); + transform: translateY(-1px); +} + +.task-plan-title, +.completed-plan-title { + min-width: 0; + display: flex; + align-items: center; + gap: 8px; + color: var(--senlin-text); + font-weight: 600; +} + +.task-plan-title svg, +.completed-plan-title svg { + color: var(--senlin-primary); +} + +.task-plan-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px 10px; + color: var(--senlin-muted); + font-size: 12px; +} + +.completed-plan-row { + width: 100%; + display: grid; + grid-template-columns: minmax(260px, 1fr) 120px 120px 86px; + align-items: center; + gap: 14px; + border: 0; + border-top: 1px solid var(--senlin-border); + background: transparent; + color: var(--senlin-muted); + padding: 10px 0; + text-align: left; + cursor: pointer; +} + +.completed-plan-row:first-of-type { + border-top: 0; +} + +.completed-plan-row:hover { + background: color-mix(in srgb, var(--senlin-primary) 5%, transparent); +} + +.completed-plan-main { + min-width: 0; + display: grid; + gap: 3px; +} + +.completed-plan-row > span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .chat-thread { display: grid; gap: 12px; diff --git a/apps/senlinai-acro-react/src/api/mappers.tsx b/apps/senlinai-acro-react/src/api/mappers.tsx index 7af92eb..a1e0135 100644 --- a/apps/senlinai-acro-react/src/api/mappers.tsx +++ b/apps/senlinai-acro-react/src/api/mappers.tsx @@ -145,6 +145,8 @@ function mapTask(task: BackendTask): TaskItem { progress: task.completed ? '100%' : '60%', due: task.due || '未设置', createdAt: formatCreatedAt(task.createdAt), + completedAt: task.completedAt ? formatCreatedAt(task.completedAt) : '', + duration: task.duration || '', tag: task.tag || (task.completed ? '已完成' : '进行中'), summary: task.summary, completed: task.completed, diff --git a/apps/senlinai-acro-react/src/api/projects.ts b/apps/senlinai-acro-react/src/api/projects.ts index 0ddab47..7217a7f 100644 --- a/apps/senlinai-acro-react/src/api/projects.ts +++ b/apps/senlinai-acro-react/src/api/projects.ts @@ -55,6 +55,8 @@ export type BackendTask = { owner: string due: string createdAt: string + completedAt: string + duration: string tag: string } diff --git a/apps/senlinai-acro-react/src/app/App.tsx b/apps/senlinai-acro-react/src/app/App.tsx index 92fe876..9bda1a9 100644 --- a/apps/senlinai-acro-react/src/app/App.tsx +++ b/apps/senlinai-acro-react/src/app/App.tsx @@ -134,7 +134,6 @@ function App() { title: draft.title.trim(), description: draft.description.trim(), status: 'open', - dueAt: normalizeOptionalTime(draft.dueAt), tag: draft.tag.trim(), }) await refreshAfterAction() diff --git a/apps/senlinai-acro-react/src/pages/projects/project-action-modals.tsx b/apps/senlinai-acro-react/src/pages/projects/project-action-modals.tsx index d2ce6a7..c84702f 100644 --- a/apps/senlinai-acro-react/src/pages/projects/project-action-modals.tsx +++ b/apps/senlinai-acro-react/src/pages/projects/project-action-modals.tsx @@ -17,7 +17,6 @@ export type ProjectDraft = { export type TaskDraft = { title: string description: string - dueAt: string tag: string } @@ -53,14 +52,14 @@ export function ProjectActionModals({ tagOptions: string[] }) { const [project, setProject] = useState({ name: '', identifier: '', icon: '', background: '', description: '' }) - const [task, setTask] = useState({ title: '', description: '', dueAt: '', tag: '' }) + const [task, setTask] = useState({ title: '', description: '', tag: '' }) const [source, setSource] = useState({ title: '', file: null }) const [cron, setCron] = useState({ title: '', schedule: '0 9 * * *', enabled: true, nextRunAt: '' }) useEffect(() => { if (activeModal === null) { setProject({ name: '', identifier: '', icon: '', background: '', description: '' }) - setTask({ title: '', description: '', dueAt: '', tag: '' }) + setTask({ title: '', description: '', tag: '' }) setSource({ title: '', file: null }) setCron({ title: '', schedule: '0 9 * * *', enabled: true, nextRunAt: '' }) } @@ -117,10 +116,6 @@ export function ProjectActionModals({ 任务说明