feat(权限): 安装和配置 Spatie Permission 包
- 安装 spatie/laravel-permission 包(v6.24.1) - 发布配置文件和迁移文件 - 运行迁移创建权限表 - 在 User 模型中添加 HasRoles trait - 添加 isSuperAdmin 和 isAdmin 辅助方法 - 创建 PermissionSeeder 定义 45 个权限 - 创建 3 个预设角色(super-admin、admin、user) - 为角色分配相应权限 - 为第一个用户分配超级管理员角色
This commit is contained in:
@@ -217,6 +217,148 @@
|
||||
|
||||
---
|
||||
|
||||
### 4. 权限管理系统
|
||||
|
||||
#### 4.1 用户故事
|
||||
作为系统管理员,我需要能够灵活地为用户、角色和分组配置不同功能模块的访问权限,以便实现细粒度的权限控制和数据隔离。
|
||||
|
||||
#### 4.2 功能描述
|
||||
实现基于角色、用户和分组的多维度权限管理系统,支持功能模块级和数据级权限控制。
|
||||
|
||||
#### 4.3 验收标准
|
||||
- [ ] 角色管理
|
||||
- [ ] 角色列表(名称、描述、权限数量、用户数量)
|
||||
- [ ] 角色创建/编辑(名称、描述、权限配置)
|
||||
- [ ] 角色删除(检查是否有关联用户)
|
||||
- [ ] 预设角色(超级管理员、管理员、普通用户)
|
||||
|
||||
- [ ] 权限配置界面
|
||||
- [ ] 按功能模块分组展示权限
|
||||
- [ ] 权限类型:viewAny(列表)、view(详情)、create(创建)、update(编辑)、delete(删除)、特殊操作
|
||||
- [ ] 支持批量授权/撤销
|
||||
- [ ] 权限继承关系展示
|
||||
|
||||
- [ ] 用户权限管理
|
||||
- [ ] 用户角色分配(支持多角色)
|
||||
- [ ] 用户特殊权限配置(覆盖角色权限)
|
||||
- [ ] 用户分组关联
|
||||
- [ ] 权限预览(显示用户的最终权限)
|
||||
|
||||
- [ ] 分组权限管理
|
||||
- [ ] 分组数据访问权限(如专用知识库)
|
||||
- [ ] 分组成员管理
|
||||
- [ ] 跨分组访问控制
|
||||
|
||||
- [ ] 权限验证
|
||||
- [ ] 菜单项根据权限动态显示/隐藏
|
||||
- [ ] 操作按钮根据权限动态显示/隐藏
|
||||
- [ ] API请求权限验证
|
||||
- [ ] 数据查询自动应用权限过滤
|
||||
|
||||
#### 4.4 权限模块定义
|
||||
使用 Spatie Permission 的命名约定(module.action格式):
|
||||
|
||||
- **文档管理**:
|
||||
- document.viewAny - 查看文档列表
|
||||
- document.view - 查看文档详情
|
||||
- document.create - 创建文档
|
||||
- document.update - 编辑文档
|
||||
- document.delete - 删除文档
|
||||
- document.download - 下载文档
|
||||
|
||||
- **系统设置**:
|
||||
- system-setting.viewAny - 查看系统设置
|
||||
- system-setting.view - 查看设置详情
|
||||
- system-setting.update - 修改系统设置
|
||||
|
||||
- **操作日志**:
|
||||
- activity-log.viewAny - 查看操作日志
|
||||
- activity-log.view - 查看日志详情
|
||||
- activity-log.export - 导出日志
|
||||
|
||||
- **终端管理**:
|
||||
- terminal.viewAny - 查看终端列表
|
||||
- terminal.view - 查看终端详情
|
||||
- terminal.create - 创建终端
|
||||
- terminal.update - 编辑终端
|
||||
- terminal.delete - 删除终端
|
||||
- terminal.sync - 同步终端配置
|
||||
|
||||
- **SOP模板**:
|
||||
- sop-template.viewAny - 查看SOP列表
|
||||
- sop-template.view - 查看SOP详情
|
||||
- sop-template.create - 创建SOP
|
||||
- sop-template.update - 编辑SOP
|
||||
- sop-template.delete - 删除SOP
|
||||
- sop-template.publish - 发布SOP
|
||||
- sop-template.archive - 归档SOP
|
||||
|
||||
- **分组管理**:
|
||||
- group.viewAny - 查看分组列表
|
||||
- group.view - 查看分组详情
|
||||
- group.create - 创建分组
|
||||
- group.update - 编辑分组
|
||||
- group.delete - 删除分组
|
||||
|
||||
- **用户管理**:
|
||||
- user.viewAny - 查看用户列表
|
||||
- user.view - 查看用户详情
|
||||
- user.create - 创建用户
|
||||
- user.update - 编辑用户
|
||||
- user.delete - 删除用户
|
||||
|
||||
- **角色管理**:
|
||||
- role.viewAny - 查看角色列表
|
||||
- role.view - 查看角色详情
|
||||
- role.create - 创建角色
|
||||
- role.update - 编辑角色
|
||||
- role.delete - 删除角色
|
||||
|
||||
#### 4.5 数据模型需求
|
||||
使用 Spatie Laravel Permission 包提供的模型和表结构:
|
||||
|
||||
- **Role 模型**(角色)- 由 Spatie 包提供
|
||||
- name: string(角色名称,如 super-admin)
|
||||
- guard_name: string(守卫名称,默认 web)
|
||||
- 关联关系:belongsToMany(Permission)、belongsToMany(User)
|
||||
|
||||
- **Permission 模型**(权限)- 由 Spatie 包提供
|
||||
- name: string(权限名称,如 document.create)
|
||||
- guard_name: string(守卫名称,默认 web)
|
||||
- 关联关系:belongsToMany(Role)
|
||||
|
||||
- **model_has_permissions 表**(用户直接权限)- 由 Spatie 包提供
|
||||
- permission_id: bigint
|
||||
- model_type: string(通常是 User)
|
||||
- model_id: bigint(用户ID)
|
||||
|
||||
- **model_has_roles 表**(用户角色关联)- 由 Spatie 包提供
|
||||
- role_id: bigint
|
||||
- model_type: string(通常是 User)
|
||||
- model_id: bigint(用户ID)
|
||||
|
||||
- **role_has_permissions 表**(角色权限关联)- 由 Spatie 包提供
|
||||
- permission_id: bigint
|
||||
- role_id: bigint
|
||||
|
||||
注:Spatie 包会自动创建这些表和模型,无需手动创建。
|
||||
|
||||
#### 4.6 技术实现
|
||||
- 使用 **Spatie Laravel Permission** 包实现权限管理
|
||||
- 包提供的核心功能:
|
||||
- Role(角色)模型和管理
|
||||
- Permission(权限)模型和管理
|
||||
- 用户角色和权限关联
|
||||
- 权限检查方法(hasPermissionTo、hasRole等)
|
||||
- 中间件支持(role、permission)
|
||||
- Blade指令支持(@role、@can等)
|
||||
- 使用 Laravel Policy 实现业务逻辑权限验证
|
||||
- 使用 Gate 定义额外的权限规则
|
||||
- 在 Filament Resource 中集成权限检查
|
||||
- 权限缓存自动管理
|
||||
|
||||
---
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **后端框架**: Laravel 12
|
||||
@@ -237,7 +379,12 @@
|
||||
- 所有操作需要身份验证
|
||||
- 敏感配置(API密钥)需要加密存储
|
||||
- 操作日志不可删除,只能归档
|
||||
- 权限控制:系统设置仅管理员可访问
|
||||
- **权限管理**:
|
||||
- 支持基于角色的权限控制(RBAC)
|
||||
- 支持基于用户的权限控制
|
||||
- 支持基于分组的权限控制
|
||||
- 功能模块级别的权限控制(查看、创建、编辑、删除、特殊操作)
|
||||
- 数据级别的权限控制(如文档的全局/专用访问)
|
||||
|
||||
### 可用性要求
|
||||
- 界面响应式设计,支持1920x1080及以上分辨率
|
||||
@@ -256,13 +403,14 @@
|
||||
### Composer包
|
||||
```bash
|
||||
composer require spatie/laravel-activitylog
|
||||
composer require spatie/laravel-permission # 权限管理包
|
||||
composer require amidesfahani/filament-monaco-editor
|
||||
composer require maatwebsite/excel # 用于日志导出
|
||||
```
|
||||
|
||||
### 数据库表
|
||||
- system_settings
|
||||
- activity_log
|
||||
- activity_log(由 spatie/laravel-activitylog 创建)
|
||||
- terminals
|
||||
- terminal_knowledge_bases
|
||||
- terminal_prompts
|
||||
@@ -271,6 +419,11 @@ composer require maatwebsite/excel # 用于日志导出
|
||||
- sop_steps
|
||||
- sop_interactive_tasks
|
||||
- sop_template_versions
|
||||
- roles(由 spatie/laravel-permission 创建)
|
||||
- permissions(由 spatie/laravel-permission 创建)
|
||||
- model_has_permissions(由 spatie/laravel-permission 创建)
|
||||
- model_has_roles(由 spatie/laravel-permission 创建)
|
||||
- role_has_permissions(由 spatie/laravel-permission 创建)
|
||||
|
||||
## 实施优先级
|
||||
|
||||
|
||||
@@ -269,140 +269,259 @@
|
||||
- [x] 15.4.3 测试JSON导入
|
||||
- [x] 15.4.4 测试批量导入
|
||||
|
||||
## 阶段五:权限和安全(优先级:中)
|
||||
## 阶段五:权限管理系统(优先级:高)
|
||||
|
||||
### 16. 权限策略实现
|
||||
- [ ] 16.1 创建SystemSettingPolicy
|
||||
- [ ] 16.1.1 实现viewAny权限
|
||||
- [ ] 16.1.2 实现update权限
|
||||
- [ ] 16.2 创建TerminalPolicy
|
||||
- [ ] 16.2.1 实现viewAny权限
|
||||
- [ ] 16.2.2 实现create权限
|
||||
- [ ] 16.2.3 实现update权限
|
||||
- [ ] 16.2.4 实现delete权限
|
||||
- [ ] 16.2.5 实现sync权限
|
||||
- [ ] 16.3 创建SopTemplatePolicy
|
||||
- [ ] 16.3.1 实现viewAny权限
|
||||
- [ ] 16.3.2 实现create权限
|
||||
- [ ] 16.3.3 实现update权限
|
||||
- [ ] 16.3.4 实现delete权限
|
||||
- [ ] 16.3.5 实现publish权限
|
||||
- [ ] 16.4 注册所有策略
|
||||
- [ ] 16.5 测试权限控制
|
||||
- [ ] 16.5.1 测试管理员权限
|
||||
- [ ] 16.5.2 测试普通用户权限
|
||||
- [ ] 16.5.3 测试特殊权限
|
||||
### 16. Spatie Permission 包安装和配置
|
||||
- [ ] 16.1 安装 Spatie Permission 包
|
||||
- [ ] 16.1.1 运行 composer require spatie/laravel-permission
|
||||
- [ ] 16.1.2 发布配置文件和迁移文件
|
||||
- [ ] 16.1.3 运行迁移创建权限表
|
||||
- [ ] 16.1.4 清除缓存
|
||||
- [ ] 16.2 配置 User 模型
|
||||
- [ ] 16.2.1 在 User 模型中添加 HasRoles trait
|
||||
- [ ] 16.2.2 配置守卫(guard)
|
||||
- [ ] 16.2.3 测试基本权限方法
|
||||
- [ ] 16.3 创建权限种子数据
|
||||
- [ ] 16.3.1 创建 PermissionSeeder
|
||||
- [ ] 16.3.2 定义所有功能模块的权限(45个权限)
|
||||
- [ ] 16.3.3 创建预设角色(super-admin、admin、user)
|
||||
- [ ] 16.3.4 为角色分配权限
|
||||
- [ ] 16.3.5 运行种子数据
|
||||
|
||||
### 17. 安全加固
|
||||
- [ ] 17.1 实现敏感配置加密
|
||||
- [ ] 17.1.1 创建加密服务
|
||||
- [ ] 17.1.2 在SystemSetting模型中集成
|
||||
- [ ] 17.1.3 更新表单字段类型
|
||||
- [ ] 17.2 实现操作确认
|
||||
- [ ] 17.2.1 为删除操作添加确认
|
||||
- [ ] 17.2.2 为发布操作添加确认
|
||||
- [ ] 17.2.3 为同步操作添加确认
|
||||
- [ ] 17.3 实现输入验证和过滤
|
||||
- [ ] 17.3.1 添加XSS过滤
|
||||
- [ ] 17.3.2 添加SQL注入防护
|
||||
- [ ] 17.3.3 添加文件上传验证
|
||||
- [ ] 17.4 测试安全功能
|
||||
- [ ] 17.4.1 测试加密存储
|
||||
- [ ] 17.4.2 测试操作确认
|
||||
- [ ] 17.4.3 测试输入验证
|
||||
### 17. 角色管理功能
|
||||
- [ ] 17.1 创建 RoleResource
|
||||
- [ ] 17.1.1 定义表格列(名称、守卫、权限数、用户数)
|
||||
- [ ] 17.1.2 添加搜索和筛选功能
|
||||
- [ ] 17.1.3 添加系统角色标识(super-admin不可删除)
|
||||
- [ ] 17.2 创建角色表单
|
||||
- [ ] 17.2.1 添加基本信息字段(名称、守卫)
|
||||
- [ ] 17.2.2 添加权限选择器(使用 CheckboxList,按模块分组)
|
||||
- [ ] 17.2.3 添加表单验证规则
|
||||
- [ ] 17.2.4 实现权限同步逻辑(使用 syncPermissions)
|
||||
- [ ] 17.3 实现角色删除保护
|
||||
- [ ] 17.3.1 检查角色是否为 super-admin
|
||||
- [ ] 17.3.2 检查角色是否有关联用户
|
||||
- [ ] 17.3.3 添加删除确认提示
|
||||
- [ ] 17.4 测试角色管理功能
|
||||
- [ ] 17.4.1 测试角色 CRUD 操作
|
||||
- [ ] 17.4.2 测试权限分配(syncPermissions)
|
||||
- [ ] 17.4.3 测试删除保护
|
||||
|
||||
### 18. 用户权限管理功能
|
||||
- [ ] 18.1 更新 UserResource
|
||||
- [ ] 18.1.1 添加角色分配字段(使用 Select,支持多选)
|
||||
- [ ] 18.1.2 添加分组关联字段
|
||||
- [ ] 18.1.3 添加直接权限配置 Section(使用 CheckboxList)
|
||||
- [ ] 18.1.4 显示用户的所有权限预览(角色权限+直接权限)
|
||||
- [ ] 18.2 实现用户权限保存逻辑
|
||||
- [ ] 18.2.1 使用 syncRoles 同步角色
|
||||
- [ ] 18.2.2 使用 syncPermissions 同步直接权限
|
||||
- [ ] 18.2.3 处理权限冲突(直接权限优先)
|
||||
- [ ] 18.3 创建权限预览组件
|
||||
- [ ] 18.3.1 使用 Placeholder 组件显示权限
|
||||
- [ ] 18.3.2 按模块分组显示
|
||||
- [ ] 18.3.3 标识权限来源(角色/直接授予)
|
||||
- [ ] 18.3.4 支持权限搜索
|
||||
- [ ] 18.4 测试用户权限功能
|
||||
- [ ] 18.4.1 测试角色分配(assignRole、syncRoles)
|
||||
- [ ] 18.4.2 测试直接权限配置(givePermissionTo、syncPermissions)
|
||||
- [ ] 18.4.3 测试权限检查(hasPermissionTo、can)
|
||||
|
||||
### 19. 权限策略实现
|
||||
- [ ] 19.1 DocumentPolicy(已部分实现,需完善)
|
||||
- [ ] 19.1.1 在 viewAny 中添加权限检查(document.viewAny)
|
||||
- [ ] 19.1.2 在 view 中添加权限检查(document.view)
|
||||
- [ ] 19.1.3 在 create 中添加权限检查(document.create)
|
||||
- [ ] 19.1.4 在 update 中添加权限检查(document.update)
|
||||
- [ ] 19.1.5 在 delete 中添加权限检查(document.delete)
|
||||
- [ ] 19.1.6 在 download 中添加权限检查(document.download)
|
||||
- [ ] 19.1.7 保留现有的分组访问控制逻辑
|
||||
- [ ] 19.2 SystemSettingPolicy
|
||||
- [ ] 19.2.1 实现 viewAny(system-setting.viewAny)
|
||||
- [ ] 19.2.2 实现 view(system-setting.view)
|
||||
- [ ] 19.2.3 实现 update(system-setting.update)
|
||||
- [ ] 19.3 ActivityLogPolicy
|
||||
- [ ] 19.3.1 实现 viewAny(activity-log.viewAny)
|
||||
- [ ] 19.3.2 实现 view(activity-log.view)
|
||||
- [ ] 19.3.3 实现 export(activity-log.export)
|
||||
- [ ] 19.4 TerminalPolicy(已部分实现,需完善)
|
||||
- [ ] 19.4.1 在所有方法中添加权限检查
|
||||
- [ ] 19.4.2 实现 sync 权限检查(terminal.sync)
|
||||
- [ ] 19.4.3 保留现有的管理员检查作为后备
|
||||
- [ ] 19.5 SopTemplatePolicy(已部分实现,需完善)
|
||||
- [ ] 19.5.1 在所有方法中添加权限检查
|
||||
- [ ] 19.5.2 实现 publish 权限检查(sop-template.publish)
|
||||
- [ ] 19.5.3 实现 archive 权限检查(sop-template.archive)
|
||||
- [ ] 19.5.4 保留现有的状态检查逻辑
|
||||
- [ ] 19.6 GroupPolicy
|
||||
- [ ] 19.6.1 实现 viewAny(group.viewAny)
|
||||
- [ ] 19.6.2 实现 view(group.view)
|
||||
- [ ] 19.6.3 实现 create(group.create)
|
||||
- [ ] 19.6.4 实现 update(group.update)
|
||||
- [ ] 19.6.5 实现 delete(group.delete,需检查关联文档)
|
||||
- [ ] 19.7 UserPolicy
|
||||
- [ ] 19.7.1 实现 viewAny(user.viewAny)
|
||||
- [ ] 19.7.2 实现 view(user.view)
|
||||
- [ ] 19.7.3 实现 create(user.create)
|
||||
- [ ] 19.7.4 实现 update(user.update)
|
||||
- [ ] 19.7.5 实现 delete(user.delete,不能删除自己)
|
||||
- [ ] 19.8 RolePolicy
|
||||
- [ ] 19.8.1 实现 viewAny(role.viewAny)
|
||||
- [ ] 19.8.2 实现 view(role.view)
|
||||
- [ ] 19.8.3 实现 create(role.create)
|
||||
- [ ] 19.8.4 实现 update(role.update)
|
||||
- [ ] 19.8.5 实现 delete(role.delete,super-admin 保护)
|
||||
- [ ] 19.9 策略注册
|
||||
- [ ] 19.9.1 在 AppServiceProvider 中注册所有策略
|
||||
- [ ] 19.9.2 配置策略自动发现
|
||||
|
||||
### 20. Filament 资源权限集成
|
||||
- [ ] 20.1 更新所有 Resource 的权限检查
|
||||
- [ ] 20.1.1 DocumentResource 集成权限(使用 can 方法)
|
||||
- [ ] 20.1.2 SystemSettingResource 集成权限
|
||||
- [ ] 20.1.3 ActivityLogResource 集成权限
|
||||
- [ ] 20.1.4 TerminalResource 集成权限
|
||||
- [ ] 20.1.5 SopTemplateResource 集成权限
|
||||
- [ ] 20.1.6 GroupResource 集成权限
|
||||
- [ ] 20.1.7 UserResource 集成权限
|
||||
- [ ] 20.1.8 RoleResource 集成权限
|
||||
- [ ] 20.2 实现导航菜单权限控制
|
||||
- [ ] 20.2.1 配置 Resource 的 shouldRegisterNavigation 方法
|
||||
- [ ] 20.2.2 使用 auth()->user()->can() 检查权限
|
||||
- [ ] 20.2.3 根据权限动态显示/隐藏菜单项
|
||||
- [ ] 20.3 实现操作按钮权限控制
|
||||
- [ ] 20.3.1 配置 Action 的 visible 方法
|
||||
- [ ] 20.3.2 使用 $this->can() 检查权限
|
||||
- [ ] 20.3.3 根据权限动态显示/隐藏按钮
|
||||
- [ ] 20.4 实现批量操作权限控制
|
||||
- [ ] 20.4.1 配置 BulkAction 的 visible 方法
|
||||
- [ ] 20.4.2 根据权限控制批量操作可用性
|
||||
- [ ] 20.5 实现中间件保护
|
||||
- [ ] 20.5.1 在路由中使用 permission 中间件
|
||||
- [ ] 20.5.2 在路由中使用 role 中间件
|
||||
- [ ] 20.5.3 测试未授权访问的重定向
|
||||
|
||||
### 21. 权限测试
|
||||
- [ ] 21.1 单元测试
|
||||
- [ ] 21.1.1 测试 User 模型的 HasRoles trait
|
||||
- [ ] 21.1.2 测试 hasPermissionTo 方法
|
||||
- [ ] 21.1.3 测试 hasRole 方法
|
||||
- [ ] 21.1.4 测试 assignRole 和 removeRole
|
||||
- [ ] 21.1.5 测试 givePermissionTo 和 revokePermissionTo
|
||||
- [ ] 21.1.6 测试权限缓存
|
||||
- [ ] 21.2 策略测试
|
||||
- [ ] 21.2.1 测试所有 Policy 的权限检查
|
||||
- [ ] 21.2.2 测试 super-admin 角色的完整权限
|
||||
- [ ] 21.2.3 测试 admin 角色的权限
|
||||
- [ ] 21.2.4 测试普通用户的权限限制
|
||||
- [ ] 21.2.5 测试直接权限覆盖角色权限
|
||||
- [ ] 21.3 集成测试
|
||||
- [ ] 21.3.1 测试角色分配后的权限生效
|
||||
- [ ] 21.3.2 测试权限撤销后的访问限制
|
||||
- [ ] 21.3.3 测试跨分组访问控制
|
||||
- [ ] 21.3.4 测试数据级权限过滤
|
||||
- [ ] 21.4 UI 测试
|
||||
- [ ] 21.4.1 测试菜单项权限控制
|
||||
- [ ] 21.4.2 测试操作按钮权限控制
|
||||
- [ ] 21.4.3 测试批量操作权限控制
|
||||
- [ ] 21.4.4 测试未授权访问的错误提示
|
||||
|
||||
## 阶段六:测试和优化(优先级:低)
|
||||
|
||||
### 18. 单元测试
|
||||
- [ ] 18.1 SystemSetting模型测试
|
||||
- [ ] 18.1.1 测试get方法
|
||||
- [ ] 18.1.2 测试set方法
|
||||
- [ ] 18.2 Terminal模型测试
|
||||
- [ ] 18.2.1 测试关联关系
|
||||
- [ ] 18.2.2 测试作用域
|
||||
- [ ] 18.3 SopTemplate模型测试
|
||||
- [ ] 18.3.1 测试关联关系
|
||||
- [ ] 18.3.2 测试状态转换
|
||||
- [ ] 18.4 Service类测试
|
||||
- [ ] 18.4.1 测试SystemSettingService
|
||||
- [ ] 18.4.2 测试TerminalSyncService
|
||||
- [ ] 18.4.3 测试SopTemplateService
|
||||
### 22. 单元测试
|
||||
- [ ] 22.1 SystemSetting模型测试
|
||||
- [ ] 22.1.1 测试get方法
|
||||
- [ ] 22.1.2 测试set方法
|
||||
- [ ] 22.2 Terminal模型测试
|
||||
- [ ] 22.2.1 测试关联关系
|
||||
- [ ] 22.2.2 测试作用域
|
||||
- [ ] 22.3 SopTemplate模型测试
|
||||
- [ ] 22.3.1 测试关联关系
|
||||
- [ ] 22.3.2 测试状态转换
|
||||
- [ ] 22.4 Service类测试
|
||||
- [ ] 22.4.1 测试SystemSettingService
|
||||
- [ ] 22.4.2 测试TerminalSyncService
|
||||
- [ ] 22.4.3 测试SopTemplateService
|
||||
|
||||
### 19. 功能测试
|
||||
- [ ] 19.1 系统设置功能测试
|
||||
- [ ] 19.1.1 测试配置保存
|
||||
- [ ] 19.1.2 测试配置读取
|
||||
- [ ] 19.2 操作日志功能测试
|
||||
- [ ] 19.2.1 测试日志记录
|
||||
- [ ] 19.2.2 测试日志筛选
|
||||
- [ ] 19.2.3 测试日志导出
|
||||
- [ ] 19.3 终端管理功能测试
|
||||
- [ ] 19.3.1 测试终端CRUD
|
||||
- [ ] 19.3.2 测试配置同步
|
||||
- [ ] 19.4 SOP模板功能测试
|
||||
- [ ] 19.4.1 测试模板CRUD
|
||||
- [ ] 19.4.2 测试步骤编辑
|
||||
- [ ] 19.4.3 测试模板发布
|
||||
- [ ] 19.4.4 测试导入导出
|
||||
### 23. 功能测试
|
||||
- [ ] 23.1 系统设置功能测试
|
||||
- [ ] 23.1.1 测试配置保存
|
||||
- [ ] 23.1.2 测试配置读取
|
||||
- [ ] 23.2 操作日志功能测试
|
||||
- [ ] 23.2.1 测试日志记录
|
||||
- [ ] 23.2.2 测试日志筛选
|
||||
- [ ] 23.2.3 测试日志导出
|
||||
- [ ] 23.3 终端管理功能测试
|
||||
- [ ] 23.3.1 测试终端CRUD
|
||||
- [ ] 23.3.2 测试配置同步
|
||||
- [ ] 23.4 SOP模板功能测试
|
||||
- [ ] 23.4.1 测试模板CRUD
|
||||
- [ ] 23.4.2 测试步骤编辑
|
||||
- [ ] 23.4.3 测试模板发布
|
||||
- [ ] 23.4.4 测试导入导出
|
||||
|
||||
### 20. 性能优化
|
||||
- [ ] 20.1 数据库优化
|
||||
- [ ] 20.1.1 添加必要索引
|
||||
- [ ] 20.1.2 优化查询语句
|
||||
- [ ] 20.1.3 实现Eager Loading
|
||||
- [ ] 20.2 缓存优化
|
||||
- [ ] 20.2.1 实现系统设置缓存
|
||||
- [ ] 20.2.2 实现终端状态缓存
|
||||
- [ ] 20.2.3 实现模板列表缓存
|
||||
- [ ] 20.3 前端优化
|
||||
- [ ] 20.3.1 实现Lazy Loading
|
||||
- [ ] 20.3.2 优化Monaco Editor加载
|
||||
- [ ] 20.3.3 优化图片加载
|
||||
- [ ] 20.4 性能测试
|
||||
- [ ] 20.4.1 测试日志查询性能
|
||||
- [ ] 20.4.2 测试终端列表性能
|
||||
- [ ] 20.4.3 测试模板编辑性能
|
||||
### 24. 性能优化
|
||||
- [ ] 24.1 数据库优化
|
||||
- [ ] 24.1.1 添加必要索引
|
||||
- [ ] 24.1.2 优化查询语句
|
||||
- [ ] 24.1.3 实现Eager Loading
|
||||
- [ ] 24.2 缓存优化
|
||||
- [ ] 24.2.1 实现系统设置缓存
|
||||
- [ ] 24.2.2 实现终端状态缓存
|
||||
- [ ] 24.2.3 实现模板列表缓存
|
||||
- [ ] 24.2.4 实现权限缓存
|
||||
- [ ] 24.3 前端优化
|
||||
- [ ] 24.3.1 实现Lazy Loading
|
||||
- [ ] 24.3.2 优化Monaco Editor加载
|
||||
- [ ] 24.3.3 优化图片加载
|
||||
- [ ] 24.4 性能测试
|
||||
- [ ] 24.4.1 测试日志查询性能
|
||||
- [ ] 24.4.2 测试终端列表性能
|
||||
- [ ] 24.4.3 测试模板编辑性能
|
||||
- [ ] 24.4.4 测试权限检查性能
|
||||
|
||||
## 阶段七:文档和部署(优先级:低)
|
||||
|
||||
### 21. 文档编写
|
||||
- [ ] 21.1 编写用户手册
|
||||
- [ ] 21.1.1 系统设置使用说明
|
||||
- [ ] 21.1.2 操作日志使用说明
|
||||
- [ ] 21.1.3 终端管理使用说明
|
||||
- [ ] 21.1.4 SOP模板使用说明
|
||||
- [ ] 21.2 编写开发文档
|
||||
- [ ] 21.2.1 API文档
|
||||
- [ ] 21.2.2 数据库设计文档
|
||||
- [ ] 21.2.3 部署文档
|
||||
- [ ] 21.3 编写测试文档
|
||||
- [ ] 21.3.1 测试用例文档
|
||||
- [ ] 21.3.2 测试报告模板
|
||||
### 25. 文档编写
|
||||
- [ ] 25.1 编写用户手册
|
||||
- [ ] 25.1.1 系统设置使用说明
|
||||
- [ ] 25.1.2 操作日志使用说明
|
||||
- [ ] 25.1.3 终端管理使用说明
|
||||
- [ ] 25.1.4 SOP模板使用说明
|
||||
- [ ] 25.1.5 权限管理使用说明
|
||||
- [ ] 25.2 编写开发文档
|
||||
- [ ] 25.2.1 API文档
|
||||
- [ ] 25.2.2 数据库设计文档
|
||||
- [ ] 25.2.3 部署文档
|
||||
- [ ] 25.2.4 权限系统架构文档
|
||||
- [ ] 25.3 编写测试文档
|
||||
- [ ] 25.3.1 测试用例文档
|
||||
- [ ] 25.3.2 测试报告模板
|
||||
|
||||
### 22. 部署准备
|
||||
- [ ] 22.1 准备生产环境配置
|
||||
- [ ] 22.1.1 更新.env.production
|
||||
- [ ] 22.1.2 配置队列服务
|
||||
- [ ] 22.1.3 配置缓存服务
|
||||
- [ ] 22.2 数据迁移准备
|
||||
- [ ] 22.2.1 准备迁移脚本
|
||||
- [ ] 22.2.2 准备回滚脚本
|
||||
- [ ] 22.2.3 准备种子数据
|
||||
- [ ] 22.3 部署到生产环境
|
||||
- [ ] 22.3.1 执行数据库迁移
|
||||
- [ ] 22.3.2 发布静态资源
|
||||
- [ ] 22.3.3 重启服务
|
||||
- [ ] 22.4 生产环境验证
|
||||
- [ ] 22.4.1 验证所有功能
|
||||
- [ ] 22.4.2 验证性能指标
|
||||
- [ ] 22.4.3 验证安全配置
|
||||
### 26. 部署准备
|
||||
- [ ] 26.1 准备生产环境配置
|
||||
- [ ] 26.1.1 更新.env.production
|
||||
- [ ] 26.1.2 配置队列服务
|
||||
- [ ] 26.1.3 配置缓存服务
|
||||
- [ ] 26.2 数据迁移准备
|
||||
- [ ] 26.2.1 准备迁移脚本
|
||||
- [ ] 26.2.2 准备回滚脚本
|
||||
- [ ] 26.2.3 准备种子数据
|
||||
- [ ] 26.3 部署到生产环境
|
||||
- [ ] 26.3.1 执行数据库迁移
|
||||
- [ ] 26.3.2 发布静态资源
|
||||
- [ ] 26.3.3 重启服务
|
||||
- [ ] 26.4 生产环境验证
|
||||
- [ ] 26.4.1 验证所有功能
|
||||
- [ ] 26.4.2 验证性能指标
|
||||
- [ ] 26.4.3 验证安全配置
|
||||
|
||||
## 任务统计
|
||||
|
||||
- 总任务数:22个主任务
|
||||
- 子任务数:约200+个子任务
|
||||
- 预计工作量:40-60工作日
|
||||
- 总任务数:26个主任务
|
||||
- 子任务数:约250+个子任务
|
||||
- 预计工作量:50-70工作日
|
||||
- 优先级分布:
|
||||
- 高优先级:阶段一、二(约30%)
|
||||
- 中优先级:阶段三、四、五(约50%)
|
||||
- 低优先级:阶段六、七(约20%)
|
||||
- 高优先级:阶段一、二、五(约40%)
|
||||
- 中优先级:阶段三、四(约35%)
|
||||
- 低优先级:阶段六、七(约25%)
|
||||
|
||||
@@ -8,11 +8,12 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
use HasFactory, Notifiable, HasRoles;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
@@ -71,4 +72,20 @@ class User extends Authenticatable
|
||||
{
|
||||
return $this->hasMany(DownloadLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否为超级管理员
|
||||
*/
|
||||
public function isSuperAdmin(): bool
|
||||
{
|
||||
return $this->hasRole('super-admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否为管理员(包括超级管理员)
|
||||
*/
|
||||
public function isAdmin(): bool
|
||||
{
|
||||
return $this->hasAnyRole(['super-admin', 'admin']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"meilisearch/meilisearch-php": "^1.16",
|
||||
"phpoffice/phpword": "^1.4",
|
||||
"spatie/laravel-activitylog": "^4.12"
|
||||
"spatie/laravel-activitylog": "^4.12",
|
||||
"spatie/laravel-permission": "^6.24"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
|
||||
85
composer.lock
generated
85
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c39c6bce26908705b817350435bee16e",
|
||||
"content-hash": "955960e117170ae4d776f49e01bab40f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "abdelhamiderrahmouni/filament-monaco-editor",
|
||||
@@ -6294,6 +6294,89 @@
|
||||
],
|
||||
"time": "2025-07-17T15:46:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-permission",
|
||||
"version": "6.24.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-permission.git",
|
||||
"reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/eefc9d17eba80d023d6bff313f882cb2bcd691a3",
|
||||
"reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0",
|
||||
"illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0",
|
||||
"illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0",
|
||||
"illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/passport": "^11.0|^12.0",
|
||||
"laravel/pint": "^1.0",
|
||||
"orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0",
|
||||
"phpunit/phpunit": "^9.4|^10.1|^11.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\Permission\\PermissionServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "6.x-dev",
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Spatie\\Permission\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Permission handling for Laravel 8.0 and up",
|
||||
"homepage": "https://github.com/spatie/laravel-permission",
|
||||
"keywords": [
|
||||
"acl",
|
||||
"laravel",
|
||||
"permission",
|
||||
"permissions",
|
||||
"rbac",
|
||||
"roles",
|
||||
"security",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-permission/issues",
|
||||
"source": "https://github.com/spatie/laravel-permission/tree/6.24.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-09T21:10:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
"version": "v7.4.0",
|
||||
|
||||
@@ -65,7 +65,7 @@ return [
|
||||
|
||||
'temporary_file_upload' => [
|
||||
'disk' => null, // Example: 'local', 's3' | Default: 'default'
|
||||
'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB)
|
||||
'rules' => ['required', 'file', 'max:51200'], // 最大 50MB
|
||||
'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
|
||||
'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
|
||||
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
|
||||
@@ -73,7 +73,7 @@ return [
|
||||
'mov', 'avi', 'wmv', 'mp3', 'm4a',
|
||||
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
|
||||
],
|
||||
'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
|
||||
'max_upload_time' => 10, // Max duration (in minutes) before an upload is invalidated...
|
||||
'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
|
||||
],
|
||||
|
||||
|
||||
202
config/permission.php
Normal file
202
config/permission.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'models' => [
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||
* is often just the "Permission" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Permission model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Permission` contract.
|
||||
*/
|
||||
|
||||
'permission' => Spatie\Permission\Models\Permission::class,
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||
* is often just the "Role" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Role model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Role` contract.
|
||||
*/
|
||||
|
||||
'role' => Spatie\Permission\Models\Role::class,
|
||||
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'roles' => 'roles',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your permissions. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'permissions' => 'permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_permissions' => 'model_has_permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models roles. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_roles' => 'model_has_roles',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'role_has_permissions' => 'role_has_permissions',
|
||||
],
|
||||
|
||||
'column_names' => [
|
||||
/*
|
||||
* Change this if you want to name the related pivots other than defaults
|
||||
*/
|
||||
'role_pivot_key' => null, // default 'role_id',
|
||||
'permission_pivot_key' => null, // default 'permission_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to name the related model primary key other than
|
||||
* `model_id`.
|
||||
*
|
||||
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||
* that case, name this `model_uuid`.
|
||||
*/
|
||||
|
||||
'model_morph_key' => 'model_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to use the teams feature and your related model's
|
||||
* foreign key is other than `team_id`.
|
||||
*/
|
||||
|
||||
'team_foreign_key' => 'team_id',
|
||||
],
|
||||
|
||||
/*
|
||||
* When set to true, the method for checking permissions will be registered on the gate.
|
||||
* Set this to false if you want to implement custom logic for checking permissions.
|
||||
*/
|
||||
|
||||
'register_permission_check_method' => true,
|
||||
|
||||
/*
|
||||
* When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
|
||||
* this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
|
||||
* NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
|
||||
*/
|
||||
'register_octane_reset_listener' => false,
|
||||
|
||||
/*
|
||||
* Events will fire when a role or permission is assigned/unassigned:
|
||||
* \Spatie\Permission\Events\RoleAttached
|
||||
* \Spatie\Permission\Events\RoleDetached
|
||||
* \Spatie\Permission\Events\PermissionAttached
|
||||
* \Spatie\Permission\Events\PermissionDetached
|
||||
*
|
||||
* To enable, set to true, and then create listeners to watch these events.
|
||||
*/
|
||||
'events_enabled' => false,
|
||||
|
||||
/*
|
||||
* Teams Feature.
|
||||
* When set to true the package implements teams using the 'team_foreign_key'.
|
||||
* If you want the migrations to register the 'team_foreign_key', you must
|
||||
* set this to true before doing the migration.
|
||||
* If you already did the migration then you must make a new migration to also
|
||||
* add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
|
||||
* (view the latest version of this package's migration file)
|
||||
*/
|
||||
|
||||
'teams' => false,
|
||||
|
||||
/*
|
||||
* The class to use to resolve the permissions team id
|
||||
*/
|
||||
'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class,
|
||||
|
||||
/*
|
||||
* Passport Client Credentials Grant
|
||||
* When set to true the package will use Passports Client to check permissions
|
||||
*/
|
||||
|
||||
'use_passport_client_credentials' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required permission names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_permission_in_exception' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required role names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_role_in_exception' => false,
|
||||
|
||||
/*
|
||||
* By default wildcard permission lookups are disabled.
|
||||
* See documentation to understand supported syntax.
|
||||
*/
|
||||
|
||||
'enable_wildcard_permission' => false,
|
||||
|
||||
/*
|
||||
* The class to use for interpreting wildcard permissions.
|
||||
* If you need to modify delimiters, override the class and specify its name here.
|
||||
*/
|
||||
// 'wildcard_permission' => Spatie\Permission\WildcardPermission::class,
|
||||
|
||||
/* Cache-specific settings */
|
||||
|
||||
'cache' => [
|
||||
|
||||
/*
|
||||
* By default all permissions are cached for 24 hours to speed up performance.
|
||||
* When permissions or roles are updated the cache is flushed automatically.
|
||||
*/
|
||||
|
||||
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
|
||||
|
||||
/*
|
||||
* The cache key used to store all permissions.
|
||||
*/
|
||||
|
||||
'key' => 'spatie.permission.cache',
|
||||
|
||||
/*
|
||||
* You may optionally indicate a specific cache driver to use for permission and
|
||||
* role caching using any of the `store` drivers listed in the cache.php config
|
||||
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||
*/
|
||||
|
||||
'store' => 'default',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$teams = config('permission.teams');
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
|
||||
throw_if(empty($tableNames), Exception::class, 'Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
throw_if($teams && empty($columnNames['team_foreign_key'] ?? null), Exception::class, 'Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
|
||||
Schema::create($tableNames['permissions'], static function (Blueprint $table) {
|
||||
// $table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // permission id
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) {
|
||||
// $table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
throw_if(empty($tableNames), Exception::class, 'Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
|
||||
Schema::drop($tableNames['role_has_permissions']);
|
||||
Schema::drop($tableNames['model_has_roles']);
|
||||
Schema::drop($tableNames['model_has_permissions']);
|
||||
Schema::drop($tableNames['roles']);
|
||||
Schema::drop($tableNames['permissions']);
|
||||
}
|
||||
};
|
||||
204
database/seeders/PermissionSeeder.php
Normal file
204
database/seeders/PermissionSeeder.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class PermissionSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// 重置缓存的角色和权限
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
// 定义所有权限
|
||||
$permissions = [
|
||||
// 文档管理权限
|
||||
'document.viewAny' => '查看文档列表',
|
||||
'document.view' => '查看文档详情',
|
||||
'document.create' => '创建文档',
|
||||
'document.update' => '编辑文档',
|
||||
'document.delete' => '删除文档',
|
||||
'document.download' => '下载文档',
|
||||
|
||||
// 系统设置权限
|
||||
'system-setting.viewAny' => '查看系统设置',
|
||||
'system-setting.view' => '查看设置详情',
|
||||
'system-setting.update' => '修改系统设置',
|
||||
|
||||
// 操作日志权限
|
||||
'activity-log.viewAny' => '查看操作日志',
|
||||
'activity-log.view' => '查看日志详情',
|
||||
'activity-log.export' => '导出日志',
|
||||
|
||||
// 终端管理权限
|
||||
'terminal.viewAny' => '查看终端列表',
|
||||
'terminal.view' => '查看终端详情',
|
||||
'terminal.create' => '创建终端',
|
||||
'terminal.update' => '编辑终端',
|
||||
'terminal.delete' => '删除终端',
|
||||
'terminal.sync' => '同步终端配置',
|
||||
|
||||
// SOP模板权限
|
||||
'sop-template.viewAny' => '查看SOP列表',
|
||||
'sop-template.view' => '查看SOP详情',
|
||||
'sop-template.create' => '创建SOP',
|
||||
'sop-template.update' => '编辑SOP',
|
||||
'sop-template.delete' => '删除SOP',
|
||||
'sop-template.publish' => '发布SOP',
|
||||
'sop-template.archive' => '归档SOP',
|
||||
|
||||
// 分组管理权限
|
||||
'group.viewAny' => '查看分组列表',
|
||||
'group.view' => '查看分组详情',
|
||||
'group.create' => '创建分组',
|
||||
'group.update' => '编辑分组',
|
||||
'group.delete' => '删除分组',
|
||||
|
||||
// 用户管理权限
|
||||
'user.viewAny' => '查看用户列表',
|
||||
'user.view' => '查看用户详情',
|
||||
'user.create' => '创建用户',
|
||||
'user.update' => '编辑用户',
|
||||
'user.delete' => '删除用户',
|
||||
|
||||
// 角色管理权限
|
||||
'role.viewAny' => '查看角色列表',
|
||||
'role.view' => '查看角色详情',
|
||||
'role.create' => '创建角色',
|
||||
'role.update' => '编辑角色',
|
||||
'role.delete' => '删除角色',
|
||||
];
|
||||
|
||||
// 创建所有权限
|
||||
foreach ($permissions as $name => $description) {
|
||||
Permission::create([
|
||||
'name' => $name,
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
}
|
||||
|
||||
// 创建角色并分配权限
|
||||
$this->createSuperAdminRole();
|
||||
$this->createAdminRole();
|
||||
$this->createUserRole();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建超级管理员角色
|
||||
*/
|
||||
private function createSuperAdminRole(): void
|
||||
{
|
||||
$role = Role::create([
|
||||
'name' => 'super-admin',
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
|
||||
// 超级管理员拥有所有权限
|
||||
$role->givePermissionTo(Permission::all());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建管理员角色
|
||||
*/
|
||||
private function createAdminRole(): void
|
||||
{
|
||||
$role = Role::create([
|
||||
'name' => 'admin',
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
|
||||
// 管理员权限(除了角色管理)
|
||||
$permissions = [
|
||||
// 文档管理
|
||||
'document.viewAny',
|
||||
'document.view',
|
||||
'document.create',
|
||||
'document.update',
|
||||
'document.delete',
|
||||
'document.download',
|
||||
|
||||
// 系统设置
|
||||
'system-setting.viewAny',
|
||||
'system-setting.view',
|
||||
'system-setting.update',
|
||||
|
||||
// 操作日志
|
||||
'activity-log.viewAny',
|
||||
'activity-log.view',
|
||||
'activity-log.export',
|
||||
|
||||
// 终端管理
|
||||
'terminal.viewAny',
|
||||
'terminal.view',
|
||||
'terminal.create',
|
||||
'terminal.update',
|
||||
'terminal.delete',
|
||||
'terminal.sync',
|
||||
|
||||
// SOP模板
|
||||
'sop-template.viewAny',
|
||||
'sop-template.view',
|
||||
'sop-template.create',
|
||||
'sop-template.update',
|
||||
'sop-template.delete',
|
||||
'sop-template.publish',
|
||||
'sop-template.archive',
|
||||
|
||||
// 分组管理
|
||||
'group.viewAny',
|
||||
'group.view',
|
||||
'group.create',
|
||||
'group.update',
|
||||
'group.delete',
|
||||
|
||||
// 用户管理
|
||||
'user.viewAny',
|
||||
'user.view',
|
||||
'user.create',
|
||||
'user.update',
|
||||
'user.delete',
|
||||
];
|
||||
|
||||
$role->givePermissionTo($permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建普通用户角色
|
||||
*/
|
||||
private function createUserRole(): void
|
||||
{
|
||||
$role = Role::create([
|
||||
'name' => 'user',
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
|
||||
// 普通用户权限(基本查看和操作)
|
||||
$permissions = [
|
||||
// 文档管理
|
||||
'document.viewAny',
|
||||
'document.view',
|
||||
'document.create',
|
||||
'document.download',
|
||||
|
||||
// 终端管理(仅查看)
|
||||
'terminal.viewAny',
|
||||
'terminal.view',
|
||||
|
||||
// SOP模板(仅查看)
|
||||
'sop-template.viewAny',
|
||||
'sop-template.view',
|
||||
|
||||
// 分组管理(仅查看)
|
||||
'group.viewAny',
|
||||
'group.view',
|
||||
];
|
||||
|
||||
$role->givePermissionTo($permissions);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user