This commit is contained in:
2025-12-03 11:00:47 +08:00
parent 29fb7cc9ac
commit a6ea6a2869
30 changed files with 4695 additions and 75 deletions

View File

@@ -0,0 +1,153 @@
/**
* package api
* 作用:附件管理相关API处理器
*/
package api
import (
"strconv"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* UploadAttachmentHandler
* 功能:上传附件
* 路径:POST /api/attachments/upload
*/
func UploadAttachmentHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
// 获取文件
file, err := c.FormFile("file")
if err != nil {
utils.BadRequest(c, "文件上传失败: "+err.Error())
return
}
// 获取文件类型
fileType := c.PostForm("type")
if fileType == "" {
// 根据文件扩展名推断类型
ext := file.Filename[len(file.Filename)-4:]
if ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == "webp" || ext == "jpeg" {
fileType = "image"
} else {
fileType = "video"
}
}
// 验证文件类型
if fileType != "image" && fileType != "video" {
utils.BadRequest(c, "文件类型必须是image或video")
return
}
// 验证文件大小
if fileType == "image" && file.Size > model.MaxImageSize {
utils.BadRequest(c, "图片大小不能超过10MB")
return
}
if fileType == "video" && file.Size > model.MaxVideoSize {
utils.BadRequest(c, "视频大小不能超过500MB")
return
}
// 打开文件
src, err := file.Open()
if err != nil {
utils.BadRequest(c, "打开文件失败: "+err.Error())
return
}
defer src.Close()
// 上传文件
attachment, err := service.AttachmentSvc.UploadFile(
userID.(string),
file.Filename,
fileType,
file.Size,
src,
)
if err != nil {
utils.BadRequest(c, err.Error())
return
}
utils.SuccessWithData(c, attachment, "上传成功")
}
/**
* GetAttachmentHandler
* 功能:获取附件信息
* 路径:GET /api/attachments/:id
*/
func GetAttachmentHandler(c *gin.Context) {
attachmentID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
attachment, err := service.AttachmentSvc.GetAttachment(uint(attachmentID))
if err != nil {
utils.NotFound(c, "附件不存在")
return
}
utils.SuccessWithData(c, attachment, "获取成功")
}
/**
* DeleteAttachmentHandler
* 功能:删除附件(仅上传者可删除)
* 路径:DELETE /api/attachments/:id
*/
func DeleteAttachmentHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
attachmentID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
if err := service.AttachmentSvc.DeleteAttachment(uint(attachmentID), userID.(string)); err != nil {
utils.BadRequest(c, err.Error())
return
}
utils.Success(c, "附件已删除")
}
/**
* GetAttachmentsHandler
* 功能:获取附件列表
* 路径:GET /api/attachments
*/
func GetAttachmentsHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
fileType := c.Query("type")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 20
}
attachments, total, err := service.AttachmentSvc.GetUserAttachments(userID.(string), fileType, page, pageSize)
if err != nil {
utils.InternalError(c, "查询失败")
return
}
// 确保返回空数组而不是null
if attachments == nil {
attachments = []model.Attachment{}
}
utils.SuccessWithData(c, gin.H{
"data": attachments,
"total": total,
"page": page,
"size": pageSize,
}, "获取成功")
}

View File

