bindbox-game/.claude/plan/admin-update-user-mobile.md
2026-02-08 17:19:27 +08:00

6.5 KiB
Raw Blame History

📋 实施计划:后台管理端 - 添加修改用户手机号功能

任务类型

  • 后端 (→ Codex)
  • 前端
  • 全栈

📊 需求描述

为后台管理端添加修改用户手机号的功能,允许管理员直接修改用户的手机号。


🎯 技术方案

API 设计

PUT /api/admin/users/{user_id}/mobile
Content-Type: application/json
Authorization: Bearer {admin_token}

Request Body:
{
  "mobile": "13800138000"
}

Response:
{
  "success": true,
  "message": "手机号更新成功"
}

安全校验

  1. 管理员权限验证RBAC: user:edit
  2. 手机号格式验证11位数字1开头
  3. 手机号唯一性检查(不能与其他用户重复)
  4. 用户存在性验证

🔧 实施步骤

步骤 1添加 API 处理函数

文件internal/api/admin/users_admin.go 位置Line 1893 后(在 UpdateUserRemark() 函数之后)

代码

// updateUserMobileRequest 更新用户手机号请求
type updateUserMobileRequest struct {
	Mobile string `json:"mobile" binding:"required"`
}

// UpdateUserMobile 更新用户手机号
// @Summary 更新用户手机号
// @Description 管理员修改用户手机号
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param body body updateUserMobileRequest true "手机号信息"
// @Success 200 {object} map[string]any
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/mobile [put]
// @Security LoginVerifyToken
func (h *handler) UpdateUserMobile() core.HandlerFunc {
	return func(ctx core.Context) {
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "用户ID无效"))
			return
		}

		req := new(updateUserMobileRequest)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}

		// 验证手机号格式11位数字1开头
		matched, _ := regexp.MatchString(`^1[3-9]\d{9}$`, req.Mobile)
		if !matched {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "手机号格式不正确"))
			return
		}

		// 检查手机号是否被其他用户占用
		existedUser, _ := h.readDB.Users.WithContext(ctx.RequestContext()).
			Where(h.readDB.Users.Mobile.Eq(req.Mobile)).
			Where(h.readDB.Users.ID.Neq(userID)).
			First()

		if existedUser != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "该手机号已被其他用户使用"))
			return
		}

		// 更新用户手机号
		_, err = h.writeDB.Users.WithContext(ctx.RequestContext()).
			Where(h.writeDB.Users.ID.Eq(userID)).
			Update(h.writeDB.Users.Mobile, req.Mobile)

		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20303, "更新失败: "+err.Error()))
			return
		}

		ctx.Payload(map[string]any{
			"success": true,
			"message": "手机号更新成功",
		})
	}
}

步骤 2添加导入依赖

文件internal/api/admin/users_admin.go 位置:文件顶部 import 区域

修改:在现有 import 中添加 regexp

import (
	"fmt"
	"math"
	"net/http"
	"regexp"  // ← 添加这一行
	"strconv"
	"strings"
	"time"

	"bindbox-game/internal/code"
	// ... 其他导入保持不变
)

步骤 3注册路由

文件internal/router/router.go 位置:在 adminAuthApiRouter 用户管理路由组中

查找位置参考

// 找到类似这样的路由组(用户管理相关)
adminAuthApiRouter.PUT("/users/:user_id/douyin_user_id", ...)
adminAuthApiRouter.PUT("/users/:user_id/remark", ...)
adminAuthApiRouter.PUT("/users/:user_id/status", ...)

添加路由

// 在上述路由附近添加
adminAuthApiRouter.PUT("/users/:user_id/mobile",
	intc.RequireAdminAction("user:edit"),
	adminHandler.UpdateUserMobile())

步骤 4更新 Swagger 文档

文件:运行命令生成文档

make gen-swagger

📋 关键文件清单

文件路径 操作 说明
internal/api/admin/users_admin.go 新增函数 添加 UpdateUserMobile() 及请求结构体
internal/api/admin/users_admin.go 修改导入 添加 regexp
internal/router/router.go 新增路由 注册 PUT /users/:user_id/mobile

验证清单

完成后请验证:

  • API 接口可正常访问
  • 手机号格式验证生效(非法格式返回错误)
  • 手机号唯一性检查生效(重复手机号返回错误)
  • 更新成功后数据库中手机号已变更
  • Swagger 文档已更新
  • 权限验证生效(非管理员或无 user:edit 权限无法访问)

⚠️ 风险与缓解

风险 缓解措施
手机号格式错误 正则验证 ^1[3-9]\d{9}$
手机号被占用 查询检查 WHERE mobile = ? AND id != ?
权限滥用 RBAC 中间件 RequireAdminAction("user:edit")
更新失败 捕获异常并返回错误码 20303

📝 测试用例

正常流程

curl -X PUT http://localhost:9991/api/admin/users/123/mobile \
  -H "Authorization: Bearer {admin_token}" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"13800138000"}'

# 预期响应
{
  "success": true,
  "message": "手机号更新成功"
}

异常流程

1. 手机号格式错误

{"mobile": "123"}
 {"code": 10001, "message": "手机号格式不正确"}

2. 手机号已被占用

{"mobile": "13800138000"}  // 已被用户456使用
 {"code": 10001, "message": "该手机号已被其他用户使用"}

3. 用户ID不存在

PUT /api/admin/users/999999/mobile
→ 更新成功但影响行数为0GORM特性不会报错

🚀 后续优化建议(可选)

  1. 操作日志记录:记录管理员修改手机号的操作到审计日志
  2. 短信验证:要求新手机号验证码确认(防止恶意修改)
  3. 旧手机号通知:向旧手机号发送变更通知短信
  4. 限制修改频率同一用户手机号修改间隔限制如7天

📌 备注

  • 本方案仅实现管理端修改功能,不包含用户端自助修改
  • 遵循现有代码风格(参考 UpdateUserRemark()UpdateUserDouyinID()
  • 使用 GORM Gen 生成的 DAO 进行数据库操作
  • 错误码 20303 用于手机号更新失败(延续现有错误码序列 20301, 20302