mirror of
https://github.com/massbug/judge4c.git
synced 2026-05-20 13:18:52 +00:00
feat(role): rename_guest_role_to_student
This commit is contained in:
parent
c4e7a3b6f5
commit
2cbe91d487
@ -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', 'STUDENT', 'TEACHER');
|
||||||
|
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 'STUDENT';
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'STUDENT';
|
||||||
@ -10,7 +10,7 @@ generator client {
|
|||||||
|
|
||||||
enum Role {
|
enum Role {
|
||||||
ADMIN
|
ADMIN
|
||||||
GUEST
|
STUDENT
|
||||||
TEACHER
|
TEACHER
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ model User {
|
|||||||
password String?
|
password String?
|
||||||
emailVerified DateTime?
|
emailVerified DateTime?
|
||||||
image String?
|
image String?
|
||||||
role Role @default(GUEST)
|
role Role @default(STUDENT)
|
||||||
|
|
||||||
accounts Account[]
|
accounts Account[]
|
||||||
sessions Session[]
|
sessions Session[]
|
||||||
|
|||||||
@ -2999,12 +2999,12 @@ export async function main() {
|
|||||||
where: { email },
|
where: { email },
|
||||||
update: {
|
update: {
|
||||||
name: `学生${index + 1}`,
|
name: `学生${index + 1}`,
|
||||||
role: "GUEST",
|
role: "STUDENT",
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
name: `学生${index + 1}`,
|
name: `学生${index + 1}`,
|
||||||
email,
|
email,
|
||||||
role: "GUEST",
|
role: "STUDENT",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export function assertTeacherOrAdmin(actor: AuthenticatedActor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function assertStudent(actor: AuthenticatedActor) {
|
export function assertStudent(actor: AuthenticatedActor) {
|
||||||
if (actor.role !== "GUEST") {
|
if (actor.role !== "STUDENT") {
|
||||||
throw new Error("仅学生可访问");
|
throw new Error("仅学生可访问");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -130,7 +130,7 @@ export async function enrollStudents(courseId: string, studentIds: string[]) {
|
|||||||
const students = await prisma.user.findMany({
|
const students = await prisma.user.findMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: uniqueStudentIds },
|
id: { in: uniqueStudentIds },
|
||||||
role: "GUEST",
|
role: "STUDENT",
|
||||||
},
|
},
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
});
|
});
|
||||||
@ -197,7 +197,7 @@ export async function listAvailableStudents() {
|
|||||||
assertTeacherOrAdmin(actor);
|
assertTeacherOrAdmin(actor);
|
||||||
|
|
||||||
return prisma.user.findMany({
|
return prisma.user.findMany({
|
||||||
where: { role: "GUEST" },
|
where: { role: "STUDENT" },
|
||||||
orderBy: { createdAt: "desc" },
|
orderBy: { createdAt: "desc" },
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
|
|||||||
@ -47,16 +47,16 @@ export default async function Layout({ children }: LayoutProps) {
|
|||||||
return <AdminSidebar user={user} />;
|
return <AdminSidebar user={user} />;
|
||||||
case "TEACHER":
|
case "TEACHER":
|
||||||
return <TeacherSidebar user={user} />;
|
return <TeacherSidebar user={user} />;
|
||||||
case "GUEST":
|
case "STUDENT":
|
||||||
default:
|
default:
|
||||||
// 学生(GUEST)需要查询错题数据
|
// 学生(STUDENT)需要查询错题数据
|
||||||
return <AppSidebar user={user} wrongProblems={[]} />;
|
return <AppSidebar user={user} wrongProblems={[]} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 只有学生才需要查询错题数据
|
// 只有学生才需要查询错题数据
|
||||||
let wrongProblemsData: WrongProblem[] = [];
|
let wrongProblemsData: WrongProblem[] = [];
|
||||||
if (fullUser.role === "GUEST") {
|
if (fullUser.role === "STUDENT") {
|
||||||
// 查询未完成(未AC)题目的最新一次提交
|
// 查询未完成(未AC)题目的最新一次提交
|
||||||
const wrongProblems = await prisma.problem.findMany({
|
const wrongProblems = await prisma.problem.findMany({
|
||||||
where: {
|
where: {
|
||||||
@ -98,7 +98,7 @@ export default async function Layout({ children }: LayoutProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarProvider>
|
<SidebarProvider>
|
||||||
{fullUser.role === "GUEST" ? (
|
{fullUser.role === "STUDENT" ? (
|
||||||
<AppSidebar user={user} wrongProblems={wrongProblemsData} />
|
<AppSidebar user={user} wrongProblems={wrongProblemsData} />
|
||||||
) : (
|
) : (
|
||||||
renderSidebar()
|
renderSidebar()
|
||||||
|
|||||||
@ -12,7 +12,7 @@ interface User {
|
|||||||
email: string;
|
email: string;
|
||||||
emailVerified?: Date | null;
|
emailVerified?: Date | null;
|
||||||
image: string | null;
|
image: string | null;
|
||||||
role: "GUEST" | "USER" | "ADMIN" | "TEACHER";
|
role: "STUDENT" | "ADMIN" | "TEACHER";
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,7 +94,7 @@ export default async function DashboardPage() {
|
|||||||
// 教师统计
|
// 教师统计
|
||||||
const [totalStudents, totalProblems, totalSubmissions, recentSubmissions] =
|
const [totalStudents, totalProblems, totalSubmissions, recentSubmissions] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
prisma.user.count({ where: { role: "GUEST" } }),
|
prisma.user.count({ where: { role: "STUDENT" } }),
|
||||||
prisma.problem.count({ where: { isPublished: true } }),
|
prisma.problem.count({ where: { isPublished: true } }),
|
||||||
prisma.submission.count(),
|
prisma.submission.count(),
|
||||||
prisma.submission.findMany({
|
prisma.submission.findMany({
|
||||||
@ -204,8 +204,8 @@ export default async function DashboardPage() {
|
|||||||
icon: Target,
|
icon: Target,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "用户管理",
|
label: "学生管理",
|
||||||
href: "/dashboard/usermanagement/guest",
|
href: "/dashboard/usermanagement/student",
|
||||||
icon: Users,
|
icon: Users,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -246,8 +246,8 @@ export default async function DashboardPage() {
|
|||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
label: "用户管理",
|
label: "学生管理",
|
||||||
href: "/dashboard/usermanagement/guest",
|
href: "/dashboard/usermanagement/student",
|
||||||
icon: Users,
|
icon: Users,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -311,7 +311,7 @@ export default async function DashboardPage() {
|
|||||||
|
|
||||||
const config = getRoleConfig();
|
const config = getRoleConfig();
|
||||||
const completionRate =
|
const completionRate =
|
||||||
fullUser.role === "GUEST"
|
fullUser.role === "STUDENT"
|
||||||
? (stats.totalProblems || 0) > 0
|
? (stats.totalProblems || 0) > 0
|
||||||
? ((stats.completedProblems || 0) / (stats.totalProblems || 1)) * 100
|
? ((stats.completedProblems || 0) / (stats.totalProblems || 1)) * 100
|
||||||
: 0
|
: 0
|
||||||
@ -349,7 +349,7 @@ export default async function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 学生进度条 */}
|
{/* 学生进度条 */}
|
||||||
{fullUser.role === "GUEST" && (
|
{fullUser.role === "STUDENT" && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center gap-2">
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
|||||||
@ -5,5 +5,5 @@ export default async function StudentCoursesLayout({
|
|||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return <ProtectedLayout roles={["GUEST"]}>{children}</ProtectedLayout>;
|
return <ProtectedLayout roles={["STUDENT"]}>{children}</ProtectedLayout>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import { Role } from "@/generated/client";
|
|||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import type { User } from "@/generated/client";
|
import type { User } from "@/generated/client";
|
||||||
|
|
||||||
type UserType = "admin" | "teacher" | "guest";
|
type ResourceType = "admin" | "teacher" | "student";
|
||||||
|
|
||||||
export async function createUser(
|
export async function createUser(
|
||||||
userType: UserType,
|
resourceType: ResourceType,
|
||||||
data: Omit<User, "id" | "createdAt" | "updatedAt"> & { password?: string }
|
data: Omit<User, "id" | "createdAt" | "updatedAt"> & { password?: string }
|
||||||
) {
|
) {
|
||||||
let password = data.password;
|
let password = data.password;
|
||||||
@ -17,13 +17,13 @@ export async function createUser(
|
|||||||
password = await bcrypt.hash(password, 10);
|
password = await bcrypt.hash(password, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
const role = userType.toUpperCase() as Role;
|
const role = resourceType.toUpperCase() as Role;
|
||||||
await prisma.user.create({ data: { ...data, password, role } });
|
await prisma.user.create({ data: { ...data, password, role } });
|
||||||
revalidatePath(`/usermanagement/${userType}`);
|
revalidatePath(`/usermanagement/${resourceType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateUser(
|
export async function updateUser(
|
||||||
userType: UserType,
|
resourceType: ResourceType,
|
||||||
id: string,
|
id: string,
|
||||||
data: Partial<Omit<User, "id" | "createdAt" | "updatedAt">>
|
data: Partial<Omit<User, "id" | "createdAt" | "updatedAt">>
|
||||||
) {
|
) {
|
||||||
@ -38,10 +38,10 @@ export async function updateUser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await prisma.user.update({ where: { id }, data: updateData });
|
await prisma.user.update({ where: { id }, data: updateData });
|
||||||
revalidatePath(`/usermanagement/${userType}`);
|
revalidatePath(`/usermanagement/${resourceType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteUser(userType: UserType, id: string) {
|
export async function deleteUser(resourceType: ResourceType, id: string) {
|
||||||
await prisma.user.delete({ where: { id } });
|
await prisma.user.delete({ where: { id } });
|
||||||
revalidatePath(`/usermanagement/${userType}`);
|
revalidatePath(`/usermanagement/${resourceType}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,5 +2,5 @@ import { adminConfig } from "@/features/user-management/config/admin";
|
|||||||
import GenericPage from "@/features/user-management/components/generic-page";
|
import GenericPage from "@/features/user-management/components/generic-page";
|
||||||
|
|
||||||
export default function AdminPage() {
|
export default function AdminPage() {
|
||||||
return <GenericPage userType="admin" config={adminConfig} />;
|
return <GenericPage resourceType="admin" config={adminConfig} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
import { guestConfig } from "@/features/user-management/config/guest";
|
|
||||||
import GenericPage from "@/features/user-management/components/generic-page";
|
|
||||||
|
|
||||||
export default function GuestPage() {
|
|
||||||
return <GenericPage userType="guest" config={guestConfig} />;
|
|
||||||
}
|
|
||||||
@ -2,5 +2,5 @@ import { problemConfig } from "@/features/user-management/config/problem";
|
|||||||
import GenericPage from "@/features/user-management/components/generic-page";
|
import GenericPage from "@/features/user-management/components/generic-page";
|
||||||
|
|
||||||
export default function ProblemPage() {
|
export default function ProblemPage() {
|
||||||
return <GenericPage userType="problem" config={problemConfig} />;
|
return <GenericPage resourceType="problem" config={problemConfig} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import GenericLayout from "../components/GenericLayout";
|
import GenericLayout from "../components/GenericLayout";
|
||||||
|
|
||||||
export default function GuestLayout({
|
export default function StudentLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { studentConfig } from "@/features/user-management/config/student";
|
||||||
|
import GenericPage from "@/features/user-management/components/generic-page";
|
||||||
|
|
||||||
|
export default function StudentPage() {
|
||||||
|
return <GenericPage resourceType="student" config={studentConfig} />;
|
||||||
|
}
|
||||||
@ -2,5 +2,5 @@ import { teacherConfig } from "@/features/user-management/config/teacher";
|
|||||||
import GenericPage from "@/features/user-management/components/generic-page";
|
import GenericPage from "@/features/user-management/components/generic-page";
|
||||||
|
|
||||||
export default function TeacherPage() {
|
export default function TeacherPage() {
|
||||||
return <GenericPage userType="teacher" config={teacherConfig} />;
|
return <GenericPage resourceType="teacher" config={teacherConfig} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ interface LayoutProps {
|
|||||||
|
|
||||||
const Layout = ({ children }: LayoutProps) => {
|
const Layout = ({ children }: LayoutProps) => {
|
||||||
return (
|
return (
|
||||||
<ProtectedLayout roles={["ADMIN", "TEACHER", "GUEST"]}>
|
<ProtectedLayout roles={["ADMIN", "TEACHER", "STUDENT"]}>
|
||||||
{children}
|
{children}
|
||||||
</ProtectedLayout>
|
</ProtectedLayout>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export const judge = async (
|
|||||||
const canAccessAssignment =
|
const canAccessAssignment =
|
||||||
actor.role === "ADMIN" ||
|
actor.role === "ADMIN" ||
|
||||||
(actor.role === "TEACHER" && isTeacherOwner) ||
|
(actor.role === "TEACHER" && isTeacherOwner) ||
|
||||||
(actor.role === "GUEST" && isStudentEnrolled);
|
(actor.role === "STUDENT" && isStudentEnrolled);
|
||||||
|
|
||||||
if (!canAccessAssignment) {
|
if (!canAccessAssignment) {
|
||||||
await createSystemErrorSubmission("No permission for assignment", {
|
await createSystemErrorSubmission("No permission for assignment", {
|
||||||
@ -100,7 +100,7 @@ export const judge = async (
|
|||||||
return Status.SE;
|
return Status.SE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!assignment.published && actor.role === "GUEST") {
|
if (!assignment.published && actor.role === "STUDENT") {
|
||||||
await createSystemErrorSubmission("Assignment is not published", {
|
await createSystemErrorSubmission("Assignment is not published", {
|
||||||
assignmentId: assignment.id,
|
assignmentId: assignment.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -44,7 +44,7 @@ export function DynamicBreadcrumb() {
|
|||||||
admin: "管理后台",
|
admin: "管理后台",
|
||||||
teacher: "教师平台",
|
teacher: "教师平台",
|
||||||
student: "学生平台",
|
student: "学生平台",
|
||||||
usermanagement: "用户管理",
|
usermanagement: "账号管理",
|
||||||
courses: "课程",
|
courses: "课程",
|
||||||
assignments: "作业",
|
assignments: "作业",
|
||||||
userdashboard: "用户仪表板",
|
userdashboard: "用户仪表板",
|
||||||
|
|||||||
@ -26,7 +26,7 @@ const adminData = {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
items: [
|
items: [
|
||||||
{ title: "管理员管理", url: "/dashboard/usermanagement/admin" },
|
{ title: "管理员管理", url: "/dashboard/usermanagement/admin" },
|
||||||
{ title: "用户管理", url: "/dashboard/usermanagement/guest" },
|
{ title: "学生管理", url: "/dashboard/usermanagement/student" },
|
||||||
{ title: "教师管理", url: "/dashboard/usermanagement/teacher" },
|
{ title: "教师管理", url: "/dashboard/usermanagement/teacher" },
|
||||||
{ title: "题目管理", url: "/dashboard/usermanagement/problem" },
|
{ title: "题目管理", url: "/dashboard/usermanagement/problem" },
|
||||||
],
|
],
|
||||||
|
|||||||
@ -26,8 +26,8 @@ const data = {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
title: "用户管理",
|
title: "学生管理",
|
||||||
url: "/dashboard/usermanagement/guest",
|
url: "/dashboard/usermanagement/student",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "题目管理",
|
title: "题目管理",
|
||||||
|
|||||||
@ -5,19 +5,19 @@ import { UserConfig } from "./user-table";
|
|||||||
import type { User, Problem } from "@/generated/client";
|
import type { User, Problem } from "@/generated/client";
|
||||||
|
|
||||||
interface GenericPageProps {
|
interface GenericPageProps {
|
||||||
userType: "admin" | "teacher" | "guest" | "problem";
|
resourceType: "admin" | "teacher" | "student" | "problem";
|
||||||
config: UserConfig;
|
config: UserConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function GenericPage({
|
export default async function GenericPage({
|
||||||
userType,
|
resourceType,
|
||||||
config,
|
config,
|
||||||
}: GenericPageProps) {
|
}: GenericPageProps) {
|
||||||
if (userType === "problem") {
|
if (resourceType === "problem") {
|
||||||
const data: Problem[] = await prisma.problem.findMany({});
|
const data: Problem[] = await prisma.problem.findMany({});
|
||||||
return <UserTable config={config} data={data} />;
|
return <UserTable config={config} data={data} />;
|
||||||
} else {
|
} else {
|
||||||
const role = userType.toUpperCase() as Role;
|
const role = resourceType.toUpperCase() as Role;
|
||||||
const data: User[] = await prisma.user.findMany({ where: { role } });
|
const data: User[] = await prisma.user.findMany({ where: { role } });
|
||||||
return <UserTable config={config} data={data} />;
|
return <UserTable config={config} data={data} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,7 +78,7 @@ import {
|
|||||||
} from "@/app/(protected)/dashboard/usermanagement/actions/problemActions";
|
} from "@/app/(protected)/dashboard/usermanagement/actions/problemActions";
|
||||||
|
|
||||||
export interface UserConfig {
|
export interface UserConfig {
|
||||||
userType: string;
|
resourceType: string;
|
||||||
title: string;
|
title: string;
|
||||||
apiPath: string;
|
apiPath: string;
|
||||||
columns: Array<{
|
columns: Array<{
|
||||||
@ -154,7 +154,7 @@ const addProblemSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function UserTable(props: UserTableProps) {
|
export function UserTable(props: UserTableProps) {
|
||||||
const isProblem = props.config.userType === "problem";
|
const isProblem = props.config.resourceType === "problem";
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const problemData = isProblem ? (props.data as Problem[]) : undefined;
|
const problemData = isProblem ? (props.data as Problem[]) : undefined;
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ export function UserTable(props: UserTableProps) {
|
|||||||
createdAt: "",
|
createdAt: "",
|
||||||
image: null,
|
image: null,
|
||||||
emailVerified: null,
|
emailVerified: null,
|
||||||
role: Role.GUEST,
|
role: Role.STUDENT,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -336,7 +336,7 @@ export function UserTable(props: UserTableProps) {
|
|||||||
createdAt: "",
|
createdAt: "",
|
||||||
image: null,
|
image: null,
|
||||||
emailVerified: null,
|
emailVerified: null,
|
||||||
role: Role.GUEST,
|
role: Role.STUDENT,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [open, form]);
|
}, [open, form]);
|
||||||
@ -354,19 +354,19 @@ export function UserTable(props: UserTableProps) {
|
|||||||
...data,
|
...data,
|
||||||
image: data.image ?? null,
|
image: data.image ?? null,
|
||||||
emailVerified: data.emailVerified ?? null,
|
emailVerified: data.emailVerified ?? null,
|
||||||
role: data.role ?? Role.GUEST,
|
role: data.role ?? Role.STUDENT,
|
||||||
};
|
};
|
||||||
if (!submitData.name) submitData.name = "";
|
if (!submitData.name) submitData.name = "";
|
||||||
if (!submitData.createdAt)
|
if (!submitData.createdAt)
|
||||||
submitData.createdAt = new Date().toISOString();
|
submitData.createdAt = new Date().toISOString();
|
||||||
else
|
else
|
||||||
submitData.createdAt = new Date(submitData.createdAt).toISOString();
|
submitData.createdAt = new Date(submitData.createdAt).toISOString();
|
||||||
if (props.config.userType === "admin")
|
if (props.config.resourceType === "admin")
|
||||||
await createUser("admin", submitData);
|
await createUser("admin", submitData);
|
||||||
else if (props.config.userType === "teacher")
|
else if (props.config.resourceType === "teacher")
|
||||||
await createUser("teacher", submitData);
|
await createUser("teacher", submitData);
|
||||||
else if (props.config.userType === "guest")
|
else if (props.config.resourceType === "student")
|
||||||
await createUser("guest", submitData);
|
await createUser("student", submitData);
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
toast.success("添加成功", { duration: 1500 });
|
toast.success("添加成功", { duration: 1500 });
|
||||||
router.refresh();
|
router.refresh();
|
||||||
@ -610,7 +610,7 @@ export function UserTable(props: UserTableProps) {
|
|||||||
name: user.name ?? "",
|
name: user.name ?? "",
|
||||||
email: user.email ?? "",
|
email: user.email ?? "",
|
||||||
password: "",
|
password: "",
|
||||||
role: user.role ?? Role.GUEST,
|
role: user.role ?? Role.STUDENT,
|
||||||
createdAt: user.createdAt
|
createdAt: user.createdAt
|
||||||
? new Date(user.createdAt).toISOString().slice(0, 16)
|
? new Date(user.createdAt).toISOString().slice(0, 16)
|
||||||
: "",
|
: "",
|
||||||
@ -625,7 +625,7 @@ export function UserTable(props: UserTableProps) {
|
|||||||
name: user.name ?? "",
|
name: user.name ?? "",
|
||||||
email: user.email ?? "",
|
email: user.email ?? "",
|
||||||
password: "",
|
password: "",
|
||||||
role: user.role ?? Role.GUEST,
|
role: user.role ?? Role.STUDENT,
|
||||||
createdAt: user.createdAt
|
createdAt: user.createdAt
|
||||||
? new Date(user.createdAt).toISOString().slice(0, 16)
|
? new Date(user.createdAt).toISOString().slice(0, 16)
|
||||||
: "",
|
: "",
|
||||||
@ -644,15 +644,15 @@ export function UserTable(props: UserTableProps) {
|
|||||||
: new Date().toISOString(),
|
: new Date().toISOString(),
|
||||||
image: data.image ?? null,
|
image: data.image ?? null,
|
||||||
emailVerified: data.emailVerified ?? null,
|
emailVerified: data.emailVerified ?? null,
|
||||||
role: data.role ?? Role.GUEST,
|
role: data.role ?? Role.STUDENT,
|
||||||
};
|
};
|
||||||
const id = typeof submitData.id === "string" ? submitData.id : "";
|
const id = typeof submitData.id === "string" ? submitData.id : "";
|
||||||
if (props.config.userType === "admin")
|
if (props.config.resourceType === "admin")
|
||||||
await updateUser("admin", id, submitData);
|
await updateUser("admin", id, submitData);
|
||||||
else if (props.config.userType === "teacher")
|
else if (props.config.resourceType === "teacher")
|
||||||
await updateUser("teacher", id, submitData);
|
await updateUser("teacher", id, submitData);
|
||||||
else if (props.config.userType === "guest")
|
else if (props.config.resourceType === "student")
|
||||||
await updateUser("guest", id, submitData);
|
await updateUser("student", id, submitData);
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
toast.success("修改成功", { duration: 1500 });
|
toast.success("修改成功", { duration: 1500 });
|
||||||
} catch {
|
} catch {
|
||||||
@ -710,7 +710,7 @@ export function UserTable(props: UserTableProps) {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{/* 编辑时显示角色选择 */}
|
{/* 编辑时显示角色选择 */}
|
||||||
{props.config.userType !== "problem" && (
|
{props.config.resourceType !== "problem" && (
|
||||||
<div className="grid grid-cols-4 items-center gap-4">
|
<div className="grid grid-cols-4 items-center gap-4">
|
||||||
<Label htmlFor="role" className="text-right">
|
<Label htmlFor="role" className="text-right">
|
||||||
角色
|
角色
|
||||||
@ -725,18 +725,18 @@ export function UserTable(props: UserTableProps) {
|
|||||||
<SelectValue placeholder="请选择角色" />
|
<SelectValue placeholder="请选择角色" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{props.config.userType === "guest" && (
|
{props.config.resourceType === "student" && (
|
||||||
<>
|
<>
|
||||||
<SelectItem value="GUEST">学生</SelectItem>
|
<SelectItem value="STUDENT">学生</SelectItem>
|
||||||
<SelectItem value="TEACHER">老师</SelectItem>
|
<SelectItem value="TEACHER">老师</SelectItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{(props.config.userType === "teacher" ||
|
{(props.config.resourceType === "teacher" ||
|
||||||
props.config.userType === "admin") && (
|
props.config.resourceType === "admin") && (
|
||||||
<>
|
<>
|
||||||
<SelectItem value="ADMIN">管理员</SelectItem>
|
<SelectItem value="ADMIN">管理员</SelectItem>
|
||||||
<SelectItem value="TEACHER">老师</SelectItem>
|
<SelectItem value="TEACHER">老师</SelectItem>
|
||||||
<SelectItem value="GUEST">学生</SelectItem>
|
<SelectItem value="STUDENT">学生</SelectItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
@ -1068,10 +1068,10 @@ export function UserTable(props: UserTableProps) {
|
|||||||
await deleteProblem((row.original as Problem).id);
|
await deleteProblem((row.original as Problem).id);
|
||||||
} else {
|
} else {
|
||||||
await deleteUser(
|
await deleteUser(
|
||||||
props.config.userType as
|
props.config.resourceType as
|
||||||
| "admin"
|
| "admin"
|
||||||
| "teacher"
|
| "teacher"
|
||||||
| "guest",
|
| "student",
|
||||||
(row.original as User).id
|
(row.original as User).id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1113,7 +1113,7 @@ export function UserTable(props: UserTableProps) {
|
|||||||
await deleteProblem((pendingDeleteItem as Problem).id);
|
await deleteProblem((pendingDeleteItem as Problem).id);
|
||||||
} else {
|
} else {
|
||||||
await deleteUser(
|
await deleteUser(
|
||||||
props.config.userType as "admin" | "teacher" | "guest",
|
props.config.resourceType as "admin" | "teacher" | "student",
|
||||||
(pendingDeleteItem as User).id
|
(pendingDeleteItem as User).id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,14 +95,14 @@ export const basePagination = {
|
|||||||
|
|
||||||
// 创建用户配置的工厂函数
|
// 创建用户配置的工厂函数
|
||||||
export function createUserConfig(
|
export function createUserConfig(
|
||||||
userType: string,
|
resourceType: string,
|
||||||
title: string,
|
title: string,
|
||||||
addLabel: string,
|
addLabel: string,
|
||||||
namePlaceholder: string,
|
namePlaceholder: string,
|
||||||
emailPlaceholder: string
|
emailPlaceholder: string
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
userType,
|
resourceType,
|
||||||
title,
|
title,
|
||||||
apiPath: "/api/user",
|
apiPath: "/api/user",
|
||||||
columns: baseColumns,
|
columns: baseColumns,
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import {
|
|
||||||
createUserConfig,
|
|
||||||
baseUserSchema,
|
|
||||||
baseAddUserSchema,
|
|
||||||
baseEditUserSchema,
|
|
||||||
} from "./base-config";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
export const guestSchema = baseUserSchema;
|
|
||||||
export type Guest = z.infer<typeof guestSchema>;
|
|
||||||
|
|
||||||
export const addGuestSchema = baseAddUserSchema;
|
|
||||||
export type AddGuestFormData = z.infer<typeof addGuestSchema>;
|
|
||||||
|
|
||||||
export const editGuestSchema = baseEditUserSchema;
|
|
||||||
export type EditGuestFormData = z.infer<typeof editGuestSchema>;
|
|
||||||
|
|
||||||
export const guestConfig = createUserConfig(
|
|
||||||
"guest",
|
|
||||||
"客户列表",
|
|
||||||
"添加客户",
|
|
||||||
"请输入客户姓名",
|
|
||||||
"请输入客户邮箱"
|
|
||||||
);
|
|
||||||
@ -19,7 +19,7 @@ export const editProblemSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const problemConfig = {
|
export const problemConfig = {
|
||||||
userType: "problem",
|
resourceType: "problem",
|
||||||
title: "题目列表",
|
title: "题目列表",
|
||||||
apiPath: "/api/problem",
|
apiPath: "/api/problem",
|
||||||
columns: [
|
columns: [
|
||||||
|
|||||||
24
src/features/user-management/config/student.ts
Normal file
24
src/features/user-management/config/student.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {
|
||||||
|
createUserConfig,
|
||||||
|
baseUserSchema,
|
||||||
|
baseAddUserSchema,
|
||||||
|
baseEditUserSchema,
|
||||||
|
} from "./base-config";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const studentSchema = baseUserSchema;
|
||||||
|
export type Student = z.infer<typeof studentSchema>;
|
||||||
|
|
||||||
|
export const addStudentSchema = baseAddUserSchema;
|
||||||
|
export type AddStudentFormData = z.infer<typeof addStudentSchema>;
|
||||||
|
|
||||||
|
export const editStudentSchema = baseEditUserSchema;
|
||||||
|
export type EditStudentFormData = z.infer<typeof editStudentSchema>;
|
||||||
|
|
||||||
|
export const studentConfig = createUserConfig(
|
||||||
|
"student",
|
||||||
|
"学生列表",
|
||||||
|
"添加学生",
|
||||||
|
"请输入学生姓名",
|
||||||
|
"请输入学生邮箱"
|
||||||
|
);
|
||||||
Loading…
Reference in New Issue
Block a user