@@ -0,0 +1,225 @@
/**
* package api
* 作用:认证相关API处理器
*/
package api
import (
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* LoginHandler
* 功能:用户登录
* 路径:POST /api/login
*/
func LoginHandler(c *gin.Context) {
var req model.LoginReq
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
// 获取客户端IP
ip := getClientIP(c)
// 调用认证服务登录
user, err := service.AuthSvc.Login(req.Account, req.Password)
if err != nil {
// 记录登录失败日志
service.LoginLogSvc.LogLogin(req.Account, "0", ip, false)
utils.Unauthorized(c, err.Error())
return
}
// 生成Token
token, err := utils.GenerateToken(user.ID)
if err != nil {
// 记录登录失败日志
service.LoginLogSvc.LogLogin(req.Account, "0", ip, false)
utils.InternalError(c, "生成Token失败")
return
}
// 清除密码字段
user.Password = ""
// 记录登录成功日志
service.LoginLogSvc.LogLogin(req.Account, user.ID, ip, true)
utils.SuccessWithData(c, model.LoginResponse{
Token: token,
User: *user,
}, "登录成功")
}
// getClientIP 获取客户端IP
func getClientIP(c *gin.Context) string {
// 优先从X-Forwarded-For获取
ip := c.GetHeader("X-Forwarded-For")
if ip != "" {
return ip
}
// 从X-Real-IP获取
ip = c.GetHeader("X-Real-IP")
if ip != "" {
return ip
}
// 从RemoteAddr获取
return c.ClientIP()
}
/**
* RegisterHandler
* 功能:用户注册
* 路径:POST /api/register
*/
func RegisterHandler(c *gin.Context) {
var req model.RegisterReq
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
// 如果提供了验证码,验证验证码
if req.Code != "" {
// 根据邮箱或手机号确定类型
codeType := "email"
if len(req.Phone) > 0 {
codeType = "sms"
}
target := req.Email
if codeType == "sms" {
target = req.Phone
}
valid, err := service.AuthSvc.VerifyCode(target, req.Code, codeType)
if err != nil || !valid {
utils.BadRequest(c, "验证码无效或已过期")
return
}
}
// 调用认证服务注册
user, err := service.AuthSvc.Register(&req)
if err != nil {
utils.BadRequest(c, err.Error())
return
}
// 生成Token
token, err := utils.GenerateToken(user.ID)
if err != nil {
utils.InternalError(c, "生成Token失败")
return
}
utils.SuccessWithData(c, model.RegisterResponse{
Token: token,
User: *user,
}, "注册成功")
}
/**
* LogoutHandler
* 功能:用户登出(可选,前端清除token)
* 路径:POST /api/logout
*/
func LogoutHandler(c *gin.Context) {
// 登出主要是前端清除token,后端可以记录日志或清除session
utils.Success(c, "登出成功")
}
/**
* CheckTokenHandler
* 功能:检查Token有效性
* 路径:GET /api/check-token
*/
func CheckTokenHandler(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
utils.Unauthorized(c, "缺少Token")
return
}
// 移除 "Bearer " 前缀(如果存在)
if len(token) > 7 && token[:7] == "Bearer " {
token = token[7:]
}
userID, err := utils.ValidateToken(token)
if err != nil {
utils.Unauthorized(c, "Token无效或已过期")
return
}
utils.SuccessWithData(c, gin.H{
"status": "valid",
"user_id": userID,
}, "Token有效")
}
/**
* SendEmailCodeHandler
* 功能:发送邮箱验证码
* 路径:POST /api/send-email-code
*/
func SendEmailCodeHandler(c *gin.Context) {
var req model.SendCodeReq
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
if req.Type != "email" {
utils.BadRequest(c, "类型必须是email")
return
}
code, err := service.AuthSvc.SendEmailCode(req.Target)
if err != nil {
utils.InternalError(c, err.Error())
return
}
// 开发环境返回验证码,生产环境不应返回
utils.SuccessWithData(c, gin.H{
"code": code, // 仅开发环境,生产环境应移除
}, "验证码已发送")
}
/**
* SendSmsCodeHandler
* 功能:发送短信验证码
* 路径:POST /api/send-sms-code
*/
func SendSmsCodeHandler(c *gin.Context) {
var req model.SendCodeReq
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
if req.Type != "sms" {
utils.BadRequest(c, "类型必须是sms")
return
}
code, err := service.AuthSvc.SendSmsCode(req.Target)
if err != nil {
utils.InternalError(c, err.Error())
return
}
// 开发环境返回验证码,生产环境不应返回
utils.SuccessWithData(c, gin.H{
"code": code, // 仅开发环境,生产环境应移除
}, "验证码已发送")
}

View File

