feat: sync Sidebar and BottomNav, standardize user profile API
Align Sidebar & BottomNav menus, remove "Search", add user profile mock data, implement /api/users, add FilterDrawer, complete Section, ProfileHeader, MetricsRFM components Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
87
components/ai-assistant/task-list.tsx
Normal file
87
components/ai-assistant/task-list.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect } from "react"
|
||||
import type { AnalysisTask } from "@/types/ai-assistant"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
function statusBadgeClass(status: AnalysisTask["status"]) {
|
||||
const map: Record<AnalysisTask["status"], string> = {
|
||||
completed: "text-green-600 bg-green-50 border-green-200",
|
||||
running: "text-blue-600 bg-blue-50 border-blue-200",
|
||||
pending: "text-yellow-600 bg-yellow-50 border-yellow-200",
|
||||
failed: "text-red-600 bg-red-50 border-red-200",
|
||||
}
|
||||
return map[status]
|
||||
}
|
||||
|
||||
export default function TaskList({
|
||||
tasks,
|
||||
onTick,
|
||||
}: {
|
||||
tasks: AnalysisTask[]
|
||||
onTick?: () => void
|
||||
}) {
|
||||
// 进度模拟:外部可传递 onTick 驱动
|
||||
useEffect(() => {
|
||||
if (!onTick) return
|
||||
const timer = setInterval(() => onTick(), 1200)
|
||||
return () => clearInterval(timer)
|
||||
}, [onTick])
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
{tasks.map((task) => (
|
||||
<Card key={task.id} className="border-2 hover:shadow-lg transition-all duration-200">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-lg">{task.name}</CardTitle>
|
||||
<Badge className={`${statusBadgeClass(task.status)} border`}>
|
||||
{task.status === "pending"
|
||||
? "等待中"
|
||||
: task.status === "running"
|
||||
? "分析中"
|
||||
: task.status === "completed"
|
||||
? "已完成"
|
||||
: "失败"}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600">数据源: {task.database}</p>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{task.description && <p className="text-sm text-gray-700">{task.description}</p>}
|
||||
|
||||
<div className="w-full bg-gray-200 rounded-full h-2.5" aria-label="任务进度">
|
||||
<div
|
||||
className={`h-2.5 rounded-full ${
|
||||
task.status === "completed"
|
||||
? "bg-green-600"
|
||||
: task.status === "running"
|
||||
? "bg-blue-600"
|
||||
: task.status === "failed"
|
||||
? "bg-red-600"
|
||||
: "bg-gray-400"
|
||||
}`}
|
||||
style={{ width: `${task.progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-gray-500">
|
||||
创建于 {new Date(task.createdAt).toLocaleString("zh-CN")}
|
||||
{task.completedAt && <> · 完成于 {new Date(task.completedAt).toLocaleString("zh-CN")}</>}
|
||||
</div>
|
||||
|
||||
{task.reportUrl && (
|
||||
<div className="flex justify-end">
|
||||
<Button asChild variant="outline" size="sm" aria-label="查看报告">
|
||||
<a href={task.reportUrl}>查看报告</a>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user