优化号主交接超时卡死问题

- 号主交接超时(owner_timeout)后允许补提交交接说明,避免临时延误导致订单卡死
- 后台新增"重置交接"动作,可将超时订单恢复为待号主交接并刷新计时
- 交接超时改以进入待交接时刻为基准计算,新增 handoff_started_at 字段

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
yml2213
2026-06-17 04:16:31 +08:00
co-authored by Claude Opus 4.8
parent ae11dd7b8d
commit 8192344027
13 changed files with 140 additions and 23 deletions
@@ -8,6 +8,7 @@ import (
"hfb_sys/backend/internal/modules/notification"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
func (r *Repository) AdminClose(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
@@ -162,6 +163,54 @@ func (r *Repository) AdminMarkAbnormal(ctx context.Context, adminID uint64, orde
})
}
// AdminResetHandoff 将号主交接超时(owner_timeout)的订单重置回待号主交接,并刷新交接计时,
// 让客服可以给号主再次提交交接说明的机会,避免订单卡死在超时状态。
func (r *Repository) AdminResetHandoff(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var order model.RentalOrder
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil {
return err
}
if order.Status != orderStatusPendingHandoff || order.HandoffStatus != handoffStatusOwnerTimeout {
return ErrOrderCannotResetHandoff
}
beforeHandoffStatus := order.HandoffStatus
now := time.Now()
order.HandoffStatus = handoffStatusPendingOwner
order.HandoffStartedAt = &now
if err := notification.Append(tx,
notification.Entry{
UserID: order.OwnerID,
Type: "order_admin",
Title: "请重新提交交接说明",
Content: "客服已重置交接状态,请尽快提交交接说明,避免再次超时。原因:" + req.Reason,
BizType: "order",
BizID: &order.ID,
},
notification.Entry{
UserID: order.RenterID,
Type: "order_admin",
Title: "订单交接已重置",
Content: "客服已重置交接状态,正在等待号主重新提交交接说明。原因:" + req.Reason,
BizType: "order",
BizID: &order.ID,
},
); err != nil {
return err
}
if err := appendAuditLog(tx, adminID, "order.reset_handoff", "order", order.ID, meta, map[string]any{
"order_id": order.ID,
"order_no": order.OrderNo,
"reason": req.Reason,
"before_handoff_status": beforeHandoffStatus,
"after_handoff_status": order.HandoffStatus,
}); err != nil {
return err
}
return tx.Save(&order).Error
})
}
// AdminRefund 触发后台人工退款,退款由 payment 模块走渠道原路退回。
func (r *Repository) AdminRefund(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
var order model.RentalOrder