mirror of
https://github.com/massbug/judge4c.git
synced 2026-05-20 13:18:52 +00:00
feat(problem-management): add localized problem title column in user table
This commit is contained in:
parent
318249d20e
commit
8473d6ed61
@ -2,7 +2,8 @@ import prisma from "@/lib/prisma";
|
||||
import { UserTable } from "./user-table";
|
||||
import { Role } from "@/generated/client";
|
||||
import { UserConfig } from "./user-table";
|
||||
import type { User, Problem } from "@/generated/client";
|
||||
import type { User } from "@/generated/client";
|
||||
import { getLocale } from "next-intl/server";
|
||||
|
||||
interface GenericPageProps {
|
||||
resourceType: "admin" | "teacher" | "student" | "problem";
|
||||
@ -14,7 +15,28 @@ export default async function GenericPage({
|
||||
config,
|
||||
}: GenericPageProps) {
|
||||
if (resourceType === "problem") {
|
||||
const data: Problem[] = await prisma.problem.findMany({});
|
||||
const locale = await getLocale();
|
||||
const problems = await prisma.problem.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
displayId: true,
|
||||
difficulty: true,
|
||||
localizations: {
|
||||
where: { type: "TITLE", locale: locale === "en" ? "en" : "zh" },
|
||||
select: { content: true },
|
||||
take: 1,
|
||||
},
|
||||
},
|
||||
orderBy: { displayId: "asc" },
|
||||
});
|
||||
|
||||
const data = problems.map((problem) => ({
|
||||
id: problem.id,
|
||||
displayId: problem.displayId,
|
||||
difficulty: problem.difficulty,
|
||||
title: problem.localizations[0]?.content ?? "-",
|
||||
}));
|
||||
|
||||
return <UserTable config={config} data={data} />;
|
||||
} else {
|
||||
const role = resourceType.toUpperCase() as Role;
|
||||
|
||||
@ -65,6 +65,7 @@ import { Label } from "@/components/ui/label";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Difficulty, Role } from "@/generated/client";
|
||||
import type { User, Problem } from "@/generated/client";
|
||||
import {
|
||||
@ -110,7 +111,11 @@ export interface UserConfig {
|
||||
|
||||
type UserTableProps =
|
||||
| { config: UserConfig; data: User[] }
|
||||
| { config: UserConfig; data: Problem[] };
|
||||
| { config: UserConfig; data: ProblemRow[] };
|
||||
|
||||
type ProblemRow = Pick<Problem, "id" | "displayId" | "difficulty"> & {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type UserForm = {
|
||||
id?: string;
|
||||
@ -154,13 +159,14 @@ const addProblemSchema = z.object({
|
||||
});
|
||||
|
||||
export function UserTable(props: UserTableProps) {
|
||||
const tDifficulty = useTranslations("Difficulty");
|
||||
const isProblem = props.config.resourceType === "problem";
|
||||
const router = useRouter();
|
||||
const problemData = isProblem ? (props.data as Problem[]) : undefined;
|
||||
const problemData = isProblem ? (props.data as ProblemRow[]) : undefined;
|
||||
|
||||
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
||||
const [editingUser, setEditingUser] = useState<User | Problem | null>(null);
|
||||
const [editingUser, setEditingUser] = useState<User | ProblemRow | null>(null);
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [deleteBatch, setDeleteBatch] = useState(false);
|
||||
const [rowSelection, setRowSelection] = useState({});
|
||||
@ -174,15 +180,15 @@ export function UserTable(props: UserTableProps) {
|
||||
const [pageInput, setPageInput] = useState(pagination.pageIndex + 1);
|
||||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
||||
const [pendingDeleteItem, setPendingDeleteItem] = useState<
|
||||
User | Problem | null
|
||||
User | ProblemRow | null
|
||||
>(null);
|
||||
useEffect(() => {
|
||||
setPageInput(pagination.pageIndex + 1);
|
||||
}, [pagination.pageIndex]);
|
||||
|
||||
// 表格列
|
||||
const tableColumns = React.useMemo<ColumnDef<User | Problem>[]>(() => {
|
||||
const columns: ColumnDef<User | Problem>[] = [
|
||||
const tableColumns = React.useMemo<ColumnDef<User | ProblemRow>[]>(() => {
|
||||
const columns: ColumnDef<User | ProblemRow>[] = [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => (
|
||||
@ -206,13 +212,20 @@ export function UserTable(props: UserTableProps) {
|
||||
},
|
||||
];
|
||||
props.config.columns.forEach((col) => {
|
||||
const column: ColumnDef<User | Problem> = {
|
||||
const column: ColumnDef<User | ProblemRow> = {
|
||||
accessorKey: col.key,
|
||||
header: col.label,
|
||||
cell: ({ row }) => {
|
||||
// 类型安全分流
|
||||
if (col.key === "displayId" && isProblem) {
|
||||
return (row.original as Problem).displayId;
|
||||
return (row.original as ProblemRow).displayId;
|
||||
}
|
||||
if (col.key === "title" && isProblem) {
|
||||
return (row.original as ProblemRow).title;
|
||||
}
|
||||
if (col.key === "difficulty" && isProblem) {
|
||||
const difficulty = String(row.getValue(col.key)) as Difficulty;
|
||||
return tDifficulty(difficulty);
|
||||
}
|
||||
if (col.key === "createdAt" || col.key === "updatedAt") {
|
||||
const value = row.getValue(col.key);
|
||||
@ -250,7 +263,7 @@ export function UserTable(props: UserTableProps) {
|
||||
onClick={() => {
|
||||
if (isProblem) {
|
||||
// 如果是problem类型,跳转到编辑路由,使用displayId
|
||||
const problem = item as Problem;
|
||||
const problem = item as ProblemRow;
|
||||
router.push(`/dashboard/admin/problems/${problem.id}/edit`);
|
||||
} else {
|
||||
// 如果是用户类型,打开编辑弹窗
|
||||
@ -280,7 +293,7 @@ export function UserTable(props: UserTableProps) {
|
||||
},
|
||||
});
|
||||
return columns;
|
||||
}, [props.config, router, isProblem]);
|
||||
}, [props.config, router, isProblem, tDifficulty]);
|
||||
|
||||
const table = useReactTable({
|
||||
data: props.data,
|
||||
@ -761,7 +774,7 @@ export function UserTable(props: UserTableProps) {
|
||||
}
|
||||
|
||||
// 用ref保证获取最新data
|
||||
const dataRef = React.useRef<User[] | Problem[]>(props.data);
|
||||
const dataRef = React.useRef<User[] | ProblemRow[]>(props.data);
|
||||
React.useEffect(() => {
|
||||
dataRef.current = props.data;
|
||||
}, [props.data]);
|
||||
@ -798,6 +811,7 @@ export function UserTable(props: UserTableProps) {
|
||||
createdAt: "创建时间",
|
||||
actions: "操作",
|
||||
displayId: "题目编号",
|
||||
title: "题目标题",
|
||||
difficulty: "难度",
|
||||
};
|
||||
return (
|
||||
@ -1065,7 +1079,7 @@ export function UserTable(props: UserTableProps) {
|
||||
table.getFilteredSelectedRowModel().rows;
|
||||
for (const row of selectedRows) {
|
||||
if (isProblem) {
|
||||
await deleteProblem((row.original as Problem).id);
|
||||
await deleteProblem((row.original as ProblemRow).id);
|
||||
} else {
|
||||
await deleteUser(
|
||||
props.config.resourceType as
|
||||
@ -1110,7 +1124,7 @@ export function UserTable(props: UserTableProps) {
|
||||
onClick={async () => {
|
||||
if (pendingDeleteItem) {
|
||||
if (isProblem) {
|
||||
await deleteProblem((pendingDeleteItem as Problem).id);
|
||||
await deleteProblem((pendingDeleteItem as ProblemRow).id);
|
||||
} else {
|
||||
await deleteUser(
|
||||
props.config.resourceType as "admin" | "teacher" | "student",
|
||||
|
||||
@ -3,6 +3,7 @@ import { z } from "zod";
|
||||
export const problemSchema = z.object({
|
||||
id: z.string(),
|
||||
displayId: z.number(),
|
||||
title: z.string().optional(),
|
||||
difficulty: z.string(),
|
||||
createdAt: z.string(),
|
||||
});
|
||||
@ -23,7 +24,6 @@ export const problemConfig = {
|
||||
title: "题目列表",
|
||||
apiPath: "/api/problem",
|
||||
columns: [
|
||||
{ key: "id", label: "ID", sortable: true },
|
||||
{
|
||||
key: "displayId",
|
||||
label: "题目编号",
|
||||
@ -31,6 +31,13 @@ export const problemConfig = {
|
||||
searchable: true,
|
||||
placeholder: "搜索编号",
|
||||
},
|
||||
{
|
||||
key: "title",
|
||||
label: "题目标题",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
placeholder: "搜索标题",
|
||||
},
|
||||
{
|
||||
key: "difficulty",
|
||||
label: "难度",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user