30 changed files with 844 additions and 1172 deletions
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
# Frontend Backend Route 重命名为 Auth Resources - 迁移说明 |
||||
|
||||
## 概述 |
||||
将 `frontend_backend_routes` 表重命名为 `auth_resources` 表,并更新所有相关的代码引用。 |
||||
|
||||
## 更改内容 |
||||
|
||||
### 1. 数据库表结构 |
||||
- **原表名**: `frontend_backend_routes` |
||||
- **新表名**: `auth_resources` |
||||
- **字段**: 保持不变,只修改表名和索引名 |
||||
|
||||
### 2. 新建表 SQL 语句 |
||||
- 文件: `backend/internal/auth/migration/create_auth_resources_table.sql` |
||||
- 包含完整的 `auth_resources` 表建表语句 |
||||
|
||||
### 3. 代码更改 |
||||
|
||||
#### 3.1 模型文件 |
||||
- **文件**: `backend/internal/auth/model/auth_resources.go` (原 `frontend_backend_route.go`) |
||||
- **更改**: |
||||
- 结构体名从 `FrontendBackendRoute` 改为 `AuthResources` |
||||
- `TableName()` 方法返回 `"auth_resources"` 而不是 `"frontend_backend_routes"` |
||||
- 唯一索引名从 `idx_frontend_backend_routes_unique` 改为 `idx_auth_resources_unique` |
||||
|
||||
#### 3.2 Repository 文件 |
||||
- **文件**: `backend/internal/auth/repository/auth_resources_repo.go` (原 `frontend_backend_route_repo.go`) |
||||
- **更改**: |
||||
- 结构体名从 `FrontendBackendRouteRepository` 改为 `AuthResourcesRepository` |
||||
- 构造函数从 `NewFrontendBackendRouteRepository` 改为 `NewAuthResourcesRepository` |
||||
- 所有方法中的模型引用从 `model.FrontendBackendRoute` 改为 `model.AuthResources` |
||||
- SQL 查询中的表名从 `frontend_backend_routes` 改为 `auth_resources` |
||||
|
||||
#### 3.3 Service 文件 |
||||
- **文件**: `backend/internal/auth/service/menus_service.go` |
||||
- **更改**: |
||||
- 字段名从 `frontendBackendRouteRepo` 改为 `authResourcesRepo` |
||||
- 类型从 `*repository.FrontendBackendRouteRepository` 改为 `*repository.AuthResourcesRepository` |
||||
- 模型引用从 `model.FrontendBackendRoute` 改为 `model.AuthResources` |
||||
|
||||
- **文件**: `backend/internal/auth/service/route_sync_service.go` |
||||
- **更改**: |
||||
- 字段名从 `frontendBackendRouteRepo` 改为 `authResourcesRepo` |
||||
- 类型从 `*repository.FrontendBackendRouteRepository` 改为 `*repository.AuthResourcesRepository` |
||||
|
||||
#### 3.4 Routes 文件 |
||||
- **文件**: `backend/internal/auth/routes/menus_routes.go` |
||||
- **文件**: `backend/internal/auth/routes/route_sync_routes.go` |
||||
- **更改**: |
||||
- 变量名从 `frontendBackendRouteRepo` 改为 `authResourcesRepo` |
||||
- 构造函数调用从 `NewFrontendBackendRouteRepository` 改为 `NewAuthResourcesRepository` |
||||
|
||||
#### 3.5 Module 文件 |
||||
- **文件**: `backend/internal/auth/module.go` |
||||
- **更改**: |
||||
- 变量名从 `frontendBackendRouteRepo` 改为 `authResourcesRepo` |
||||
- 构造函数调用从 `NewFrontendBackendRouteRepository` 改为 `NewAuthResourcesRepository` |
||||
|
||||
#### 3.6 Middleware 文件 |
||||
- **文件**: `backend/internal/shared/middleware/permission_middleware.go` |
||||
- **更改**: |
||||
- 变量名从 `frontendBackendRouteRepo` 改为 `authResourcesRepo` |
||||
- 构造函数调用从 `NewFrontendBackendRouteRepository` 改为 `NewAuthResourcesRepository` |
||||
- 函数参数类型从 `*model.FrontendBackendRoute` 改为 `*model.AuthResources` |
||||
|
||||
### 4. 迁移脚本 |
||||
- **SQL 脚本**: `backend/internal/auth/migration/create_auth_resources_table.sql` |
||||
|
||||
## 迁移步骤 |
||||
|
||||
### 方法一:使用 SQL 重命名(推荐) |
||||
```sql |
||||
-- 重命名表 |
||||
RENAME TABLE frontend_backend_routes TO auth_resources; |
||||
|
||||
-- 重命名索引 |
||||
ALTER TABLE auth_resources DROP INDEX idx_frontend_backend_routes_unique; |
||||
ALTER TABLE auth_resources ADD UNIQUE INDEX idx_auth_resources_unique (frontend_route_id, backend_route); |
||||
``` |
||||
|
||||
### 方法二:如果表不存在,创建新表 |
||||
```sql |
||||
-- 执行 create_auth_resources_table.sql 中的建表语句 |
||||
``` |
||||
|
||||
## 注意事项 |
||||
|
||||
1. **备份数据**: 执行迁移前请务必备份现有数据 |
||||
2. **停止应用**: 迁移期间需要停止应用程序 |
||||
3. **测试验证**: 迁移完成后请验证所有功能正常 |
||||
4. **API 兼容性**: API 路径和参数保持不变,只修改了数据库表名和内部结构 |
||||
5. **字段不变**: 所有字段名称和类型保持不变 |
||||
|
||||
## 影响范围 |
||||
|
||||
- ✅ 数据库表名 |
||||
- ✅ Go 模型中的表名引用 |
||||
- ✅ Repository 中的 SQL 查询 |
||||
- ✅ Service 中的依赖注入 |
||||
- ✅ Routes 中的初始化 |
||||
- ✅ Module 中的依赖管理 |
||||
- ✅ Middleware 中的权限检查 |
||||
- ❌ API 路径(保持不变) |
||||
- ❌ 字段名称(保持不变) |
||||
- ❌ 业务逻辑(保持不变) |
||||
|
||||
## 验证清单 |
||||
|
||||
- [ ] 数据库表已重命名为 `auth_resources` |
||||
- [ ] 应用程序能正常启动 |
||||
- [ ] 菜单/路由相关 API 正常工作 |
||||
- [ ] 数据查询和统计功能正常 |
||||
- [ ] 前后台路由关联功能正常 |
||||
- [ ] 权限中间件正常工作 |
||||
- [ ] 路由同步功能正常 |
@ -1,211 +0,0 @@
@@ -1,211 +0,0 @@
|
||||
package controller |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/service" |
||||
"gofaster/internal/shared/response" |
||||
"net/http" |
||||
"strconv" |
||||
|
||||
"github.com/gin-gonic/gin" |
||||
"go.uber.org/zap" |
||||
) |
||||
|
||||
// FrontendRouteController 前台路由控制器
|
||||
type FrontendRouteController struct { |
||||
frontendRouteService *service.FrontendRouteService |
||||
logger *zap.Logger |
||||
} |
||||
|
||||
// NewFrontendRouteController 创建前台路由控制器实例
|
||||
func NewFrontendRouteController(frontendRouteService *service.FrontendRouteService, logger *zap.Logger) *FrontendRouteController { |
||||
return &FrontendRouteController{ |
||||
frontendRouteService: frontendRouteService, |
||||
logger: logger, |
||||
} |
||||
} |
||||
|
||||
// SyncFrontendRoute 同步单个前台路由
|
||||
// @Summary 同步单个前台路由
|
||||
// @Description 同步单个前台路由及其后台路由关联
|
||||
// @Tags 前台路由
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param route body map[string]interface{} true "前台路由数据"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/sync [post]
|
||||
func (c *FrontendRouteController) SyncFrontendRoute(ctx *gin.Context) { |
||||
var routeData map[string]interface{} |
||||
if err := ctx.ShouldBindJSON(&routeData); err != nil { |
||||
c.logger.Error("解析前台路由数据失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||
return |
||||
} |
||||
|
||||
if err := c.frontendRouteService.SyncFrontendRoute(routeData); err != nil { |
||||
c.logger.Error("同步前台路由失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "同步前台路由失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "前台路由同步成功", nil) |
||||
} |
||||
|
||||
// BatchSyncFrontendRoutes 批量同步前台路由
|
||||
// @Summary 批量同步前台路由
|
||||
// @Description 批量同步前台路由及其后台路由关联
|
||||
// @Tags 前台路由
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param routes body []map[string]interface{} true "前台路由数据列表"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/batch-sync [post]
|
||||
func (c *FrontendRouteController) BatchSyncFrontendRoutes(ctx *gin.Context) { |
||||
var routesData []map[string]interface{} |
||||
if err := ctx.ShouldBindJSON(&routesData); err != nil { |
||||
c.logger.Error("解析前台路由数据失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||
return |
||||
} |
||||
|
||||
if err := c.frontendRouteService.BatchSyncFrontendRoutes(routesData); err != nil { |
||||
c.logger.Error("批量同步前台路由失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "批量同步前台路由失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "批量同步前台路由成功", nil) |
||||
} |
||||
|
||||
// GetFrontendRoutes 获取前台路由列表
|
||||
// @Summary 获取前台路由列表
|
||||
// @Description 获取所有前台路由列表
|
||||
// @Tags 前台路由
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes [get]
|
||||
func (c *FrontendRouteController) GetFrontendRoutes(ctx *gin.Context) { |
||||
routes, err := c.frontendRouteService.GetFrontendRoutes() |
||||
if err != nil { |
||||
c.logger.Error("获取前台路由列表失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取前台路由列表失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取前台路由列表成功", routes) |
||||
} |
||||
|
||||
// GetFrontendRouteByID 根据ID获取前台路由
|
||||
// @Summary 根据ID获取前台路由
|
||||
// @Description 根据ID获取前台路由详情
|
||||
// @Tags 前台路由
|
||||
// @Produce json
|
||||
// @Param id path int true "前台路由ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/{id} [get]
|
||||
func (c *FrontendRouteController) GetFrontendRouteByID(ctx *gin.Context) { |
||||
idStr := ctx.Param("id") |
||||
id, err := strconv.ParseUint(idStr, 10, 32) |
||||
if err != nil { |
||||
c.logger.Error("解析前台路由ID失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "无效的前台路由ID", err.Error()) |
||||
return |
||||
} |
||||
|
||||
route, err := c.frontendRouteService.GetFrontendRouteByID(uint(id)) |
||||
if err != nil { |
||||
c.logger.Error("获取前台路由失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取前台路由失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取前台路由成功", route) |
||||
} |
||||
|
||||
// GetFrontendRoutesByModule 根据模块获取前台路由
|
||||
// @Summary 根据模块获取前台路由
|
||||
// @Description 根据模块获取前台路由列表
|
||||
// @Tags 前台路由
|
||||
// @Produce json
|
||||
// @Param module query string true "模块名称"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/by-module [get]
|
||||
func (c *FrontendRouteController) GetFrontendRoutesByModule(ctx *gin.Context) { |
||||
module := ctx.Query("module") |
||||
if module == "" { |
||||
c.logger.Error("模块参数为空") |
||||
response.Error(ctx, http.StatusBadRequest, "模块参数不能为空", "module parameter is required") |
||||
return |
||||
} |
||||
|
||||
routes, err := c.frontendRouteService.GetFrontendRoutesByModule(module) |
||||
if err != nil { |
||||
c.logger.Error("根据模块获取前台路由失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "根据模块获取前台路由失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "根据模块获取前台路由成功", routes) |
||||
} |
||||
|
||||
// GetRouteRelations 获取路由关联关系
|
||||
// @Summary 获取路由关联关系
|
||||
// @Description 获取前台路由与后台路由的关联关系
|
||||
// @Tags 前台路由
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/relations [get]
|
||||
func (c *FrontendRouteController) GetRouteRelations(ctx *gin.Context) { |
||||
relations, err := c.frontendRouteService.GetRouteRelations() |
||||
if err != nil { |
||||
c.logger.Error("获取路由关联关系失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取路由关联关系失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取路由关联关系成功", relations) |
||||
} |
||||
|
||||
// GetRouteRelationsByFrontendRouteID 根据前台路由ID获取关联关系
|
||||
// @Summary 根据前台路由ID获取关联关系
|
||||
// @Description 根据前台路由ID获取其与后台路由的关联关系
|
||||
// @Tags 前台路由
|
||||
// @Produce json
|
||||
// @Param id path int true "前台路由ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/{id}/relations [get]
|
||||
func (c *FrontendRouteController) GetRouteRelationsByFrontendRouteID(ctx *gin.Context) { |
||||
idStr := ctx.Param("id") |
||||
id, err := strconv.ParseUint(idStr, 10, 32) |
||||
if err != nil { |
||||
c.logger.Error("解析前台路由ID失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "无效的前台路由ID", err.Error()) |
||||
return |
||||
} |
||||
|
||||
relations, err := c.frontendRouteService.GetRouteRelationsByFrontendRouteID(uint(id)) |
||||
if err != nil { |
||||
c.logger.Error("获取前台路由关联关系失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取前台路由关联关系失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取前台路由关联关系成功", relations) |
||||
} |
||||
|
||||
// GetStats 获取统计信息
|
||||
// @Summary 获取前台路由统计信息
|
||||
// @Description 获取前台路由和路由关联的统计信息
|
||||
// @Tags 前台路由
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/frontend-routes/stats [get]
|
||||
func (c *FrontendRouteController) GetStats(ctx *gin.Context) { |
||||
stats, err := c.frontendRouteService.GetStats() |
||||
if err != nil { |
||||
c.logger.Error("获取前台路由统计信息失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取前台路由统计信息失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取前台路由统计信息成功", stats) |
||||
} |
@ -0,0 +1,211 @@
@@ -0,0 +1,211 @@
|
||||
package controller |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/service" |
||||
"gofaster/internal/shared/response" |
||||
"net/http" |
||||
"strconv" |
||||
|
||||
"github.com/gin-gonic/gin" |
||||
"go.uber.org/zap" |
||||
) |
||||
|
||||
// MenusController 菜单控制器
|
||||
type MenusController struct { |
||||
menusService *service.MenusService |
||||
logger *zap.Logger |
||||
} |
||||
|
||||
// NewMenusController 创建菜单控制器实例
|
||||
func NewMenusController(menusService *service.MenusService, logger *zap.Logger) *MenusController { |
||||
return &MenusController{ |
||||
menusService: menusService, |
||||
logger: logger, |
||||
} |
||||
} |
||||
|
||||
// SyncMenu 同步单个菜单
|
||||
// @Summary 同步单个菜单
|
||||
// @Description 同步单个菜单及其后台路由关联
|
||||
// @Tags 菜单
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param menu body map[string]interface{} true "菜单数据"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/sync [post]
|
||||
func (c *MenusController) SyncMenu(ctx *gin.Context) { |
||||
var menuData map[string]interface{} |
||||
if err := ctx.ShouldBindJSON(&menuData); err != nil { |
||||
c.logger.Error("解析菜单数据失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||
return |
||||
} |
||||
|
||||
if err := c.menusService.SyncMenu(menuData); err != nil { |
||||
c.logger.Error("同步菜单失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "同步菜单失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "菜单同步成功", nil) |
||||
} |
||||
|
||||
// BatchSyncMenus 批量同步菜单
|
||||
// @Summary 批量同步菜单
|
||||
// @Description 批量同步菜单及其后台路由关联
|
||||
// @Tags 菜单
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param menus body []map[string]interface{} true "菜单数据列表"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/batch-sync [post]
|
||||
func (c *MenusController) BatchSyncMenus(ctx *gin.Context) { |
||||
var menusData []map[string]interface{} |
||||
if err := ctx.ShouldBindJSON(&menusData); err != nil { |
||||
c.logger.Error("解析菜单数据失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||
return |
||||
} |
||||
|
||||
if err := c.menusService.BatchSyncMenus(menusData); err != nil { |
||||
c.logger.Error("批量同步菜单失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "批量同步菜单失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "批量同步菜单成功", nil) |
||||
} |
||||
|
||||
// GetMenus 获取菜单列表
|
||||
// @Summary 获取菜单列表
|
||||
// @Description 获取所有菜单列表
|
||||
// @Tags 菜单
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus [get]
|
||||
func (c *MenusController) GetMenus(ctx *gin.Context) { |
||||
menus, err := c.menusService.GetMenus() |
||||
if err != nil { |
||||
c.logger.Error("获取菜单列表失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单列表失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取菜单列表成功", menus) |
||||
} |
||||
|
||||
// GetMenuByID 根据ID获取菜单
|
||||
// @Summary 根据ID获取菜单
|
||||
// @Description 根据ID获取菜单详情
|
||||
// @Tags 菜单
|
||||
// @Produce json
|
||||
// @Param id path int true "菜单ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/{id} [get]
|
||||
func (c *MenusController) GetMenuByID(ctx *gin.Context) { |
||||
idStr := ctx.Param("id") |
||||
id, err := strconv.ParseUint(idStr, 10, 32) |
||||
if err != nil { |
||||
c.logger.Error("解析菜单ID失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "无效的菜单ID", err.Error()) |
||||
return |
||||
} |
||||
|
||||
menu, err := c.menusService.GetMenuByID(uint(id)) |
||||
if err != nil { |
||||
c.logger.Error("获取菜单失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取菜单成功", menu) |
||||
} |
||||
|
||||
// GetMenusByModule 根据模块获取菜单
|
||||
// @Summary 根据模块获取菜单
|
||||
// @Description 根据模块获取菜单列表
|
||||
// @Tags 菜单
|
||||
// @Produce json
|
||||
// @Param module query string true "模块名称"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/by-module [get]
|
||||
func (c *MenusController) GetMenusByModule(ctx *gin.Context) { |
||||
module := ctx.Query("module") |
||||
if module == "" { |
||||
c.logger.Error("模块参数为空") |
||||
response.Error(ctx, http.StatusBadRequest, "模块参数不能为空", "module parameter is required") |
||||
return |
||||
} |
||||
|
||||
menus, err := c.menusService.GetMenusByModule(module) |
||||
if err != nil { |
||||
c.logger.Error("根据模块获取菜单失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "根据模块获取菜单失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "根据模块获取菜单成功", menus) |
||||
} |
||||
|
||||
// GetRouteRelations 获取路由关联关系
|
||||
// @Summary 获取路由关联关系
|
||||
// @Description 获取菜单与后台路由的关联关系
|
||||
// @Tags 菜单
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/relations [get]
|
||||
func (c *MenusController) GetRouteRelations(ctx *gin.Context) { |
||||
relations, err := c.menusService.GetRouteRelations() |
||||
if err != nil { |
||||
c.logger.Error("获取路由关联关系失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取路由关联关系失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取路由关联关系成功", relations) |
||||
} |
||||
|
||||
// GetRouteRelationsByMenuID 根据菜单ID获取关联关系
|
||||
// @Summary 根据菜单ID获取关联关系
|
||||
// @Description 根据菜单ID获取其与后台路由的关联关系
|
||||
// @Tags 菜单
|
||||
// @Produce json
|
||||
// @Param id path int true "菜单ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/{id}/relations [get]
|
||||
func (c *MenusController) GetRouteRelationsByMenuID(ctx *gin.Context) { |
||||
idStr := ctx.Param("id") |
||||
id, err := strconv.ParseUint(idStr, 10, 32) |
||||
if err != nil { |
||||
c.logger.Error("解析菜单ID失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusBadRequest, "无效的菜单ID", err.Error()) |
||||
return |
||||
} |
||||
|
||||
relations, err := c.menusService.GetRouteRelationsByMenuID(uint(id)) |
||||
if err != nil { |
||||
c.logger.Error("获取菜单关联关系失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单关联关系失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取菜单关联关系成功", relations) |
||||
} |
||||
|
||||
// GetStats 获取统计信息
|
||||
// @Summary 获取菜单统计信息
|
||||
// @Description 获取菜单和路由关联的统计信息
|
||||
// @Tags 菜单
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/menus/stats [get]
|
||||
func (c *MenusController) GetStats(ctx *gin.Context) { |
||||
stats, err := c.menusService.GetStats() |
||||
if err != nil { |
||||
c.logger.Error("获取菜单统计信息失败", zap.Error(err)) |
||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单统计信息失败", err.Error()) |
||||
return |
||||
} |
||||
|
||||
response.Success(ctx, "获取菜单统计信息成功", stats) |
||||
} |
@ -1,58 +0,0 @@
@@ -1,58 +0,0 @@
|
||||
package migration |
||||
|
||||
import ( |
||||
"fmt" |
||||
"gofaster/internal/auth/model" |
||||
|
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// AddPermissionCodeField 为权限表添加code字段
|
||||
func AddPermissionCodeField(db *gorm.DB) error { |
||||
fmt.Println("🔧 开始为权限表添加code字段...") |
||||
|
||||
// 检查code字段是否已存在
|
||||
var count int64 |
||||
err := db.Raw("SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'permissions' AND column_name = 'code'").Count(&count).Error |
||||
if err != nil { |
||||
return fmt.Errorf("检查code字段失败: %v", err) |
||||
} |
||||
|
||||
if count > 0 { |
||||
fmt.Println("✅ code字段已存在,跳过添加") |
||||
return nil |
||||
} |
||||
|
||||
// 添加code字段
|
||||
err = db.Exec("ALTER TABLE permissions ADD COLUMN code VARCHAR(50)").Error |
||||
if err != nil { |
||||
return fmt.Errorf("添加code字段失败: %v", err) |
||||
} |
||||
|
||||
// 为现有权限记录生成code
|
||||
var permissions []model.Permission |
||||
err = db.Find(&permissions).Error |
||||
if err != nil { |
||||
return fmt.Errorf("查询现有权限失败: %v", err) |
||||
} |
||||
|
||||
fmt.Printf("🔧 为 %d 条现有权限记录生成code...\n", len(permissions)) |
||||
|
||||
for _, permission := range permissions { |
||||
code := fmt.Sprintf("%s:%s", permission.Resource, permission.Action) |
||||
err = db.Model(&permission).Update("code", code).Error |
||||
if err != nil { |
||||
return fmt.Errorf("更新权限 %d 的code失败: %v", permission.ID, err) |
||||
} |
||||
fmt.Printf("✅ 已为权限 '%s' 生成code: %s\n", permission.Name, code) |
||||
} |
||||
|
||||
// 添加唯一索引
|
||||
err = db.Exec("CREATE UNIQUE INDEX idx_permissions_code ON permissions(code)").Error |
||||
if err != nil { |
||||
return fmt.Errorf("创建code唯一索引失败: %v", err) |
||||
} |
||||
|
||||
fmt.Println("✅ 权限表code字段添加完成") |
||||
return nil |
||||
} |
@ -1,52 +0,0 @@
@@ -1,52 +0,0 @@
|
||||
package migration |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"go.uber.org/zap" |
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// AddUniqueIndexToFrontendBackendRoutes 为 frontend_backend_routes 表添加唯一索引
|
||||
func AddUniqueIndexToFrontendBackendRoutes(db *gorm.DB, log *zap.Logger) error { |
||||
log.Info("开始为 frontend_backend_routes 表添加唯一索引...") |
||||
|
||||
// 检查表是否存在
|
||||
if !db.Migrator().HasTable("frontend_backend_routes") { |
||||
log.Info("frontend_backend_routes 表不存在,跳过添加唯一索引") |
||||
return nil |
||||
} |
||||
|
||||
// 检查唯一索引是否已存在
|
||||
var indexExists bool |
||||
err := db.Raw(` |
||||
SELECT COUNT(*) > 0
|
||||
FROM pg_indexes
|
||||
WHERE tablename = 'frontend_backend_routes'
|
||||
AND indexname = 'idx_frontend_backend_routes_unique' |
||||
`).Scan(&indexExists).Error |
||||
|
||||
if err != nil { |
||||
log.Error("检查唯一索引是否存在失败", zap.Error(err)) |
||||
return fmt.Errorf("检查唯一索引失败: %w", err) |
||||
} |
||||
|
||||
if indexExists { |
||||
log.Info("唯一索引已存在,跳过创建") |
||||
return nil |
||||
} |
||||
|
||||
// 创建唯一索引
|
||||
err = db.Exec(` |
||||
CREATE UNIQUE INDEX idx_frontend_backend_routes_unique
|
||||
ON frontend_backend_routes (frontend_route_id, backend_route) |
||||
`).Error |
||||
|
||||
if err != nil { |
||||
log.Error("创建唯一索引失败", zap.Error(err)) |
||||
return fmt.Errorf("创建唯一索引失败: %w", err) |
||||
} |
||||
|
||||
log.Info("✅ frontend_backend_routes 表唯一索引创建成功") |
||||
return nil |
||||
} |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
-- 创建 auth_resources 表(原 frontend_backend_routes 表) |
||||
CREATE TABLE IF NOT EXISTS `auth_resources` ( |
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', |
||||
`created_at` datetime(3) DEFAULT NULL COMMENT '创建时间', |
||||
`updated_at` datetime(3) DEFAULT NULL COMMENT '更新时间', |
||||
`deleted_at` datetime(3) DEFAULT NULL COMMENT '删除时间', |
||||
`frontend_route_id` bigint(20) unsigned NOT NULL COMMENT '前台路由ID', |
||||
`backend_route` varchar(255) NOT NULL COMMENT '后台API路径', |
||||
`http_method` varchar(10) NOT NULL COMMENT 'HTTP方法', |
||||
`component` varchar(255) NOT NULL COMMENT '前端组件名称', |
||||
`module` varchar(255) NOT NULL COMMENT '所属模块', |
||||
`description` text COMMENT '描述', |
||||
`sort` int(11) DEFAULT '0' COMMENT '排序', |
||||
`status` int(11) DEFAULT '1' COMMENT '状态:1-启用,0-禁用', |
||||
PRIMARY KEY (`id`), |
||||
UNIQUE KEY `idx_auth_resources_unique` (`frontend_route_id`, `backend_route`), |
||||
KEY `idx_auth_resources_frontend_route_id` (`frontend_route_id`), |
||||
KEY `idx_auth_resources_backend_route` (`backend_route`), |
||||
KEY `idx_auth_resources_module` (`module`), |
||||
KEY `idx_auth_resources_component` (`component`), |
||||
KEY `idx_auth_resources_status` (`status`), |
||||
KEY `idx_auth_resources_sort` (`sort`), |
||||
KEY `idx_auth_resources_deleted_at` (`deleted_at`) |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='认证资源表(原前后台路由关系表)'; |
@ -1,37 +0,0 @@
@@ -1,37 +0,0 @@
|
||||
package migration |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/model" |
||||
|
||||
"go.uber.org/zap" |
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// CreateRouteTables 创建路由相关表
|
||||
func CreateRouteTables(db *gorm.DB, log *zap.Logger) error { |
||||
log.Info("开始创建路由相关表...") |
||||
|
||||
// 创建菜单分组表
|
||||
if err := db.AutoMigrate(&model.MenuGroup{}); err != nil { |
||||
log.Error("创建菜单分组表失败", zap.Error(err)) |
||||
return err |
||||
} |
||||
log.Info("✅ 菜单分组表创建完成") |
||||
|
||||
// 创建前台路由表
|
||||
if err := db.AutoMigrate(&model.FrontendRoute{}); err != nil { |
||||
log.Error("创建前台路由表失败", zap.Error(err)) |
||||
return err |
||||
} |
||||
log.Info("✅ 前台路由表创建完成") |
||||
|
||||
// 创建前后台路由关系表
|
||||
if err := db.AutoMigrate(&model.FrontendBackendRoute{}); err != nil { |
||||
log.Error("创建前后台路由关系表失败", zap.Error(err)) |
||||
return err |
||||
} |
||||
log.Info("✅ 前后台路由关系表创建完成") |
||||
|
||||
log.Info("路由相关表创建完成") |
||||
return nil |
||||
} |
@ -1,221 +0,0 @@
@@ -1,221 +0,0 @@
|
||||
package migration |
||||
|
||||
import ( |
||||
"fmt" |
||||
"gofaster/internal/auth/model" |
||||
"gofaster/internal/auth/repository" |
||||
"gofaster/internal/shared/logger" |
||||
|
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// RunMigrations 运行数据库迁移
|
||||
func RunMigrations(db *gorm.DB) error { |
||||
log := logger.NewLogger("info", "") |
||||
defer log.Sync() |
||||
// 自动迁移用户表
|
||||
if err := db.AutoMigrate(&model.User{}); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 手动检查并添加可能缺失的字段
|
||||
if err := ensureUserFields(db); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 自动迁移角色表
|
||||
if err := db.AutoMigrate(&model.Role{}); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 自动迁移用户角色关联表
|
||||
if err := db.AutoMigrate(&model.UserRole{}); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 自动迁移验证码表
|
||||
if err := db.AutoMigrate(&repository.Captcha{}); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 自动迁移密码策略相关表
|
||||
if err := db.AutoMigrate( |
||||
&model.PasswordPolicy{}, |
||||
&model.PasswordHistory{}, |
||||
&model.PasswordReset{}, |
||||
); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 自动迁移权限相关表
|
||||
if err := db.AutoMigrate( |
||||
&model.Permission{}, |
||||
&model.RolePermission{}, |
||||
); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 为权限表添加code字段
|
||||
if err := AddPermissionCodeField(db); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 创建路由相关表
|
||||
if err := CreateRouteTables(db, log); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 移除相关表的 delete_at 字段
|
||||
if err := RemoveDeleteAtFields(db, log); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 为 frontend_backend_routes 表添加唯一索引
|
||||
if err := AddUniqueIndexToFrontendBackendRoutes(db, log); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 创建默认角色
|
||||
if err := createDefaultRoles(db); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 创建默认管理员用户
|
||||
if err := createDefaultAdmin(db); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 创建默认密码策略
|
||||
if err := createDefaultPasswordPolicy(db); err != nil { |
||||
return err |
||||
} |
||||
|
||||
|
||||
return nil |
||||
} |
||||
|
||||
// ensureUserFields 确保用户表有必要的字段
|
||||
func ensureUserFields(db *gorm.DB) error { |
||||
// 检查PasswordChangedAt字段是否存在
|
||||
if !db.Migrator().HasColumn(&model.User{}, "password_changed_at") { |
||||
fmt.Println("添加 password_changed_at 字段到 users 表") |
||||
if err := db.Exec("ALTER TABLE users ADD COLUMN password_changed_at TIMESTAMP NULL").Error; err != nil { |
||||
return fmt.Errorf("添加 password_changed_at 字段失败: %w", err) |
||||
} |
||||
} |
||||
|
||||
// 检查ForceChangePassword字段是否存在
|
||||
if !db.Migrator().HasColumn(&model.User{}, "force_change_password") { |
||||
fmt.Println("添加 force_change_password 字段到 users 表") |
||||
if err := db.Exec("ALTER TABLE users ADD COLUMN force_change_password BOOLEAN DEFAULT FALSE").Error; err != nil { |
||||
return fmt.Errorf("添加 force_change_password 字段失败: %w", err) |
||||
} |
||||
} |
||||
|
||||
fmt.Println("用户表字段检查完成") |
||||
return nil |
||||
} |
||||
|
||||
// createDefaultRoles 创建默认角色
|
||||
func createDefaultRoles(db *gorm.DB) error { |
||||
// 检查是否已存在角色
|
||||
var count int64 |
||||
db.Model(&model.Role{}).Count(&count) |
||||
if count > 0 { |
||||
return nil // 已存在角色,跳过
|
||||
} |
||||
|
||||
roles := []model.Role{ |
||||
{ |
||||
Name: "超级管理员", |
||||
Code: "SUPER_ADMIN", |
||||
Description: "系统超级管理员,拥有所有权限", |
||||
}, |
||||
{ |
||||
Name: "管理员", |
||||
Code: "ADMIN", |
||||
Description: "系统管理员,拥有大部分权限", |
||||
}, |
||||
{ |
||||
Name: "普通用户", |
||||
Code: "USER", |
||||
Description: "普通用户,拥有基本权限", |
||||
}, |
||||
} |
||||
|
||||
for _, role := range roles { |
||||
if err := db.Create(&role).Error; err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// createDefaultAdmin 创建默认管理员用户
|
||||
func createDefaultAdmin(db *gorm.DB) error { |
||||
// 检查是否已存在管理员用户
|
||||
var count int64 |
||||
db.Model(&model.User{}).Where("username = ?", "admin").Count(&count) |
||||
if count > 0 { |
||||
return nil // 已存在管理员用户,跳过
|
||||
} |
||||
|
||||
// 创建默认管理员用户
|
||||
adminUser := &model.User{ |
||||
Username: "admin", |
||||
Password: "$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", // "password"
|
||||
Email: "admin@gofaster.com", |
||||
Phone: "13800138000", |
||||
Status: 1, // 正常状态
|
||||
} |
||||
|
||||
if err := db.Create(adminUser).Error; err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 获取超级管理员角色
|
||||
var superAdminRole model.Role |
||||
if err := db.Where("code = ?", "SUPER_ADMIN").First(&superAdminRole).Error; err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 关联超级管理员角色
|
||||
if err := db.Model(adminUser).Association("Roles").Append(&superAdminRole); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// createDefaultPasswordPolicy 创建默认密码策略
|
||||
func createDefaultPasswordPolicy(db *gorm.DB) error { |
||||
// 检查是否已存在默认策略
|
||||
var count int64 |
||||
db.Model(&model.PasswordPolicy{}).Count(&count) |
||||
if count > 0 { |
||||
return nil // 已存在默认策略,跳过
|
||||
} |
||||
|
||||
// 创建默认密码策略(1级)
|
||||
defaultPolicy := &model.PasswordPolicy{ |
||||
Level: 1, |
||||
MinRequiredLevel: 1, // 新增:要求最低1级强度
|
||||
MinLength: 6, |
||||
RequireUppercase: false, |
||||
RequireLowercase: false, |
||||
RequireNumbers: false, |
||||
RequireSpecial: false, |
||||
MinCharTypes: 1, |
||||
ExpirationDays: 30, |
||||
PreventReuse: 3, |
||||
IsActive: true, |
||||
} |
||||
|
||||
if err := db.Create(defaultPolicy).Error; err != nil { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
package model |
||||
|
||||
import ( |
||||
"time" |
||||
) |
||||
|
||||
// AuthResources 认证资源模型(原前后台路由关系模型)
|
||||
type AuthResources struct { |
||||
ID uint `gorm:"primarykey" json:"id"` |
||||
UpdatedAt time.Time `json:"updated_at"` |
||||
FrontendRouteID uint `gorm:"uniqueIndex:idx_auth_resources_unique" json:"frontend_route_id"` // 前台路由ID
|
||||
BackendRoute string `gorm:"uniqueIndex:idx_auth_resources_unique" json:"backend_route"` // 后台API路径
|
||||
HTTPMethod string `json:"http_method"` // HTTP方法
|
||||
Component string `json:"component"` // 前端组件名称
|
||||
Module string `json:"module"` // 所属模块
|
||||
Description string `json:"description"` // 描述
|
||||
Sort int `gorm:"default:0" json:"sort"` // 排序
|
||||
Status int `gorm:"default:1" json:"status"` // 状态:1-启用,0-禁用
|
||||
} |
||||
|
||||
// TableName 指定表名
|
||||
func (AuthResources) TableName() string { |
||||
return "auth_resources" |
||||
} |
@ -1,24 +0,0 @@
@@ -1,24 +0,0 @@
|
||||
package model |
||||
|
||||
import ( |
||||
"time" |
||||
) |
||||
|
||||
// FrontendBackendRoute 前后台路由关系模型
|
||||
type FrontendBackendRoute struct { |
||||
ID uint `gorm:"primarykey" json:"id"` |
||||
UpdatedAt time.Time `json:"updated_at"` |
||||
FrontendRouteID uint `gorm:"uniqueIndex:idx_frontend_backend_routes_unique" json:"frontend_route_id"` // 前台路由ID
|
||||
BackendRoute string `gorm:"uniqueIndex:idx_frontend_backend_routes_unique" json:"backend_route"` // 后台API路径
|
||||
HTTPMethod string `json:"http_method"` // HTTP方法
|
||||
Component string `json:"component"` // 前端组件名称
|
||||
Module string `json:"module"` // 所属模块
|
||||
Description string `json:"description"` // 描述
|
||||
Sort int `gorm:"default:0" json:"sort"` // 排序
|
||||
Status int `gorm:"default:1" json:"status"` // 状态:1-启用,0-禁用
|
||||
} |
||||
|
||||
// TableName 指定表名
|
||||
func (FrontendBackendRoute) TableName() string { |
||||
return "frontend_backend_routes" |
||||
} |
@ -0,0 +1,170 @@
@@ -0,0 +1,170 @@
|
||||
package repository |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/model" |
||||
|
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// AuthResourcesRepository 认证资源仓库(原前后台路由关系仓库)
|
||||
type AuthResourcesRepository struct { |
||||
db *gorm.DB |
||||
} |
||||
|
||||
// NewAuthResourcesRepository 创建认证资源仓库实例
|
||||
func NewAuthResourcesRepository(db *gorm.DB) *AuthResourcesRepository { |
||||
return &AuthResourcesRepository{db: db} |
||||
} |
||||
|
||||
// Create 创建认证资源
|
||||
func (r *AuthResourcesRepository) Create(resource *model.AuthResources) error { |
||||
return r.db.Create(resource).Error |
||||
} |
||||
|
||||
// FindByID 根据ID查找认证资源
|
||||
func (r *AuthResourcesRepository) FindByID(id uint) (*model.AuthResources, error) { |
||||
var resource model.AuthResources |
||||
err := r.db.Where("id = ?", id).First(&resource).Error |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &resource, nil |
||||
} |
||||
|
||||
// FindByFrontendRouteID 根据前台路由ID查找资源
|
||||
func (r *AuthResourcesRepository) FindByFrontendRouteID(frontendRouteID uint) ([]*model.AuthResources, error) { |
||||
var resources []*model.AuthResources |
||||
err := r.db.Where("frontend_route_id = ?", frontendRouteID).Order("sort ASC").Find(&resources).Error |
||||
return resources, err |
||||
} |
||||
|
||||
// FindByBackendRoute 根据后台路由查找资源
|
||||
func (r *AuthResourcesRepository) FindByBackendRoute(backendRoute string) ([]*model.AuthResources, error) { |
||||
var resources []*model.AuthResources |
||||
err := r.db.Where("backend_route = ?", backendRoute).Find(&resources).Error |
||||
return resources, err |
||||
} |
||||
|
||||
// FindByModule 根据模块查找资源
|
||||
func (r *AuthResourcesRepository) FindByModule(module string) ([]*model.AuthResources, error) { |
||||
var resources []*model.AuthResources |
||||
err := r.db.Where("module = ?", module).Order("sort ASC").Find(&resources).Error |
||||
return resources, err |
||||
} |
||||
|
||||
// FindByComponent 根据组件名称查找资源
|
||||
func (r *AuthResourcesRepository) FindByComponent(component string) ([]*model.AuthResources, error) { |
||||
var resources []*model.AuthResources |
||||
err := r.db.Where("component = ?", component).Order("sort ASC").Find(&resources).Error |
||||
return resources, err |
||||
} |
||||
|
||||
// List 获取认证资源列表
|
||||
func (r *AuthResourcesRepository) List() ([]*model.AuthResources, error) { |
||||
var resources []*model.AuthResources |
||||
err := r.db.Order("sort ASC").Find(&resources).Error |
||||
return resources, err |
||||
} |
||||
|
||||
// Update 更新认证资源
|
||||
func (r *AuthResourcesRepository) Update(resource *model.AuthResources) error { |
||||
return r.db.Save(resource).Error |
||||
} |
||||
|
||||
// Delete 删除认证资源
|
||||
func (r *AuthResourcesRepository) Delete(id uint) error { |
||||
return r.db.Delete(&model.AuthResources{}, id).Error |
||||
} |
||||
|
||||
// DeleteByFrontendRouteID 根据前台路由ID删除资源
|
||||
func (r *AuthResourcesRepository) DeleteByFrontendRouteID(frontendRouteID uint) error { |
||||
return r.db.Where("frontend_route_id = ?", frontendRouteID).Delete(&model.AuthResources{}).Error |
||||
} |
||||
|
||||
// Upsert 更新或插入认证资源
|
||||
func (r *AuthResourcesRepository) Upsert(resource *model.AuthResources) error { |
||||
// 使用 PostgreSQL 的 ON CONFLICT 语法处理唯一索引冲突
|
||||
sql := ` |
||||
INSERT INTO auth_resources
|
||||
(frontend_route_id, backend_route, http_method, component, module, description, sort, status, updated_at) |
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW()) |
||||
ON CONFLICT (frontend_route_id, backend_route)
|
||||
DO UPDATE SET |
||||
http_method = EXCLUDED.http_method, |
||||
component = EXCLUDED.component, |
||||
module = EXCLUDED.module, |
||||
description = EXCLUDED.description, |
||||
sort = EXCLUDED.sort, |
||||
status = EXCLUDED.status, |
||||
updated_at = NOW() |
||||
RETURNING id |
||||
` |
||||
|
||||
var id uint |
||||
err := r.db.Raw(sql, |
||||
resource.FrontendRouteID, |
||||
resource.BackendRoute, |
||||
resource.HTTPMethod, |
||||
resource.Component, |
||||
resource.Module, |
||||
resource.Description, |
||||
resource.Sort, |
||||
resource.Status, |
||||
).Scan(&id).Error |
||||
|
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 设置返回的ID
|
||||
resource.ID = id |
||||
return nil |
||||
} |
||||
|
||||
// GetStats 获取认证资源统计信息
|
||||
func (r *AuthResourcesRepository) GetStats() (map[string]interface{}, error) { |
||||
var total int64 |
||||
var componentStats []struct { |
||||
Component string `json:"component"` |
||||
Count int64 `json:"count"` |
||||
} |
||||
var moduleStats []struct { |
||||
Module string `json:"module"` |
||||
Count int64 `json:"count"` |
||||
} |
||||
|
||||
if err := r.db.Model(&model.AuthResources{}).Count(&total).Error; err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if err := r.db.Model(&model.AuthResources{}). |
||||
Select("component, count(*) as count"). |
||||
Group("component"). |
||||
Scan(&componentStats).Error; err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if err := r.db.Model(&model.AuthResources{}). |
||||
Select("module, count(*) as count"). |
||||
Group("module"). |
||||
Scan(&moduleStats).Error; err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return map[string]interface{}{ |
||||
"total": total, |
||||
"component_stats": componentStats, |
||||
"module_stats": moduleStats, |
||||
}, nil |
||||
} |
||||
|
||||
// GetWithFrontendRoute 获取资源并包含前台路由信息
|
||||
func (r *AuthResourcesRepository) GetWithFrontendRoute() ([]map[string]interface{}, error) { |
||||
var results []map[string]interface{} |
||||
err := r.db.Table("auth_resources"). |
||||
Select("auth_resources.*, menus.path as frontend_path, menus.name as frontend_name"). |
||||
Joins("LEFT JOIN menus ON auth_resources.frontend_route_id = menus.id"). |
||||
Order("auth_resources.sort ASC"). |
||||
Scan(&results).Error |
||||
return results, err |
||||
} |
@ -1,170 +0,0 @@
@@ -1,170 +0,0 @@
|
||||
package repository |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/model" |
||||
|
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// FrontendBackendRouteRepository 前后台路由关系仓库
|
||||
type FrontendBackendRouteRepository struct { |
||||
db *gorm.DB |
||||
} |
||||
|
||||
// NewFrontendBackendRouteRepository 创建前后台路由关系仓库实例
|
||||
func NewFrontendBackendRouteRepository(db *gorm.DB) *FrontendBackendRouteRepository { |
||||
return &FrontendBackendRouteRepository{db: db} |
||||
} |
||||
|
||||
// Create 创建前后台路由关系
|
||||
func (r *FrontendBackendRouteRepository) Create(relation *model.FrontendBackendRoute) error { |
||||
return r.db.Create(relation).Error |
||||
} |
||||
|
||||
// FindByID 根据ID查找前后台路由关系
|
||||
func (r *FrontendBackendRouteRepository) FindByID(id uint) (*model.FrontendBackendRoute, error) { |
||||
var relation model.FrontendBackendRoute |
||||
err := r.db.Where("id = ?", id).First(&relation).Error |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &relation, nil |
||||
} |
||||
|
||||
// FindByFrontendRouteID 根据前台路由ID查找关系
|
||||
func (r *FrontendBackendRouteRepository) FindByFrontendRouteID(frontendRouteID uint) ([]*model.FrontendBackendRoute, error) { |
||||
var relations []*model.FrontendBackendRoute |
||||
err := r.db.Where("frontend_route_id = ?", frontendRouteID).Order("sort ASC").Find(&relations).Error |
||||
return relations, err |
||||
} |
||||
|
||||
// FindByBackendRoute 根据后台路由查找关系
|
||||
func (r *FrontendBackendRouteRepository) FindByBackendRoute(backendRoute string) ([]*model.FrontendBackendRoute, error) { |
||||
var relations []*model.FrontendBackendRoute |
||||
err := r.db.Where("backend_route = ?", backendRoute).Find(&relations).Error |
||||
return relations, err |
||||
} |
||||
|
||||
// FindByModule 根据模块查找关系
|
||||
func (r *FrontendBackendRouteRepository) FindByModule(module string) ([]*model.FrontendBackendRoute, error) { |
||||
var relations []*model.FrontendBackendRoute |
||||
err := r.db.Where("module = ?", module).Order("sort ASC").Find(&relations).Error |
||||
return relations, err |
||||
} |
||||
|
||||
// FindByComponent 根据组件名称查找关系
|
||||
func (r *FrontendBackendRouteRepository) FindByComponent(component string) ([]*model.FrontendBackendRoute, error) { |
||||
var relations []*model.FrontendBackendRoute |
||||
err := r.db.Where("component = ?", component).Order("sort ASC").Find(&relations).Error |
||||
return relations, err |
||||
} |
||||
|
||||
// List 获取前后台路由关系列表
|
||||
func (r *FrontendBackendRouteRepository) List() ([]*model.FrontendBackendRoute, error) { |
||||
var relations []*model.FrontendBackendRoute |
||||
err := r.db.Order("sort ASC").Find(&relations).Error |
||||
return relations, err |
||||
} |
||||
|
||||
// Update 更新前后台路由关系
|
||||
func (r *FrontendBackendRouteRepository) Update(relation *model.FrontendBackendRoute) error { |
||||
return r.db.Save(relation).Error |
||||
} |
||||
|
||||
// Delete 删除前后台路由关系
|
||||
func (r *FrontendBackendRouteRepository) Delete(id uint) error { |
||||
return r.db.Delete(&model.FrontendBackendRoute{}, id).Error |
||||
} |
||||
|
||||
// DeleteByFrontendRouteID 根据前台路由ID删除关系
|
||||
func (r *FrontendBackendRouteRepository) DeleteByFrontendRouteID(frontendRouteID uint) error { |
||||
return r.db.Where("frontend_route_id = ?", frontendRouteID).Delete(&model.FrontendBackendRoute{}).Error |
||||
} |
||||
|
||||
// Upsert 更新或插入前后台路由关系
|
||||
func (r *FrontendBackendRouteRepository) Upsert(relation *model.FrontendBackendRoute) error { |
||||
// 使用 PostgreSQL 的 ON CONFLICT 语法处理唯一索引冲突
|
||||
sql := ` |
||||
INSERT INTO frontend_backend_routes
|
||||
(frontend_route_id, backend_route, http_method, component, module, description, sort, status, updated_at) |
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW()) |
||||
ON CONFLICT (frontend_route_id, backend_route)
|
||||
DO UPDATE SET |
||||
http_method = EXCLUDED.http_method, |
||||
component = EXCLUDED.component, |
||||
module = EXCLUDED.module, |
||||
description = EXCLUDED.description, |
||||
sort = EXCLUDED.sort, |
||||
status = EXCLUDED.status, |
||||
updated_at = NOW() |
||||
RETURNING id |
||||
` |
||||
|
||||
var id uint |
||||
err := r.db.Raw(sql, |
||||
relation.FrontendRouteID, |
||||
relation.BackendRoute, |
||||
relation.HTTPMethod, |
||||
relation.Component, |
||||
relation.Module, |
||||
relation.Description, |
||||
relation.Sort, |
||||
relation.Status, |
||||
).Scan(&id).Error |
||||
|
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 设置返回的ID
|
||||
relation.ID = id |
||||
return nil |
||||
} |
||||
|
||||
// GetStats 获取前后台路由关系统计信息
|
||||
func (r *FrontendBackendRouteRepository) GetStats() (map[string]interface{}, error) { |
||||
var total int64 |
||||
var componentStats []struct { |
||||
Component string `json:"component"` |
||||
Count int64 `json:"count"` |
||||
} |
||||
var moduleStats []struct { |
||||
Module string `json:"module"` |
||||
Count int64 `json:"count"` |
||||
} |
||||
|
||||
if err := r.db.Model(&model.FrontendBackendRoute{}).Count(&total).Error; err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if err := r.db.Model(&model.FrontendBackendRoute{}). |
||||
Select("component, count(*) as count"). |
||||
Group("component"). |
||||
Scan(&componentStats).Error; err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if err := r.db.Model(&model.FrontendBackendRoute{}). |
||||
Select("module, count(*) as count"). |
||||
Group("module"). |
||||
Scan(&moduleStats).Error; err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return map[string]interface{}{ |
||||
"total": total, |
||||
"component_stats": componentStats, |
||||
"module_stats": moduleStats, |
||||
}, nil |
||||
} |
||||
|
||||
// GetWithFrontendRoute 获取关系并包含前台路由信息
|
||||
func (r *FrontendBackendRouteRepository) GetWithFrontendRoute() ([]map[string]interface{}, error) { |
||||
var results []map[string]interface{} |
||||
err := r.db.Table("frontend_backend_routes"). |
||||
Select("frontend_backend_routes.*, frontend_routes.path as frontend_path, frontend_routes.name as frontend_name"). |
||||
Joins("LEFT JOIN frontend_routes ON frontend_backend_routes.frontend_route_id = frontend_routes.id"). |
||||
Order("frontend_backend_routes.sort ASC"). |
||||
Scan(&results).Error |
||||
return results, err |
||||
} |
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
package routes |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/controller" |
||||
"gofaster/internal/auth/repository" |
||||
"gofaster/internal/auth/service" |
||||
|
||||
"github.com/gin-gonic/gin" |
||||
"go.uber.org/zap" |
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// RegisterFrontendRouteRoutes 注册前台路由相关路由
|
||||
func RegisterFrontendRouteRoutes(router *gin.RouterGroup, db *gorm.DB, logger *zap.Logger) { |
||||
// 初始化依赖
|
||||
frontendRouteRepo := repository.NewFrontendRouteRepository(db) |
||||
frontendBackendRouteRepo := repository.NewFrontendBackendRouteRepository(db) |
||||
frontendRouteService := service.NewFrontendRouteService(frontendRouteRepo, frontendBackendRouteRepo, logger) |
||||
frontendRouteController := controller.NewFrontendRouteController(frontendRouteService, logger) |
||||
|
||||
// 前台路由路由组
|
||||
frontendRouteGroup := router.Group("/frontend-routes") |
||||
{ |
||||
// 前台路由同步(系统初始化操作,不需要认证)
|
||||
{ |
||||
frontendRouteGroup.POST("/sync", frontendRouteController.SyncFrontendRoute) // 同步单个前台路由
|
||||
frontendRouteGroup.POST("/batch-sync", frontendRouteController.BatchSyncFrontendRoutes) // 批量同步前台路由
|
||||
} |
||||
|
||||
// 前台路由查询(需要认证)
|
||||
{ |
||||
frontendRouteGroup.GET("", frontendRouteController.GetFrontendRoutes) // 获取前台路由列表
|
||||
frontendRouteGroup.GET("/:id", frontendRouteController.GetFrontendRouteByID) // 根据ID获取前台路由
|
||||
frontendRouteGroup.GET("/by-module", frontendRouteController.GetFrontendRoutesByModule) // 根据模块获取前台路由
|
||||
frontendRouteGroup.GET("/relations", frontendRouteController.GetRouteRelations) // 获取路由关联关系
|
||||
frontendRouteGroup.GET("/:id/relations", frontendRouteController.GetRouteRelationsByFrontendRouteID) // 根据前台路由ID获取关联关系
|
||||
frontendRouteGroup.GET("/stats", frontendRouteController.GetStats) // 获取统计信息
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
package routes |
||||
|
||||
import ( |
||||
"gofaster/internal/auth/controller" |
||||
"gofaster/internal/auth/repository" |
||||
"gofaster/internal/auth/service" |
||||
|
||||
"github.com/gin-gonic/gin" |
||||
"go.uber.org/zap" |
||||
"gorm.io/gorm" |
||||
) |
||||
|
||||
// RegisterMenusRoutes 注册菜单相关路由
|
||||
func RegisterMenusRoutes(router *gin.RouterGroup, db *gorm.DB, logger *zap.Logger) { |
||||
// 初始化依赖
|
||||
menusRepo := repository.NewMenusRepository(db) |
||||
authResourcesRepo := repository.NewAuthResourcesRepository(db) |
||||
menusService := service.NewMenusService(menusRepo, authResourcesRepo, logger) |
||||
menusController := controller.NewMenusController(menusService, logger) |
||||
|
||||
// 菜单路由组
|
||||
menusGroup := router.Group("/menus") |
||||
{ |
||||
// 菜单同步(系统初始化操作,不需要认证)
|
||||
{ |
||||
menusGroup.POST("/sync", menusController.SyncMenu) // 同步单个菜单
|
||||
menusGroup.POST("/batch-sync", menusController.BatchSyncMenus) // 批量同步菜单
|
||||
} |
||||
|
||||
// 菜单查询(需要认证)
|
||||
{ |
||||
menusGroup.GET("", menusController.GetMenus) // 获取菜单列表
|
||||
menusGroup.GET("/:id", menusController.GetMenuByID) // 根据ID获取菜单
|
||||
menusGroup.GET("/by-module", menusController.GetMenusByModule) // 根据模块获取菜单
|
||||
menusGroup.GET("/relations", menusController.GetRouteRelations) // 获取路由关联关系
|
||||
menusGroup.GET("/:id/relations", menusController.GetRouteRelationsByMenuID) // 根据菜单ID获取关联关系
|
||||
menusGroup.GET("/stats", menusController.GetStats) // 获取统计信息
|
||||
} |
||||
} |
||||
} |
@ -1,155 +0,0 @@
@@ -1,155 +0,0 @@
|
||||
package service |
||||
|
||||
import ( |
||||
"fmt" |
||||
"gofaster/internal/auth/model" |
||||
"gofaster/internal/auth/repository" |
||||
|
||||
"go.uber.org/zap" |
||||
) |
||||
|
||||
// FrontendRouteService 前台路由服务
|
||||
type FrontendRouteService struct { |
||||
frontendRouteRepo *repository.FrontendRouteRepository |
||||
frontendBackendRouteRepo *repository.FrontendBackendRouteRepository |
||||
logger *zap.Logger |
||||
} |
||||
|
||||
// NewFrontendRouteService 创建前台路由服务实例
|
||||
func NewFrontendRouteService( |
||||
frontendRouteRepo *repository.FrontendRouteRepository, |
||||
frontendBackendRouteRepo *repository.FrontendBackendRouteRepository, |
||||
logger *zap.Logger, |
||||
) *FrontendRouteService { |
||||
return &FrontendRouteService{ |
||||
frontendRouteRepo: frontendRouteRepo, |
||||
frontendBackendRouteRepo: frontendBackendRouteRepo, |
||||
logger: logger, |
||||
} |
||||
} |
||||
|
||||
// SyncFrontendRoute 同步单个前台路由
|
||||
func (s *FrontendRouteService) SyncFrontendRoute(routeData map[string]interface{}) error { |
||||
// s.logger.Info("开始同步前台路由", zap.String("path", routeData["path"].(string)))
|
||||
|
||||
// 1. 创建或更新前台路由
|
||||
frontendRoute := &model.FrontendRoute{ |
||||
Path: routeData["path"].(string), |
||||
Name: routeData["name"].(string), |
||||
Component: routeData["component"].(string), |
||||
Module: routeData["module"].(string), |
||||
Description: routeData["description"].(string), |
||||
Sort: int(routeData["sort"].(float64)), |
||||
Status: 1, |
||||
} |
||||
|
||||
if err := s.frontendRouteRepo.UpsertByPath(frontendRoute); err != nil { |
||||
s.logger.Error("同步前台路由失败", zap.Error(err)) |
||||
return fmt.Errorf("同步前台路由失败: %w", err) |
||||
} |
||||
|
||||
// 2. 获取前台路由ID
|
||||
existingRoute, err := s.frontendRouteRepo.FindByPath(frontendRoute.Path) |
||||
if err != nil { |
||||
s.logger.Error("查找前台路由失败", zap.Error(err)) |
||||
return fmt.Errorf("查找前台路由失败: %w", err) |
||||
} |
||||
|
||||
// 3. 处理后台路由关联
|
||||
if backendRoutes, ok := routeData["backend_routes"].([]interface{}); ok { |
||||
// 先删除现有的关联
|
||||
if err := s.frontendBackendRouteRepo.DeleteByFrontendRouteID(existingRoute.ID); err != nil { |
||||
s.logger.Error("删除现有关联失败", zap.Error(err)) |
||||
return fmt.Errorf("删除现有关联失败: %w", err) |
||||
} |
||||
|
||||
// 创建新的关联
|
||||
for i, backendRouteData := range backendRoutes { |
||||
backendRoute := backendRouteData.(map[string]interface{}) |
||||
relation := &model.FrontendBackendRoute{ |
||||
FrontendRouteID: existingRoute.ID, |
||||
BackendRoute: backendRoute["backend_route"].(string), |
||||
HTTPMethod: backendRoute["http_method"].(string), |
||||
Component: routeData["component"].(string), // 使用前台路由的组件名称
|
||||
Module: backendRoute["module"].(string), |
||||
Description: backendRoute["description"].(string), |
||||
Sort: i, |
||||
Status: 1, |
||||
} |
||||
|
||||
if err := s.frontendBackendRouteRepo.Upsert(relation); err != nil { |
||||
s.logger.Error("创建前后台路由关联失败", zap.Error(err)) |
||||
return fmt.Errorf("创建前后台路由关联失败: %w", err) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// s.logger.Info("前台路由同步成功", zap.String("path", frontendRoute.Path))
|
||||
return nil |
||||
} |
||||
|
||||
// BatchSyncFrontendRoutes 批量同步前台路由
|
||||
func (s *FrontendRouteService) BatchSyncFrontendRoutes(routesData []map[string]interface{}) error { |
||||
s.logger.Info("开始批量同步前台路由", zap.Int("count", len(routesData))) |
||||
|
||||
for i, routeData := range routesData { |
||||
if err := s.SyncFrontendRoute(routeData); err != nil { |
||||
s.logger.Error("批量同步前台路由失败", |
||||
zap.Int("index", i), |
||||
zap.String("path", routeData["path"].(string)), |
||||
zap.Error(err)) |
||||
return fmt.Errorf("批量同步前台路由失败 [%d]: %w", i, err) |
||||
} |
||||
} |
||||
|
||||
s.logger.Info("批量同步前台路由完成", zap.Int("count", len(routesData))) |
||||
return nil |
||||
} |
||||
|
||||
// GetFrontendRoutes 获取前台路由列表
|
||||
func (s *FrontendRouteService) GetFrontendRoutes() ([]*model.FrontendRoute, error) { |
||||
return s.frontendRouteRepo.List() |
||||
} |
||||
|
||||
// GetFrontendRouteByID 根据ID获取前台路由
|
||||
func (s *FrontendRouteService) GetFrontendRouteByID(id uint) (*model.FrontendRoute, error) { |
||||
return s.frontendRouteRepo.FindByID(id) |
||||
} |
||||
|
||||
// GetFrontendRouteByPath 根据路径获取前台路由
|
||||
func (s *FrontendRouteService) GetFrontendRouteByPath(path string) (*model.FrontendRoute, error) { |
||||
return s.frontendRouteRepo.FindByPath(path) |
||||
} |
||||
|
||||
// GetFrontendRoutesByModule 根据模块获取前台路由
|
||||
func (s *FrontendRouteService) GetFrontendRoutesByModule(module string) ([]*model.FrontendRoute, error) { |
||||
return s.frontendRouteRepo.FindByModule(module) |
||||
} |
||||
|
||||
// GetRouteRelations 获取路由关联关系
|
||||
func (s *FrontendRouteService) GetRouteRelations() ([]map[string]interface{}, error) { |
||||
return s.frontendBackendRouteRepo.GetWithFrontendRoute() |
||||
} |
||||
|
||||
// GetRouteRelationsByFrontendRouteID 根据前台路由ID获取关联关系
|
||||
func (s *FrontendRouteService) GetRouteRelationsByFrontendRouteID(frontendRouteID uint) ([]*model.FrontendBackendRoute, error) { |
||||
return s.frontendBackendRouteRepo.FindByFrontendRouteID(frontendRouteID) |
||||
} |
||||
|
||||
// GetStats 获取统计信息
|
||||
func (s *FrontendRouteService) GetStats() (map[string]interface{}, error) { |
||||
frontendStats, err := s.frontendRouteRepo.GetStats() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
relationStats, err := s.frontendBackendRouteRepo.GetStats() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return map[string]interface{}{ |
||||
"frontend_routes": frontendStats, |
||||
"route_relations": relationStats, |
||||
}, nil |
||||
} |
@ -0,0 +1,155 @@
@@ -0,0 +1,155 @@
|
||||
package service |
||||
|
||||
import ( |
||||
"fmt" |
||||
"gofaster/internal/auth/model" |
||||
"gofaster/internal/auth/repository" |
||||
|
||||
"go.uber.org/zap" |
||||
) |
||||
|
||||
// MenusService 菜单服务
|
||||
type MenusService struct { |
||||
menusRepo *repository.MenusRepository |
||||
authResourcesRepo *repository.AuthResourcesRepository |
||||
logger *zap.Logger |
||||
} |
||||
|
||||
// NewMenusService 创建菜单服务实例
|
||||
func NewMenusService( |
||||
menusRepo *repository.MenusRepository, |
||||
authResourcesRepo *repository.AuthResourcesRepository, |
||||
logger *zap.Logger, |
||||
) *MenusService { |
||||
return &MenusService{ |
||||
menusRepo: menusRepo, |
||||
authResourcesRepo: authResourcesRepo, |
||||
logger: logger, |
||||
} |
||||
} |
||||
|
||||
// SyncMenu 同步单个菜单
|
||||
func (s *MenusService) SyncMenu(menuData map[string]interface{}) error { |
||||
// s.logger.Info("开始同步菜单", zap.String("path", menuData["path"].(string)))
|
||||
|
||||
// 1. 创建或更新菜单
|
||||
menu := &model.Menus{ |
||||
Path: menuData["path"].(string), |
||||
Name: menuData["name"].(string), |
||||
Component: menuData["component"].(string), |
||||
Module: menuData["module"].(string), |
||||
Description: menuData["description"].(string), |
||||
Sort: int(menuData["sort"].(float64)), |
||||
Status: 1, |
||||
} |
||||
|
||||
if err := s.menusRepo.UpsertByPath(menu); err != nil { |
||||
s.logger.Error("同步菜单失败", zap.Error(err)) |
||||
return fmt.Errorf("同步菜单失败: %w", err) |
||||
} |
||||
|
||||
// 2. 获取菜单ID
|
||||
existingMenu, err := s.menusRepo.FindByPath(menu.Path) |
||||
if err != nil { |
||||
s.logger.Error("查找菜单失败", zap.Error(err)) |
||||
return fmt.Errorf("查找菜单失败: %w", err) |
||||
} |
||||
|
||||
// 3. 处理后台路由关联
|
||||
if backendRoutes, ok := menuData["backend_routes"].([]interface{}); ok { |
||||
// 先删除现有的关联
|
||||
if err := s.authResourcesRepo.DeleteByFrontendRouteID(existingMenu.ID); err != nil { |
||||
s.logger.Error("删除现有关联失败", zap.Error(err)) |
||||
return fmt.Errorf("删除现有关联失败: %w", err) |
||||
} |
||||
|
||||
// 创建新的关联
|
||||
for i, backendRouteData := range backendRoutes { |
||||
backendRoute := backendRouteData.(map[string]interface{}) |
||||
relation := &model.AuthResources{ |
||||
FrontendRouteID: existingMenu.ID, |
||||
BackendRoute: backendRoute["backend_route"].(string), |
||||
HTTPMethod: backendRoute["http_method"].(string), |
||||
Component: menuData["component"].(string), // 使用菜单的组件名称
|
||||
Module: backendRoute["module"].(string), |
||||
Description: backendRoute["description"].(string), |
||||
Sort: i, |
||||
Status: 1, |
||||
} |
||||
|
||||
if err := s.authResourcesRepo.Upsert(relation); err != nil { |
||||
s.logger.Error("创建菜单路由关联失败", zap.Error(err)) |
||||
return fmt.Errorf("创建菜单路由关联失败: %w", err) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// s.logger.Info("菜单同步成功", zap.String("path", menu.Path))
|
||||
return nil |
||||
} |
||||
|
||||
// BatchSyncMenus 批量同步菜单
|
||||
func (s *MenusService) BatchSyncMenus(menusData []map[string]interface{}) error { |
||||
s.logger.Info("开始批量同步菜单", zap.Int("count", len(menusData))) |
||||
|
||||
for i, menuData := range menusData { |
||||
if err := s.SyncMenu(menuData); err != nil { |
||||
s.logger.Error("批量同步菜单失败", |
||||
zap.Int("index", i), |
||||
zap.String("path", menuData["path"].(string)), |
||||
zap.Error(err)) |
||||
return fmt.Errorf("批量同步菜单失败 [%d]: %w", i, err) |
||||
} |
||||
} |
||||
|
||||
s.logger.Info("批量同步菜单完成", zap.Int("count", len(menusData))) |
||||
return nil |
||||
} |
||||
|
||||
// GetMenus 获取菜单列表
|
||||
func (s *MenusService) GetMenus() ([]*model.Menus, error) { |
||||
return s.menusRepo.List() |
||||
} |
||||
|
||||
// GetMenuByID 根据ID获取菜单
|
||||
func (s *MenusService) GetMenuByID(id uint) (*model.Menus, error) { |
||||
return s.menusRepo.FindByID(id) |
||||
} |
||||
|
||||
// GetMenuByPath 根据路径获取菜单
|
||||
func (s *MenusService) GetMenuByPath(path string) (*model.Menus, error) { |
||||
return s.menusRepo.FindByPath(path) |
||||
} |
||||
|
||||
// GetMenusByModule 根据模块获取菜单
|
||||
func (s *MenusService) GetMenusByModule(module string) ([]*model.Menus, error) { |
||||
return s.menusRepo.FindByModule(module) |
||||
} |
||||
|
||||
// GetRouteRelations 获取路由关联关系
|
||||
func (s *MenusService) GetRouteRelations() ([]map[string]interface{}, error) { |
||||
return s.authResourcesRepo.GetWithFrontendRoute() |
||||
} |
||||
|
||||
// GetRouteRelationsByMenuID 根据菜单ID获取关联关系
|
||||
func (s *MenusService) GetRouteRelationsByMenuID(menuID uint) ([]*model.AuthResources, error) { |
||||
return s.authResourcesRepo.FindByFrontendRouteID(menuID) |
||||
} |
||||
|
||||
// GetStats 获取统计信息
|
||||
func (s *MenusService) GetStats() (map[string]interface{}, error) { |
||||
menusStats, err := s.menusRepo.GetStats() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
relationStats, err := s.authResourcesRepo.GetStats() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return map[string]interface{}{ |
||||
"menus": menusStats, |
||||
"route_relations": relationStats, |
||||
}, nil |
||||
} |
Binary file not shown.
Loading…
Reference in new issue