完善后台分页与令牌刷新

This commit is contained in:
yml
2026-05-24 17:56:26 +08:00
parent cb636e4e89
commit abc4447401
19 changed files with 392 additions and 91 deletions
+61 -9
View File
@@ -35,6 +35,7 @@ func (r *Repository) Create(userID uint64, orderID uint64, req CreateRequest) (*
if order.Status == "completed" || order.Status == "cancelled" || order.Status == "closed" {
return ErrInvalidDispute
}
isCheckoutDispute := order.Status == "pending_checkout_confirm" || order.Status == "pending_checkout_accept"
var count int64
if err := tx.Model(&model.Dispute{}).
Where("order_id = ? AND status IN ?", order.ID, []string{"open", "processing"}).
@@ -57,7 +58,7 @@ func (r *Repository) Create(userID uint64, orderID uint64, req CreateRequest) (*
OrderID: order.ID,
InitiatorID: userID,
TargetUserID: targetID,
Type: req.Type,
Type: disputeType(req.Type, isCheckoutDispute),
Status: "open",
Description: req.Description,
EvidenceURLS: evidence,
@@ -65,17 +66,42 @@ func (r *Repository) Create(userID uint64, orderID uint64, req CreateRequest) (*
if err := tx.Create(&row).Error; err != nil {
return err
}
order.Status = "disputing"
if isCheckoutDispute {
now := time.Now()
order.Status = "checkout_disputing"
order.HandoffStatus = "checkout_disputed"
order.SettlementStatus = "disputed"
updates := map[string]any{
"status": "disputed",
"updated_at": now,
}
if userID == order.RenterID {
updates["renter_rejected_at"] = now
}
if err := tx.Model(&model.OrderCheckout{}).
Where("order_id = ? AND status IN ?", order.ID, []string{"submitted", "countered"}).
Updates(updates).Error; err != nil {
return err
}
} else {
order.Status = "disputing"
}
if err := tx.Save(&order).Error; err != nil {
return err
}
disputeID := row.ID
title := "订单进入申诉"
content := "对方已发起申诉,请等待客服仲裁或补充沟通记录。"
if isCheckoutDispute {
title = "订单进入结账争议"
content = "对方已发起结账争议,请等待客服仲裁或补充结账证据。"
}
if err := notification.Append(tx,
notification.Entry{
UserID: targetID,
Type: "dispute",
Title: "订单进入申诉",
Content: "对方已发起申诉,请等待客服仲裁或补充沟通记录。",
Title: title,
Content: content,
BizType: "dispute",
BizID: &disputeID,
},
@@ -99,16 +125,23 @@ func (r *Repository) Create(userID uint64, orderID uint64, req CreateRequest) (*
return r.FindForUser(userID, createdID)
}
func (r *Repository) ListForUser(userID uint64) ([]DisputeDTO, error) {
func (r *Repository) ListForUser(userID uint64, page, pageSize int) (*PaginatedResult, error) {
conditions := r.db.Model(&model.Dispute{}).Where("initiator_id = ? OR target_user_id = ?", userID, userID)
var total int64
if err := conditions.Count(&total).Error; err != nil {
return nil, err
}
offset := (page - 1) * pageSize
var rows []disputeRow
err := r.baseQuery().
Where("d.initiator_id = ? OR d.target_user_id = ?", userID, userID).
Order("d.id DESC").
Offset(offset).Limit(pageSize).
Scan(&rows).Error
if err != nil {
return nil, err
}
return toDTOs(rows), nil
return &PaginatedResult{Items: toDTOs(rows), Total: total, Page: page, PageSize: pageSize}, nil
}
func (r *Repository) FindForUser(userID uint64, id uint64) (*DisputeDTO, error) {
@@ -122,13 +155,18 @@ func (r *Repository) FindForUser(userID uint64, id uint64) (*DisputeDTO, error)
return &dto, nil
}
func (r *Repository) ListAdmin() ([]DisputeDTO, error) {
func (r *Repository) ListAdmin(page, pageSize int) (*PaginatedResult, error) {
var total int64
if err := r.db.Model(&model.Dispute{}).Count(&total).Error; err != nil {
return nil, err
}
offset := (page - 1) * pageSize
var rows []disputeRow
err := r.baseQuery().Order("d.id DESC").Limit(200).Scan(&rows).Error
err := r.baseQuery().Order("d.id DESC").Offset(offset).Limit(pageSize).Scan(&rows).Error
if err != nil {
return nil, err
}
return toDTOs(rows), nil
return &PaginatedResult{Items: toDTOs(rows), Total: total, Page: page, PageSize: pageSize}, nil
}
func (r *Repository) Arbitrate(adminID uint64, id uint64, req ArbitrateRequest, meta AuditMeta) (*DisputeDTO, error) {
@@ -177,6 +215,9 @@ func (r *Repository) Arbitrate(adminID uint64, id uint64, req ArbitrateRequest,
if req.Result == "order_close" {
listing.Status = "offline"
account.Status = "offline"
} else if req.Result == "mark_abnormal" {
listing.Status = "abnormal"
account.Status = "abnormal"
} else {
listing.Status = "published"
account.Status = "published"
@@ -335,6 +376,8 @@ func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest) (
addRenterRefund(order.DepositAmount-deductAmount, "仲裁退回剩余押金给租客")
case "order_close":
// Only release frozen funds. No available-balance settlement happens in development mode.
case "mark_abnormal":
// 标记异常只释放冻结账务,后续由客服继续线下复核。
default:
return settlement, ErrInvalidDispute
}
@@ -395,11 +438,20 @@ func arbitrateOrderStatus(result string) string {
switch result {
case "full_refund", "partial_refund", "order_close":
return "closed"
case "mark_abnormal":
return "abnormal"
default:
return "completed"
}
}
func disputeType(input string, isCheckoutDispute bool) string {
if isCheckoutDispute {
return "checkout_dispute"
}
return input
}
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizType string, bizID uint64, meta AuditMeta, detail map[string]any) error {
raw, err := json.Marshal(detail)
if err != nil {