2026-06-30 23:11:19 +08:00
// middleware/permissions.js —— 接口权限 + 数据范围 + 合同类型校验 + 层级检查
2026-06-24 22:44:14 +08:00
/ * *
* 检查当前用户是否拥有指定权限
* /
function checkPermission ( resource , action ) {
return ( req , res , next ) => {
const permName = ` ${ resource } : ${ action } `
if ( ! req . user || ! req . user . permissions || ! req . user . permissions . includes ( permName ) ) {
return res . status ( 403 ) . json ( { code : 403 , message : '权限不足' } )
}
next ( )
}
}
/ * *
2026-06-30 23:11:19 +08:00
* 根据用户角色级别和部门计算数据范围 , 挂到 req . scope
*
* 角色层级 :
* - 总经理 ( level = 1 ) : 全量数据
* - 部门经理 ( level = 2 ) : 本部门数据
* - 部门副经理 ( level = 3 ) : 本部门内自己及以下的数据
* - 一般专员 ( level = 4 ) : 仅自己的数据
2026-06-24 22:44:14 +08:00
* /
2026-06-26 09:44:54 +08:00
function dataScope ( resource ) {
2026-06-30 23:11:19 +08:00
return async ( req , res , next ) => {
const { pool } = require ( '../db' )
const roleLevel = req . user . role _level || 4
const deptName = req . user . departmentName
const deptDesc = req . user . departmentDesc
// 总经理:全量数据
if ( roleLevel === 1 ) {
2026-06-26 09:44:54 +08:00
return next ( )
}
2026-06-30 23:11:19 +08:00
let sql = null
let params = [ ]
2026-06-26 09:44:54 +08:00
switch ( resource ) {
2026-06-30 23:11:19 +08:00
case 'employees' :
if ( roleLevel === 1 ) {
// 总经理:全量数据(已在上面处理)
} else if ( roleLevel === 2 ) {
if ( deptName === 'hr' ) {
// 人力资源部经理:查看所有员工
// 无过滤
} else {
// 其他部门经理:本部门所有员工
sql = 'AND department = ?'
params = [ deptDesc ]
}
} else if ( roleLevel === 3 ) {
// 部门副经理:本部门内非经理级别的员工 + 自己
sql = 'AND (department = ? AND position NOT LIKE ?) OR id = (SELECT employee_id FROM users WHERE id = ?)'
params = [ deptDesc , '%经理%' , req . user . id ]
} else {
// 一般专员:不能看到总经理的信息,但能看到其他员工
sql = 'AND position NOT LIKE ?'
params = [ '%总经理%' ]
}
2026-06-26 09:44:54 +08:00
break
case 'contracts' :
2026-06-30 23:11:19 +08:00
if ( roleLevel === 2 ) {
// 部门经理:本部门人员负责的合同
// 先查本部门的用户ID列表
const [ deptUsers ] = await pool . query (
'SELECT u.id FROM users u LEFT JOIN departments d ON u.department_id = d.id WHERE d.name = ?' ,
[ deptName ]
)
const deptUserIds = deptUsers . map ( u => u . id )
if ( deptUserIds . length > 0 ) {
sql = ` AND responsible_user_id IN ( ${ deptUserIds . map ( ( ) => '?' ) . join ( ',' ) } ) `
params = deptUserIds
} else {
sql = 'AND 1=0' // 无数据
}
} else if ( roleLevel >= 3 ) {
// 副经理和专员:自己负责的合同
sql = 'AND responsible_user_id = ?'
params = [ req . user . id ]
2026-06-26 09:44:54 +08:00
}
2026-06-30 23:11:19 +08:00
// 招商部/采购部的类型限制仍然通过 validateContractType 处理
2026-06-26 09:44:54 +08:00
break
case 'after_sales' :
2026-06-30 23:11:19 +08:00
if ( roleLevel === 2 ) {
// 部门经理:本部门人员负责的售后
const [ deptUsersAS ] = await pool . query (
'SELECT u.id FROM users u LEFT JOIN departments d ON u.department_id = d.id WHERE d.name = ?' ,
[ deptName ]
)
const deptUserIdsAS = deptUsersAS . map ( u => u . id )
if ( deptUserIdsAS . length > 0 ) {
sql = ` AND responsible_user_id IN ( ${ deptUserIdsAS . map ( ( ) => '?' ) . join ( ',' ) } ) `
params = deptUserIdsAS
} else {
sql = 'AND 1=0'
}
} else if ( roleLevel >= 3 ) {
// 副经理和专员:自己负责的售后
sql = 'AND responsible_user_id = ?'
params = [ req . user . id ]
}
2026-06-26 09:44:54 +08:00
break
2026-06-30 23:11:19 +08:00
case 'customers' :
// 加盟商是公共资源,所有有权限的人都能看
// 但一般专员只能看自己关联的(通过合同/售后间接关联)
if ( roleLevel === 4 ) {
// 一般专员:只能看到与自己负责的合同/售后关联的客户
sql = 'AND id IN (SELECT customer_id FROM contracts WHERE responsible_user_id = ? UNION SELECT customer_id FROM after_sales WHERE responsible_user_id = ?)'
params = [ req . user . id , req . user . id ]
2026-06-26 09:44:54 +08:00
}
break
}
if ( sql ) {
req . scope = { sql , params }
}
next ( )
}
}
/ * *
* 合同创建 / 修改时校验类型是否匹配部门
* /
function validateContractType ( req , res , next ) {
const deptName = req . user . departmentName
const type = req . body . type
if ( type === undefined ) return next ( )
2026-06-24 22:44:14 +08:00
2026-06-30 23:11:19 +08:00
// 总经理和财务不限制
if ( [ 'general_manager' , 'finance' ] . includes ( deptName ) ) return next ( )
// 信息技术部也不再是超级管理员,按部门权限走
if ( deptName === 'admin' ) return next ( )
2026-06-26 09:44:54 +08:00
if ( deptName === 'procurement_manager' && type !== 'supply' ) {
return res . status ( 403 ) . json ( { code : 403 , message : '采购部只能操作采购合同' } )
2026-06-24 22:44:14 +08:00
}
2026-06-26 09:44:54 +08:00
if ( deptName === 'franchise_manager' && type !== 'franchise' ) {
return res . status ( 403 ) . json ( { code : 403 , message : '招商部只能操作加盟合同' } )
2026-06-24 22:44:14 +08:00
}
2026-06-26 09:44:54 +08:00
next ( )
2026-06-24 22:44:14 +08:00
}
2026-06-30 23:11:19 +08:00
/ * *
* 层级检查 : 确保操作者不能操作比自己级别高的用户
* 用于用户管理的删除 / 修改操作
* /
function checkHierarchy ( req , res , next ) {
return async ( req , res , next ) => {
try {
const { pool } = require ( '../db' )
const operatorLevel = req . user . role _level || 4
const targetId = Number ( req . params . id )
// 查询目标用户的role_level
const [ rows ] = await pool . query ( 'SELECT role_level FROM users WHERE id = ?' , [ targetId ] )
if ( rows . length === 0 ) {
return res . status ( 404 ) . json ( { code : 404 , message : '用户不存在' } )
}
const targetLevel = rows [ 0 ] . role _level || 4
// 不能操作比自己级别高的用户
if ( targetLevel < operatorLevel ) {
return res . status ( 403 ) . json ( { code : 403 , message : '不能操作比自己级别高的用户' } )
}
// 最高只能操作同级
if ( targetLevel < operatorLevel ) {
return res . status ( 403 ) . json ( { code : 403 , message : '权限不足,无法操作该用户' } )
}
next ( )
} catch ( e ) {
console . error ( '[checkHierarchy] error:' , e )
return res . status ( 500 ) . json ( { code : 500 , message : e . message } )
}
}
}
module . exports = { checkPermission , dataScope , validateContractType , checkHierarchy }