合并 main 分支并融合订单列表最小化与 SQL 治理
- Auth/权限中间件取 main 演进版(错误细分、token 来源),保留 dev 的用户 cookie 与登出撤销语义 - 后台订单列表:融合 main 的首页免 COUNT 优化与关键词索引路由,保留 dev 的最小化 AdminOrderListItemDTO(结账明细仍由详情接口返回,同步调整对应集成测试) - 保留 dev 的 token_version 冻结/解冻递增与 main 的状态变化判断及通知 - 前端:保留 dev 登出接口与 main 的 fetchMe silent 参数、SSE 登录跳转;后台订单表按 dev 最小化 DTO 移除号主到手列
This commit is contained in:
@@ -4,21 +4,32 @@ import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ChatConversation struct {
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
OrderID *uint64 `gorm:"uniqueIndex" json:"order_id"`
|
||||
ListingID *uint64 `gorm:"index" json:"listing_id"`
|
||||
Type string `gorm:"size:32;not null;default:'order_group'" json:"type"`
|
||||
SupportScene string `gorm:"column:support_scene;size:32;not null;default:''" json:"support_scene"`
|
||||
Title string `gorm:"size:128;not null" json:"title"`
|
||||
Status string `gorm:"size:32;not null;default:'active'" json:"status"`
|
||||
LastMessageID *uint64 `json:"last_message_id"`
|
||||
LastMessagePreview string `gorm:"size:255;not null;default:''" json:"last_message_preview"`
|
||||
LastMessageAt *time.Time `json:"last_message_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
OrderID *uint64 `gorm:"uniqueIndex" json:"order_id"`
|
||||
ListingID *uint64 `gorm:"index" json:"listing_id"`
|
||||
// 发布群没有固定订单时,以下字段保存该商品最新订单的轻量快照,供客服列表筛选使用。
|
||||
// 这样读取会话列表不必每次扫描全部订单再按商品分组。
|
||||
LatestOrderID *uint64 `gorm:"index" json:"-"`
|
||||
LatestOrderNo string `gorm:"size:64;not null;default:''" json:"-"`
|
||||
LatestOrderStatus string `gorm:"size:32;not null;default:'';index" json:"-"`
|
||||
LatestOrderHandoffStatus string `gorm:"size:32;not null;default:''" json:"-"`
|
||||
LatestOrderRefundStatus string `gorm:"size:32;not null;default:''" json:"-"`
|
||||
// 待回复判断只需比较两个游标,避免每个会话再扫描聊天消息表。
|
||||
LastAttentionMessageID uint64 `gorm:"not null;default:0" json:"-"`
|
||||
LastAdminMessageID uint64 `gorm:"not null;default:0" json:"-"`
|
||||
Type string `gorm:"size:32;not null;default:'order_group'" json:"type"`
|
||||
SupportScene string `gorm:"column:support_scene;size:32;not null;default:''" json:"support_scene"`
|
||||
Title string `gorm:"size:128;not null" json:"title"`
|
||||
Status string `gorm:"size:32;not null;default:'active'" json:"status"`
|
||||
LastMessageID *uint64 `json:"last_message_id"`
|
||||
LastMessagePreview string `gorm:"size:255;not null;default:''" json:"last_message_preview"`
|
||||
LastMessageAt *time.Time `json:"last_message_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (ChatConversation) TableName() string {
|
||||
@@ -42,22 +53,58 @@ func (ChatParticipant) TableName() string {
|
||||
return "chat_participants"
|
||||
}
|
||||
|
||||
// ChatAdminConversationState stores per-admin state even when the admin is not
|
||||
// an assigned participant of the conversation.
|
||||
type ChatAdminConversationState struct {
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
ConversationID uint64 `gorm:"not null;uniqueIndex:uk_chat_admin_conversation_state;index" json:"conversation_id"`
|
||||
AdminUserID uint64 `gorm:"not null;uniqueIndex:uk_chat_admin_conversation_state;index" json:"admin_user_id"`
|
||||
Remark string `gorm:"size:128;not null;default:''" json:"remark"`
|
||||
LastReadMessageID uint64 `gorm:"not null;default:0" json:"last_read_message_id"`
|
||||
LastReadAt *time.Time `json:"last_read_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (ChatAdminConversationState) TableName() string {
|
||||
return "chat_admin_conversation_states"
|
||||
}
|
||||
|
||||
type ChatMessage struct {
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
ConversationID uint64 `gorm:"not null;index" json:"conversation_id"`
|
||||
SenderType string `gorm:"size:16;not null" json:"sender_type"`
|
||||
SenderID uint64 `gorm:"not null;default:0" json:"sender_id"`
|
||||
SenderRole string `gorm:"size:32;not null;default:''" json:"sender_role"`
|
||||
ContentType string `gorm:"size:32;not null;default:'text'" json:"content_type"`
|
||||
Content string `json:"content"`
|
||||
AttachmentURLS datatypes.JSON `gorm:"column:attachment_urls" json:"attachment_urls"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
ConversationID uint64 `gorm:"not null;index" json:"conversation_id"`
|
||||
SenderType string `gorm:"size:16;not null" json:"sender_type"`
|
||||
SenderID uint64 `gorm:"not null;default:0" json:"sender_id"`
|
||||
SenderRole string `gorm:"size:32;not null;default:''" json:"sender_role"`
|
||||
ContentType string `gorm:"size:32;not null;default:'text'" json:"content_type"`
|
||||
Content string `json:"content"`
|
||||
AttachmentURLS datatypes.JSON `gorm:"column:attachment_urls" json:"attachment_urls"`
|
||||
AdminAttentionType string `gorm:"column:admin_attention_type;size:32;not null;default:'';index" json:"admin_attention_type"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (ChatMessage) TableName() string {
|
||||
return "chat_messages"
|
||||
}
|
||||
|
||||
// AfterCreate 维护客服列表所需的两个消息游标;列表页只比较游标,不再对每个会话聚合消息表。
|
||||
func (m *ChatMessage) AfterCreate(tx *gorm.DB) error {
|
||||
if m.ID == 0 || m.ConversationID == 0 {
|
||||
return nil
|
||||
}
|
||||
updates := map[string]any{}
|
||||
if m.AdminAttentionType != "" || m.SenderType == "user" {
|
||||
updates["last_attention_message_id"] = m.ID
|
||||
}
|
||||
if m.SenderType == "admin" {
|
||||
updates["last_admin_message_id"] = m.ID
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
return tx.Model(&ChatConversation{}).Where("id = ?", m.ConversationID).Updates(updates).Error
|
||||
}
|
||||
|
||||
type ChatQrCode struct {
|
||||
ID uint64 `gorm:"primaryKey" json:"id"`
|
||||
ImageURL string `gorm:"size:512;not null" json:"image_url"`
|
||||
|
||||
Reference in New Issue
Block a user