package handler import ( "net/http" "strings" "time" "silk-server-go/internal/middleware" "silk-server-go/internal/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // RegisterOrganizationRoutes 注册组织和成员数据范围路由。 func RegisterOrganizationRoutes(rg *gin.RouterGroup, db *gorm.DB) { perm := middleware.RequirePermission(db, "organization:manage") rg.GET("/organizations", perm, listOrganizations(db)) rg.POST("/organizations", perm, createOrganization(db)) rg.PATCH("/organizations/:id", perm, updateOrganization(db)) rg.GET("/organizations/:id/members", perm, listOrganizationMembers(db)) rg.POST("/organizations/:id/members", perm, addOrganizationMember(db)) rg.DELETE("/organizations/:id/members/:userId", perm, removeOrganizationMember(db)) } func listOrganizations(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { q := db.Model(&model.Organization{}) if !hasGlobalAccess(c) { q = applyOrgScope(q, c, "organizations.id") } var list []model.Organization q.Order("created_at DESC").Find(&list) c.JSON(http.StatusOK, list) } } func createOrganization(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var body struct { Name string `json:"name"` Code string `json:"code"` Description *string `json:"description"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if strings.TrimSpace(body.Name) == "" || strings.TrimSpace(body.Code) == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "组织名称和编码不能为空"}) return } var count int64 db.Model(&model.Organization{}).Where("code = ?", body.Code).Count(&count) if count > 0 { c.JSON(http.StatusConflict, gin.H{"error": "组织编码已存在"}) return } org := model.Organization{Name: body.Name, Code: body.Code, Description: body.Description, Status: "active"} if err := db.Create(&org).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "创建组织失败"}) return } c.JSON(http.StatusCreated, org) } } func updateOrganization(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var org model.Organization if db.Where("id = ?", id).First(&org).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "organization not found"}) return } if !canAccessOrganization(db, c, id) { c.JSON(http.StatusForbidden, gin.H{"error": "无权管理该组织"}) return } updates, err := bindUpdates(c) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if len(updates) > 0 { if err := db.Model(&model.Organization{}).Where("id = ?", id).Updates(updates).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "更新组织失败"}) return } } db.Where("id = ?", id).First(&org) c.JSON(http.StatusOK, org) } } func addOrganizationMember(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { orgID := c.Param("id") var org model.Organization if db.Where("id = ?", orgID).First(&org).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "organization not found"}) return } if !canAccessOrganization(db, c, orgID) { c.JSON(http.StatusForbidden, gin.H{"error": "无权管理该组织"}) return } var body struct { UserID string `json:"userId"` Role string `json:"role"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if !isUUID(body.UserID) { c.JSON(http.StatusBadRequest, gin.H{"error": "userId 不是合法的 UUID"}) return } var user model.User if db.Where("id = ?", body.UserID).First(&user).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) return } role := body.Role if role == "" { role = "member" } if role != "member" && role != "admin" { c.JSON(http.StatusBadRequest, gin.H{"error": "组织角色仅支持 member/admin"}) return } var count int64 db.Model(&model.OrganizationMember{}). Where("organization_id = ? AND user_id = ?", orgID, body.UserID). Count(&count) if count > 0 { c.JSON(http.StatusConflict, gin.H{"error": "用户已在该组织"}) return } member := model.OrganizationMember{OrganizationID: orgID, UserID: body.UserID, Role: role} if err := db.Create(&member).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "添加成员失败"}) return } c.JSON(http.StatusCreated, member) } } func listOrganizationMembers(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { orgID := c.Param("id") var org model.Organization if db.Where("id = ?", orgID).First(&org).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "organization not found"}) return } if !canAccessOrganization(db, c, orgID) { c.JSON(http.StatusForbidden, gin.H{"error": "无权查看该组织成员"}) return } var rows []struct { ID string `gorm:"column:id" json:"id"` OrganizationID string `gorm:"column:organization_id" json:"organizationId"` UserID string `gorm:"column:user_id" json:"userId"` Role string `gorm:"column:role" json:"role"` CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"` Username string `gorm:"column:username" json:"username"` Email string `gorm:"column:email" json:"email"` FullName *string `gorm:"column:full_name" json:"fullName,omitempty"` } if err := db.Table("organization_members om"). Select("om.id, om.organization_id, om.user_id, om.role, om.created_at, u.username, u.email, u.full_name"). Joins("JOIN users u ON u.id = om.user_id"). Where("om.organization_id = ?", orgID). Order("om.created_at DESC"). Scan(&rows).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "查询组织成员失败"}) return } c.JSON(http.StatusOK, rows) } } func removeOrganizationMember(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { orgID := c.Param("id") userID := c.Param("userId") var member model.OrganizationMember if db.Where("organization_id = ? AND user_id = ?", orgID, userID).First(&member).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "organization member not found"}) return } if !canAccessOrganization(db, c, orgID) { c.JSON(http.StatusForbidden, gin.H{"error": "无权管理该组织"}) return } db.Where("id = ?", member.ID).Delete(&model.OrganizationMember{}) c.JSON(http.StatusOK, gin.H{"organizationId": orgID, "userId": userID}) } }