package member import ( "net/http" "strconv" "git.iwork-ai.com/xdc/iqudo-top1/internal/audit" "git.iwork-ai.com/xdc/iqudo-top1/internal/auth" "git.iwork-ai.com/xdc/iqudo-top1/internal/model" "git.iwork-ai.com/xdc/iqudo-top1/internal/response" "github.com/gin-gonic/gin" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) type Handler struct{ db *gorm.DB } func NewHandler(db *gorm.DB) *Handler { return &Handler{db: db} } type MemberItem struct { ID uint64 `json:"id"` UserID uint64 `json:"user_id"` Username string `json:"username"` DisplayName string `json:"display_name"` RoleCode string `json:"role_code"` RoleName string `json:"role_name"` Status string `json:"status"` } func (h *Handler) List(c *gin.Context) { principal, _ := auth.PrincipalFromContext(c) items := make([]MemberItem, 0) err := h.db.Table("tenant_members tm").Select("tm.id, tm.user_id, u.username, u.display_name, r.code AS role_code, r.name AS role_name, tm.status").Joins("JOIN users u ON u.id = tm.user_id").Joins("JOIN roles r ON r.id = tm.role_id").Where("tm.tenant_id = ?", principal.TenantID).Order("tm.id").Scan(&items).Error if err != nil { response.Error(c, http.StatusInternalServerError, "QUERY_FAILED", "查询企业成员失败") return } roles := make([]model.Role, 0) if err := h.db.Where("tenant_id = ?", principal.TenantID).Order("id").Find(&roles).Error; err != nil { response.Error(c, http.StatusInternalServerError, "QUERY_FAILED", "查询角色失败") return } response.OK(c, gin.H{"items": items, "roles": roles, "total": len(items)}) } func (h *Handler) Create(c *gin.Context) { principal, _ := auth.PrincipalFromContext(c) var input struct { Username string `json:"username" binding:"required,min=2,max=64"` Password string `json:"password" binding:"required,min=6,max=128"` DisplayName string `json:"display_name" binding:"required,max=128"` RoleCode string `json:"role_code" binding:"required,max=64"` } if err := c.ShouldBindJSON(&input); err != nil { response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "成员信息不完整") return } var role model.Role if err := h.db.Where("tenant_id = ? AND code = ?", principal.TenantID, input.RoleCode).First(&role).Error; err != nil { response.Error(c, http.StatusBadRequest, "INVALID_ROLE", "角色不存在") return } hash, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost) if err != nil { response.Error(c, http.StatusInternalServerError, "CREATE_FAILED", "创建成员失败") return } var user model.User var membership model.TenantMember err = h.db.Transaction(func(tx *gorm.DB) error { user = model.User{Username: input.Username, PasswordHash: string(hash), DisplayName: input.DisplayName, Status: "active"} if err := tx.Create(&user).Error; err != nil { return err } membership = model.TenantMember{TenantID: principal.TenantID, UserID: user.ID, RoleID: role.ID, Status: "active"} return tx.Create(&membership).Error }) if err != nil { response.Error(c, http.StatusConflict, "MEMBER_EXISTS", "用户名已存在") return } _ = audit.Record(h.db, principal, "create", "tenant_member", membership.ID, gin.H{"username": input.Username, "role_code": input.RoleCode}) response.Created(c, gin.H{"id": membership.ID, "user_id": user.ID}) } func (h *Handler) Update(c *gin.Context) { principal, _ := auth.PrincipalFromContext(c) id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil || id == 0 { response.Error(c, http.StatusBadRequest, "INVALID_ID", "成员 ID 不正确") return } var input struct { RoleCode string `json:"role_code" binding:"required,max=64"` Status string `json:"status" binding:"required,oneof=active disabled"` } if err := c.ShouldBindJSON(&input); err != nil { response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "成员配置不正确") return } var membership model.TenantMember if err := h.db.Where("id = ? AND tenant_id = ?", id, principal.TenantID).First(&membership).Error; err != nil { response.Error(c, http.StatusNotFound, "NOT_FOUND", "成员不存在") return } if membership.UserID == principal.UserID { response.Error(c, http.StatusConflict, "SELF_UPDATE_FORBIDDEN", "不能修改自己的角色或状态") return } var role model.Role if err := h.db.Where("tenant_id = ? AND code = ?", principal.TenantID, input.RoleCode).First(&role).Error; err != nil { response.Error(c, http.StatusBadRequest, "INVALID_ROLE", "角色不存在") return } err = h.db.Transaction(func(tx *gorm.DB) error { if err := tx.Model(&membership).Updates(map[string]interface{}{"role_id": role.ID, "status": input.Status}).Error; err != nil { return err } return tx.Model(&model.User{}).Where("id = ?", membership.UserID).Update("status", input.Status).Error }) if err != nil { response.Error(c, http.StatusInternalServerError, "UPDATE_FAILED", "更新成员失败") return } _ = audit.Record(h.db, principal, "update", "tenant_member", id, input) response.OK(c, gin.H{"id": id, "role_code": input.RoleCode, "status": input.Status}) }