diff --git a/src/app/(app)/usermanagement/_actions/adminActions.ts b/src/app/(app)/usermanagement/_actions/adminActions.ts deleted file mode 100644 index fa3a594..0000000 --- a/src/app/(app)/usermanagement/_actions/adminActions.ts +++ /dev/null @@ -1,34 +0,0 @@ -'use server' -import prisma from '@/lib/prisma' -import { revalidatePath } from 'next/cache' -import bcrypt from 'bcryptjs' -import type { User } from '@/generated/client' - -export async function createAdmin(data: Omit & { password?: string }) { - 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: string, data: Partial>) { - let updateData = { ...data } - - // 如果包含密码字段且不为空,则进行加密 - if (data.password && data.password.trim() !== '') { - updateData.password = await bcrypt.hash(data.password, 10) - } else { - // 如果密码为空,则从更新数据中移除密码字段,保持原密码不变 - delete updateData.password - } - - await prisma.user.update({ where: { id }, data: updateData }) - revalidatePath('/usermanagement/admin') -} - -export async function deleteAdmin(id: string) { - 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 deleted file mode 100644 index b780739..0000000 --- a/src/app/(app)/usermanagement/_actions/guestActions.ts +++ /dev/null @@ -1,34 +0,0 @@ -'use server' -import prisma from '@/lib/prisma' -import { revalidatePath } from 'next/cache' -import bcrypt from 'bcryptjs' -import type { User } from '@/generated/client' - -export async function createGuest(data: Omit & { password?: string }) { - 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: string, data: Partial>) { - let updateData = { ...data } - - // 如果包含密码字段且不为空,则进行加密 - if (data.password && data.password.trim() !== '') { - updateData.password = await bcrypt.hash(data.password, 10) - } else { - // 如果密码为空,则从更新数据中移除密码字段,保持原密码不变 - delete updateData.password - } - - await prisma.user.update({ where: { id }, data: updateData }) - revalidatePath('/usermanagement/guest') -} - -export async function deleteGuest(id: string) { - 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 index 4d5ed90..ca7ca81 100644 --- a/src/app/(app)/usermanagement/_actions/problemActions.ts +++ b/src/app/(app)/usermanagement/_actions/problemActions.ts @@ -8,11 +8,6 @@ export async function createProblem(data: Omit>) { - await prisma.problem.update({ where: { id }, data }) - revalidatePath('/usermanagement/problem') -} - export async function deleteProblem(id: string) { await prisma.problem.delete({ where: { id } }) revalidatePath('/usermanagement/problem') diff --git a/src/app/(app)/usermanagement/_actions/teacherActions.ts b/src/app/(app)/usermanagement/_actions/teacherActions.ts deleted file mode 100644 index 2211669..0000000 --- a/src/app/(app)/usermanagement/_actions/teacherActions.ts +++ /dev/null @@ -1,34 +0,0 @@ -'use server' -import prisma from '@/lib/prisma' -import { revalidatePath } from 'next/cache' -import bcrypt from 'bcryptjs' -import type { User } from '@/generated/client' - -export async function createTeacher(data: Omit & { password?: string }) { - 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: string, data: Partial>) { - let updateData = { ...data } - - // 如果包含密码字段且不为空,则进行加密 - if (data.password && data.password.trim() !== '') { - updateData.password = await bcrypt.hash(data.password, 10) - } else { - // 如果密码为空,则从更新数据中移除密码字段,保持原密码不变 - delete updateData.password - } - - await prisma.user.update({ where: { id }, data: updateData }) - revalidatePath('/usermanagement/teacher') -} - -export async function deleteTeacher(id: string) { - await prisma.user.delete({ where: { id } }) - revalidatePath('/usermanagement/teacher') -} \ No newline at end of file diff --git a/src/app/(app)/usermanagement/_actions/userActions.ts b/src/app/(app)/usermanagement/_actions/userActions.ts new file mode 100644 index 0000000..e49269f --- /dev/null +++ b/src/app/(app)/usermanagement/_actions/userActions.ts @@ -0,0 +1,46 @@ +'use server' +import prisma from '@/lib/prisma' +import { revalidatePath } from 'next/cache' +import bcrypt from 'bcryptjs' +import type { User } from '@/generated/client' +import { Role } from '@/generated/client' + +type UserType = 'admin' | 'teacher' | 'guest' + +export async function createUser( + userType: UserType, + data: Omit & { password?: string } +) { + let password = data.password + if (password) { + password = await bcrypt.hash(password, 10) + } + + const role = userType.toUpperCase() as Role + await prisma.user.create({ data: { ...data, password, role } }) + revalidatePath(`/usermanagement/${userType}`) +} + +export async function updateUser( + userType: UserType, + id: string, + data: Partial> +) { + const updateData = { ...data } + + // 如果包含密码字段且不为空,则进行加密 + if (data.password && data.password.trim() !== '') { + updateData.password = await bcrypt.hash(data.password, 10) + } else { + // 如果密码为空,则从更新数据中移除密码字段,保持原密码不变 + delete updateData.password + } + + await prisma.user.update({ where: { id }, data: updateData }) + revalidatePath(`/usermanagement/${userType}`) +} + +export async function deleteUser(userType: UserType, id: string) { + await prisma.user.delete({ where: { id } }) + revalidatePath(`/usermanagement/${userType}`) +} \ No newline at end of file diff --git a/src/app/(app)/usermanagement/_components/GenericLayout.tsx b/src/app/(app)/usermanagement/_components/GenericLayout.tsx new file mode 100644 index 0000000..a182e77 --- /dev/null +++ b/src/app/(app)/usermanagement/_components/GenericLayout.tsx @@ -0,0 +1,10 @@ +import ProtectedLayout from "./ProtectedLayout"; + +interface GenericLayoutProps { + children: React.ReactNode; + allowedRoles: string[]; +} + +export default function GenericLayout({ children, allowedRoles }: GenericLayoutProps) { + return {children}; +} \ No newline at end of file diff --git a/src/app/(app)/usermanagement/admin/layout.tsx b/src/app/(app)/usermanagement/admin/layout.tsx index 4a0b1d1..db50dae 100644 --- a/src/app/(app)/usermanagement/admin/layout.tsx +++ b/src/app/(app)/usermanagement/admin/layout.tsx @@ -1,5 +1,5 @@ -import ProtectedLayout from "../_components/ProtectedLayout"; +import GenericLayout from "../_components/GenericLayout"; export default function AdminLayout({ children }: { children: React.ReactNode }) { - return {children}; + return {children}; } \ 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 543ce47..d911127 100644 --- a/src/app/(app)/usermanagement/admin/page.tsx +++ b/src/app/(app)/usermanagement/admin/page.tsx @@ -1,9 +1,6 @@ -import { UserTable } from '@/features/user-management/components/user-table' +import GenericPage from '@/features/user-management/components/generic-page' import { adminConfig } from '@/features/user-management/config/admin' -import prisma from '@/lib/prisma' -import type { User } from '@/generated/client' -export default async function AdminPage() { - const data: User[] = await prisma.user.findMany({ where: { role: 'ADMIN' } }) - return +export default function AdminPage() { + return } \ No newline at end of file diff --git a/src/app/(app)/usermanagement/guest/layout.tsx b/src/app/(app)/usermanagement/guest/layout.tsx index a29c947..6c084f4 100644 --- a/src/app/(app)/usermanagement/guest/layout.tsx +++ b/src/app/(app)/usermanagement/guest/layout.tsx @@ -1,5 +1,5 @@ -import ProtectedLayout from "../_components/ProtectedLayout"; +import GenericLayout from "../_components/GenericLayout"; export default function GuestLayout({ children }: { children: React.ReactNode }) { - return {children}; + 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 index 8dfaae8..5d8d1bc 100644 --- a/src/app/(app)/usermanagement/guest/page.tsx +++ b/src/app/(app)/usermanagement/guest/page.tsx @@ -1,9 +1,6 @@ -import { UserTable } from '@/features/user-management/components/user-table' +import GenericPage from '@/features/user-management/components/generic-page' import { guestConfig } from '@/features/user-management/config/guest' -import prisma from '@/lib/prisma' -import type { User } from '@/generated/client' -export default async function GuestPage() { - const data: User[] = await prisma.user.findMany({ where: { role: 'GUEST' } }) - return +export default function GuestPage() { + return } \ No newline at end of file diff --git a/src/app/(app)/usermanagement/problem/layout.tsx b/src/app/(app)/usermanagement/problem/layout.tsx index 8ba9c17..b4a002e 100644 --- a/src/app/(app)/usermanagement/problem/layout.tsx +++ b/src/app/(app)/usermanagement/problem/layout.tsx @@ -1,5 +1,5 @@ -import ProtectedLayout from "../_components/ProtectedLayout"; +import GenericLayout from "../_components/GenericLayout"; export default function ProblemLayout({ children }: { children: React.ReactNode }) { - return {children}; + return {children}; } \ 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 3d96f71..e67a3d0 100644 --- a/src/app/(app)/usermanagement/problem/page.tsx +++ b/src/app/(app)/usermanagement/problem/page.tsx @@ -1,9 +1,6 @@ -import { UserTable } from '@/features/user-management/components/user-table' +import GenericPage from '@/features/user-management/components/generic-page' import { problemConfig } from '@/features/user-management/config/problem' -import prisma from '@/lib/prisma' -import type { Problem } from '@/generated/client' -export default async function ProblemPage() { - const data: Problem[] = await prisma.problem.findMany({}) - return +export default function ProblemPage() { + return } \ No newline at end of file diff --git a/src/app/(app)/usermanagement/teacher/layout.tsx b/src/app/(app)/usermanagement/teacher/layout.tsx index b216f4f..8051801 100644 --- a/src/app/(app)/usermanagement/teacher/layout.tsx +++ b/src/app/(app)/usermanagement/teacher/layout.tsx @@ -1,5 +1,5 @@ -import ProtectedLayout from "../_components/ProtectedLayout"; +import GenericLayout from "../_components/GenericLayout"; export default function TeacherLayout({ children }: { children: React.ReactNode }) { - return {children}; + return {children}; } \ 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 93d6933..9bccf6f 100644 --- a/src/app/(app)/usermanagement/teacher/page.tsx +++ b/src/app/(app)/usermanagement/teacher/page.tsx @@ -1,9 +1,6 @@ -import { UserTable } from '@/features/user-management/components/user-table' +import GenericPage from '@/features/user-management/components/generic-page' import { teacherConfig } from '@/features/user-management/config/teacher' -import prisma from '@/lib/prisma' -import type { User } from '@/generated/client' -export default async function TeacherPage() { - const data: User[] = await prisma.user.findMany({ where: { role: 'TEACHER' } }) - return +export default function TeacherPage() { + return } \ No newline at end of file diff --git a/src/features/user-management/components/generic-page.tsx b/src/features/user-management/components/generic-page.tsx new file mode 100644 index 0000000..7063fea --- /dev/null +++ b/src/features/user-management/components/generic-page.tsx @@ -0,0 +1,21 @@ +import { UserTable } from './user-table' +import { UserConfig } from './user-table' +import prisma from '@/lib/prisma' +import type { User, Problem } from '@/generated/client' +import { Role } from '@/generated/client' + +interface GenericPageProps { + userType: 'admin' | 'teacher' | 'guest' | 'problem' + config: UserConfig +} + +export default async function GenericPage({ userType, config }: GenericPageProps) { + if (userType === 'problem') { + const data: Problem[] = await prisma.problem.findMany({}) + return + } else { + const role = userType.toUpperCase() as Role + const data: User[] = await prisma.user.findMany({ where: { role } }) + return + } +} \ 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 285f0c8..9f9c3ee 100644 --- a/src/features/user-management/components/user-table.tsx +++ b/src/features/user-management/components/user-table.tsx @@ -69,9 +69,7 @@ import { Tabs, } from "@/components/ui/tabs" -import { createAdmin, updateAdmin, deleteAdmin } from '@/app/(app)/usermanagement/_actions/adminActions' -import { createTeacher, updateTeacher } from '@/app/(app)/usermanagement/_actions/teacherActions' -import { createGuest, updateGuest } from '@/app/(app)/usermanagement/_actions/guestActions' +import { createUser, updateUser, deleteUser } from '@/app/(app)/usermanagement/_actions/userActions' import { createProblem, deleteProblem } from '@/app/(app)/usermanagement/_actions/problemActions' import type { User, Problem } from '@/generated/client' import { Difficulty, Role } from '@/generated/client' @@ -128,7 +126,7 @@ type AddUserForm = Omit const addUserSchema = z.object({ name: z.string(), email: z.string().email(), - password: z.string(), + password: z.string().min(1, "密码不能为空").min(8, "密码长度至少8位"), createdAt: z.string(), image: z.string().nullable(), emailVerified: z.date().nullable(), @@ -312,6 +310,13 @@ export function UserTable(props: UserTableProps) { async function onSubmit(data: AddUserForm) { try { setIsLoading(true) + + // 验证必填字段 + if (!data.password || data.password.trim() === '') { + toast.error('密码不能为空', { duration: 1500 }) + return + } + const submitData = { ...data, image: data.image ?? null, @@ -321,9 +326,9 @@ export function UserTable(props: UserTableProps) { if (!submitData.name) submitData.name = '' if (!submitData.createdAt) submitData.createdAt = new Date().toISOString() else submitData.createdAt = new Date(submitData.createdAt).toISOString() - if (props.config.userType === 'admin') await createAdmin(submitData) - else if (props.config.userType === 'teacher') await createTeacher(submitData) - else if (props.config.userType === 'guest') await createGuest(submitData) + if (props.config.userType === 'admin') await createUser('admin', submitData) + else if (props.config.userType === 'teacher') await createUser('teacher', submitData) + else if (props.config.userType === 'guest') await createUser('guest', submitData) onOpenChange(false) toast.success('添加成功', { duration: 1500 }) router.refresh() @@ -526,9 +531,9 @@ export function UserTable(props: UserTableProps) { role: data.role ?? Role.GUEST, } const id = typeof submitData.id === 'string' ? submitData.id : '' - if (props.config.userType === 'admin') await updateAdmin(id, submitData) - else if (props.config.userType === 'teacher') await updateTeacher(id, submitData) - else if (props.config.userType === 'guest') await updateGuest(id, submitData) + if (props.config.userType === 'admin') await updateUser('admin', id, submitData) + else if (props.config.userType === 'teacher') await updateUser('teacher', id, submitData) + else if (props.config.userType === 'guest') await updateUser('guest', id, submitData) onOpenChange(false) toast.success('修改成功', { duration: 1500 }) } catch { @@ -898,7 +903,7 @@ export function UserTable(props: UserTableProps) { if (isProblem) { await deleteProblem((row.original as Problem).id) } else { - await deleteAdmin((row.original as User).id) + await deleteUser(props.config.userType as 'admin' | 'teacher' | 'guest', (row.original as User).id) } } toast.success(`成功删除 ${selectedRows.length} 条记录`, { duration: 1500 }) @@ -930,7 +935,7 @@ export function UserTable(props: UserTableProps) { if (isProblem) { await deleteProblem((pendingDeleteItem as Problem).id) } else { - await deleteAdmin((pendingDeleteItem as User).id) + await deleteUser(props.config.userType as 'admin' | 'teacher' | 'guest', (pendingDeleteItem as User).id) } toast.success('删除成功', { duration: 1500 }) router.refresh() diff --git a/src/features/user-management/config/admin.ts b/src/features/user-management/config/admin.ts index 95d8b15..8be5d50 100644 --- a/src/features/user-management/config/admin.ts +++ b/src/features/user-management/config/admin.ts @@ -1,126 +1,23 @@ import { z } from "zod" +import { createUserConfig, baseUserSchema, baseAddUserSchema, baseEditUserSchema } from './base-config' // 管理员数据校验 schema -export const adminSchema = z.object({ - id: z.string(), - name: z.string().optional(), - email: z.string(), - password: z.string().optional(), - role: z.string().optional(), - createdAt: z.string(), - updatedAt: z.string().optional(), -}) - +export const adminSchema = baseUserSchema export type Admin = z.infer // 添加管理员表单校验 schema -export const addAdminSchema = z.object({ - name: z.string().min(1, "姓名为必填项"), - email: z.string().email("请输入有效的邮箱地址"), - password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), - createdAt: z.string(), -}) +export const addAdminSchema = baseAddUserSchema +export type AddAdminFormData = z.infer // 编辑管理员表单校验 schema -export const editAdminSchema = z.object({ - id: z.string(), - name: z.string().min(1, "姓名为必填项"), - email: z.string().email("请输入有效的邮箱地址"), - password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), - createdAt: z.string(), -}) - -export type AddAdminFormData = z.infer +export const editAdminSchema = baseEditUserSchema export type EditAdminFormData = z.infer // 管理员配置 -export const adminConfig = { - userType: "admin", - title: "管理员列表", - apiPath: "/api/user", - - // 表格列配置 - columns: [ - { - key: "id", - label: "ID", - sortable: true, - }, - { - key: "name", - label: "姓名", - sortable: true, - searchable: true, - placeholder: "搜索姓名", - }, - { - key: "email", - label: "邮箱", - sortable: true, - searchable: true, - placeholder: "搜索邮箱", - }, - { - key: "createdAt", - label: "创建时间", - sortable: true, - }, - ], - - // 表单字段配置 - formFields: [ - { - key: "name", - label: "姓名", - type: "text", - placeholder: "请输入管理员姓名", - required: true, - }, - { - key: "email", - label: "邮箱", - type: "email", - placeholder: "请输入管理员邮箱", - required: true, - }, - { - key: "password", - label: "密码", - type: "password", - placeholder: "请输入8-32位密码", - required: true, - }, - { - key: "createdAt", - label: "创建时间", - type: "datetime-local", - required: false, - }, - ], - - // 操作按钮配置 - actions: { - add: { - label: "添加管理员", - icon: "PlusIcon", - }, - edit: { - label: "编辑", - icon: "PencilIcon", - }, - delete: { - label: "删除", - icon: "TrashIcon", - }, - batchDelete: { - label: "批量删除", - icon: "TrashIcon", - }, - }, - - // 分页配置 - pagination: { - pageSizes: [10, 50, 100, 500], - defaultPageSize: 10, - }, -} \ No newline at end of file +export const adminConfig = createUserConfig( + "admin", + "管理员列表", + "添加管理员", + "请输入管理员姓名", + "请输入管理员邮箱" +) \ No newline at end of file diff --git a/src/features/user-management/config/base-config.ts b/src/features/user-management/config/base-config.ts new file mode 100644 index 0000000..154ac94 --- /dev/null +++ b/src/features/user-management/config/base-config.ts @@ -0,0 +1,86 @@ +import { z } from "zod" + +// 基础用户 schema +export const baseUserSchema = z.object({ + id: z.string(), + name: z.string().optional(), + email: z.string(), + password: z.string().optional(), + role: z.string().optional(), + createdAt: z.string(), + updatedAt: z.string().optional(), +}) + +// 基础添加用户 schema +export const baseAddUserSchema = z.object({ + name: z.string().min(1, "姓名为必填项"), + email: z.string().email("请输入有效的邮箱地址"), + password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), + createdAt: z.string(), +}) + +// 基础编辑用户 schema +export const baseEditUserSchema = z.object({ + id: z.string(), + name: z.string().min(1, "姓名为必填项"), + email: z.string().email("请输入有效的邮箱地址"), + password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), + createdAt: z.string(), +}) + +// 基础表格列配置 +export const baseColumns = [ + { key: "id", label: "ID", sortable: true }, + { key: "name", label: "姓名", sortable: true, searchable: true, placeholder: "搜索姓名" }, + { key: "email", label: "邮箱", sortable: true, searchable: true, placeholder: "搜索邮箱" }, + { key: "createdAt", label: "创建时间", sortable: true }, +] + +// 基础表单字段配置 +export const baseFormFields = [ + { key: "name", label: "姓名", type: "text", placeholder: "请输入姓名", required: true }, + { key: "email", label: "邮箱", type: "email", placeholder: "请输入邮箱", required: true }, + { key: "password", label: "密码", type: "password", placeholder: "请输入8-32位密码", required: true }, + { key: "createdAt", label: "创建时间", type: "datetime-local", required: false }, +] + +// 基础操作配置 +export const baseActions = { + add: { label: "添加", icon: "PlusIcon" }, + edit: { label: "编辑", icon: "PencilIcon" }, + delete: { label: "删除", icon: "TrashIcon" }, + batchDelete: { label: "批量删除", icon: "TrashIcon" }, +} + +// 基础分页配置 +export const basePagination = { + pageSizes: [10, 50, 100, 500], + defaultPageSize: 10, +} + +// 创建用户配置的工厂函数 +export function createUserConfig( + userType: string, + title: string, + addLabel: string, + namePlaceholder: string, + emailPlaceholder: string +) { + return { + userType, + title, + apiPath: "/api/user", + columns: baseColumns, + formFields: baseFormFields.map(field => ({ + ...field, + placeholder: field.key === 'name' ? namePlaceholder : + field.key === 'email' ? emailPlaceholder : + field.placeholder + })), + actions: { + ...baseActions, + add: { ...baseActions.add, label: addLabel } + }, + pagination: basePagination, + } +} \ No newline at end of file diff --git a/src/features/user-management/config/guest.ts b/src/features/user-management/config/guest.ts index bb31fc5..f41c910 100644 --- a/src/features/user-management/config/guest.ts +++ b/src/features/user-management/config/guest.ts @@ -1,51 +1,19 @@ import { z } from "zod"; +import { createUserConfig, baseUserSchema, baseAddUserSchema, baseEditUserSchema } from './base-config' -export const guestSchema = z.object({ - id: z.string(), - name: z.string().optional(), - email: z.string(), - password: z.string().optional(), - role: z.string().optional(), - createdAt: z.string(), - updatedAt: z.string().optional(), -}); +export const guestSchema = baseUserSchema; +export type Guest = z.infer; -export const addGuestSchema = z.object({ - name: z.string().min(1, "姓名为必填项"), - email: z.string().email("请输入有效的邮箱地址"), - password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), - createdAt: z.string(), -}); +export const addGuestSchema = baseAddUserSchema; +export type AddGuestFormData = z.infer; -export const editGuestSchema = z.object({ - id: z.string(), - name: z.string().min(1, "姓名为必填项"), - email: z.string().email("请输入有效的邮箱地址"), - password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), - createdAt: z.string(), -}); +export const editGuestSchema = baseEditUserSchema; +export type EditGuestFormData = z.infer; -export const guestConfig = { - userType: "guest", - title: "客户列表", - apiPath: "/api/user", - columns: [ - { key: "id", label: "ID", sortable: true }, - { key: "name", label: "姓名", sortable: true, searchable: true, placeholder: "搜索姓名" }, - { key: "email", label: "邮箱", sortable: true, searchable: true, placeholder: "搜索邮箱" }, - { key: "createdAt", label: "创建时间", sortable: true }, - ], - formFields: [ - { key: "name", label: "姓名", type: "text", placeholder: "请输入客户姓名", required: true }, - { key: "email", label: "邮箱", type: "email", placeholder: "请输入客户邮箱", required: true }, - { key: "password", label: "密码", type: "password", placeholder: "请输入8-32位密码", required: true }, - { key: "createdAt", label: "创建时间", type: "datetime-local", required: false }, - ], - actions: { - add: { label: "添加客户", icon: "PlusIcon" }, - edit: { label: "编辑", icon: "PencilIcon" }, - delete: { label: "删除", icon: "TrashIcon" }, - batchDelete: { label: "批量删除", icon: "TrashIcon" }, - }, - pagination: { pageSizes: [10, 50, 100, 500], defaultPageSize: 10 }, -}; \ No newline at end of file +export const guestConfig = createUserConfig( + "guest", + "客户列表", + "添加客户", + "请输入客户姓名", + "请输入客户邮箱" +); \ No newline at end of file diff --git a/src/features/user-management/config/teacher.ts b/src/features/user-management/config/teacher.ts index 387e2b8..ace2564 100644 --- a/src/features/user-management/config/teacher.ts +++ b/src/features/user-management/config/teacher.ts @@ -1,51 +1,19 @@ import { z } from "zod"; +import { createUserConfig, baseUserSchema, baseAddUserSchema, baseEditUserSchema } from './base-config' -export const teacherSchema = z.object({ - id: z.string(), - name: z.string().optional(), - email: z.string(), - password: z.string().optional(), - role: z.string().optional(), - createdAt: z.string(), - updatedAt: z.string().optional(), -}); +export const teacherSchema = baseUserSchema; +export type Teacher = z.infer; -export const addTeacherSchema = z.object({ - name: z.string().min(1, "姓名为必填项"), - email: z.string().email("请输入有效的邮箱地址"), - password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), - createdAt: z.string(), -}); +export const addTeacherSchema = baseAddUserSchema; +export type AddTeacherFormData = z.infer; -export const editTeacherSchema = z.object({ - id: z.string(), - name: z.string().min(1, "姓名为必填项"), - email: z.string().email("请输入有效的邮箱地址"), - password: z.string().min(8, "密码长度8-32位").max(32, "密码长度8-32位"), - createdAt: z.string(), -}); +export const editTeacherSchema = baseEditUserSchema; +export type EditTeacherFormData = z.infer; -export const teacherConfig = { - userType: "teacher", - title: "教师列表", - apiPath: "/api/user", - columns: [ - { key: "id", label: "ID", sortable: true }, - { key: "name", label: "姓名", sortable: true, searchable: true, placeholder: "搜索姓名" }, - { key: "email", label: "邮箱", sortable: true, searchable: true, placeholder: "搜索邮箱" }, - { key: "createdAt", label: "创建时间", sortable: true }, - ], - formFields: [ - { key: "name", label: "姓名", type: "text", placeholder: "请输入教师姓名", required: true }, - { key: "email", label: "邮箱", type: "email", placeholder: "请输入教师邮箱", required: true }, - { key: "password", label: "密码", type: "password", placeholder: "请输入8-32位密码", required: true }, - { key: "createdAt", label: "创建时间", type: "datetime-local", required: false }, - ], - actions: { - add: { label: "添加教师", icon: "PlusIcon" }, - edit: { label: "编辑", icon: "PencilIcon" }, - delete: { label: "删除", icon: "TrashIcon" }, - batchDelete: { label: "批量删除", icon: "TrashIcon" }, - }, - pagination: { pageSizes: [10, 50, 100, 500], defaultPageSize: 10 }, -}; \ No newline at end of file +export const teacherConfig = createUserConfig( + "teacher", + "教师列表", + "添加教师", + "请输入教师姓名", + "请输入教师邮箱" +); \ No newline at end of file