菜单权限 · 角色与公司等级(深度说明)
管理者、公司员工、项目员工、公司部门:权限与流程全面分析报告
代码基线:D:\www\baoan(ThinkPHP3.1)
报告目标:系统性说明四类主体的权限边界、添加流程、数据关系、相互联系与现状缺口。
1. 结论先看(摘要)
- 公司管理者(店主):以
shop.user_id为核心身份;进入Merchant后getPermissionCodes()对店主返回*(全权限)。 - 公司员工(shop_worker):
- 员工端:主入口为 Worker 模块(如 worker/index/index),菜单由 shop_worker.is_xxx 控制,大量操作通过链接进入 Distributors 子模块完成。
- 公司后台(Merchant/Distributors):并非只有店主能进。只要当前环境能解析出用户可操作的 shop_id(如 resolve_merchant_shop_for_uid($uid) 等),且该用户在 org_user_role 等 RBAC 中有授权,即可进入公司后台;菜单与按钮由 hasPermission(permission_code) 裁剪,与店主全开通形成差异。
- 项目员工(project_worker):是“公司员工进入某个项目”的二级映射,项目内操作几乎都以
project_id + worker_id验权。 - 公司部门(org_*):RBAC 相关表已落地;
Merchant侧已提供部门、角色、人员授权、审计日志等控制器(需配合权限点org.*使用)。 - 权限体系是“双轨”:
- 轨道A:shop_worker.is_xxx(员工功能开关,偏业务能力,主要体现在 Worker 端与跳转 Distributors 的入口)
- 轨道B:org_* RBAC(角色-权限点,偏组织权限,主要体现在 Merchant 端菜单与 requirePermission 动作)
- 关键现实问题:若运行环境未提供
resolve_merchant_shop_for_uid/get_merchant_accessible_shops等解析函数,Merchant/CommonAction会退化为仅Shop.user_id = 当前用户,非店主员工仍无法进入 PC 公司后台——与“员工也应能进后台”的目标冲突,需保证 helper 部署一致或改造兜底逻辑。
2. 角色与数据模型
2.1 公司管理者(店主)
- 核心表:
shop - 核心字段:
shop.user_id - 语义:该用户是公司主账号,默认拥有后台高权限(
*) - 入口控制:
Merchant/CommonAction、Distributors/CommonAction初始化时解析当前公司
2.2 公司员工
- 核心表:
shop_worker - 关键字段:
worker_id,shop_id,user_id,status,closed,is_* - 语义:员工属于某公司;业务能力主要由
is_*控制(Worker/Distributors 入口);组织后台能力由org_user_role等 RBAC 控制(Merchant 入口,与店主全权限区分) - 扩展表:
- worker_qualification(个人资质)
- worker_achievement(工作业绩)
2.3 项目员工
- 核心表:
project_worker - 关键字段:
id,project_id,worker_id,role(项目内角色,1常见为管理) - 语义:把“公司员工”绑定到“项目”,形成项目维度权限与操作主体
2.4 公司部门
- 设计表(迁移SQL已给出):
org_department - 关键字段:
dept_id,shop_id,parent_dept_id,dept_name,dept_code,dept_leader_user_id - 当前代码侧落地:
Merchant模块已提供OrgdepartmentAction、OrgroleAction、OrguserroleAction、OrgauditAction等与 RBAC 配套的管理入口(具体菜单在merchant/index/index.html等公司后台菜单中挂载,受hasPermission('org.xxx')等控制)。
3. 权限体系总览
3.1 体系A:员工业务权限位(shop_worker.is_xxx)
在 Merchant/WorkerAction 中写入并校验,典型字段:
is_photo,is_coupon,is_news,is_worker,is_dianping,is_jobis_tender,is_companycollect,is_shop,is_branch,is_project
特征:
- 粒度是“功能模块开关”
- 适合快速控制员工在各业务模块是否可见/可用
- 常见于员工个人后台和公司后台员工配置页
3.2 体系B:组织 RBAC(org_*)
已存在的数据结构:
org_departmentorg_roleorg_permissionorg_role_permissionorg_user_role
已存在的权限点示例(迁移脚本):
legal.project.menulegal.project.index/create/edit/detail/deleteorg.department.manage,org.role.manage,org.user_role.manage
特征:
- 粒度是“权限点(permission_code)”
- 更适合管理者/部门/角色治理;在 Merchant 侧已通过
getPermissionCodes()+hasPermission()/requirePermission()驱动菜单与动作 - 落地约束主要在于:非店主能否解析到
shop_id(见第8章resolve_merchant_shop_for_uid部署一致性),以及 Distributors/WAP 与 Merchant 是否共用同一套 RBAC 展示策略
4. 添加流程(全链路)
4.1 公司员工添加流程(Merchant)
入口:Merchant/WorkerAction::create
流程:
- 提交
data(员工基础信息 + 权限位) - 校验用户是否存在:
Users.find(user_id) - 校验是否已属其他公司 / 重复添加(基于
shop_worker) - 写入
shop_worker,默认status=1(直接生效,无需员工在会员中心再点同意) - 写入资质
worker_qualification(可多条) - 写入业绩
worker_achievement(可多条) - 发系统消息通知员工(文案为已添加生效类提示,非“必须同意”)
结果:
- 员工记录创建完成后立即可作为有效员工参与
member_visible_worker_entries_for_uid、Worker 端等逻辑(仍需公司shop.audit=1等条件,见会员中心员工入口实现)。
4.2 公司员工编辑流程(Merchant)
入口:Merchant/WorkerAction::edit
流程:
- 校验
worker_id属于当前shop_id - 更新
shop_worker基本信息与权限位 - 遍历
qualifications:
- 有 qual_id + 有标题:更新
- 有 qual_id + 标题空:删除
- 无 qual_id + 有标题:新增
- 遍历
achievements同样逻辑处理
4.3 项目员工添加流程(Distributors)
入口:Distributors/ProjectAction::addWorker
流程:
- 校验
project_id与shop_id归属 - 校验
worker_id是当前公司员工 - 检查
project_id + worker_id是否重复 - 写入
project_worker(含role,并兼容扩展字段)
补充:
- 项目员工可在
setting中更新 role、排班时间、岗位等扩展信息 - 删除项目员工走
removeWorker
4.4 公司部门添加流程(现状)
- DB 设计层:有
org_department表结构与索引 - 业务层:
Merchant/OrgdepartmentAction等提供部门 CRUD、成员迁移与审计;与org_role、org_user_role、权限种子脚本配合使用 - 结论:部门与 RBAC 已在 Merchant 侧形成主链路;Distributors 端是否镜像同等菜单取决于产品与路由配置
5. 相互关系(管理者-员工-项目-部门)
flowchart TD
U[Users 会员]
S[Shop 公司]
SW[ShopWorker 公司员工]
P[Project 项目]
PW[ProjectWorker 项目员工]
D[OrgDepartment 部门]
R[OrgRole 角色]
UR[OrgUserRole 用户角色]
RP[OrgRolePermission]
PM[OrgPermission]
U -->|shop.user_id| S
U -->|shop_worker.user_id| SW
S -->|shop_id| SW
S -->|shop_id| P
SW -->|worker_id| PW
P -->|project_id| PW
S --> D
S --> R
U --> UR
SW -->|可绑定 worker_id| UR
D --> UR
R --> UR
R --> RP
RP --> PM
关系解读:
- “公司员工”是“项目员工”的前置集合
- RBAC(部门/角色)与员工业务权限位可并行存在
- 当前实现里,RBAC 与员工位权限并未完全统一成一套决策引擎
6. 实际权限判定路径
6.1 Merchant 侧
Merchant/CommonAction::getPermissionCodes()
- 店主:直接 *
- 非店主:查 org_user_role -> org_role_permission -> org_permission
hasPermission()在菜单和动作中被调用(如项目、市场)
6.2 Project(Merchant)侧
Merchant/ProjectAction::requirePermission('legal.project.xxx')- 对项目增删改查进行 permission_code 级拦截
6.3 Worker(员工端)侧
- 主要通过
Projectworker绑定关系校验 - 访问项目模块时统一检查:
project_id + worker_id是否存在 role可区分项目管理者与普通成员(模板常用is_manager = role == 1)
7. 管理流程与联系图(业务视角)
- 管理者创建公司(或被认领绑定)
- 管理者添加公司员工,配置
is_xxx权限位 - 员工添加后默认已生效(
status=1);若历史数据仍为status=0,会员中心“员工登录”等逻辑会不展示该身份 - 管理者在项目中分配员工(写入
project_worker) - 项目员工在 Worker 端执行门禁、巡检、考勤、日志、租户事务
- 若组织体系上线,可再叠加部门/角色/RBAC 做纵深权限治理
8. 现状问题与风险
- 问题1:公司后台
shop解析与 RBAC 进场
- Merchant/CommonAction 依赖 resolve_merchant_shop_for_uid($uid)(若存在)解析“当前公司”;否则兜底为 Shop.user_id = uid(仅店主)
- getPermissionCodes():店主 *;非店主依赖 org_user_role(含部门默认角色解析)拉取 permission_code
- 风险:生产环境若未部署 resolve_merchant_shop_for_uid,协作员工即使有 RBAC 也无法进入 Merchant,表现为“只有店主能进公司后台”
- 问题2:权限双轨未统一
- shop_worker.is_xxx 与 org_permission 并存
- 部分模块走位权限,部分走 permission_code,维护成本高
- 问题3:部门与 RBAC 的产品闭环仍不完整
- Merchant 侧已有部门/角色/授权/审计控制器,但 Distributors(手机公司端) 未必提供同等入口,用户容易误以为“部门只有表没有功能”
- “部门负责人—默认角色继承—员工授权”依赖 OrgDepartmentRoleResolveService 等与业务配置是否配齐;与 shop_worker.is_xxx 双轨并存时,运营解释成本高
- 问题4:项目角色与公司角色割裂
- project_worker.role 与组织 org_role 尚未打通映射
- 项目内角色变更不自动反馈组织侧权限
9. 优化建议(按优先级)
P0(必须)
- 统一“后台进场逻辑”并保证环境一致:
- 全环境部署 resolve_merchant_shop_for_uid(或等价解析),使非店主可基于 org_user_role 解析到 shop_id 后进入 Merchant
- 店主仍保留 * 超管能力;协作员工仅拥有已授予的 permission_code 集合
P1(高)
- 建立权限决策中台:
- 统一封装 can($user, $shop, $permission_code, $module_flag)
- 在关键控制器统一调用,避免散落 if 判断
- 对齐双轨:
- is_xxx 作为快速开关(UI/模块)
- permission_code 作为动作级校验(接口/按钮)
- 两者组合判定,形成可解释授权
P2(中)
- 完善部门/RBAC 产品闭环:
- Merchant 已有能力基础上,评估是否在 Distributors 提供对称入口或只读视图
- 统一文档与培训:说明 is_xxx 与 org.* 的适用场景,降低双轨误配
- 打通项目角色与组织角色:
- 例如 project_worker.role=1 自动映射某项目管理权限集合
10. 核对清单(可用于验收)
- [ ] 公司管理者可正常进入 Merchant
- [ ] 已配置
org_user_role的协作员工在部署了resolve_merchant_shop_for_uid的环境下可进入 Merchant,且菜单与hasPermission一致 - [ ] 公司员工可被添加、编辑、删除,资质/业绩可完整增删改
- [ ] 项目员工可从公司员工池分配,且防重复分配
- [ ] 项目员工在 Worker 端所有操作都受
project_worker关系校验 - [ ] 部门/角色/权限点可配置并对菜单与动作生效
- [ ] 权限拒绝时有明确错误提示与审计记录
11. 关键代码与文档定位
Banyan/Lib/Action/Merchant/CommonAction.class.phpBanyan/Lib/Action/Merchant/WorkerAction.class.phpBanyan/Lib/Action/Merchant/ProjectAction.class.phpBanyan/Lib/Action/Distributors/ProjectAction.class.phpBanyan/Lib/Action/Worker/CommonAction.class.phpBanyan/Lib/Action/Worker/ProjectAction.class.phpBanyan/Lib/Model/ProjectworkerModel.class.phpdocs/sql/migrations/V20260326_002_init_org_rbac.sqldocs/sql/migrations/V20260326_005_seed_permission_menu.sql
12. 三端对比:worker/index/index、公司后台、个人会员中心
下表便于区分 员工移动端门户、公司管理后台、个人会员中心 三者定位;同一 Users 账号可能同时具备多种身份(例如既是会员又是某店 shop_worker)。
| 维度 | 个人会员中心(User) | 公司后台(Merchant / 部分 Distributors) | 员工端首页 themes/default/Worker/index/index.html |
|---|---|---|---|
| 典型路由/模块 | user/member/... 等 | merchant/...(PC);distributors/...(WAP 公司端) | worker/index/index(Worker 模块) |
| 主要使用者 | 任意注册用户 | 店主 + 已授权协作员工(RBAC) | 已绑定 shop_worker 的员工 |
| 身份依据 | Users 登录态 | 当前解析到的 shop_id + 店主或 org_user_role | shop_worker(user_id、status、closed 等) |
| 权限主要来源 | 会员业务、订单、个人资料等 | getPermissionCodes():店主 *;否则 org_permission 代码集;动作上 requirePermission | 模板中大量 <if condition="$worker.is_xxx">;项目类能力另依赖 project_worker |
| 与“公司”的关系 | 可认领/绑定公司、查看“员工登录”入口等 | 直接操作当前公司的配置、员工、项目、法务菜单等 | 门户页:聚合验证、巡检、租户等入口;多数业务链通过链接进入 Distributors/* 或 worker/project/*,而非在本页完成全部 CRUD |
| 和本报告的关系 | 个人侧展示“员工身份”依赖 member_visible_worker_entries_for_uid 等 | 双轨中的 RBAC 轨主战场 | 双轨中的 is_xxx 轨主战场 + 项目绑定 |
一句话区分:
- 个人会员中心:以“自然人会员”为中心,不默认等于某公司后台。
- 公司后台(Merchant):以“当前
shop_id公司”为中心,店主与授权员工均可进入,差异在hasPermission可见菜单与可操作动作。 worker/index/index:面向已建档员工的 移动端工作台/验证中心,用is_*决定显示哪些模块入口,并常 跳转到 Distributors 子路径 完成具体业务;它不是 PC 公司后台的等价替换,而是员工日常操作的聚合入口。
