后台增加撤销用户实名功能

实名姓名与收款账户不一致会导致收款码登记失败,新增后台撤销实名能力:
- 新增 user:revoke_realname 权限,授予超级管理员与运营角色
- 撤销时重置用户实名状态为未认证并删除实名记录,使其可重新认证,写入审计日志
- 用户管理页新增实名状态列与"撤销实名"操作(含原因弹窗)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
yml2213
2026-06-17 07:03:52 +08:00
co-authored by Claude Opus 4.8
parent 8192344027
commit 4d54f1b03a
8 changed files with 184 additions and 5 deletions
@@ -136,6 +136,43 @@ func (r *Repository) updateStatus(ctx context.Context, adminID uint64, userID ui
return r.Find(ctx, userID)
}
// RevokeRealname 撤销用户实名:将用户实名状态重置为未认证,并删除实名记录,
// 使用户可重新发起实名认证(用于实名姓名与收款账户不一致导致收款码登记失败的场景)。
func (r *Repository) RevokeRealname(ctx context.Context, adminID uint64, userID uint64, req RevokeRealnameRequest, meta AuditMeta) (*UserDTO, error) {
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var user model.User
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, userID).Error; err != nil {
return err
}
var realnameCount int64
if err := tx.Model(&model.UserRealname{}).Where("user_id = ?", userID).Count(&realnameCount).Error; err != nil {
return err
}
// 已是未认证且无实名记录,无可撤销内容。
if user.RealnameStatus == "unverified" && realnameCount == 0 {
return ErrRealnameNotRevocable
}
beforeRealnameStatus := user.RealnameStatus
user.RealnameStatus = "unverified"
if err := tx.Save(&user).Error; err != nil {
return err
}
if err := tx.Where("user_id = ?", userID).Delete(&model.UserRealname{}).Error; err != nil {
return err
}
return appendAuditLog(tx, adminID, "admin_user.revoke_realname", user.ID, meta, map[string]any{
"user_id": user.ID,
"reason": req.Reason,
"before_realname_status": beforeRealnameStatus,
"after_realname_status": user.RealnameStatus,
})
})
if err != nil {
return nil, err
}
return r.Find(ctx, userID)
}
func (r *Repository) Find(ctx context.Context, userID uint64) (*UserDTO, error) {
var row userRow
err := r.db.WithContext(ctx).Table("users AS u").