128 lines
5.0 KiB
Go
128 lines
5.0 KiB
Go
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})
|
|
}
|