Files
2026-07-11 23:37:24 +08:00

129 lines
2.7 KiB
Go

package listingstatus
import (
"strings"
"time"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/timeutil"
"gorm.io/gorm"
)
// 统计用的事件类型(与 to_status 对齐时优先用这些标准值)。
const (
EventPublished = "published"
EventOffline = "offline"
EventRented = "rented"
EventCompleted = "completed"
EventSealed = "sealed"
EventAbnormal = "abnormal"
)
// 来源
const (
SourceSeller = "seller"
SourceAdmin = "admin"
SourceReview = "review"
SourceOrder = "order"
SourcePickup = "pickup"
SourceDispute = "dispute"
SourceSystem = "system"
)
// 操作者类型
const (
ActorUser = "user"
ActorAdmin = "admin"
ActorSystem = "system"
)
// Entry 单次状态变更事件。
type Entry struct {
ListingID uint64
OwnerID uint64
EventType string
FromStatus string
ToStatus string
Source string
ActorType string
ActorID uint64
Remark string
// CreatedAt 为空时使用上海时间当前时刻。
CreatedAt time.Time
}
// Append 写入一条状态事件。from==to 或 event 无法识别时跳过。
func Append(tx *gorm.DB, entry Entry) error {
if tx == nil {
return nil
}
from := strings.TrimSpace(entry.FromStatus)
to := strings.TrimSpace(entry.ToStatus)
if to == "" {
to = strings.TrimSpace(entry.EventType)
}
if to == "" || from == to {
return nil
}
eventType := strings.TrimSpace(entry.EventType)
if eventType == "" {
eventType = normalizeEventType(to)
}
if eventType == "" {
return nil
}
createdAt := entry.CreatedAt
if createdAt.IsZero() {
createdAt = timeutil.ShanghaiNow()
}
row := model.ListingStatusEvent{
ListingID: entry.ListingID,
OwnerID: entry.OwnerID,
EventType: eventType,
FromStatus: from,
ToStatus: to,
Source: strings.TrimSpace(entry.Source),
ActorType: strings.TrimSpace(entry.ActorType),
ActorID: entry.ActorID,
Remark: strings.TrimSpace(entry.Remark),
CreatedAt: createdAt,
}
return tx.Create(&row).Error
}
// AppendTransition 根据 listing 变更前后状态写事件。
func AppendTransition(
tx *gorm.DB,
listing *model.RentalListing,
fromStatus string,
source string,
actorType string,
actorID uint64,
remark string,
) error {
if listing == nil {
return nil
}
return Append(tx, Entry{
ListingID: listing.ID,
OwnerID: listing.OwnerID,
EventType: normalizeEventType(listing.Status),
FromStatus: fromStatus,
ToStatus: listing.Status,
Source: source,
ActorType: actorType,
ActorID: actorID,
Remark: remark,
})
}
func normalizeEventType(status string) string {
switch strings.TrimSpace(status) {
case EventPublished, EventOffline, EventRented, EventCompleted, EventSealed, EventAbnormal:
return status
default:
return ""
}
}