library-picturebook-activity/backend/scripts/init-menus.ts

238 lines
6.3 KiB
TypeScript
Raw Normal View History

2025-11-23 14:04:20 +08:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
// 加载环境变量(必须在其他导入之前)
import * as dotenv from 'dotenv';
import * as path from 'path';
// 根据 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';
const prisma = new PrismaClient();
// 根据路由配置定义的菜单数据
const menus = [
// 顶级菜单:仪表盘
{
name: '仪表盘',
path: '/dashboard',
icon: 'DashboardOutlined',
component: 'dashboard/Index',
parentId: null,
sort: 1,
},
// 父菜单:系统管理
{
name: '系统管理',
path: '/system',
icon: 'SettingOutlined',
component: null, // 父菜单不需要组件
parentId: null,
sort: 10,
children: [
{
name: '用户管理',
path: '/system/users',
icon: 'UserOutlined',
component: 'system/users/Index',
sort: 1,
},
{
name: '角色管理',
path: '/system/roles',
icon: 'TeamOutlined',
component: 'system/roles/Index',
sort: 2,
},
{
name: '菜单管理',
path: '/system/menus',
icon: 'MenuOutlined',
component: 'system/menus/Index',
sort: 3,
},
{
name: '数据字典',
path: '/system/dict',
icon: 'BookOutlined',
component: 'system/dict/Index',
sort: 4,
},
{
name: '系统配置',
path: '/system/config',
icon: 'ToolOutlined',
component: 'system/config/Index',
sort: 5,
},
{
name: '日志记录',
path: '/system/logs',
icon: 'FileTextOutlined',
component: 'system/logs/Index',
sort: 6,
},
],
},
];
async function initMenus() {
try {
console.log('🚀 开始初始化菜单数据...\n');
// 递归创建菜单
async function createMenu(menuData: any, parentId: number | null = null) {
const { children, ...menuFields } = menuData;
// 查找是否已存在相同名称和父菜单的菜单
const existingMenu = await prisma.menu.findFirst({
where: {
name: menuFields.name,
parentId: parentId,
},
});
let menu;
if (existingMenu) {
// 更新现有菜单
menu = await prisma.menu.update({
where: { id: existingMenu.id },
data: {
name: menuFields.name,
path: menuFields.path || null,
icon: menuFields.icon || null,
component: menuFields.component || null,
parentId: parentId,
sort: menuFields.sort || 0,
validState: 1,
},
});
} else {
// 创建新菜单
menu = await prisma.menu.create({
data: {
name: menuFields.name,
path: menuFields.path || null,
icon: menuFields.icon || null,
component: menuFields.component || null,
parentId: parentId,
sort: menuFields.sort || 0,
validState: 1,
},
});
}
console.log(`${menu.name} (${menu.path || '无路径'})`);
// 如果有子菜单,递归创建
if (children && children.length > 0) {
for (const child of children) {
await createMenu(child, menu.id);
}
}
return menu;
}
// 清空现有菜单(重新初始化)
console.log('🗑️ 清空现有菜单...');
// 先删除所有子菜单,再删除父菜单(避免外键约束问题)
await prisma.menu.deleteMany({
where: {
parentId: {
not: null,
},
},
});
await prisma.menu.deleteMany({
where: {
parentId: null,
},
});
console.log('✅ 已清空现有菜单\n');
// 创建所有菜单
console.log('📝 创建菜单...\n');
for (const menu of menus) {
await createMenu(menu);
}
// 验证结果
console.log('\n🔍 验证结果...');
const allMenus = await prisma.menu.findMany({
orderBy: [{ sort: 'asc' }, { id: 'asc' }],
include: {
children: {
orderBy: {
sort: 'asc',
},
},
},
});
const topLevelMenus = allMenus.filter((m) => !m.parentId);
const totalMenus = allMenus.length;
console.log(`\n📊 初始化结果:`);
console.log(` 顶级菜单数量: ${topLevelMenus.length}`);
console.log(` 总菜单数量: ${totalMenus}`);
console.log(`\n📋 菜单结构:`);
function printMenuTree(menu: any, indent: string = '') {
console.log(`${indent}├─ ${menu.name} (${menu.path || '无路径'})`);
if (menu.children && menu.children.length > 0) {
menu.children.forEach((child: any, index: number) => {
const isLast = index === menu.children.length - 1;
const childIndent = indent + (isLast ? ' ' : '│ ');
printMenuTree(child, childIndent);
});
}
}
topLevelMenus.forEach((menu) => {
printMenuTree(menu);
});
console.log(`\n✅ 菜单初始化完成!`);
} catch (error) {
console.error('\n💥 初始化菜单失败:', error);
throw error;
} finally {
await prisma.$disconnect();
}
}
// 执行初始化
initMenus()
.then(() => {
console.log('\n🎉 菜单初始化脚本执行完成!');
process.exit(0);
})
.catch((error) => {
console.error('\n💥 菜单初始化脚本执行失败:', error);
process.exit(1);
});