384 lines
9.7 KiB
JavaScript
384 lines
9.7 KiB
JavaScript
|
|
/**
|
|||
|
|
* 菜单权限模型
|
|||
|
|
* @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;
|