import { PrismaClient } from '@prisma/client'; import * as bcrypt from 'bcrypt'; const prisma = new PrismaClient(); // 初始权限数据 const permissions = [ // 用户管理权限 { code: 'user:create', name: '创建用户', resource: 'user', action: 'create' }, { code: 'user:read', name: '查看用户', resource: 'user', action: 'read' }, { code: 'user:update', name: '更新用户', resource: 'user', action: 'update' }, { code: 'user:delete', name: '删除用户', resource: 'user', action: 'delete' }, // 角色管理权限 { code: 'role:create', name: '创建角色', resource: 'role', action: 'create' }, { code: 'role:read', name: '查看角色', resource: 'role', action: 'read' }, { code: 'role:update', name: '更新角色', resource: 'role', action: 'update' }, { code: 'role:delete', name: '删除角色', resource: 'role', action: 'delete' }, // 权限管理权限 { code: 'permission:create', name: '创建权限', resource: 'permission', action: 'create' }, { code: 'permission:read', name: '查看权限', resource: 'permission', action: 'read' }, { code: 'permission:update', name: '更新权限', resource: 'permission', action: 'update' }, { code: 'permission:delete', name: '删除权限', resource: 'permission', action: 'delete' }, // 菜单管理权限 { code: 'menu:create', name: '创建菜单', resource: 'menu', action: 'create' }, { code: 'menu:read', name: '查看菜单', resource: 'menu', action: 'read' }, { code: 'menu:update', name: '更新菜单', resource: 'menu', action: 'update' }, { code: 'menu:delete', name: '删除菜单', resource: 'menu', action: 'delete' }, // 文件管理权限 { code: 'file:read', name: '查看文件', resource: 'file', action: 'read' }, { code: 'file:delete', name: '删除文件', resource: 'file', action: 'delete' }, // 教师管理权限 { code: 'teacher:create', name: '创建教师', resource: 'teacher', action: 'create' }, { code: 'teacher:read', name: '查看教师', resource: 'teacher', action: 'read' }, { code: 'teacher:update', name: '更新教师', resource: 'teacher', action: 'update' }, { code: 'teacher:delete', name: '删除教师', resource: 'teacher', action: 'delete' }, // 班级管理权限 { code: 'class:create', name: '创建班级', resource: 'class', action: 'create' }, { code: 'class:read', name: '查看班级', resource: 'class', action: 'read' }, { code: 'class:update', name: '更新班级', resource: 'class', action: 'update' }, { code: 'class:delete', name: '删除班级', resource: 'class', action: 'delete' }, // 学生管理权限 { code: 'student:create', name: '创建学生', resource: 'student', action: 'create' }, { code: 'student:read', name: '查看学生', resource: 'student', action: 'read' }, { code: 'student:update', name: '更新学生', resource: 'student', action: 'update' }, { code: 'student:delete', name: '删除学生', resource: 'student', action: 'delete' }, // OIDC 客户端管理权限 { code: 'oidc-client:create', name: '创建 OIDC 客户端', resource: 'oidc-client', action: 'create' }, { code: 'oidc-client:read', name: '查看 OIDC 客户端', resource: 'oidc-client', action: 'read' }, { code: 'oidc-client:update', name: '更新 OIDC 客户端', resource: 'oidc-client', action: 'update' }, { code: 'oidc-client:delete', name: '删除 OIDC 客户端', resource: 'oidc-client', action: 'delete' }, ]; // 初始角色数据 const roles = [ { code: 'super_admin', name: '超级管理员', description: '拥有系统所有权限', isSystem: true, sort: 0, }, { code: 'admin', name: '管理员', description: '拥有大部分管理权限', isSystem: true, sort: 1, }, { code: 'user', name: '普通用户', description: '基础用户权限', isSystem: true, sort: 2, }, ]; // 初始菜单数据 const menus = [ { code: 'dashboard', name: '仪表盘', type: 'menu', path: '/dashboard', icon: 'LayoutDashboard', sort: 0, isStatic: true, }, // 教学管理目录 { code: 'teaching', name: '教学管理', type: 'dir', icon: 'GraduationCap', sort: 10, isStatic: false, }, { code: 'student-management', name: '学生管理', type: 'menu', path: '/students', icon: 'Users', sort: 0, isStatic: false, }, { code: 'teacher-management', name: '教师管理', type: 'menu', path: '/teachers', icon: 'UserCheck', sort: 1, isStatic: false, }, { code: 'class-management', name: '班级管理', type: 'menu', path: '/classes', icon: 'School', sort: 2, isStatic: false, }, // 系统管理目录 { code: 'system', name: '系统管理', type: 'dir', icon: 'Settings', sort: 100, isStatic: true, }, { code: 'user-management', name: '用户管理', type: 'menu', path: '/users', icon: 'Users', sort: 0, isStatic: true, }, { code: 'file-management', name: '文件管理', type: 'menu', path: '/files', icon: 'FolderOpen', sort: 1, isStatic: true, }, { code: 'role-management', name: '角色管理', type: 'menu', path: '/roles', icon: 'Shield', sort: 2, isStatic: true, }, { code: 'permission-management', name: '权限管理', type: 'menu', path: '/permissions', icon: 'Key', sort: 3, isStatic: true, }, { code: 'menu-management', name: '菜单管理', type: 'menu', path: '/menus', icon: 'Menu', sort: 4, isStatic: true, }, { code: 'oidc-client-management', name: 'OIDC 客户端', type: 'menu', path: '/oidc-clients', icon: 'KeyRound', sort: 5, isStatic: true, }, { code: 'profile', name: '个人中心', type: 'menu', path: '/profile', icon: 'User', sort: 200, isStatic: true, }, { code: 'settings', name: '系统设置', type: 'menu', path: '/settings', icon: 'Settings', sort: 201, isStatic: true, }, ]; // 系统管理子菜单 codes const systemSubMenuCodes = [ 'user-management', 'file-management', 'role-management', 'permission-management', 'menu-management', 'oidc-client-management', ]; // 教学管理子菜单 codes const teachingSubMenuCodes = [ 'student-management', 'teacher-management', 'class-management', ]; async function main() { console.log('开始初始化种子数据...'); // 1. 创建权限 console.log('创建权限...'); for (const permission of permissions) { await prisma.permission.upsert({ where: { code: permission.code }, update: permission, create: permission, }); } console.log(`已创建 ${permissions.length} 个权限`); // 2. 创建角色 console.log('创建角色...'); for (const role of roles) { await prisma.role.upsert({ where: { code: role.code }, update: role, create: role, }); } console.log(`已创建 ${roles.length} 个角色`); // 3. 创建菜单 console.log('创建菜单...'); // 所有子菜单 codes const allSubMenuCodes = [...systemSubMenuCodes, ...teachingSubMenuCodes]; // 先创建顶级菜单(排除所有子菜单) const topMenus = menus.filter((m) => !allSubMenuCodes.includes(m.code)); for (const menu of topMenus) { await prisma.menu.upsert({ where: { code: menu.code }, update: menu, create: menu, }); } // 获取系统管理菜单的 ID const systemMenu = await prisma.menu.findUnique({ where: { code: 'system' }, }); // 创建系统管理子菜单 if (systemMenu) { const subMenus = menus.filter((m) => systemSubMenuCodes.includes(m.code)); for (const menu of subMenus) { await prisma.menu.upsert({ where: { code: menu.code }, update: { ...menu, parentId: systemMenu.id }, create: { ...menu, parentId: systemMenu.id }, }); } } // 获取教学管理菜单的 ID const teachingMenu = await prisma.menu.findUnique({ where: { code: 'teaching' }, }); // 创建教学管理子菜单 if (teachingMenu) { const subMenus = menus.filter((m) => teachingSubMenuCodes.includes(m.code)); for (const menu of subMenus) { await prisma.menu.upsert({ where: { code: menu.code }, update: { ...menu, parentId: teachingMenu.id }, create: { ...menu, parentId: teachingMenu.id }, }); } } console.log(`已创建 ${menus.length} 个菜单`); // 4. 清空所有角色的权限和菜单(不分配任何默认权限和菜单) console.log('清空角色权限和菜单...'); const adminRole = await prisma.role.findUnique({ where: { code: 'admin' }, }); const userRole = await prisma.role.findUnique({ where: { code: 'user' }, }); if (adminRole) { await prisma.rolePermission.deleteMany({ where: { roleId: adminRole.id }, }); await prisma.roleMenu.deleteMany({ where: { roleId: adminRole.id }, }); console.log('已清空管理员角色的权限和菜单'); } if (userRole) { await prisma.rolePermission.deleteMany({ where: { roleId: userRole.id }, }); await prisma.roleMenu.deleteMany({ where: { roleId: userRole.id }, }); console.log('已清空普通用户角色的权限和菜单'); } // 5. 创建超级管理员用户 console.log('创建超级管理员用户...'); const superAdminPassword = await bcrypt.hash('admin123', 10); // 由于复合唯一约束包含 deletedAt,无法使用 upsert,改用 findFirst + update/create let superAdminUser = await prisma.user.findFirst({ where: { email: 'admin@seclusion.dev' }, }); if (superAdminUser) { superAdminUser = await prisma.user.update({ where: { id: superAdminUser.id }, data: { isSuperAdmin: true }, }); } else { superAdminUser = await prisma.user.create({ data: { email: 'admin@seclusion.dev', password: superAdminPassword, name: '超级管理员', isSuperAdmin: true, }, }); } // 为超管用户分配超管角色 const superAdminRole = await prisma.role.findUnique({ where: { code: 'super_admin' }, }); if (superAdminRole) { await prisma.userRole.upsert({ where: { userId_roleId: { userId: superAdminUser.id, roleId: superAdminRole.id, }, }, update: {}, create: { userId: superAdminUser.id, roleId: superAdminRole.id, }, }); } console.log('超级管理员用户创建完成'); console.log(' 邮箱: admin@seclusion.dev'); console.log(' 密码: admin123'); // 6. 创建教学管理演示数据 console.log('\n创建教学管理演示数据...'); // 6.1 创建教师 const teachersData = [ { teacherNo: 'T001', name: '张明', gender: 'male', phone: '13800000001', email: 'zhangming@school.edu', subject: '语文' }, { teacherNo: 'T002', name: '李华', gender: 'female', phone: '13800000002', email: 'lihua@school.edu', subject: '数学' }, { teacherNo: 'T003', name: '王芳', gender: 'female', phone: '13800000003', email: 'wangfang@school.edu', subject: '英语' }, { teacherNo: 'T004', name: '赵强', gender: 'male', phone: '13800000004', email: 'zhaoqiang@school.edu', subject: '物理' }, { teacherNo: 'T005', name: '陈静', gender: 'female', phone: '13800000005', email: 'chenjing@school.edu', subject: '化学' }, { teacherNo: 'T006', name: '刘伟', gender: 'male', phone: '13800000006', email: 'liuwei@school.edu', subject: '生物' }, { teacherNo: 'T007', name: '周敏', gender: 'female', phone: '13800000007', email: 'zhoumin@school.edu', subject: '历史' }, { teacherNo: 'T008', name: '吴刚', gender: 'male', phone: '13800000008', email: 'wugang@school.edu', subject: '体育' }, ]; const teachers: Record = {}; for (const teacher of teachersData) { const created = await prisma.teacher.upsert({ where: { teacherNo: teacher.teacherNo }, update: teacher, create: teacher, }); teachers[teacher.teacherNo] = created; } console.log(`已创建 ${teachersData.length} 名教师`); // 6.2 创建班级 const classesData = [ { code: 'C2024-01', name: '高一(1)班', grade: '高一', headTeacherNo: 'T001' }, { code: 'C2024-02', name: '高一(2)班', grade: '高一', headTeacherNo: 'T002' }, { code: 'C2024-03', name: '高二(1)班', grade: '高二', headTeacherNo: 'T003' }, { code: 'C2024-04', name: '高三(1)班', grade: '高三', headTeacherNo: 'T004' }, ]; const classes: Record = {}; for (const cls of classesData) { const headTeacher = teachers[cls.headTeacherNo]; const created = await prisma.class.upsert({ where: { code: cls.code }, update: { name: cls.name, grade: cls.grade, headTeacherId: headTeacher?.id }, create: { code: cls.code, name: cls.name, grade: cls.grade, headTeacherId: headTeacher?.id }, }); classes[cls.code] = created; } console.log(`已创建 ${classesData.length} 个班级`); // 6.3 分配任课教师(多对多) const classTeacherAssignments = [ { classCode: 'C2024-01', teacherNos: ['T001', 'T002', 'T003', 'T004', 'T008'] }, { classCode: 'C2024-02', teacherNos: ['T002', 'T003', 'T005', 'T006', 'T008'] }, { classCode: 'C2024-03', teacherNos: ['T003', 'T004', 'T005', 'T007', 'T008'] }, { classCode: 'C2024-04', teacherNos: ['T001', 'T002', 'T004', 'T006', 'T007'] }, ]; for (const assignment of classTeacherAssignments) { const classEntity = classes[assignment.classCode]; if (!classEntity) continue; // 先删除该班级的所有任课教师关系 await prisma.classTeacher.deleteMany({ where: { classId: classEntity.id }, }); // 创建新的任课教师关系 for (const teacherNo of assignment.teacherNos) { const teacher = teachers[teacherNo]; if (!teacher) continue; await prisma.classTeacher.create({ data: { classId: classEntity.id, teacherId: teacher.id, }, }); } } console.log('已分配班级任课教师'); // 6.4 创建学生 const studentsData = [ { studentNo: 'S2024001', name: '小明', gender: 'male', phone: '13900000001', classCode: 'C2024-01' }, { studentNo: 'S2024002', name: '小红', gender: 'female', phone: '13900000002', classCode: 'C2024-01' }, { studentNo: 'S2024003', name: '小刚', gender: 'male', phone: '13900000003', classCode: 'C2024-01' }, { studentNo: 'S2024004', name: '小丽', gender: 'female', phone: '13900000004', classCode: 'C2024-01' }, { studentNo: 'S2024005', name: '小华', gender: 'male', phone: '13900000005', classCode: 'C2024-02' }, { studentNo: 'S2024006', name: '小芳', gender: 'female', phone: '13900000006', classCode: 'C2024-02' }, { studentNo: 'S2024007', name: '小强', gender: 'male', phone: '13900000007', classCode: 'C2024-02' }, { studentNo: 'S2024008', name: '小敏', gender: 'female', phone: '13900000008', classCode: 'C2024-03' }, { studentNo: 'S2024009', name: '小伟', gender: 'male', phone: '13900000009', classCode: 'C2024-03' }, { studentNo: 'S2024010', name: '小静', gender: 'female', phone: '13900000010', classCode: 'C2024-03' }, { studentNo: 'S2024011', name: '小杰', gender: 'male', phone: '13900000011', classCode: 'C2024-04' }, { studentNo: 'S2024012', name: '小雪', gender: 'female', phone: '13900000012', classCode: 'C2024-04' }, { studentNo: 'S2024013', name: '小龙', gender: 'male', phone: '13900000013', classCode: 'C2024-04' }, { studentNo: 'S2024014', name: '小燕', gender: 'female', phone: '13900000014', classCode: 'C2024-04' }, { studentNo: 'S2024015', name: '小峰', gender: 'male', phone: '13900000015', classCode: 'C2024-04' }, ]; for (const student of studentsData) { const classEntity = classes[student.classCode]; await prisma.student.upsert({ where: { studentNo: student.studentNo }, update: { name: student.name, gender: student.gender, phone: student.phone, classId: classEntity?.id, }, create: { studentNo: student.studentNo, name: student.name, gender: student.gender, phone: student.phone, classId: classEntity?.id, }, }); } console.log(`已创建 ${studentsData.length} 名学生`); console.log('\n种子数据初始化完成!'); } main() .catch((e) => { console.error('种子数据初始化失败:', e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });