2026-07-20 12:26:21 +08:00
|
|
|
import { Button, Card, Progress, Space, Tag, Typography } from '@arco-design/web-react'
|
|
|
|
|
import { IconCalendar, IconCheckCircle, IconPlus, IconUser } from '@arco-design/web-react/icon'
|
2026-07-20 13:02:26 +08:00
|
|
|
import type { ProjectWorkspace, TaskItem } from './project-types'
|
2026-07-20 12:26:21 +08:00
|
|
|
|
|
|
|
|
const { Title, Text } = Typography
|
|
|
|
|
|
2026-07-20 13:02:26 +08:00
|
|
|
export function ProjectTasks({ activeWorkspace, onSelectItem }: { activeWorkspace: ProjectWorkspace; onSelectItem: (title: string) => void }) {
|
|
|
|
|
const { tasks, project } = activeWorkspace
|
|
|
|
|
const lanes = makeLanes(tasks)
|
2026-07-20 12:26:21 +08:00
|
|
|
return (
|
|
|
|
|
<div className="project-channel-page project-tasks-page overview-page">
|
|
|
|
|
<div className="overview-head">
|
|
|
|
|
<div>
|
|
|
|
|
<Title heading={4}>工作计划</Title>
|
2026-07-20 13:02:26 +08:00
|
|
|
<Text type="secondary">{project.name} 的 TODO 计划、负责人和截止时间。</Text>
|
2026-07-20 12:26:21 +08:00
|
|
|
</div>
|
|
|
|
|
<Button type="primary" icon={<IconPlus />}>新建任务</Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Card className="queue-section" bordered>
|
|
|
|
|
<div className="section-header">
|
|
|
|
|
<Title heading={6}>任务清单</Title>
|
|
|
|
|
<Tag color="arcoblue">{tasks.length} 个进行中</Tag>
|
|
|
|
|
</div>
|
|
|
|
|
{tasks.map((task) => (
|
|
|
|
|
<button className="data-row task-row" key={task.title} onClick={() => onSelectItem(task.title)}>
|
|
|
|
|
<span className="row-title"><IconCheckCircle /> {task.title}</span>
|
|
|
|
|
<Tag color="arcoblue">{task.tag}</Tag>
|
|
|
|
|
<span><IconUser /> {task.owner}</span>
|
|
|
|
|
<span><IconCalendar /> {task.due}</span>
|
|
|
|
|
<Progress percent={Number.parseInt(task.progress, 10)} size="small" />
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<div className="task-board">
|
|
|
|
|
{lanes.map((lane) => (
|
|
|
|
|
<Card className="task-lane" bordered key={lane.title}>
|
|
|
|
|
<div className="section-header">
|
|
|
|
|
<Title heading={6}>{lane.title}</Title>
|
|
|
|
|
<Tag color={lane.color}>{lane.items.length}</Tag>
|
|
|
|
|
</div>
|
|
|
|
|
<Space direction="vertical" size={8}>
|
|
|
|
|
{lane.items.map((title) => (
|
|
|
|
|
<button className="task-card-button" key={title} onClick={() => onSelectItem(title)}>
|
|
|
|
|
<Text>{title}</Text>
|
|
|
|
|
<Text type="secondary">优先级 · 本周</Text>
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</Space>
|
|
|
|
|
</Card>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
2026-07-20 13:02:26 +08:00
|
|
|
|
|
|
|
|
function makeLanes(tasks: TaskItem[]) {
|
|
|
|
|
const done = tasks.filter((task) => task.completed)
|
|
|
|
|
const active = tasks.filter((task) => !task.completed)
|
|
|
|
|
return [
|
|
|
|
|
{ title: '待开始', color: 'gray', items: active.slice(0, 1).map((task) => task.title) },
|
|
|
|
|
{ title: '进行中', color: 'arcoblue', items: active.map((task) => task.title) },
|
|
|
|
|
{ title: '已完成', color: 'green', items: done.length ? done.map((task) => task.title) : ['暂无已完成任务'] },
|
|
|
|
|
]
|
|
|
|
|
}
|