// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck // 加载环境变量(必须在其他导入之前) import * as dotenv from 'dotenv'; import * as path from 'path'; import * as fs from 'fs'; // 根据 NODE_ENV 加载对应的环境配置文件 const nodeEnv = process.env.NODE_ENV || 'development'; const envFile = `.env.${nodeEnv}`; // scripts 目录的父目录就是 backend 目录 const backendDir = path.resolve(__dirname, '..'); const envPath = path.resolve(backendDir, envFile); // 尝试加载环境特定的配置文件 dotenv.config({ path: envPath }); // 如果环境特定文件不存在,尝试加载默认的 .env 文件 if (!process.env.DATABASE_URL) { dotenv.config({ path: path.resolve(backendDir, '.env') }); } // 验证必要的环境变量 if (!process.env.DATABASE_URL) { console.error('❌ 错误: 未找到 DATABASE_URL 环境变量'); console.error(` 请确保存在以下文件之一:`); console.error(` - ${envPath}`); console.error(` - ${path.resolve(backendDir, '.env')}`); console.error(` 或者设置 NODE_ENV 环境变量(当前: ${nodeEnv})`); process.exit(1); } import { PrismaClient } from '@prisma/client'; import * as bcrypt from 'bcrypt'; const prisma = new PrismaClient(); // 从 JSON 文件加载权限数据 const permissionsFilePath = path.resolve(backendDir, 'data', 'permissions.json'); if (!fs.existsSync(permissionsFilePath)) { console.error(`❌ 错误: 权限数据文件不存在: ${permissionsFilePath}`); process.exit(1); } const permissions = JSON.parse(fs.readFileSync(permissionsFilePath, 'utf-8')); async function initTenantMenuAndPermissions(tenantCode: string) { try { console.log(`🚀 开始为租户 "${tenantCode}" 初始化菜单和权限...\n`); // 1. 查找或创建租户 console.log(`📋 步骤 1: 查找或创建租户 "${tenantCode}"...`); let tenant = await prisma.tenant.findUnique({ where: { code: tenantCode }, }); if (!tenant) { // 创建租户 tenant = await prisma.tenant.create({ data: { name: `${tenantCode} 租户`, code: tenantCode, domain: tenantCode, description: `租户 ${tenantCode}`, isSuper: 0, validState: 1, }, }); console.log(`✅ 租户创建成功: ${tenant.name} (${tenant.code})\n`); } else { if (tenant.validState !== 1) { console.error(`❌ 错误: 租户 "${tenantCode}" 状态无效!`); process.exit(1); } console.log(`✅ 找到租户: ${tenant.name} (${tenant.code})\n`); } // 2. 查找或创建 admin 用户 console.log(`👤 步骤 2: 查找或创建 admin 用户...`); let adminUser = await prisma.user.findFirst({ where: { tenantId: tenant.id, username: 'admin', }, }); const password = `admin@${tenantCode}`; const hashedPassword = await bcrypt.hash(password, 10); if (!adminUser) { adminUser = await prisma.user.create({ data: { tenantId: tenant.id, username: 'admin', password: hashedPassword, nickname: '管理员', email: `admin@${tenantCode}.com`, validState: 1, }, }); console.log(`✅ admin 用户创建成功: ${adminUser.username}\n`); } else { // 更新密码(确保密码是最新的) adminUser = await prisma.user.update({ where: { id: adminUser.id }, data: { password: hashedPassword, nickname: '管理员', email: `admin@${tenantCode}.com`, validState: 1, }, }); console.log(`✅ admin 用户已存在: ${adminUser.username}\n`); } // 3. 查找或创建 admin 角色 console.log(`👤 步骤 3: 查找或创建 admin 角色...`); let adminRole = await prisma.role.findFirst({ where: { tenantId: tenant.id, code: 'admin', }, }); if (!adminRole) { adminRole = await prisma.role.create({ data: { tenantId: tenant.id, name: '管理员', code: 'admin', description: '租户管理员角色,拥有租户的所有权限', validState: 1, }, }); console.log(`✅ admin 角色创建成功: ${adminRole.name} (${adminRole.code})\n`); } else { adminRole = await prisma.role.update({ where: { id: adminRole.id }, data: { name: '管理员', description: '租户管理员角色,拥有租户的所有权限', validState: 1, }, }); console.log(`✅ admin 角色已存在: ${adminRole.name} (${adminRole.code})\n`); } // 4. 为 admin 用户分配 admin 角色 console.log(`🔗 步骤 4: 为 admin 用户分配 admin 角色...`); const existingUserRole = await prisma.userRole.findUnique({ where: { userId_roleId: { userId: adminUser.id, roleId: adminRole.id, }, }, }); if (!existingUserRole) { await prisma.userRole.create({ data: { userId: adminUser.id, roleId: adminRole.id, }, }); console.log(`✅ 角色分配成功\n`); } else { console.log(`✅ 用户已拥有 admin 角色\n`); } // 5. 初始化租户权限(如果不存在则创建) console.log(`📝 步骤 5: 初始化租户权限...`); const createdPermissions = []; for (const perm of permissions) { // 检查权限是否已存在 const existingPermission = await prisma.permission.findFirst({ where: { tenantId: tenant.id, code: perm.code, }, }); if (!existingPermission) { // 创建权限 const permission = await prisma.permission.create({ data: { tenantId: tenant.id, code: perm.code, resource: perm.resource, action: perm.action, name: perm.name, description: perm.description, validState: 1, }, }); createdPermissions.push(permission); console.log(` ✓ 创建权限: ${perm.code} - ${perm.name}`); } else { // 更新现有权限(确保信息是最新的) const permission = await prisma.permission.update({ where: { id: existingPermission.id }, data: { name: perm.name, resource: perm.resource, action: perm.action, description: perm.description, validState: 1, }, }); createdPermissions.push(permission); } } console.log(`✅ 共确保 ${createdPermissions.length} 个权限存在\n`); // 获取租户的所有有效权限 const tenantPermissions = await prisma.permission.findMany({ where: { tenantId: tenant.id, validState: 1, }, }); // 6. 为 admin 角色分配所有权限 console.log(`🔗 步骤 6: 为 admin 角色分配所有权限...`); const existingRolePermissions = await prisma.rolePermission.findMany({ where: { roleId: adminRole.id }, select: { permissionId: true }, }); const existingPermissionIds = new Set( existingRolePermissions.map((rp) => rp.permissionId), ); let addedPermissionCount = 0; for (const permission of tenantPermissions) { if (!existingPermissionIds.has(permission.id)) { await prisma.rolePermission.create({ data: { roleId: adminRole.id, permissionId: permission.id, }, }); addedPermissionCount++; } } if (addedPermissionCount > 0) { console.log(`✅ 为 admin 角色添加了 ${addedPermissionCount} 个权限`); console.log(`✅ admin 角色现在拥有 ${tenantPermissions.length} 个权限\n`); } else { console.log( `✅ admin 角色已拥有所有权限(${tenantPermissions.length} 个)\n`, ); } // 7. 为租户分配所有菜单 console.log(`📋 步骤 7: 为租户分配所有菜单...`); // 获取所有有效菜单 const allMenus = await prisma.menu.findMany({ where: { validState: 1, }, orderBy: [{ sort: 'asc' }, { id: 'asc' }], }); if (allMenus.length === 0) { console.log('⚠️ 警告: 数据库中没有任何菜单'); console.log(' 请先运行 pnpm init:menus 初始化菜单\n'); } else { console.log(` 找到 ${allMenus.length} 个菜单\n`); // 获取租户已分配的菜单 const existingTenantMenus = await prisma.tenantMenu.findMany({ where: { tenantId: tenant.id, }, select: { menuId: true, }, }); const existingMenuIds = new Set(existingTenantMenus.map((tm) => tm.menuId)); // 为租户分配所有菜单 let addedMenuCount = 0; const menuNames: string[] = []; for (const menu of allMenus) { if (!existingMenuIds.has(menu.id)) { await prisma.tenantMenu.create({ data: { tenantId: tenant.id, menuId: menu.id, }, }); addedMenuCount++; menuNames.push(menu.name); } } if (addedMenuCount > 0) { console.log(`✅ 为租户添加了 ${addedMenuCount} 个菜单:`); menuNames.forEach((name) => { console.log(` ✓ ${name}`); }); console.log(`\n✅ 租户现在拥有 ${allMenus.length} 个菜单\n`); } else { console.log(`✅ 租户已拥有所有菜单(${allMenus.length} 个)\n`); } } // 8. 验证结果 console.log('🔍 步骤 8: 验证结果...'); const userWithRoles = await prisma.user.findUnique({ where: { id: adminUser.id }, include: { roles: { include: { role: { include: { permissions: { include: { permission: true, }, }, }, }, }, }, }, }); const roleCodes = userWithRoles?.roles.map((ur) => ur.role.code) || []; const permissionCodes = new Set(); userWithRoles?.roles.forEach((ur) => { ur.role.permissions.forEach((rp) => { permissionCodes.add(rp.permission.code); }); }); const finalMenus = await prisma.tenantMenu.findMany({ where: { tenantId: tenant.id, }, include: { menu: true, }, }); console.log(`\n📊 初始化结果:`); console.log('========================================'); console.log('租户信息:'); console.log(` 租户名称: ${tenant.name}`); console.log(` 租户编码: ${tenant.code}`); console.log(` 访问链接: http://your-domain.com/?tenant=${tenant.code}`); console.log('========================================'); console.log('管理员登录信息:'); console.log(` 用户名: ${adminUser.username}`); console.log(` 密码: ${password}`); console.log(` 昵称: ${adminUser.nickname}`); console.log(` 邮箱: ${adminUser.email}`); console.log('========================================'); console.log('角色和权限:'); console.log(` 角色: ${roleCodes.join(', ')}`); console.log(` 权限数量: ${permissionCodes.size}`); if (permissionCodes.size > 0 && permissionCodes.size <= 20) { console.log(` 权限列表:`); Array.from(permissionCodes) .sort() .forEach((code) => { console.log(` - ${code}`); }); } else if (permissionCodes.size > 20) { console.log(` 权限列表(前20个):`); Array.from(permissionCodes) .sort() .slice(0, 20) .forEach((code) => { console.log(` - ${code}`); }); console.log(` ... 还有 ${permissionCodes.size - 20} 个权限`); } console.log('========================================'); console.log('菜单分配:'); console.log(` 已分配菜单数: ${finalMenus.length}`); if (finalMenus.length > 0) { const topLevelMenus = finalMenus.filter((tm) => !tm.menu.parentId); console.log(` 顶级菜单数: ${topLevelMenus.length}`); } console.log('========================================'); console.log(`\n✅ 租户菜单和权限初始化完成!`); console.log(`\n💡 现在可以使用以下凭据登录:`); console.log(` 租户编码: ${tenant.code}`); console.log(` 用户名: ${adminUser.username}`); console.log(` 密码: ${password}`); } catch (error) { console.error('❌ 初始化失败:', error); throw error; } finally { await prisma.$disconnect(); } } // 获取命令行参数 const tenantCode = process.argv[2]; if (!tenantCode) { console.error('❌ 错误: 请提供租户编码作为参数'); console.error(' 使用方法:'); console.error(' pnpm init:tenant-menu-permissions <租户编码>'); console.error(' 示例:'); console.error(' pnpm init:tenant-menu-permissions tenant1'); process.exit(1); } // 执行初始化 initTenantMenuAndPermissions(tenantCode) .then(() => { console.log('\n🎉 初始化脚本执行完成!'); process.exit(0); }) .catch((error) => { console.error('\n💥 初始化脚本执行失败:', error); process.exit(1); });