PMFlow/frontend/src/pages/SkillTasksPage.tsx

116 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Link, useParams } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import { ArrowLeft, ListTodo } from "lucide-react";
import { getUserSkillTasks } from "@/api/skill";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { toZhPriority, toZhStatus } from "@/lib/display";
import { formatBeijingDateTime } from "@/lib/datetime";
export default function SkillTasksPage() {
const { id: userId, skillId } = useParams();
const { data, isLoading, error, refetch } = useQuery({
queryKey: ["skill-tasks", userId, skillId],
queryFn: () => getUserSkillTasks(userId!, skillId!),
enabled: !!userId && !!skillId,
});
const items = data?.items ?? [];
const total = data?.total ?? items.length;
return (
<div className="space-y-6">
<div className="flex flex-wrap items-center gap-4">
<Button variant="ghost" size="icon" asChild>
<Link to={userId ? `/users/${userId}/profile` : "/users"}>
<ArrowLeft className="h-4 w-4" />
</Link>
</Button>
<div>
<h1 className="text-2xl font-bold tracking-tight">技能历史任务</h1>
<p className="text-muted-foreground">
用户 {userId} / 技能 {skillId}
</p>
</div>
</div>
<Card>
<CardHeader>
<CardTitle>任务列表 ({total})</CardTitle>
</CardHeader>
<CardContent>
{isLoading ? (
<p className="text-muted-foreground">加载中…</p>
) : error ? (
<div className="space-y-3">
<p className="text-destructive">
加载失败:{(error as Error).message || "请求异常"}
</p>
<Button variant="outline" size="sm" onClick={() => refetch()}>
重试
</Button>
</div>
) : items.length === 0 ? (
<div className="flex flex-col items-center py-10 text-center text-muted-foreground">
<ListTodo className="mb-3 h-10 w-10 opacity-60" />
<p>暂无历史任务</p>
<p className="mt-1 text-xs">
当前后端可能尚未提供技能历史任务接口,页面已兼容空数据。
</p>
</div>
) : (
<div className="overflow-x-auto [-webkit-overflow-scrolling:touch]">
<Table className="min-w-[720px]">
<TableHeader>
<TableRow>
<TableHead>任务</TableHead>
<TableHead>状态</TableHead>
<TableHead>优先级</TableHead>
<TableHead className="text-right">工时 (h)</TableHead>
<TableHead>更新时间</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{items.map((task) => (
<TableRow key={task.id}>
<TableCell>
<div>
<p className="font-medium">{task.title}</p>
{task.description && (
<p className="line-clamp-1 text-xs text-muted-foreground">
{task.description}
</p>
)}
</div>
</TableCell>
<TableCell>{toZhStatus(task.status)}</TableCell>
<TableCell>{toZhPriority(task.priority)}</TableCell>
<TableCell className="text-right">
{typeof task.estimated_hours === "number"
? task.estimated_hours.toFixed(1)
: "-"}
</TableCell>
<TableCell>
{task.updated_at
? formatBeijingDateTime(task.updated_at)
: "-"}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
</CardContent>
</Card>
</div>
);
}