Files
hfb_sys/backend/internal/modules/order/assets.go
T
yml2213andClaude Opus 4.8 be5d322c10 feat: 客服封存订单功能(号主失联场景)
新增客服「封存订单」动作,用于号主失联、无法联系的场景:单事务内
完成关闭订单、全量原路退款、永久封存关联商品、解散发布群、双方通知
与审计日志。

- 新增 listing 终态 sealed(封存),区别于可恢复的 offline
- listingLockedForOwnerMutation 锁定 sealed,号主无法再编辑/提审/上架
- 解散群聊按 listing_id 查发布群(listing_group)置 archived,
  阻断所有成员发言并留系统消息
- 新增 order.AdminSeal 及 /admin/orders/:id/seal 路由
- 前端:卖家页 PC/移动端 sealed 视为终态禁用操作,客服后台新增
  「封存订单」按钮与二次确认

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:52:20 +08:00

86 lines
2.4 KiB
Go

package order
import (
"hfb_sys/backend/internal/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type orderAssets struct {
Order *model.RentalOrder
Listing *model.RentalListing
Account *model.GameAccount
}
func (r *Repository) lockOrderAssets(tx *gorm.DB, orderID uint64) (*orderAssets, error) {
var order model.RentalOrder
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil {
return nil, err
}
listing, account, err := r.lockListingAccountForOrder(tx, &order)
if err != nil {
return nil, err
}
return &orderAssets{
Order: &order,
Listing: listing,
Account: account,
}, nil
}
func (r *Repository) lockListingAccountForOrder(tx *gorm.DB, order *model.RentalOrder) (*model.RentalListing, *model.GameAccount, error) {
var listing model.RentalListing
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&listing, order.ListingID).Error; err != nil {
return nil, nil, err
}
var account model.GameAccount
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&account, order.AccountID).Error; err != nil {
return nil, nil, err
}
return &listing, &account, nil
}
func reserveListingForOrder(listing *model.RentalListing) {
listing.InTransaction = true
}
func markAssetsRented(listing *model.RentalListing, account *model.GameAccount) {
listing.Status = listingStatusRented
account.Status = accountStatusRented
}
func releaseAssetsForRental(listing *model.RentalListing, account *model.GameAccount) {
listing.Status = listingStatusPublished
listing.InTransaction = false
account.Status = accountStatusPublished
}
func archiveAssets(listing *model.RentalListing, account *model.GameAccount) {
listing.Status = listingStatusOffline
listing.InTransaction = false
listing.PublishedAt = nil
account.Status = accountStatusOffline
}
func sealAssets(listing *model.RentalListing, account *model.GameAccount) {
listing.Status = listingStatusSealed
listing.InTransaction = false
listing.PublishedAt = nil
account.Status = accountStatusSealed
}
func completeAssets(listing *model.RentalListing, account *model.GameAccount) {
listing.Status = listingStatusCompleted
listing.InTransaction = false
listing.PublishedAt = nil
account.Status = accountStatusOffline
}
func markAssetsAbnormal(listing *model.RentalListing, account *model.GameAccount) {
listing.Status = listingStatusAbnormal
listing.InTransaction = false
listing.PublishedAt = nil
account.Status = accountStatusAbnormal
}