6.5 KiB
6.5 KiB
📋 实施计划:后台管理端 - 添加修改用户手机号功能
任务类型
- 后端 (→ 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": "手机号更新成功"
}
安全校验
- ✅ 管理员权限验证(RBAC:
user:edit) - ✅ 手机号格式验证(11位数字,1开头)
- ✅ 手机号唯一性检查(不能与其他用户重复)
- ✅ 用户存在性验证
🔧 实施步骤
步骤 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
→ 更新成功但影响行数为0(GORM特性,不会报错)
🚀 后续优化建议(可选)
- 操作日志记录:记录管理员修改手机号的操作到审计日志
- 短信验证:要求新手机号验证码确认(防止恶意修改)
- 旧手机号通知:向旧手机号发送变更通知短信
- 限制修改频率:同一用户手机号修改间隔限制(如7天)
📌 备注
- 本方案仅实现管理端修改功能,不包含用户端自助修改
- 遵循现有代码风格(参考
UpdateUserRemark()和UpdateUserDouyinID()) - 使用 GORM Gen 生成的 DAO 进行数据库操作
- 错误码 20303 用于手机号更新失败(延续现有错误码序列 20301, 20302)