Files

94 lines
3.9 KiB
TypeScript
Raw Permalink 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.
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import { AlertTriangle, CheckCircle2, Database, FileQuestion, Library, Play, Rows3, Timer } from "lucide-react";
import { api, formatDateTime } from "@/lib/api";
import type { DashboardSummary, TaskRun } from "@/lib/types";
import StatCard from "@/components/StatCard";
import StatusBadge from "@/components/StatusBadge";
export default function DashboardPage() {
const [summary, setSummary] = useState<DashboardSummary | null>(null);
const [loading, setLoading] = useState(true);
const [running, setRunning] = useState(false);
async function load() {
setLoading(true);
const data = await api.get<DashboardSummary>("/dashboard/summary");
setSummary(data);
setLoading(false);
}
async function runTask() {
setRunning(true);
await api.post<TaskRun>("/tasks/run-now", {});
await load();
setRunning(false);
}
useEffect(() => {
load().catch(() => setLoading(false));
}, []);
if (loading || !summary) {
return <div className="text-sm text-slate-500">...</div>;
}
const actions = [
{ href: "/review", label: "去审核" },
{ href: "/high-risk", label: "查看高风险" },
{ href: "/standard-qa", label: "查看标准问答库" },
{ href: "/logs", label: "查看运行日志" }
];
return (
<div className="space-y-6">
<div className="flex flex-wrap items-center justify-between gap-3">
<div>
<h1 className="text-2xl font-semibold text-ink"></h1>
<p className="mt-1 text-sm text-slate-500">{summary.last_task_time ? formatDateTime(summary.last_task_time) : "-"}</p>
</div>
<button
onClick={runTask}
disabled={running}
className="inline-flex h-10 items-center gap-2 rounded-md bg-jade px-4 text-sm font-medium text-white hover:bg-teal-800 disabled:opacity-60"
>
<Play className="h-4 w-4" aria-hidden />
{running ? "处理中" : "手动触发处理任务"}
</button>
</div>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
<StatCard title="昨晚处理答疑场次数" value={summary.processed_sessions} icon={<Timer className="h-5 w-5" />} />
<StatCard title="已拆解问答总数" value={summary.pending_review_count + summary.approved_qa_count} icon={<Rows3 className="h-5 w-5" />} tone="indigo" />
<StatCard title="待审核问答数" value={summary.pending_review_count} icon={<FileQuestion className="h-5 w-5" />} tone="amber" />
<StatCard title="高风险问答数" value={summary.high_risk_count} icon={<AlertTriangle className="h-5 w-5" />} tone="rose" />
<StatCard title="已审核问答数" value={summary.approved_qa_count} icon={<CheckCircle2 className="h-5 w-5" />} />
<StatCard title="标准问答数" value={summary.standard_qa_count} icon={<Library className="h-5 w-5" />} tone="indigo" />
<StatCard title="可被智能体调用问答数" value={summary.callable_qa_count} icon={<Database className="h-5 w-5" />} />
<div className="rounded-md border border-line bg-white p-4">
<div className="text-sm text-slate-500"></div>
<div className="mt-3">
{summary.last_task_status ? <StatusBadge status={summary.last_task_status} /> : <span className="text-sm text-slate-400"></span>}
</div>
{summary.last_task_error ? <p className="mt-3 text-sm text-rose-700">{summary.last_task_error}</p> : null}
</div>
</div>
<div className="flex flex-wrap gap-2">
{actions.map((action) => (
<Link
key={action.href}
href={action.href}
className="inline-flex h-10 items-center rounded-md border border-line bg-white px-4 text-sm font-medium text-ink hover:bg-slate-50"
>
{action.label}
</Link>
))}
</div>
</div>
);
}