// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import * as dotenv from 'dotenv'; import * as path from 'path'; const nodeEnv = process.env.NODE_ENV || 'development'; const envFile = `.env.${nodeEnv}`; const backendDir = path.resolve(__dirname, '..'); const envPath = path.resolve(backendDir, envFile); dotenv.config({ path: envPath }); if (!process.env.DATABASE_URL) { dotenv.config({ path: path.resolve(backendDir, '.env') }); } if (!process.env.DATABASE_URL) { console.error('DATABASE_URL not found'); process.exit(1); } import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); // ============================================ // 权限定义 // ============================================ // 基础权限(所有角色共享的权限池) const allPermissions = [ // 工作台 { code: 'workbench:read', resource: 'workbench', action: 'read', name: '查看工作台', description: '允许查看工作台' }, // 用户管理 { code: 'user:create', resource: 'user', action: 'create', name: '创建用户', description: '允许创建新用户' }, { code: 'user:read', resource: 'user', action: 'read', name: '查看用户', description: '允许查看用户列表和详情' }, { code: 'user:update', resource: 'user', action: 'update', name: '更新用户', description: '允许更新用户信息' }, { code: 'user:delete', resource: 'user', action: 'delete', name: '删除用户', description: '允许删除用户' }, // 角色管理 { code: 'role:create', resource: 'role', action: 'create', name: '创建角色', description: '允许创建新角色' }, { code: 'role:read', resource: 'role', action: 'read', name: '查看角色', description: '允许查看角色列表和详情' }, { code: 'role:update', resource: 'role', action: 'update', name: '更新角色', description: '允许更新角色信息' }, { code: 'role:delete', resource: 'role', action: 'delete', name: '删除角色', description: '允许删除角色' }, { code: 'role:assign', resource: 'role', action: 'assign', name: '分配角色', description: '允许给用户分配角色' }, // 权限管理 { code: 'permission:read', resource: 'permission', action: 'read', name: '查看权限', description: '允许查看权限列表' }, // 菜单管理 { code: 'menu:read', resource: 'menu', action: 'read', name: '查看菜单', description: '允许查看菜单列表' }, // 租户管理(超级租户专属) { code: 'tenant:create', resource: 'tenant', action: 'create', name: '创建租户', description: '允许创建租户' }, { code: 'tenant:read', resource: 'tenant', action: 'read', name: '查看租户', description: '允许查看租户列表' }, { code: 'tenant:update', resource: 'tenant', action: 'update', name: '更新租户', description: '允许更新租户信息' }, { code: 'tenant:delete', resource: 'tenant', action: 'delete', name: '删除租户', description: '允许删除租户' }, // 学校管理 { code: 'school:create', resource: 'school', action: 'create', name: '创建学校', description: '允许创建学校信息' }, { code: 'school:read', resource: 'school', action: 'read', name: '查看学校', description: '允许查看学校信息' }, { code: 'school:update', resource: 'school', action: 'update', name: '更新学校', description: '允许更新学校信息' }, { code: 'school:delete', resource: 'school', action: 'delete', name: '删除学校', description: '允许删除学校信息' }, // 部门管理 { code: 'department:create', resource: 'department', action: 'create', name: '创建部门', description: '允许创建部门' }, { code: 'department:read', resource: 'department', action: 'read', name: '查看部门', description: '允许查看部门列表' }, { code: 'department:update', resource: 'department', action: 'update', name: '更新部门', description: '允许更新部门信息' }, { code: 'department:delete', resource: 'department', action: 'delete', name: '删除部门', description: '允许删除部门' }, // 年级管理 { code: 'grade:create', resource: 'grade', action: 'create', name: '创建年级', description: '允许创建年级' }, { code: 'grade:read', resource: 'grade', action: 'read', name: '查看年级', description: '允许查看年级列表' }, { code: 'grade:update', resource: 'grade', action: 'update', name: '更新年级', description: '允许更新年级信息' }, { code: 'grade:delete', resource: 'grade', action: 'delete', name: '删除年级', description: '允许删除年级' }, // 班级管理 { code: 'class:create', resource: 'class', action: 'create', name: '创建班级', description: '允许创建班级' }, { code: 'class:read', resource: 'class', action: 'read', name: '查看班级', description: '允许查看班级列表' }, { code: 'class:update', resource: 'class', action: 'update', name: '更新班级', description: '允许更新班级信息' }, { code: 'class:delete', resource: 'class', action: 'delete', name: '删除班级', description: '允许删除班级' }, // 教师管理 { code: 'teacher:create', resource: 'teacher', action: 'create', name: '创建教师', description: '允许创建教师' }, { code: 'teacher:read', resource: 'teacher', action: 'read', name: '查看教师', description: '允许查看教师列表' }, { code: 'teacher:update', resource: 'teacher', action: 'update', name: '更新教师', description: '允许更新教师信息' }, { code: 'teacher:delete', resource: 'teacher', action: 'delete', name: '删除教师', description: '允许删除教师' }, // 学生管理 { code: 'student:create', resource: 'student', action: 'create', name: '创建学生', description: '允许创建学生' }, { code: 'student:read', resource: 'student', action: 'read', name: '查看学生', description: '允许查看学生列表' }, { code: 'student:update', resource: 'student', action: 'update', name: '更新学生', description: '允许更新学生信息' }, { code: 'student:delete', resource: 'student', action: 'delete', name: '删除学生', description: '允许删除学生' }, // 赛事管理(超级租户) { code: 'contest:create', resource: 'contest', action: 'create', name: '创建赛事', description: '允许创建赛事' }, { code: 'contest:read', resource: 'contest', action: 'read', name: '查看赛事', description: '允许查看赛事列表' }, { code: 'contest:update', resource: 'contest', action: 'update', name: '更新赛事', description: '允许更新赛事信息' }, { code: 'contest:delete', resource: 'contest', action: 'delete', name: '删除赛事', description: '允许删除赛事' }, { code: 'contest:publish', resource: 'contest', action: 'publish', name: '发布赛事', description: '允许发布/取消发布赛事' }, { code: 'contest:finish', resource: 'contest', action: 'finish', name: '结束赛事', description: '允许结束赛事' }, // 评审规则管理 { code: 'review-rule:create', resource: 'review-rule', action: 'create', name: '创建评审规则', description: '允许创建评审规则' }, { code: 'review-rule:read', resource: 'review-rule', action: 'read', name: '查看评审规则', description: '允许查看评审规则' }, { code: 'review-rule:update', resource: 'review-rule', action: 'update', name: '更新评审规则', description: '允许更新评审规则' }, { code: 'review-rule:delete', resource: 'review-rule', action: 'delete', name: '删除评审规则', description: '允许删除评审规则' }, // 评委管理 { code: 'judge:create', resource: 'judge', action: 'create', name: '添加评委', description: '允许添加评委' }, { code: 'judge:read', resource: 'judge', action: 'read', name: '查看评委', description: '允许查看评委列表' }, { code: 'judge:update', resource: 'judge', action: 'update', name: '更新评委', description: '允许更新评委信息' }, { code: 'judge:delete', resource: 'judge', action: 'delete', name: '删除评委', description: '允许删除评委' }, { code: 'judge:assign', resource: 'judge', action: 'assign', name: '分配评委', description: '允许为赛事分配评委' }, // 赛事报名(学校端) { code: 'registration:create', resource: 'registration', action: 'create', name: '创建报名', description: '允许报名赛事' }, { code: 'registration:read', resource: 'registration', action: 'read', name: '查看报名', description: '允许查看报名记录' }, { code: 'registration:update', resource: 'registration', action: 'update', name: '更新报名', description: '允许更新报名信息' }, { code: 'registration:delete', resource: 'registration', action: 'delete', name: '取消报名', description: '允许取消报名' }, { code: 'registration:approve', resource: 'registration', action: 'approve', name: '审核报名', description: '允许审核报名' }, // 参赛作品 { code: 'work:create', resource: 'work', action: 'create', name: '上传作品', description: '允许上传参赛作品' }, { code: 'work:read', resource: 'work', action: 'read', name: '查看作品', description: '允许查看参赛作品' }, { code: 'work:update', resource: 'work', action: 'update', name: '更新作品', description: '允许更新作品信息' }, { code: 'work:delete', resource: 'work', action: 'delete', name: '删除作品', description: '允许删除作品' }, { code: 'work:submit', resource: 'work', action: 'submit', name: '提交作品', description: '允许提交作品' }, // 作品评审(评委端) { code: 'review:read', resource: 'review', action: 'read', name: '查看评审任务', description: '允许查看待评审作品' }, { code: 'review:score', resource: 'review', action: 'score', name: '评审打分', description: '允许对作品打分' }, // 赛事公告 { code: 'notice:create', resource: 'notice', action: 'create', name: '创建公告', description: '允许创建赛事公告' }, { code: 'notice:read', resource: 'notice', action: 'read', name: '查看公告', description: '允许查看赛事公告' }, { code: 'notice:update', resource: 'notice', action: 'update', name: '更新公告', description: '允许更新公告信息' }, { code: 'notice:delete', resource: 'notice', action: 'delete', name: '删除公告', description: '允许删除公告' }, // 作业管理 { code: 'homework:create', resource: 'homework', action: 'create', name: '创建作业', description: '允许创建作业' }, { code: 'homework:read', resource: 'homework', action: 'read', name: '查看作业', description: '允许查看作业列表' }, { code: 'homework:update', resource: 'homework', action: 'update', name: '更新作业', description: '允许更新作业信息' }, { code: 'homework:delete', resource: 'homework', action: 'delete', name: '删除作业', description: '允许删除作业' }, { code: 'homework:publish', resource: 'homework', action: 'publish', name: '发布作业', description: '允许发布作业' }, // 作业提交 { code: 'homework-submission:create', resource: 'homework-submission', action: 'create', name: '提交作业', description: '允许提交作业' }, { code: 'homework-submission:read', resource: 'homework-submission', action: 'read', name: '查看作业提交', description: '允许查看作业提交记录' }, { code: 'homework-submission:update', resource: 'homework-submission', action: 'update', name: '更新作业提交', description: '允许更新提交的作业' }, // 作业评审规则 { code: 'homework-review-rule:create', resource: 'homework-review-rule', action: 'create', name: '创建作业评审规则', description: '允许创建作业评审规则' }, { code: 'homework-review-rule:read', resource: 'homework-review-rule', action: 'read', name: '查看作业评审规则', description: '允许查看作业评审规则' }, { code: 'homework-review-rule:update', resource: 'homework-review-rule', action: 'update', name: '更新作业评审规则', description: '允许更新作业评审规则' }, { code: 'homework-review-rule:delete', resource: 'homework-review-rule', action: 'delete', name: '删除作业评审规则', description: '允许删除作业评审规则' }, // 作业评分 { code: 'homework-score:create', resource: 'homework-score', action: 'create', name: '作业评分', description: '允许对作业评分' }, { code: 'homework-score:read', resource: 'homework-score', action: 'read', name: '查看作业评分', description: '允许查看作业评分' }, // 字典管理 { code: 'dict:create', resource: 'dict', action: 'create', name: '创建字典', description: '允许创建新字典' }, { code: 'dict:read', resource: 'dict', action: 'read', name: '查看字典', description: '允许查看字典列表和详情' }, { code: 'dict:update', resource: 'dict', action: 'update', name: '更新字典', description: '允许更新字典信息' }, { code: 'dict:delete', resource: 'dict', action: 'delete', name: '删除字典', description: '允许删除字典' }, // 系统配置 { code: 'config:create', resource: 'config', action: 'create', name: '创建配置', description: '允许创建新配置' }, { code: 'config:read', resource: 'config', action: 'read', name: '查看配置', description: '允许查看配置列表和详情' }, { code: 'config:update', resource: 'config', action: 'update', name: '更新配置', description: '允许更新配置信息' }, { code: 'config:delete', resource: 'config', action: 'delete', name: '删除配置', description: '允许删除配置' }, // 日志管理 { code: 'log:read', resource: 'log', action: 'read', name: '查看日志', description: '允许查看系统日志' }, { code: 'log:delete', resource: 'log', action: 'delete', name: '删除日志', description: '允许删除系统日志' }, // 赛事活动(学校端) { code: 'activity:read', resource: 'activity', action: 'read', name: '查看赛事活动', description: '允许查看已发布的赛事活动' }, { code: 'activity:guidance', resource: 'activity', action: 'guidance', name: '指导学生', description: '允许指导学生参赛' }, ]; // ============================================ // 角色定义和权限映射 // ============================================ // 超级租户角色 const superTenantRoles = [ { code: 'super_admin', name: '超级管理员', description: '系统超级管理员,管理赛事和系统配置', permissions: [ // 工作台 'workbench:read', // 系统管理 'user:create', 'user:read', 'user:update', 'user:delete', 'role:create', 'role:read', 'role:update', 'role:delete', 'role:assign', 'permission:read', 'menu:read', 'tenant:create', 'tenant:read', 'tenant:update', 'tenant:delete', 'dict:create', 'dict:read', 'dict:update', 'dict:delete', 'config:create', 'config:read', 'config:update', 'config:delete', 'log:read', 'log:delete', // 赛事管理 'contest:create', 'contest:read', 'contest:update', 'contest:delete', 'contest:publish', 'contest:finish', 'review-rule:create', 'review-rule:read', 'review-rule:update', 'review-rule:delete', 'judge:create', 'judge:read', 'judge:update', 'judge:delete', 'judge:assign', 'registration:read', 'registration:approve', 'work:read', 'notice:create', 'notice:read', 'notice:update', 'notice:delete', ], }, { code: 'judge', name: '评委', description: '赛事评委,可以评审作品', permissions: [ 'workbench:read', 'activity:read', // 查看赛事活动 'work:read', // 查看待评审作品 'review:read', // 查看评审任务 'review:score', // 评审打分 'notice:read', // 查看公告 ], }, ]; // 普通租户(学校)角色 const normalTenantRoles = [ { code: 'school_admin', name: '学校管理员', description: '学校管理员,管理学校信息、教师、学生等', permissions: [ 'workbench:read', 'user:create', 'user:read', 'user:update', 'user:delete', 'role:create', 'role:read', 'role:update', 'role:delete', 'role:assign', 'permission:read', 'menu:read', // 学校管理 'school:create', 'school:read', 'school:update', 'school:delete', 'department:create', 'department:read', 'department:update', 'department:delete', 'grade:create', 'grade:read', 'grade:update', 'grade:delete', 'class:create', 'class:read', 'class:update', 'class:delete', 'teacher:create', 'teacher:read', 'teacher:update', 'teacher:delete', 'student:create', 'student:read', 'student:update', 'student:delete', // 赛事活动 'activity:read', 'notice:read', // 可以查看报名和作品 'registration:read', 'work:read', ], }, { code: 'teacher', name: '教师', description: '教师角色,可以报名赛事、指导学生、管理作业', permissions: [ 'workbench:read', // 查看基础信息 'grade:read', 'class:read', 'student:read', // 赛事活动 'activity:read', // 查看赛事活动列表 'activity:guidance', // 指导学生参赛 'notice:read', // 查看赛事公告 'registration:create', 'registration:read', 'registration:update', 'registration:delete', // 报名管理 'work:create', 'work:read', 'work:update', 'work:submit', // 指导学生上传作品 // 作业管理 'homework:create', 'homework:read', 'homework:update', 'homework:delete', 'homework:publish', 'homework-submission:read', 'homework-review-rule:create', 'homework-review-rule:read', 'homework-review-rule:update', 'homework-review-rule:delete', 'homework-score:create', 'homework-score:read', ], }, { code: 'student', name: '学生', description: '学生角色,可以查看赛事、上传作品、提交作业', permissions: [ 'workbench:read', // 赛事活动 'activity:read', // 查看赛事活动列表 'notice:read', // 查看赛事公告 'registration:read', // 查看自己的报名记录 'work:create', 'work:read', 'work:update', 'work:submit', // 上传/管理自己的作品 // 作业 'homework:read', // 查看作业 'homework-submission:create', 'homework-submission:read', 'homework-submission:update', // 提交作业 'homework-score:read', // 查看自己的作业评分 ], }, ]; // ============================================ // 初始化函数 // ============================================ /** * 为租户创建权限 */ async function createPermissions(tenantId: number, permissionCodes: string[]) { const createdPermissions: { [code: string]: number } = {}; for (const code of permissionCodes) { const permDef = allPermissions.find(p => p.code === code); if (!permDef) { console.log(` ⚠️ 权限定义不存在: ${code}`); continue; } // 检查是否已存在 let permission = await prisma.permission.findFirst({ where: { tenantId, code }, }); if (!permission) { permission = await prisma.permission.create({ data: { tenantId, code: permDef.code, resource: permDef.resource, action: permDef.action, name: permDef.name, description: permDef.description, validState: 1, }, }); console.log(` ✓ 创建权限: ${code}`); } createdPermissions[code] = permission.id; } return createdPermissions; } /** * 为租户创建角色并分配权限 */ async function createRoleWithPermissions( tenantId: number, roleConfig: { code: string; name: string; description: string; permissions: string[] }, permissionMap: { [code: string]: number } ) { // 创建或获取角色 let role = await prisma.role.findFirst({ where: { tenantId, code: roleConfig.code }, }); if (!role) { role = await prisma.role.create({ data: { tenantId, code: roleConfig.code, name: roleConfig.name, description: roleConfig.description, validState: 1, }, }); console.log(` ✓ 创建角色: ${roleConfig.name} (${roleConfig.code})`); } else { // 更新角色信息 role = await prisma.role.update({ where: { id: role.id }, data: { name: roleConfig.name, description: roleConfig.description, }, }); console.log(` ✓ 更新角色: ${roleConfig.name} (${roleConfig.code})`); } // 分配权限 const existingRolePermissions = await prisma.rolePermission.findMany({ where: { roleId: role.id }, select: { permissionId: true }, }); const existingPermissionIds = new Set(existingRolePermissions.map(rp => rp.permissionId)); let addedCount = 0; for (const permCode of roleConfig.permissions) { const permissionId = permissionMap[permCode]; if (!permissionId) { console.log(` ⚠️ 权限不存在: ${permCode}`); continue; } if (!existingPermissionIds.has(permissionId)) { await prisma.rolePermission.create({ data: { roleId: role.id, permissionId, }, }); addedCount++; } } if (addedCount > 0) { console.log(` 添加了 ${addedCount} 个权限`); } return role; } /** * 初始化超级租户的角色和权限 */ async function initSuperTenantRoles() { console.log('\n🚀 开始初始化超级租户角色和权限...\n'); // 查找超级租户 const superTenant = await prisma.tenant.findFirst({ where: { isSuper: 1, validState: 1 }, }); if (!superTenant) { console.error('❌ 超级租户不存在!请先运行 init:super-tenant'); return; } console.log(`找到超级租户: ${superTenant.name} (${superTenant.code})\n`); // 收集所有需要的权限码 const allPermissionCodes = new Set(); superTenantRoles.forEach(role => { role.permissions.forEach(code => allPermissionCodes.add(code)); }); // 创建权限 console.log('📝 创建权限...'); const permissionMap = await createPermissions(superTenant.id, Array.from(allPermissionCodes)); console.log(`✅ 共 ${Object.keys(permissionMap).length} 个权限\n`); // 创建角色 console.log('👥 创建角色...'); for (const roleConfig of superTenantRoles) { await createRoleWithPermissions(superTenant.id, roleConfig, permissionMap); } console.log('\n✅ 超级租户角色和权限初始化完成!'); } /** * 初始化普通租户的角色和权限 */ async function initNormalTenantRoles(tenantCode: string) { console.log(`\n🚀 开始初始化租户 "${tenantCode}" 的角色和权限...\n`); // 查找租户 const tenant = await prisma.tenant.findFirst({ where: { code: tenantCode, validState: 1 }, }); if (!tenant) { console.error(`❌ 租户 "${tenantCode}" 不存在!`); return; } if (tenant.isSuper === 1) { console.log('⚠️ 这是超级租户,请使用 --super 选项'); return; } console.log(`找到租户: ${tenant.name} (${tenant.code})\n`); // 收集所有需要的权限码 const allPermissionCodes = new Set(); normalTenantRoles.forEach(role => { role.permissions.forEach(code => allPermissionCodes.add(code)); }); // 创建权限 console.log('📝 创建权限...'); const permissionMap = await createPermissions(tenant.id, Array.from(allPermissionCodes)); console.log(`✅ 共 ${Object.keys(permissionMap).length} 个权限\n`); // 创建角色 console.log('👥 创建角色...'); for (const roleConfig of normalTenantRoles) { await createRoleWithPermissions(tenant.id, roleConfig, permissionMap); } // 输出角色信息 console.log('\n📊 角色权限概览:'); for (const roleConfig of normalTenantRoles) { console.log(` ${roleConfig.name} (${roleConfig.code}): ${roleConfig.permissions.length} 个权限`); } console.log(`\n✅ 租户 "${tenantCode}" 角色和权限初始化完成!`); } /** * 初始化所有普通租户的角色和权限 */ async function initAllNormalTenantRoles() { console.log('\n🚀 开始初始化所有普通租户的角色和权限...\n'); // 查找所有普通租户 const normalTenants = await prisma.tenant.findMany({ where: { isSuper: { not: 1 }, validState: 1 }, }); if (normalTenants.length === 0) { console.log('⚠️ 没有找到普通租户'); return; } console.log(`找到 ${normalTenants.length} 个普通租户\n`); for (const tenant of normalTenants) { await initNormalTenantRoles(tenant.code); console.log(''); } console.log('\n✅ 所有普通租户角色和权限初始化完成!'); } // ============================================ // 主函数 // ============================================ async function main() { const args = process.argv.slice(2); const isSuper = args.includes('--super'); const isAll = args.includes('--all'); const tenantCode = args.find(arg => !arg.startsWith('--')); try { if (isSuper) { await initSuperTenantRoles(); } else if (isAll) { await initAllNormalTenantRoles(); } else if (tenantCode) { await initNormalTenantRoles(tenantCode); } else { console.log('使用方法:'); console.log(' 初始化超级租户角色: ts-node scripts/init-roles-permissions.ts --super'); console.log(' 初始化指定租户角色: ts-node scripts/init-roles-permissions.ts <租户编码>'); console.log(' 初始化所有普通租户: ts-node scripts/init-roles-permissions.ts --all'); process.exit(1); } } finally { await prisma.$disconnect(); } } main() .then(() => { console.log('\n🎉 脚本执行完成!'); process.exit(0); }) .catch((error) => { console.error('\n💥 脚本执行失败:', error); process.exit(1); });