聊天增加图片功能

This commit is contained in:
yml2213
2026-05-29 12:56:25 +08:00
parent 3b8b65ab56
commit 0f44b024cb
11 changed files with 590 additions and 28 deletions
+2 -1
View File
@@ -52,7 +52,8 @@ type MessageDTO struct {
}
type SendMessageRequest struct {
Content string `json:"content" binding:"required"`
Content string `json:"content"`
AttachmentURLS []string `json:"attachment_urls"`
}
type TransferRequest struct {
+1 -1
View File
@@ -340,7 +340,7 @@ func (h *Handler) send(c *gin.Context, principal Principal) {
}
var req SendMessageRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "消息内容不能为空")
response.BadRequest(c, "消息格式不正确")
return
}
message, err := h.service.SendMessage(principal, id, req)
+19 -2
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"hfb_sys/backend/internal/model"
@@ -312,13 +313,13 @@ func (r *Repository) SendMessage(principal Principal, conversationID uint64, req
SenderRole: participant.Role,
ContentType: "text",
Content: req.Content,
AttachmentURLS: emptyJSONList(),
AttachmentURLS: encodeStringList(req.AttachmentURLS),
}
if err := tx.Create(&message).Error; err != nil {
return err
}
conversation.LastMessageID = &message.ID
conversation.LastMessagePreview = truncatePreview(message.Content)
conversation.LastMessagePreview = messagePreview(message.Content, req.AttachmentURLS)
conversation.LastMessageAt = &message.CreatedAt
if err := tx.Save(&conversation).Error; err != nil {
return err
@@ -708,6 +709,17 @@ func truncatePreview(content string) string {
return string(runes[:80])
}
func messagePreview(content string, attachments []string) string {
content = strings.TrimSpace(content)
if content != "" {
return truncatePreview(content)
}
if len(attachments) > 0 {
return "[图片]"
}
return ""
}
// TransferConversation 转接会话给其他客服
func (r *Repository) TransferConversation(principal Principal, conversationID uint64, toAdminID uint64) error {
return r.db.Transaction(func(tx *gorm.DB) error {
@@ -908,6 +920,11 @@ func emptyJSONList() datatypes.JSON {
return datatypes.JSON(raw)
}
func encodeStringList(items []string) datatypes.JSON {
raw, _ := json.Marshal(items)
return datatypes.JSON(raw)
}
// UpdateRemark 更新会话备注
func (r *Repository) UpdateRemark(principal Principal, conversationID uint64, remark string) error {
return r.db.Model(&model.ChatParticipant{}).
+41 -1
View File
@@ -2,6 +2,7 @@ package chat
import (
"errors"
"net/url"
"strings"
)
@@ -63,15 +64,54 @@ func (s *Service) SendMessage(principal Principal, conversationID uint64, req Se
return nil, ErrDependencyUnavailable
}
req.Content = strings.TrimSpace(req.Content)
if conversationID == 0 || req.Content == "" {
attachments, ok := normalizeAttachmentURLS(req.AttachmentURLS)
req.AttachmentURLS = attachments
if conversationID == 0 || (req.Content == "" && len(req.AttachmentURLS) == 0) {
return nil, ErrInvalidMessage
}
if len([]rune(req.Content)) > 1000 {
return nil, ErrInvalidMessage
}
if !ok {
return nil, ErrInvalidMessage
}
return s.repo.SendMessage(principal, conversationID, req)
}
func normalizeAttachmentURLS(items []string) ([]string, bool) {
if len(items) > 9 {
return nil, false
}
result := make([]string, 0, len(items))
for _, item := range items {
value := strings.TrimSpace(item)
if value == "" {
continue
}
if len(value) > 500 || strings.Contains(value, "..") {
return nil, false
}
parsed, err := url.Parse(value)
if err != nil {
return nil, false
}
if parsed.Host != "" {
return nil, false
}
switch parsed.Path {
case "/api/files/object", "/api/admin/files/object", "/api/public/files/object":
default:
return nil, false
}
key := strings.TrimSpace(parsed.Query().Get("key"))
if key == "" || strings.Contains(key, "..") {
return nil, false
}
result = append(result, value)
}
return result, true
}
func (s *Service) MarkRead(principal Principal, conversationID uint64) error {
if s.repo == nil {
return ErrDependencyUnavailable