Files
nxxmdata/backend/models/MenuPermission.js

384 lines
9.7 KiB
JavaScript
Raw Normal View History

2025-09-12 20:08:42 +08:00
/**
* 菜单权限模型
* @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;