Initial MVP for QA asset backend

This commit is contained in:
2026-07-05 17:44:15 +08:00
commit 95b5e09fd4
71 changed files with 6546 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
"use client";
import { useEffect, useState } from "react";
import { useParams } from "next/navigation";
import { api } from "@/lib/api";
import type { FeishuSession, RawQAItem } from "@/lib/types";
import RiskBadge from "@/components/RiskBadge";
import StatusBadge from "@/components/StatusBadge";
export default function SessionDetailPage() {
const params = useParams<{ id: string }>();
const [session, setSession] = useState<FeishuSession | null>(null);
const [items, setItems] = useState<RawQAItem[]>([]);
useEffect(() => {
async function load() {
const id = Number(params.id);
const [sessionData, rawData] = await Promise.all([
api.get<FeishuSession>(`/sessions/${id}`),
api.get<RawQAItem[]>(`/raw-qa?session_id=${id}`)
]);
setSession(sessionData);
setItems(rawData);
}
load();
}, [params.id]);
if (!session) return <div className="text-sm text-slate-500">...</div>;
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">{session.title}</h1>
<p className="mt-1 text-sm text-slate-500">
{session.session_code} / {session.date ?? "-"} / {session.teachers ?? "-"}
</p>
</div>
<StatusBadge status={session.process_status} />
</div>
<div className="rounded-md border border-line bg-white p-4">
<div className="mb-3 text-sm font-semibold text-ink"></div>
<pre className="max-h-96 overflow-auto whitespace-pre-wrap rounded-md bg-panel p-4 text-sm leading-6 text-slate-700">
{session.source_text || "暂无原始资料"}
</pre>
</div>
<div className="space-y-3">
{items.map((item) => (
<div key={item.id} className="rounded-md border border-line bg-white p-4">
<div className="mb-3 flex flex-wrap items-center gap-2">
<span className="text-sm font-semibold">{item.qa_code}</span>
<RiskBadge level={item.risk_level} />
<StatusBadge status={item.review_status} />
</div>
<div className="grid gap-4 lg:grid-cols-2">
<div>
<div className="text-xs text-slate-500"></div>
<div className="mt-1 text-sm leading-6">{item.raw_question}</div>
</div>
<div>
<div className="text-xs text-slate-500"></div>
<div className="mt-1 text-sm leading-6">{item.raw_answer}</div>
</div>
</div>
</div>
))}
</div>
</div>
);
}