/** * 菜单权限模型 * @file MenuPermission.js * @description 菜单权限配置数据模型 */ const { DataTypes } = require('sequelize'); const BaseModel = require('./BaseModel'); const { sequelize } = require('../config/database-simple'); class MenuPermission extends BaseModel { /** * 获取用户可访问的菜单 * @param {Array} userRoles 用户角色数组 * @param {Array} userPermissions 用户权限数组 * @returns {Array} 菜单树结构 */ static async getUserMenus(userRoles = [], userPermissions = []) { try { const allMenus = await this.findAll({ where: { is_visible: true, is_enabled: true }, order: [['sort_order', 'ASC']] }); // 过滤用户有权限的菜单 const accessibleMenus = allMenus.filter(menu => { return this.checkMenuAccess(menu, userRoles, userPermissions); }); // 构建菜单树 return this.buildMenuTree(accessibleMenus); } catch (error) { console.error('获取用户菜单失败:', error); return []; } } /** * 检查菜单访问权限 * @param {Object} menu 菜单对象 * @param {Array} userRoles 用户角色 * @param {Array} userPermissions 用户权限 * @returns {boolean} 是否有权限 */ static checkMenuAccess(menu, userRoles, userPermissions) { // 解析所需角色 let requiredRoles = []; if (menu.required_roles) { try { requiredRoles = JSON.parse(menu.required_roles); } catch (error) { console.error('解析菜单所需角色失败:', error); } } // 解析所需权限 let requiredPermissions = []; if (menu.required_permissions) { try { requiredPermissions = JSON.parse(menu.required_permissions); } catch (error) { console.error('解析菜单所需权限失败:', error); } } // 如果没有配置权限要求,则默认允许访问 if (requiredRoles.length === 0 && requiredPermissions.length === 0) { return true; } // 检查角色权限 if (requiredRoles.length > 0) { const hasRole = requiredRoles.some(role => userRoles.includes(role)); if (!hasRole) { return false; } } // 检查具体权限 if (requiredPermissions.length > 0) { const hasPermission = requiredPermissions.some(permission => userPermissions.includes(permission) ); if (!hasPermission) { return false; } } return true; } /** * 构建菜单树结构 * @param {Array} menus 菜单数组 * @returns {Array} 菜单树 */ static buildMenuTree(menus) { const menuMap = new Map(); const roots = []; // 创建菜单映射 menus.forEach(menu => { menuMap.set(menu.id, { ...menu.dataValues, children: [] }); }); // 构建树结构 menus.forEach(menu => { const menuNode = menuMap.get(menu.id); if (menu.parent_id && menuMap.has(menu.parent_id)) { const parent = menuMap.get(menu.parent_id); parent.children.push(menuNode); } else { roots.push(menuNode); } }); return roots; } /** * 初始化默认菜单权限 */ static async initDefaultMenus() { try { const defaultMenus = [ // 主要功能模块 { menu_key: 'home', menu_name: '首页', menu_path: '/', menu_type: 'page', icon: 'home-outlined', sort_order: 1, required_roles: '["user", "admin", "manager"]' }, { menu_key: 'dashboard', menu_name: '系统概览', menu_path: '/dashboard', menu_type: 'page', icon: 'dashboard-outlined', sort_order: 2, required_roles: '["user", "admin", "manager"]' }, { menu_key: 'monitor', menu_name: '实时监控', menu_path: '/monitor', menu_type: 'page', icon: 'line-chart-outlined', sort_order: 3, required_roles: '["user", "admin", "manager"]' }, { menu_key: 'analytics', menu_name: '数据分析', menu_path: '/analytics', menu_type: 'page', icon: 'bar-chart-outlined', sort_order: 4, required_roles: '["user", "admin", "manager"]' }, // 管理功能模块 { menu_key: 'farms', menu_name: '养殖场管理', menu_path: '/farms', menu_type: 'page', icon: 'home-outlined', sort_order: 10, required_roles: '["admin", "manager"]' }, { menu_key: 'animals', menu_name: '动物管理', menu_path: '/animals', menu_type: 'page', icon: 'bug-outlined', sort_order: 11, required_roles: '["admin", "manager"]' }, { menu_key: 'devices', menu_name: '设备管理', menu_path: '/devices', menu_type: 'page', icon: 'desktop-outlined', sort_order: 12, required_roles: '["admin", "manager"]' }, { menu_key: 'alerts', menu_name: '预警管理', menu_path: '/alerts', menu_type: 'page', icon: 'alert-outlined', sort_order: 13, required_roles: '["admin", "manager"]' }, // 业务功能模块 { menu_key: 'products', menu_name: '产品管理', menu_path: '/products', menu_type: 'page', icon: 'shopping-outlined', sort_order: 20, required_roles: '["admin", "manager"]' }, { menu_key: 'orders', menu_name: '订单管理', menu_path: '/orders', menu_type: 'page', icon: 'shopping-cart-outlined', sort_order: 21, required_roles: '["admin", "manager"]' }, { menu_key: 'reports', menu_name: '报表管理', menu_path: '/reports', menu_type: 'page', icon: 'file-text-outlined', sort_order: 22, required_roles: '["admin", "manager"]' }, // 系统管理模块 { menu_key: 'users', menu_name: '用户管理', menu_path: '/users', menu_type: 'page', icon: 'user-outlined', sort_order: 30, required_roles: '["admin"]' }, { menu_key: 'system', menu_name: '系统管理', menu_path: '/system', menu_type: 'page', icon: 'setting-outlined', sort_order: 31, required_roles: '["admin"]' } ]; for (const menuData of defaultMenus) { const existing = await this.findOne({ where: { menu_key: menuData.menu_key } }); if (!existing) { await this.create(menuData); } } console.log('默认菜单权限初始化完成'); } catch (error) { console.error('初始化默认菜单权限失败:', error); throw error; } } } // 初始化MenuPermission模型 MenuPermission.init({ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, comment: '权限ID' }, menu_key: { type: DataTypes.STRING(100), allowNull: false, comment: '菜单标识' }, menu_name: { type: DataTypes.STRING(100), allowNull: false, comment: '菜单名称' }, menu_path: { type: DataTypes.STRING(200), allowNull: true, comment: '菜单路径' }, parent_id: { type: DataTypes.INTEGER, allowNull: true, comment: '父菜单ID' }, menu_type: { type: DataTypes.ENUM('page', 'button', 'api'), allowNull: false, defaultValue: 'page', comment: '菜单类型' }, required_roles: { type: DataTypes.TEXT, allowNull: true, comment: '所需角色(JSON数组)' }, required_permissions: { type: DataTypes.TEXT, allowNull: true, comment: '所需权限(JSON数组)' }, icon: { type: DataTypes.STRING(50), allowNull: true, comment: '菜单图标' }, sort_order: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, comment: '排序顺序' }, is_visible: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true, comment: '是否可见' }, is_enabled: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true, comment: '是否启用' }, description: { type: DataTypes.STRING(255), allowNull: true, comment: '菜单描述' } }, { sequelize, tableName: 'menu_permissions', modelName: 'MenuPermission', comment: '菜单权限表', indexes: [ { fields: ['menu_key'], unique: true }, { fields: ['parent_id'] }, { fields: ['menu_type'] }, { fields: ['sort_order'] } ] }); // 定义自关联关系 MenuPermission.associate = function(models) { // 自关联:父子菜单关系 MenuPermission.hasMany(MenuPermission, { as: 'children', foreignKey: 'parent_id' }); MenuPermission.belongsTo(MenuPermission, { as: 'parent', foreignKey: 'parent_id' }); }; module.exports = MenuPermission;