diff --git a/prisma/migrations/20250619101509_beiyu/migration.sql b/prisma/migrations/20250619101509_beiyu/migration.sql
new file mode 100644
index 0000000..aeae9bf
--- /dev/null
+++ b/prisma/migrations/20250619101509_beiyu/migration.sql
@@ -0,0 +1,19 @@
+/*
+ Warnings:
+
+ - The values [GUEST] on the enum `Role` will be removed. If these variants are still used in the database, this will fail.
+
+*/
+-- AlterEnum
+BEGIN;
+CREATE TYPE "Role_new" AS ENUM ('ADMIN', 'TEACHER', 'GUEST');
+ALTER TABLE "User" ALTER COLUMN "role" DROP DEFAULT;
+ALTER TABLE "User" ALTER COLUMN "role" TYPE "Role_new" USING ("role"::text::"Role_new");
+ALTER TYPE "Role" RENAME TO "Role_old";
+ALTER TYPE "Role_new" RENAME TO "Role";
+DROP TYPE "Role_old";
+ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'GUEST';
+COMMIT;
+
+-- AlterTable
+ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'GUEST';
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 17488cd..067bfb6 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -10,6 +10,7 @@ generator client {
enum Role {
ADMIN
+ TEACHER
GUEST
}
diff --git a/src/api/problem.ts b/src/api/problem.ts
deleted file mode 100644
index 11cf54a..0000000
--- a/src/api/problem.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import type { Problem } from "@/types/problem";
-
-// 获取所有题目
-export async function getProblems(): Promise {
- const res = await fetch("/api/problem");
- if (!res.ok) throw new Error("获取题目失败");
- return res.json();
-}
-
-// 新建题目
-export async function createProblem(data: Partial): Promise {
- const res = await fetch("/api/problem", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(data),
- });
- if (!res.ok) throw new Error("新建题目失败");
- return res.json();
-}
-
-// 编辑题目
-export async function updateProblem(data: Partial): Promise {
- const res = await fetch("/api/problem", {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(data),
- });
- if (!res.ok) throw new Error("更新题目失败");
- return res.json();
-}
-
-// 删除题目
-export async function deleteProblem(id: string): Promise {
- const res = await fetch("/api/problem", {
- method: "DELETE",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ id }),
- });
- if (!res.ok) throw new Error("删除题目失败");
-}
\ No newline at end of file
diff --git a/src/api/user.ts b/src/api/user.ts
deleted file mode 100644
index f08cb61..0000000
--- a/src/api/user.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import type { UserBase } from "@/types/user";
-
-// 获取所有用户
-export async function getUsers(userType: string): Promise {
- const res = await fetch(`/api/user`);
- if (!res.ok) {
- const error = await res.json();
- throw new Error(error.error || "获取用户失败");
- }
- return res.json();
-}
-
-// 新建用户
-export async function createUser(userType: string, data: Partial): Promise {
- const res = await fetch(`/api/user`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(data),
- });
- if (!res.ok) {
- const error = await res.json();
- throw new Error(error.error || "新建用户失败");
- }
- return res.json();
-}
-
-// 更新用户
-export async function updateUser(userType: string, data: Partial): Promise {
- const res = await fetch(`/api/user`, {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(data),
- });
- if (!res.ok) {
- const error = await res.json();
- throw new Error(error.error || "更新用户失败");
- }
- return res.json();
-}
-
-// 删除用户
-export async function deleteUser(userType: string, id: string): Promise {
- const res = await fetch(`/api/user`, {
- method: "DELETE",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ id }),
- });
- if (!res.ok) {
- const error = await res.json();
- throw new Error(error.error || "删除用户失败");
- }
-}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/_actions/adminActions.ts b/src/app/(app)/usermanagement/_actions/adminActions.ts
new file mode 100644
index 0000000..9874ba1
--- /dev/null
+++ b/src/app/(app)/usermanagement/_actions/adminActions.ts
@@ -0,0 +1,23 @@
+'use server'
+import prisma from '@/lib/prisma'
+import { revalidatePath } from 'next/cache'
+import bcrypt from 'bcryptjs'
+
+export async function createAdmin(data) {
+ let password = data.password
+ if (password) {
+ password = await bcrypt.hash(password, 10)
+ }
+ await prisma.user.create({ data: { ...data, password, role: 'ADMIN' } })
+ revalidatePath('/usermanagement/admin')
+}
+
+export async function updateAdmin(id, data) {
+ await prisma.user.update({ where: { id }, data })
+ revalidatePath('/usermanagement/admin')
+}
+
+export async function deleteAdmin(id) {
+ await prisma.user.delete({ where: { id } })
+ revalidatePath('/usermanagement/admin')
+}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/_actions/guestActions.ts b/src/app/(app)/usermanagement/_actions/guestActions.ts
new file mode 100644
index 0000000..cb1cdd8
--- /dev/null
+++ b/src/app/(app)/usermanagement/_actions/guestActions.ts
@@ -0,0 +1,23 @@
+'use server'
+import prisma from '@/lib/prisma'
+import { revalidatePath } from 'next/cache'
+import bcrypt from 'bcryptjs'
+
+export async function createGuest(data) {
+ let password = data.password
+ if (password) {
+ password = await bcrypt.hash(password, 10)
+ }
+ await prisma.user.create({ data: { ...data, password, role: 'GUEST' } })
+ revalidatePath('/usermanagement/guest')
+}
+
+export async function updateGuest(id, data) {
+ await prisma.user.update({ where: { id }, data })
+ revalidatePath('/usermanagement/guest')
+}
+
+export async function deleteGuest(id) {
+ await prisma.user.delete({ where: { id } })
+ revalidatePath('/usermanagement/guest')
+}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/_actions/problemActions.ts b/src/app/(app)/usermanagement/_actions/problemActions.ts
new file mode 100644
index 0000000..6e682fa
--- /dev/null
+++ b/src/app/(app)/usermanagement/_actions/problemActions.ts
@@ -0,0 +1,18 @@
+'use server'
+import prisma from '@/lib/prisma'
+import { revalidatePath } from 'next/cache'
+
+export async function createProblem(data) {
+ await prisma.problem.create({ data })
+ revalidatePath('/usermanagement/problem')
+}
+
+export async function updateProblem(id, data) {
+ await prisma.problem.update({ where: { id }, data })
+ revalidatePath('/usermanagement/problem')
+}
+
+export async function deleteProblem(id) {
+ await prisma.problem.delete({ where: { id } })
+ revalidatePath('/usermanagement/problem')
+}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/_actions/teacherActions.ts b/src/app/(app)/usermanagement/_actions/teacherActions.ts
new file mode 100644
index 0000000..5326fce
--- /dev/null
+++ b/src/app/(app)/usermanagement/_actions/teacherActions.ts
@@ -0,0 +1,23 @@
+'use server'
+import prisma from '@/lib/prisma'
+import { revalidatePath } from 'next/cache'
+import bcrypt from 'bcryptjs'
+
+export async function createTeacher(data) {
+ let password = data.password
+ if (password) {
+ password = await bcrypt.hash(password, 10)
+ }
+ await prisma.user.create({ data: { ...data, password, role: 'TEACHER' } })
+ revalidatePath('/usermanagement/teacher')
+}
+
+export async function updateTeacher(id, data) {
+ await prisma.user.update({ where: { id }, data })
+ revalidatePath('/usermanagement/teacher')
+}
+
+export async function deleteTeacher(id) {
+ await prisma.user.delete({ where: { id } })
+ revalidatePath('/usermanagement/teacher')
+}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/admin/page.tsx b/src/app/(app)/usermanagement/admin/page.tsx
index fc631b5..d5e41dc 100644
--- a/src/app/(app)/usermanagement/admin/page.tsx
+++ b/src/app/(app)/usermanagement/admin/page.tsx
@@ -1,5 +1,8 @@
-import { UserManagement } from "@/features/user-management"
+import { UserTable } from '@/features/user-management/components/user-table'
+import { adminConfig } from '@/features/user-management/config/admin'
+import prisma from '@/lib/prisma'
-export default function Page() {
- return
+export default async function AdminPage() {
+ const data = await prisma.user.findMany({ where: { role: 'ADMIN' } })
+ return
}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/student/layout.tsx b/src/app/(app)/usermanagement/guest/layout.tsx
similarity index 64%
rename from src/app/(app)/usermanagement/student/layout.tsx
rename to src/app/(app)/usermanagement/guest/layout.tsx
index f5a6a03..a29c947 100644
--- a/src/app/(app)/usermanagement/student/layout.tsx
+++ b/src/app/(app)/usermanagement/guest/layout.tsx
@@ -1,5 +1,5 @@
import ProtectedLayout from "../_components/ProtectedLayout";
-export default function StudentLayout({ children }: { children: React.ReactNode }) {
+export default function GuestLayout({ children }: { children: React.ReactNode }) {
return {children};
}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/guest/page.tsx b/src/app/(app)/usermanagement/guest/page.tsx
new file mode 100644
index 0000000..b64edbf
--- /dev/null
+++ b/src/app/(app)/usermanagement/guest/page.tsx
@@ -0,0 +1,7 @@
+import { UserTable } from '@/features/user-management/components/user-table'
+import { guestConfig } from '@/features/user-management/config/guest'
+import prisma from '@/lib/prisma'
+export default async function GuestPage() {
+ const data = await prisma.user.findMany({ where: { role: 'GUEST' as any } })
+ return
+}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/problem/page.tsx b/src/app/(app)/usermanagement/problem/page.tsx
index 40af293..08bca0b 100644
--- a/src/app/(app)/usermanagement/problem/page.tsx
+++ b/src/app/(app)/usermanagement/problem/page.tsx
@@ -1,5 +1,8 @@
-import { UserManagement } from "@/features/user-management"
+import { UserTable } from '@/features/user-management/components/user-table'
+import { problemConfig } from '@/features/user-management/config/problem'
+import prisma from '@/lib/prisma'
-export default function Page() {
- return
+export default async function ProblemPage() {
+ const data = await prisma.problem.findMany({})
+ return
}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/student/page.tsx b/src/app/(app)/usermanagement/student/page.tsx
deleted file mode 100644
index 7b750d9..0000000
--- a/src/app/(app)/usermanagement/student/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { UserManagement } from "@/features/user-management"
-
-export default function Page() {
- return
-}
\ No newline at end of file
diff --git a/src/app/(app)/usermanagement/teacher/page.tsx b/src/app/(app)/usermanagement/teacher/page.tsx
index 3983daf..13d854d 100644
--- a/src/app/(app)/usermanagement/teacher/page.tsx
+++ b/src/app/(app)/usermanagement/teacher/page.tsx
@@ -1,5 +1,8 @@
-import { UserManagement } from "@/features/user-management"
+import { UserTable } from '@/features/user-management/components/user-table'
+import { teacherConfig } from '@/features/user-management/config/teacher'
+import prisma from '@/lib/prisma'
-export default function Page() {
- return
+export default async function TeacherPage() {
+ const data = await prisma.user.findMany({ where: { role: 'TEACHER' as any } })
+ return
}
\ No newline at end of file
diff --git a/src/app/api/problem/route.ts b/src/app/api/problem/route.ts
deleted file mode 100644
index 75656c5..0000000
--- a/src/app/api/problem/route.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import prisma from "@/lib/prisma";
-import { NextRequest, NextResponse } from "next/server";
-import { auth } from "@/lib/auth";
-
-// 获取所有题目
-export async function GET() {
- try {
- // 权限校验(可选:只允许管理员/教师)
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
- // 可根据需要校验角色
- // const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { role: true } });
- // if (user?.role !== "ADMIN" && user?.role !== "TEACHER") {
- // return NextResponse.json({ error: "权限不足" }, { status: 403 });
- // }
- const problems = await prisma.problem.findMany({
- select: {
- id: true,
- displayId: true,
- difficulty: true,
- }
- });
- return NextResponse.json(problems);
- } catch (error) {
- console.error("获取题目列表失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
-
-// 新建题目
-export async function POST(req: NextRequest) {
- try {
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
- // 只允许管理员/教师添加
- // const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { role: true } });
- // if (user?.role !== "ADMIN" && user?.role !== "TEACHER") {
- // return NextResponse.json({ error: "权限不足" }, { status: 403 });
- // }
- const data = await req.json();
- const newProblem = await prisma.problem.create({ data });
- return NextResponse.json(newProblem);
- } catch (error) {
- console.error("创建题目失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
-
-// 编辑题目
-export async function PUT(req: NextRequest) {
- try {
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
- // 只允许管理员/教师编辑
- // const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { role: true } });
- // if (user?.role !== "ADMIN" && user?.role !== "TEACHER") {
- // return NextResponse.json({ error: "权限不足" }, { status: 403 });
- // }
- const data = await req.json();
- const updatedProblem = await prisma.problem.update({
- where: { id: data.id },
- data,
- });
- return NextResponse.json(updatedProblem);
- } catch (error) {
- console.error("更新题目失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
-
-// 删除题目
-export async function DELETE(req: NextRequest) {
- try {
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
- // 只允许管理员/教师删除
- // const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { role: true } });
- // if (user?.role !== "ADMIN" && user?.role !== "TEACHER") {
- // return NextResponse.json({ error: "权限不足" }, { status: 403 });
- // }
- const { id } = await req.json();
- await prisma.problem.delete({ where: { id } });
- return NextResponse.json({ success: true });
- } catch (error) {
- console.error("删除题目失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
\ No newline at end of file
diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts
deleted file mode 100644
index 1dd5df6..0000000
--- a/src/app/api/user/route.ts
+++ /dev/null
@@ -1,189 +0,0 @@
-import prisma from "@/lib/prisma";
-import { NextRequest, NextResponse } from "next/server";
-import bcrypt from "bcryptjs";
-import { auth } from "@/lib/auth";
-
-// 获取所有用户
-export async function GET() {
- try {
- // 验证管理员权限
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
-
- const user = await prisma.user.findUnique({
- where: { id: session.user.id },
- select: { role: true }
- });
-
- if (user?.role !== "ADMIN") {
- return NextResponse.json({ error: "权限不足" }, { status: 403 });
- }
-
- const users = await prisma.user.findMany({
- select: {
- id: true,
- name: true,
- email: true,
- role: true,
- createdAt: true,
- updatedAt: true,
- password: true, // 包含密码字段用于处理
- }
- });
-
- // 在服务器端处理密码显示逻辑
- const processedUsers = users.map(user => ({
- ...user,
- password: user.password ? "******" : "(无)", // 服务器端处理密码显示
- createdAt: user.createdAt instanceof Date ? user.createdAt.toLocaleString() : user.createdAt, // 服务器端处理日期格式
- }));
-
- return NextResponse.json(processedUsers);
- } catch (error) {
- console.error("获取用户列表失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
-
-// 新建用户
-export async function POST(req: NextRequest) {
- try {
- // 验证管理员权限
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
-
- const user = await prisma.user.findUnique({
- where: { id: session.user.id },
- select: { role: true }
- });
-
- if (user?.role !== "ADMIN") {
- return NextResponse.json({ error: "权限不足" }, { status: 403 });
- }
-
- const data = await req.json();
-
- // 如果提供了密码,进行加密
- if (data.password) {
- data.password = await bcrypt.hash(data.password, 10);
- }
-
- const newUser = await prisma.user.create({
- data,
- select: {
- id: true,
- name: true,
- email: true,
- role: true,
- createdAt: true,
- updatedAt: true,
- password: true,
- }
- });
-
- // 处理返回数据
- const processedUser = {
- ...newUser,
- password: newUser.password ? "******" : "(无)",
- createdAt: newUser.createdAt instanceof Date ? newUser.createdAt.toLocaleString() : newUser.createdAt,
- };
-
- return NextResponse.json(processedUser);
- } catch (error) {
- console.error("创建用户失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
-
-// 编辑用户
-export async function PUT(req: NextRequest) {
- try {
- // 验证管理员权限
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
-
- const user = await prisma.user.findUnique({
- where: { id: session.user.id },
- select: { role: true }
- });
-
- if (user?.role !== "ADMIN") {
- return NextResponse.json({ error: "权限不足" }, { status: 403 });
- }
-
- const data = await req.json();
-
- // 如果提供了密码且不为空,进行加密
- if (data.password && data.password.trim() !== '') {
- data.password = await bcrypt.hash(data.password, 10);
- } else {
- // 如果密码为空,则不更新密码字段
- delete data.password;
- }
-
- const updatedUser = await prisma.user.update({
- where: { id: data.id },
- data,
- select: {
- id: true,
- name: true,
- email: true,
- role: true,
- createdAt: true,
- updatedAt: true,
- password: true,
- }
- });
-
- // 处理返回数据
- const processedUser = {
- ...updatedUser,
- password: updatedUser.password ? "******" : "(无)",
- createdAt: updatedUser.createdAt instanceof Date ? updatedUser.createdAt.toLocaleString() : updatedUser.createdAt,
- };
-
- return NextResponse.json(processedUser);
- } catch (error) {
- console.error("更新用户失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
-
-// 删除用户
-export async function DELETE(req: NextRequest) {
- try {
- // 验证管理员权限
- const session = await auth();
- if (!session?.user?.id) {
- return NextResponse.json({ error: "未授权" }, { status: 401 });
- }
-
- const user = await prisma.user.findUnique({
- where: { id: session.user.id },
- select: { role: true }
- });
-
- if (user?.role !== "ADMIN") {
- return NextResponse.json({ error: "权限不足" }, { status: 403 });
- }
-
- const { id } = await req.json();
-
- // 防止删除自己
- if (id === session.user.id) {
- return NextResponse.json({ error: "不能删除自己的账户" }, { status: 400 });
- }
-
- await prisma.user.delete({ where: { id } });
- return NextResponse.json({ success: true });
- } catch (error) {
- console.error("删除用户失败:", error);
- return NextResponse.json({ error: "服务器错误" }, { status: 500 });
- }
-}
\ No newline at end of file
diff --git a/src/features/user-management/components/user-table.tsx b/src/features/user-management/components/user-table.tsx
index d17aa07..185dd5d 100644
--- a/src/features/user-management/components/user-table.tsx
+++ b/src/features/user-management/components/user-table.tsx
@@ -30,6 +30,7 @@ import { useState, useEffect } from "react"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
+import { useRouter } from "next/navigation"
import {
Dialog,
@@ -68,8 +69,10 @@ import {
Tabs,
} from "@/components/ui/tabs"
-import * as userApi from "@/api/user"
-import * as problemApi from "@/api/problem"
+import { createAdmin, updateAdmin, deleteAdmin } from '@/app/(app)/usermanagement/_actions/adminActions'
+import { createTeacher, updateTeacher, deleteTeacher } from '@/app/(app)/usermanagement/_actions/teacherActions'
+import { createGuest, updateGuest, deleteGuest } from '@/app/(app)/usermanagement/_actions/guestActions'
+import { createProblem, updateProblem, deleteProblem } from '@/app/(app)/usermanagement/_actions/problemActions'
// 通用用户类型
export interface UserConfig {
@@ -89,6 +92,7 @@ export interface UserConfig {
type: string
placeholder?: string
required?: boolean
+ options?: Array<{ value: string; label: string }>
}>
actions: {
add: { label: string; icon: string }
@@ -112,7 +116,7 @@ const addUserSchema = z.object({
name: z.string().optional(),
email: z.string().email("请输入有效的邮箱地址"),
password: z.string().optional(),
- createdAt: z.string(),
+ createdAt: z.string().optional(),
})
const editUserSchema = z.object({
@@ -120,6 +124,7 @@ const editUserSchema = z.object({
name: z.string().optional(),
email: z.string().email("请输入有效的邮箱地址"),
password: z.string().optional(),
+ role: z.string().optional(),
createdAt: z.string(),
})
@@ -134,8 +139,7 @@ const editProblemSchema = z.object({
difficulty: z.string(),
})
-export function UserTable({ config, data: initialData }: UserTableProps) {
- const [data, setData] = useState(initialData)
+export function UserTable({ config, data }: UserTableProps) {
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false)
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
const [editingUser, setEditingUser] = useState(null)
@@ -212,6 +216,14 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
},
cell: ({ row }) => {
const value = row.getValue(col.key)
+ if (col.key === 'createdAt' || col.key === 'updatedAt') {
+ if (value instanceof Date) {
+ return value.toLocaleString()
+ }
+ if (typeof value === 'string' && !isNaN(Date.parse(value))) {
+ return new Date(value).toLocaleString()
+ }
+ }
return value
},
enableSorting: col.sortable !== false,
@@ -288,19 +300,6 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
getFacetedUniqueValues: getFacetedUniqueValues(),
})
- // 数据加载与API对接
- useEffect(() => {
- if (isProblem) {
- problemApi.getProblems()
- .then(setData)
- .catch(() => toast.error('获取数据失败', { duration: 1500 }))
- } else {
- userApi.getUsers(config.userType)
- .then(setData)
- .catch(() => toast.error('获取数据失败', { duration: 1500 }))
- }
- }, [config.userType])
-
// 生成唯一ID
function generateUniqueId(existingIds: string[]): string {
let id: string
@@ -315,28 +314,41 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
const [isLoading, setIsLoading] = useState(false)
const form = useForm({
resolver: zodResolver(addUserSchema),
- defaultValues: { name: "", email: "", password: "", createdAt: new Date().toISOString().slice(0, 16) },
+ defaultValues: { name: "", email: "", password: "", createdAt: "" },
})
React.useEffect(() => {
if (open) {
- form.reset({ name: "", email: "", password: "", createdAt: new Date().toISOString().slice(0, 16) })
+ form.reset({ name: "", email: "", password: "", createdAt: "" })
}
}, [open, form])
async function onSubmit(formData: any) {
try {
setIsLoading(true)
- const existingIds = dataRef.current.map(item => item.id)
- const id = generateUniqueId(existingIds)
const submitData = {
...formData,
- id,
- createdAt: formData.createdAt ? new Date(formData.createdAt).toISOString() : new Date().toISOString(),
+ // 移除手动生成的 id,让数据库自动生成
+ // 移除 createdAt,让数据库自动设置
}
- await userApi.createUser(config.userType, submitData)
- userApi.getUsers(config.userType).then(setData)
+ // 清理空字段
+ if (!submitData.name) delete submitData.name
+ if (!submitData.password) delete submitData.password
+ if (!submitData.createdAt) delete submitData.createdAt
+
+ // 如果用户提供了创建时间,转换为完整的 ISO-8601 格式
+ if (submitData.createdAt) {
+ const date = new Date(submitData.createdAt)
+ submitData.createdAt = date.toISOString()
+ }
+
+ if (config.userType === 'admin') await createAdmin(submitData)
+ else if (config.userType === 'teacher') await createTeacher(submitData)
+ else if (config.userType === 'guest') await createGuest(submitData)
+ else if (config.userType === 'problem') await createProblem(submitData)
onOpenChange(false)
toast.success('添加成功', { duration: 1500 })
- } catch {
+ router.refresh()
+ } catch (error) {
+ console.error('添加失败:', error)
toast.error('添加失败', { duration: 1500 })
} finally {
setIsLoading(false)
@@ -359,13 +371,29 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
-
+ {field.type === 'select' && field.options ? (
+
+ ) : (
+
+ )}
{form.formState.errors[field.key as keyof typeof form.formState.errors]?.message && (
{form.formState.errors[field.key as keyof typeof form.formState.errors]?.message as string}
@@ -400,18 +428,20 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
async function onSubmit(formData: any) {
try {
setIsLoading(true)
- const existingIds = dataRef.current.map(item => item.id)
- const id = generateUniqueId(existingIds)
const submitData = {
...formData,
displayId: Number(formData.displayId),
- id,
+ // 移除手动生成的 id,让数据库自动生成
}
- await problemApi.createProblem(submitData)
- problemApi.getProblems().then(setData)
+ if (config.userType === 'admin') await createAdmin(submitData)
+ else if (config.userType === 'teacher') await createTeacher(submitData)
+ else if (config.userType === 'guest') await createGuest(submitData)
+ else if (config.userType === 'problem') await createProblem(submitData)
onOpenChange(false)
toast.success('添加成功', { duration: 1500 })
- } catch {
+ router.refresh()
+ } catch (error) {
+ console.error('添加失败:', error)
toast.error('添加失败', { duration: 1500 })
} finally {
setIsLoading(false)
@@ -465,11 +495,11 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
const [isLoading, setIsLoading] = useState(false)
const form = useForm({
resolver: zodResolver(editUserSchema),
- defaultValues: { id: user.id, name: user.name || "", email: user.email || "", password: "", createdAt: user.createdAt ? new Date(user.createdAt).toISOString().slice(0, 16) : new Date().toISOString().slice(0, 16) },
+ defaultValues: { id: user.id, name: user.name || "", email: user.email || "", password: "", role: user.role || "", createdAt: user.createdAt ? new Date(user.createdAt).toISOString().slice(0, 16) : new Date().toISOString().slice(0, 16) },
})
React.useEffect(() => {
if (open) {
- form.reset({ id: user.id, name: user.name || "", email: user.email || "", password: "", createdAt: user.createdAt ? new Date(user.createdAt).toISOString().slice(0, 16) : new Date().toISOString().slice(0, 16) })
+ form.reset({ id: user.id, name: user.name || "", email: user.email || "", password: "", role: user.role || "", createdAt: user.createdAt ? new Date(user.createdAt).toISOString().slice(0, 16) : new Date().toISOString().slice(0, 16) })
}
}, [open, user, form])
async function onSubmit(formData: any) {
@@ -482,8 +512,10 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
if (!submitData.password) {
delete submitData.password;
}
- await userApi.updateUser(config.userType, submitData)
- userApi.getUsers(config.userType).then(setData)
+ if (config.userType === 'admin') await updateAdmin(submitData.id, submitData)
+ else if (config.userType === 'teacher') await updateTeacher(submitData.id, submitData)
+ else if (config.userType === 'guest') await updateGuest(submitData.id, submitData)
+ else if (config.userType === 'problem') await updateProblem(submitData.id, submitData)
onOpenChange(false)
toast.success('修改成功', { duration: 1500 })
} catch {
@@ -524,6 +556,43 @@ export function UserTable({ config, data: initialData }: UserTableProps) {
)}
))}
+
+ {/* 编辑时显示角色选择 */}
+ {config.userType !== 'problem' && (
+
+
+
+ {form.formState.errors.role?.message && (
+
+ {form.formState.errors.role?.message as string}
+
+ )}
+
+ )}
)}
+
+
+
+ {form.formState.errors.difficulty?.message && (
+
+ {form.formState.errors.difficulty?.message as string}
+
+ )}
+