修复了一些问题

This commit is contained in:
李琦
2026-07-08 08:18:58 +08:00
parent bb7891706b
commit 3417856607
19 changed files with 615 additions and 778 deletions

View File

@@ -25,7 +25,7 @@ func LoginHandler(c *gin.Context) {
}
// 获取客户端IP
ip := getClientIP(c)
ip := utils.GetClientIP(c)
// 调用认证服务登录
user, err := service.AuthSvc.Login(req.Account, req.Password)
@@ -57,24 +57,6 @@ func LoginHandler(c *gin.Context) {
}, "登录成功")
}
// 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
* 功能:用户注册
@@ -222,4 +204,3 @@ func SendSmsCodeHandler(c *gin.Context) {
"code": code, // 仅开发环境,生产环境应移除
}, "验证码已发送")
}

View File

@@ -310,6 +310,7 @@ func UpdateContactHandler(c *gin.Context) {
GroupID uint `json:"group_id"`
IsTop *bool `json:"is_top"`
IsMuted *bool `json:"is_muted"`
IsBlocked *bool `json:"is_blocked"`
}
if err := c.ShouldBindJSON(&req); err != nil {
@@ -330,6 +331,9 @@ func UpdateContactHandler(c *gin.Context) {
if req.IsMuted != nil {
updates["is_muted"] = *req.IsMuted
}
if req.IsBlocked != nil {
updates["is_blocked"] = *req.IsBlocked
}
if err := service.ContactSvc.UpdateContact(userID.(string), contactID, updates); err != nil {
utils.BadRequest(c, "更新失败: "+err.Error())

View File

@@ -56,14 +56,19 @@ func SendHandler(c *gin.Context) {
// 4. 构造临时的发送者客户端对象
// 这个对象将传递给 Service 层,用于识别消息来源
mockClient := &manager.Client{
UserID: senderID,
ID: clientID,
UserID: senderID,
ID: clientID,
RemoteIP: utils.GetClientIP(c),
}
// 5. 调用核心业务逻辑处理消息
service.ChatSvc.HandleUserMessage(mockClient, &req)
// 5. 调用核心业务逻辑处理消息,返回持久化后的消息体供前端对齐 ID
savedMsg := service.ChatSvc.HandleUserMessage(mockClient, &req)
// 6. 返回成功响应
// 6. 返回成功响应(含服务端消息 ID避免前端重复展示
if savedMsg != nil {
utils.SuccessWithData(c, savedMsg, "消息已发送")
return
}
utils.Success(c, "消息已发送")
}
@@ -169,6 +174,54 @@ func HistoryHandler(c *gin.Context) {
}, "获取成功")
}
/**
* RecallMessageHandler
* 功能撤回消息2 分钟内,仅发送者可撤回)
* 路径POST /api/messages/recall
*/
func RecallMessageHandler(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
utils.Unauthorized(c, "未认证")
return
}
var req struct {
MessageID uint `json:"message_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
var msg model.ChatMessage
if err := service.ChatSvc.DB.First(&msg, req.MessageID).Error; err != nil {
utils.NotFound(c, "消息不存在")
return
}
if msg.SenderUserID != userID.(string) {
utils.Forbidden(c, "无权撤回该消息")
return
}
if time.Since(msg.CreatedAt) > 2*time.Minute {
utils.BadRequest(c, "超过2分钟无法撤回")
return
}
msg.MessageType = model.MessageTypeSystem
msg.Content = "撤回了一条消息"
if err := service.ChatSvc.DB.Save(&msg).Error; err != nil {
utils.InternalError(c, "撤回失败")
return
}
service.ChatSvc.BroadcastChatMessage(msg)
utils.SuccessWithData(c, msg, "撤回成功")
}
/**
* SyncMessagesHandler
* 功能:全量同步消息 (V1 兼容)。
@@ -178,7 +231,6 @@ func SyncMessagesHandler(c *gin.Context) {
HistoryHandler(c)
}
// ==========================================
// 系统与 WebRTC 接口
// ==========================================

View File

@@ -934,3 +934,93 @@ func GetMemberMuteStatusHandler(c *gin.Context) {
"muted_until": mutedUntil,
}, "获取成功")
}
/**
* GetGroupSettingsHandler
* 功能:获取群设置(名称、头像、公告、邀请权限等)
* 路径GET /api/groups/:room_id/settings
*/
func GetGroupSettingsHandler(c *gin.Context) {
roomID := c.Param("room_id")
room, err := service.RoomSvc.GetRoom(roomID)
if err != nil {
utils.NotFound(c, "群聊不存在")
return
}
utils.SuccessWithData(c, gin.H{
"name": room.RoomName,
"avatar": room.RoomAvatar,
"description": room.Announcement,
"invite_permission": 0,
"created_at": room.CreatedAt,
"updated_at": room.UpdatedAt,
}, "获取成功")
}
/**
* UpdateGroupSettingsHandler
* 功能:更新群设置
* 路径POST /api/groups/:room_id/settings
*/
func UpdateGroupSettingsHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
roomID := c.Param("room_id")
ok, err := service.RoomSvc.IsGroupAdminOrOwner(roomID, userID.(string))
if err != nil || !ok {
utils.Forbidden(c, "无权限修改群设置")
return
}
var req struct {
Name string `json:"name"`
Avatar string `json:"avatar"`
Description string `json:"description"`
InvitePermission *int `json:"invite_permission"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
updates := map[string]interface{}{}
if req.Name != "" {
updates["room_name"] = req.Name
}
if req.Avatar != "" {
updates["room_avatar"] = req.Avatar
}
if req.Description != "" {
updates["announcement"] = req.Description
}
if len(updates) == 0 {
utils.BadRequest(c, "没有可更新的字段")
return
}
if err := service.RoomSvc.DB.Model(&model.ChatRoom{}).Where("room_id = ?", roomID).Updates(updates).Error; err != nil {
utils.InternalError(c, "更新失败")
return
}
GetGroupSettingsHandler(c)
}
/**
* GetCallHistoryHandler
* 功能:获取当前用户的通话记录(基于 call_id 消息)
* 路径GET /api/calls/history
*/
func GetCallHistoryHandler(c *gin.Context) {
userID, _ := c.Get("user_id")
var messages []model.ChatMessage
err := service.ChatSvc.DB.
Where("(sender_user_id = ? OR receiver_user_id = ?) AND call_id <> '' AND call_id IS NOT NULL", userID, userID).
Order("created_at DESC").
Limit(50).
Find(&messages).Error
if err != nil {
utils.InternalError(c, "查询失败")
return
}
utils.SuccessWithData(c, messages, "获取成功")
}

View File

@@ -0,0 +1,126 @@
/**
* package api
* 作用:用户设置与消息已读回执 HTTP 接口
*/
package api
import (
"encoding/json"
"time"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* GetUserSettingsHandler
* 功能:获取当前用户的全部设置
*/
func GetUserSettingsHandler(c *gin.Context) {
userID, ok := c.Get("user_id")
if !ok {
utils.Unauthorized(c, "未认证")
return
}
var rows []model.UserSetting
if err := service.ChatSvc.DB.Where("user_id = ?", userID.(string)).Find(&rows).Error; err != nil {
utils.InternalError(c, "查询失败")
return
}
result := make(map[string]string, len(rows))
for _, row := range rows {
result[row.SettingKey] = row.SettingValue
}
utils.SuccessWithData(c, result, "获取成功")
}
/**
* UpdateUserSettingsHandler
* 功能:批量更新用户设置
*/
func UpdateUserSettingsHandler(c *gin.Context) {
userID, ok := c.Get("user_id")
if !ok {
utils.Unauthorized(c, "未认证")
return
}
var req struct {
Settings map[string]string `json:"settings" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
uid := userID.(string)
now := time.Now()
for key, val := range req.Settings {
setting := model.UserSetting{
UserID: uid,
SettingKey: key,
SettingValue: val,
UpdatedAt: now,
}
service.ChatSvc.DB.Save(&setting)
}
GetUserSettingsHandler(c)
}
/**
* MarkMessagesReadHandler
* 功能:批量标记消息已读
*/
func MarkMessagesReadHandler(c *gin.Context) {
userID, ok := c.Get("user_id")
if !ok {
utils.Unauthorized(c, "未认证")
return
}
var req struct {
MessageIDs []uint `json:"message_ids" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "参数错误")
return
}
uid := userID.(string)
now := time.Now()
readIDs := make([]uint, 0, len(req.MessageIDs))
for _, mid := range req.MessageIDs {
receipt := model.MessageReadReceipt{
MessageID: mid,
UserID: uid,
ReadAt: now,
}
service.ChatSvc.DB.Where("message_id = ? AND user_id = ?", mid, uid).
Assign(receipt).FirstOrCreate(&receipt)
readIDs = append(readIDs, mid)
// 通知消息发送者(已读回执)
var msg model.ChatMessage
if err := service.ChatSvc.DB.First(&msg, mid).Error; err == nil && msg.SenderUserID != "" && msg.SenderUserID != uid {
payload := model.WsPayload{
RequestType: "messages_read",
Data: map[string]interface{}{
"message_ids": []uint{mid},
"reader_id": uid,
"room_id": msg.RoomID,
},
}
if bytes, err := json.Marshal(payload); err == nil {
service.ChatSvc.DispatchMessage(msg.SenderUserID, bytes)
}
}
}
utils.SuccessWithData(c, gin.H{"message_ids": readIDs}, "已标记已读")
}

View File

@@ -40,6 +40,27 @@ func GetMyInfoHandler(c *gin.Context) {
utils.SuccessWithData(c, user, "获取成功")
}
/**
* GetUserByIDHandler
* 功能:根据用户 ID 获取公开资料
* 路径GET /api/user/:id
*/
func GetUserByIDHandler(c *gin.Context) {
targetID := c.Param("id")
if targetID == "" {
utils.BadRequest(c, "用户ID不能为空")
return
}
user, err := service.UserSvc.GetUserByID(targetID)
if err != nil {
utils.NotFound(c, "用户不存在")
return
}
user.Password = ""
utils.SuccessWithData(c, user, "获取成功")
}
/**
* GetUserListHandler
* 功能:获取用户列表