@@ -0,0 +1,362 @@
/**
* package api
* 作用:联系人管理相关API处理器
*/
package api
import (
"strconv"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* ContactListHandler
* 功能:获取联系人列表(已存在,需改为从数据库查询)
* 路径:GET /api/contacts
*/
func ContactListHandler(c *gin.Context) {
// 从Context获取用户ID(由JWT中间件注入)
userID, exists := c.Get("user_id")
if !exists {
// 如果没有认证,返回空列表(兼容旧代码)
utils.SuccessWithData(c, []interface{}{}, "获取成功")
return
}
contacts, err := service.ContactSvc.GetContactsWithUserInfo(userID.(string))
if err != nil {
utils.InternalError(c, "查询失败")
return
}
// 确保返回空数组而不是null
if contacts == nil {
contacts = []map[string]interface{}{}
}
utils.SuccessWithData(c, contacts, "获取成功")
}
/**
* SearchUsersHandler
* 功能:搜索用户
* 路径:GET /api/contacts/search
*/
func SearchUsersHandler(c *gin.Context) {
keyword := c.Query("keyword")
if keyword == "" {
utils.BadRequest(c, "搜索关键词不能为空")
return
}
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
if limit < 1 || limit > 100 {
limit = 20
}
users, err := service.ContactSvc.SearchUsers(keyword, limit)
if err != nil {
utils.InternalError(c, "搜索失败")
return
}
// 确保返回空数组而不是null
if users == nil {
users = []model.User{}
}
utils.SuccessWithData(c, users, "搜索成功")
}
/**
* AddFriendHandler
* 功能:添加好友(发送申请)
* 路径:POST /api/contacts/add-friend
*/
func AddFriendHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
var req struct {
ToUserID string `json:"to_user_id" binding:"required"`
Message string `json:"message"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
if err := service.ContactSvc.AddFriend(userID.(string), req.ToUserID, req.Message); err != nil {
utils.BadRequest(c, err.Error())
return
}
utils.Success(c, "好友申请已发送")
}
/**
* GetFriendRequestsHandler
* 功能:获取好友申请列表
* 路径:GET /api/contacts/friend-requests
*/
func GetFriendRequestsHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
requests, err := service.ContactSvc.GetFriendRequests(userID.(string))
if err != nil {
utils.InternalError(c, "查询失败")
return
}
// 确保返回空数组而不是null
if requests == nil {
requests = []model.FriendRequest{}
}
utils.SuccessWithData(c, requests, "获取成功")
}
/**
* AcceptFriendRequestHandler
* 功能:接受好友申请
* 路径:POST /api/contacts/accept-request
*/
func AcceptFriendRequestHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
var req struct {
RequestID uint `json:"request_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
if err := service.ContactSvc.AcceptFriendRequest(req.RequestID, userID.(string)); err != nil {
utils.BadRequest(c, err.Error())
return
}
utils.Success(c, "已接受好友申请")
}
/**
* RejectFriendRequestHandler
* 功能:拒绝好友申请
* 路径:POST /api/contacts/reject-request
*/
func RejectFriendRequestHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
var req struct {
RequestID uint `json:"request_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
if err := service.ContactSvc.RejectFriendRequest(req.RequestID, userID.(string)); err != nil {
utils.BadRequest(c, err.Error())
return
}
utils.Success(c, "已拒绝好友申请")
}
/**
* GetGroupsHandler
* 功能:获取分组列表
* 路径:GET /api/contacts/groups
*/
func GetGroupsHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
groups, err := service.ContactSvc.GetGroups(userID.(string))
if err != nil {
utils.InternalError(c, "查询失败")
return
}
// 确保返回空数组而不是null
if groups == nil {
groups = []model.ContactGroup{}
}
utils.SuccessWithData(c, groups, "获取成功")
}
/**
* CreateGroupHandler
* 功能:创建分组
* 路径:POST /api/contacts/groups
*/
func CreateGroupHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
var req struct {
GroupName string `json:"group_name" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
group, err := service.ContactSvc.CreateGroup(userID.(string), req.GroupName)
if err != nil {
utils.BadRequest(c, "创建失败: "+err.Error())
return
}
utils.SuccessWithData(c, group, "创建成功")
}
/**
* UpdateGroupHandler
* 功能:更新分组
* 路径:PUT /api/contacts/groups/:id
*/
func UpdateGroupHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
groupID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
var req struct {
GroupName string `json:"group_name"`
SortOrder int `json:"sort_order"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
updates := make(map[string]interface{})
if req.GroupName != "" {
updates["group_name"] = req.GroupName
}
if req.SortOrder > 0 {
updates["sort_order"] = req.SortOrder
}
if err := service.ContactSvc.UpdateGroup(uint(groupID), userID.(string), updates); err != nil {
utils.BadRequest(c, "更新失败: "+err.Error())
return
}
utils.Success(c, "更新成功")
}
/**
* DeleteGroupHandler
* 功能:删除分组
* 路径:DELETE /api/contacts/groups/:id
*/
func DeleteGroupHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
groupID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
if err := service.ContactSvc.DeleteGroup(uint(groupID), userID.(string)); err != nil {
utils.BadRequest(c, "删除失败: "+err.Error())
return
}
utils.Success(c, "删除成功")
}
/**
* GetContactDetailHandler
* 功能:获取好友详情
* 路径:GET /api/contacts/:id
*/
func GetContactDetailHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
contactID := c.Param("id")
contact, err := service.ContactSvc.GetContactDetail(userID.(string), contactID)
if err != nil {
utils.NotFound(c, "好友不存在")
return
}
// 获取联系人用户信息
user, err := service.UserSvc.GetUserByID(contactID)
if err != nil {
utils.NotFound(c, "用户不存在")
return
}
result := map[string]interface{}{
"contact": contact,
"user": user,
}
utils.SuccessWithData(c, result, "获取成功")
}
/**
* UpdateContactHandler
* 功能:更新好友信息
* 路径:PUT /api/contacts/:id
*/
func UpdateContactHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
contactID := c.Param("id")
var req struct {
RemarkName string `json:"remark_name"`
GroupID uint `json:"group_id"`
IsTop *bool `json:"is_top"`
IsMuted *bool `json:"is_muted"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
updates := make(map[string]interface{})
if req.RemarkName != "" {
updates["remark_name"] = req.RemarkName
}
if req.GroupID > 0 {
updates["group_id"] = req.GroupID
}
if req.IsTop != nil {
updates["is_top"] = *req.IsTop
}
if req.IsMuted != nil {
updates["is_muted"] = *req.IsMuted
}
if err := service.ContactSvc.UpdateContact(userID.(string), contactID, updates); err != nil {
utils.BadRequest(c, "更新失败: "+err.Error())
return
}
utils.Success(c, "更新成功")
}
/**
* DeleteContactHandler
* 功能:删除好友
* 路径:DELETE /api/contacts/:id
*/
func DeleteContactHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
contactID := c.Param("id")
if err := service.ContactSvc.DeleteContact(userID.(string), contactID); err != nil {
utils.BadRequest(c, "删除失败: "+err.Error())
return
}
utils.Success(c, "已删除好友")
}

