feat: add agent user edit, card type permission check and balance deduction

- Backend: check AgentApplicationCardType.can_generate before allowing card recharge
- Backend: deduct agent balance and record consumption when creating user with card
- Backend: add GET /agent/users/:id and PUT /agent/users/:id for user edit
- Backend: extract checkAgentUserPermission helper, refactor handleUpdateUserStatus
- Frontend: add user edit page ([id].vue) with username/email/password
- Frontend: add edit action in user list dropdown menu
- Frontend: add route for agent user edit page
- Add i18n keys for agent user edit
This commit is contained in:
2026-05-11 08:48:02 +08:00
parent 57e1d10689
commit a76a30ee78
8 changed files with 374 additions and 22 deletions
+134 -21
View File
@@ -15,6 +15,7 @@ import (
"verification-platform-backend/pkg/utils"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
func SetupAgentRoutes(r *gin.RouterGroup) {
@@ -25,6 +26,8 @@ func SetupAgentRoutes(r *gin.RouterGroup) {
r.POST("/cards/generate", handleGenerateCards)
r.GET("/users", handleGetUsers)
r.POST("/users", handleCreateUser)
r.PUT("/users/:id", handleUpdateUser)
r.GET("/users/:id", handleGetUser)
r.PUT("/users/:id/status", handleUpdateUserStatus)
r.GET("/finance", handleGetFinance)
r.GET("/profile", handleGetProfile)
@@ -1005,13 +1008,33 @@ func handleCreateUser(c *gin.Context) {
}
var cardType *model.CardType
var agentCardType *model.AgentApplicationCardType
if req.CardTypeID != nil && *req.CardTypeID > 0 {
var ct model.CardType
if err := database.DB.Where("id = ? AND application_id = ?", *req.CardTypeID, req.ApplicationID).First(&ct).Error; err != nil {
response.Error(c, 400, "卡密类型不存在或不属于该应用")
return
}
var act model.AgentApplicationCardType
if err := database.DB.Where("agent_application_id = ? AND card_type_id = ? AND can_generate = ?", agentApp.ID, *req.CardTypeID, true).First(&act).Error; err != nil {
response.Error(c, 403, "无权使用该卡类充值")
return
}
totalPrice := act.Price * float64(req.CardQuantity)
var agent model.User
if err := database.DB.First(&agent, userID).Error; err != nil {
response.Error(c, 404, "代理不存在")
return
}
if agent.Balance < totalPrice {
response.Error(c, 400, fmt.Sprintf("余额不足,当前余额: %.2f,需要: %.2f", agent.Balance, totalPrice))
return
}
cardType = &ct
agentCardType = &act
}
tx := database.DB.Begin()
@@ -1121,6 +1144,27 @@ func handleCreateUser(c *gin.Context) {
response.Error(c, 500, "充值失败")
return
}
totalPrice := agentCardType.Price * float64(req.CardQuantity)
if err := tx.Model(&model.User{}).Where("id = ?", userID).Update("balance", gorm.Expr("balance - ?", totalPrice)).Error; err != nil {
tx.Rollback()
response.Error(c, 500, "扣除余额失败")
return
}
consumeRecord := model.RechargeRecord{
UserID: userID,
OrderNo: generateAgentOrderNo("C"),
Amount: -totalPrice,
Status: "success",
PaymentType: "balance",
Remark: fmt.Sprintf("创建用户充值卡密: %s x%d", cardType.Name, req.CardQuantity),
}
if err := tx.Create(&consumeRecord).Error; err != nil {
tx.Rollback()
response.Error(c, 500, "记录消费失败")
return
}
}
if err := tx.Commit().Error; err != nil {
@@ -1171,27 +1215,7 @@ func handleUpdateUserStatus(c *gin.Context) {
return
}
agentIDs := []uint{userID}
var childAgents []model.User
database.DB.Where("parent_agent_id = ? AND role = ?", userID, "agent").Find(&childAgents)
for _, child := range childAgents {
agentIDs = append(agentIDs, child.ID)
}
var cardIDs []uint
database.DB.Model(&model.Card{}).Where("agent_id IN ?", agentIDs).Pluck("id", &cardIDs)
if len(cardIDs) == 0 {
response.Error(c, 403, "无权限操作该用户")
return
}
var count int64
database.DB.Model(&model.RechargeRecord{}).
Where("user_id = ? AND card_id IN ? AND status = ?", user.ID, cardIDs, "success").
Count(&count)
if count == 0 {
if !checkAgentUserPermission(userID, user.ID) {
response.Error(c, 403, "无权限操作该用户")
return
}
@@ -1207,3 +1231,92 @@ func handleUpdateUserStatus(c *gin.Context) {
response.Success(c, user)
}
func checkAgentUserPermission(userID uint, appUserID uint) bool {
agentIDs := []uint{userID}
var childAgents []model.User
database.DB.Where("parent_agent_id = ? AND role = ?", userID, "agent").Find(&childAgents)
for _, child := range childAgents {
agentIDs = append(agentIDs, child.ID)
}
var cardIDs []uint
database.DB.Model(&model.Card{}).Where("agent_id IN ?", agentIDs).Pluck("id", &cardIDs)
if len(cardIDs) == 0 {
return false
}
var count int64
database.DB.Model(&model.RechargeRecord{}).
Where("user_id = ? AND card_id IN ? AND status = ?", appUserID, cardIDs, "success").
Count(&count)
return count > 0
}
func handleGetUser(c *gin.Context) {
userID := c.GetUint("user_id")
id := c.Param("id")
var user model.AppUser
if err := database.DB.Preload("Application").First(&user, id).Error; err != nil {
response.Error(c, 404, "用户不存在")
return
}
if !checkAgentUserPermission(userID, user.ID) {
response.Error(c, 403, "无权限查看该用户")
return
}
response.Success(c, gin.H{
"user": user,
})
}
func handleUpdateUser(c *gin.Context) {
userID := c.GetUint("user_id")
id := c.Param("id")
var req struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, 400, "参数错误")
return
}
var user model.AppUser
if err := database.DB.First(&user, id).Error; err != nil {
response.Error(c, 404, "用户不存在")
return
}
if !checkAgentUserPermission(userID, user.ID) {
response.Error(c, 403, "无权限修改该用户")
return
}
if req.Username != "" {
user.Username = req.Username
}
if req.Email != "" {
user.Email = req.Email
}
if req.Password != "" {
user.Password = req.Password
}
if err := database.DB.Save(&user).Error; err != nil {
response.Error(c, 500, "更新用户失败")
return
}
logDesc := fmt.Sprintf("代理更新用户: %s", user.Username)
service.LogOperation(c, "update", "app_user", &user.ID, logDesc, nil)
response.Success(c, user)
}