View File

@@ -7,12 +7,13 @@ package api
import (
"fmt"
"net/http"
"strconv"
"time"
"xk-websocket-v2/internal/manager"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/turnserver"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
@@ -33,7 +34,7 @@ func SendHandler(c *gin.Context) {
var req model.SendMessageReq
// 1. 绑定并校验 JSON 参数
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的JSON参数"})
utils.BadRequest(c, "无效的JSON参数")
return
}
@@ -63,7 +64,7 @@ func SendHandler(c *gin.Context) {
service.ChatSvc.HandleUserMessage(mockClient, &req)
// 6. 返回成功响应
c.JSON(http.StatusOK, gin.H{"status": "ok"})
utils.Success(c, "消息已发送")
}
/**
@@ -89,12 +90,12 @@ func SendToUserHandler(c *gin.Context) {
func BindHandler(c *gin.Context) {
var req model.BindReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
utils.BadRequest(c, "参数错误")
return
}
// 调用服务层进行绑定
service.ChatSvc.BindUserByClientID(req.ClientID, req.UserID)
c.JSON(http.StatusOK, gin.H{"status": "success"})
utils.Success(c, "绑定成功")
}
/**
@@ -106,7 +107,7 @@ func CheckUserOnlineHandler(c *gin.Context) {
userID := c.Query("user_id")
// 调用服务层查询 Redis
isOnline := service.ChatSvc.IsUserOnline(userID)
c.JSON(http.StatusOK, gin.H{"status": "success", "result": isOnline})
utils.SuccessWithData(c, gin.H{"is_online": isOnline}, "查询成功")
}
// ==========================================
@@ -120,18 +121,52 @@ func CheckUserOnlineHandler(c *gin.Context) {
*/
func HistoryHandler(c *gin.Context) {
roomID := c.Query("room_id")
var msgs []model.ChatMessage
// 简单查询最近 50 条
// 生产环境应添加 page, page_size 参数
result := service.ChatSvc.DB.Where("room_id = ?", roomID).
Order("created_at desc").Limit(50).Find(&msgs)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "db error"})
if roomID == "" {
utils.BadRequest(c, "room_id参数必填")
return
}
c.JSON(http.StatusOK, gin.H{"data": msgs})
// 分页参数
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 50
}
var msgs []model.ChatMessage
var total int64
// 获取总数
service.ChatSvc.DB.Model(&model.ChatMessage{}).Where("room_id = ?", roomID).Count(&total)
// 分页查询
offset := (page - 1) * pageSize
result := service.ChatSvc.DB.Where("room_id = ?", roomID).
Order("created_at desc").
Offset(offset).
Limit(pageSize).
Find(&msgs)
if result.Error != nil {
utils.InternalError(c, "db error")
return
}
// 确保返回空数组而不是null
if msgs == nil {
msgs = []model.ChatMessage{}
}
utils.SuccessWithData(c, gin.H{
"data": msgs,
"total": total,
"page": page,
"size": pageSize,
}, "获取成功")
}
/**
@@ -143,28 +178,6 @@ func SyncMessagesHandler(c *gin.Context) {
HistoryHandler(c)
}
/**
* ContactListHandler
* 功能:获取联系人列表 (模拟数据)。
* 路径:GET /api/contacts
* 说明:用于前端展示登录后的好友列表。
*/
func ContactListHandler(c *gin.Context) {
// 模拟 10 个用户数据
users := []model.UserContact{
{ID: "1001", Name: "张三 (我)", Avatar: "张", Desc: "Golang 专家"},
{ID: "1002", Name: "李琦 (妻)", Avatar: "李", Desc: "在线"},
{ID: "1003", Name: "王医生", Avatar: "医", Desc: "主任医师"},
{ID: "1004", Name: "客服小蜜", Avatar: "客", Desc: "全天在线"},
{ID: "1005", Name: "技术支持", Avatar: "技", Desc: "请重启试试"},
{ID: "1006", Name: "财务小赵", Avatar: "财", Desc: "报销单请提交"},
{ID: "1007", Name: "运维阿强", Avatar: "运", Desc: "服务器维护中"},
{ID: "1008", Name: "测试小丽", Avatar: "测", Desc: "Bug 太多了"},
{ID: "1009", Name: "HR", Avatar: "人", Desc: "本月考勤异常"},
{ID: "1010", Name: "老板", Avatar: "老", Desc: "今晚开会"},
}
c.JSON(http.StatusOK, gin.H{"data": users})
}
// ==========================================
// 系统与 WebRTC 接口
@@ -176,11 +189,11 @@ func ContactListHandler(c *gin.Context) {
* 路径:GET /api/health
*/
func HealthHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
utils.SuccessWithData(c, gin.H{
"status": "ok",
"node": viper.GetString("app.node_id"),
"time": time.Now().Format(time.RFC3339),
})
}, "服务正常")
}
/**
@@ -205,5 +218,5 @@ func ICEHandler(c *gin.Context) {
Username: username,
Credential: credential,
}
c.JSON(http.StatusOK, gin.H{"data": []model.ICEServerConfig{cfg}})
utils.SuccessWithData(c, []model.ICEServerConfig{cfg}, "获取成功")
}

View File

@@ -0,0 +1,71 @@
/**
* package api
* 作用:房间管理相关API处理器
*/
package api
import (
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* CreateRoomHandler
* 功能:创建房间
* 路径:POST /api/rooms
*/
func CreateRoomHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
var req struct {
RoomType string `json:"room_type" binding:"required,oneof=p2p group"`
Members []string `json:"members" binding:"required"`
RoomName string `json:"room_name"`
RoomAvatar string `json:"room_avatar"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
room, err := service.RoomSvc.CreateRoom(req.RoomType, req.Members, userID.(string))
if err != nil {
utils.BadRequest(c, err.Error())
return
}
// 如果提供了房间名称和头像,更新
if req.RoomName != "" || req.RoomAvatar != "" {
updates := make(map[string]interface{})
if req.RoomName != "" {
updates["room_name"] = req.RoomName
}
if req.RoomAvatar != "" {
updates["room_avatar"] = req.RoomAvatar
}
service.RoomSvc.DB.Model(room).Updates(updates)
}
utils.SuccessWithData(c, room, "创建成功")
}
/**
* GetRoomHandler
* 功能:获取房间信息
* 路径:GET /api/rooms/:id
*/
func GetRoomHandler(c *gin.Context) {
roomID := c.Param("id")
room, err := service.RoomSvc.GetRoom(roomID)
if err != nil {
utils.NotFound(c, "房间不存在")
return
}
utils.SuccessWithData(c, room, "获取成功")
}

View File

@@ -0,0 +1,155 @@
/**
* package api
* 作用:用户管理相关API处理器
*/
package api
import (
"fmt"
"math/rand"
"strconv"
"time"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* GetMyInfoHandler
* 功能:获取当前用户信息
* 路径:GET /api/user/my-info
* 需要:JWT认证
*/
func GetMyInfoHandler(c *gin.Context) {
// 从Context获取用户ID(由JWT中间件注入)
userID, exists := c.Get("user_id")
if !exists {
utils.Unauthorized(c, "未认证")
return
}
user, err := service.UserSvc.GetUserByID(userID.(string))
if err != nil {
utils.NotFound(c, "用户不存在")
return
}
utils.SuccessWithData(c, user, "获取成功")
}
/**
* GetUserListHandler
* 功能:获取用户列表
* 路径:GET /api/user/list
*/
func GetUserListHandler(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 20
}
users, total, err := service.UserSvc.GetUserList(page, pageSize)
if err != nil {
utils.InternalError(c, "查询失败")
return
}
// 确保返回空数组而不是null
if users == nil {
users = []model.User{}
}
utils.SuccessWithData(c, gin.H{
"data": users,
"total": total,
"page": page,
"size": pageSize,
}, "获取成功")
}
/**
* CreateUserHandler
* 功能:创建用户(管理员)
* 路径:POST /api/user/create
*/
func CreateUserHandler(c *gin.Context) {
var user model.User
if err := c.ShouldBindJSON(&user); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
// 生成用户ID
user.ID = generateUserID()
if err := service.UserSvc.CreateUser(&user); err != nil {
utils.BadRequest(c, "创建用户失败: "+err.Error())
return
}
user.Password = "" // 清除密码
utils.SuccessWithData(c, user, "创建成功")
}
/**
* UpdateUserHandler
* 功能:更新用户信息
* 路径:POST /api/user/update
*/
func UpdateUserHandler(c *gin.Context) {
var req struct {
ID string `json:"id" binding:"required"`
Updates map[string]interface{} `json:"updates" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误: "+err.Error())
return
}
if err := service.UserSvc.UpdateUser(req.ID, req.Updates); err != nil {
utils.BadRequest(c, "更新失败: "+err.Error())
return
}
utils.Success(c, "更新成功")
}
/**
* DeleteUserHandler
* 功能:删除用户
* 路径:POST /api/user/delete
*/
func DeleteUserHandler(c *gin.Context) {
var req struct {
ID string `json:"id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
if err := service.UserSvc.DeleteUser(req.ID); err != nil {
utils.BadRequest(c, "删除失败: "+err.Error())
return
}
utils.Success(c, "删除成功")
}
// 辅助函数:生成用户ID
func generateUserID() string {
// 使用时间戳+随机数生成用户ID
timestamp := time.Now().UnixNano()
random := rand.Intn(1000000)
return fmt.Sprintf("user_%d_%d", timestamp, random)
}