diff --git a/backend/internal/model/order.go b/backend/internal/model/order.go index f54b8bc..9016ecc 100644 --- a/backend/internal/model/order.go +++ b/backend/internal/model/order.go @@ -76,9 +76,11 @@ type RentalOrder struct { OwnerSettledAt *time.Time `json:"owner_settled_at"` SettledAt *time.Time `json:"settled_at"` // 推广归因:下单时由前端携带的短码,用于成交统计。 - SourceTrackCode string `gorm:"size:64;index:idx_rental_orders_source_track_code" json:"source_track_code,omitempty"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + SourceTrackCode string `gorm:"size:64;index:idx_rental_orders_source_track_code" json:"source_track_code,omitempty"` + // 号主从自己的订单列表隐藏的时间。订单、款项、租客和后台记录都保留。 + OwnerHiddenAt *time.Time `json:"-"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } func (RentalOrder) TableName() string { diff --git a/backend/internal/modules/order/dto.go b/backend/internal/modules/order/dto.go index c63c69c..7c7a13f 100644 --- a/backend/internal/modules/order/dto.go +++ b/backend/internal/modules/order/dto.go @@ -101,6 +101,7 @@ type UserOrderListItemDTO struct { DepositWaivedAmountCent int64 `json:"deposit_waived_amount_cent"` Status string `json:"status"` HandoffStatus string `json:"handoff_status"` + CanHide bool `json:"can_hide,omitempty"` PaymentDeadlineAt *time.Time `json:"payment_deadline_at,omitempty"` DistributionSiteID *uint64 `json:"distribution_site_id,omitempty"` CreatedAt time.Time `json:"created_at"` diff --git a/backend/internal/modules/order/handler_error.go b/backend/internal/modules/order/handler_error.go index a39cb48..2ad899b 100644 --- a/backend/internal/modules/order/handler_error.go +++ b/backend/internal/modules/order/handler_error.go @@ -30,6 +30,8 @@ func writeOrderError(c *gin.Context, err error) { response.Error(c, http.StatusConflict, "order_cannot_pay", "当前订单不能支付") case errors.Is(err, ErrOrderCannotCancel): response.Error(c, http.StatusConflict, "order_cannot_cancel", "当前订单不能取消") + case errors.Is(err, ErrOrderCannotHide): + response.Error(c, http.StatusConflict, "order_cannot_hide", "只有已结束且款项处理完毕的订单可以删除") case errors.Is(err, ErrOrderCannotHandoff): response.Error(c, http.StatusConflict, "order_cannot_handoff", "当前订单不能交接") case errors.Is(err, ErrOrderCannotForceHandoff): diff --git a/backend/internal/modules/order/handler_user.go b/backend/internal/modules/order/handler_user.go index 2d5738b..129a1f4 100644 --- a/backend/internal/modules/order/handler_user.go +++ b/backend/internal/modules/order/handler_user.go @@ -104,6 +104,23 @@ func (h *Handler) Cancel(c *gin.Context) { response.OK(c, gin.H{"cancelled": true}) } +func (h *Handler) HideForOwner(c *gin.Context) { + userID, ok := currentUserID(c) + if !ok { + response.Unauthorized(c, "缺少用户上下文") + return + } + id, ok := parseID(c) + if !ok { + return + } + if err := h.service.HideForOwner(c.Request.Context(), userID, id); err != nil { + writeOrderError(c, err) + return + } + response.OK(c, gin.H{"hidden": true}) +} + func (h *Handler) Pay(c *gin.Context) { userID, ok := currentUserID(c) if !ok { diff --git a/backend/internal/modules/order/owner_hide.go b/backend/internal/modules/order/owner_hide.go new file mode 100644 index 0000000..61a6c96 --- /dev/null +++ b/backend/internal/modules/order/owner_hide.go @@ -0,0 +1,112 @@ +package order + +import ( + "context" + "time" + + "hfb_sys/backend/internal/model" + + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +// ownerMayHideOrder 判断号主能否把订单从自己的列表里隐藏。 +// 进行中的订单、未结清的款项、暂扣押金、处理中争议和未释放的分销结算都不能藏。 +func ownerMayHideOrder(order model.RentalOrder, hasOpenDispute bool, distributionSettlement string) bool { + if order.OwnerHiddenAt != nil { + return false + } + switch order.Status { + case orderStatusCompleted, orderStatusClosed: + if order.SettlementStatus != settlementStatusSettled && + order.SettlementStatus != settlementStatusClosed && + order.SettlementStatus != settlementStatusArbitrated { + return false + } + if order.OfflineSettlementStatus == offlineSettlementStatusPending { + return false + } + case orderStatusCancelled: + default: + return false + } + switch order.RefundStatus { + case "", "none", refundStatusRefunded: + default: + return false + } + if order.DepositHoldStatus == model.DepositHoldStatusHeld { + return false + } + if hasOpenDispute { + return false + } + if distributionSettlement != "" && distributionSettlement != "settled" { + return false + } + return true +} + +type ownerHideSignal struct { + disputed map[uint64]struct{} + dist map[uint64]string +} + +func loadOwnerHideSignals(db *gorm.DB, orderIDs []uint64) (ownerHideSignal, error) { + signal := ownerHideSignal{ + disputed: map[uint64]struct{}{}, + dist: map[uint64]string{}, + } + if len(orderIDs) == 0 { + return signal, nil + } + var disputeIDs []uint64 + if err := db.Model(&model.Dispute{}). + Where("order_id IN ? AND status IN ?", orderIDs, []string{"open", "processing"}). + Distinct(). + Pluck("order_id", &disputeIDs).Error; err != nil { + return signal, err + } + for _, id := range disputeIDs { + signal.disputed[id] = struct{}{} + } + var rows []struct { + OrderID uint64 `gorm:"column:order_id"` + SettlementStatus string `gorm:"column:settlement_status"` + } + if err := db.Model(&model.DistributionOrderFinancial{}). + Select("order_id, settlement_status"). + Where("order_id IN ?", orderIDs). + Scan(&rows).Error; err != nil { + return signal, err + } + for _, row := range rows { + signal.dist[row.OrderID] = row.SettlementStatus + } + return signal, nil +} + +func (r *Repository) HideForOwner(ctx context.Context, userID uint64, orderID uint64) 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.OwnerID != userID { + return ErrPermissionDenied + } + if order.OwnerHiddenAt != nil { + return nil + } + signals, err := loadOwnerHideSignals(tx, []uint64{order.ID}) + if err != nil { + return err + } + _, disputed := signals.disputed[order.ID] + if !ownerMayHideOrder(order, disputed, signals.dist[order.ID]) { + return ErrOrderCannotHide + } + now := time.Now() + return tx.Model(&model.RentalOrder{}).Where("id = ?", order.ID).Update("owner_hidden_at", now).Error + }) +} diff --git a/backend/internal/modules/order/owner_hide_test.go b/backend/internal/modules/order/owner_hide_test.go new file mode 100644 index 0000000..90d358d --- /dev/null +++ b/backend/internal/modules/order/owner_hide_test.go @@ -0,0 +1,61 @@ +package order + +import ( + "testing" + "time" + + "hfb_sys/backend/internal/model" +) + +func settledHistoryOrder() model.RentalOrder { + return model.RentalOrder{ + Status: orderStatusCompleted, + SettlementStatus: settlementStatusSettled, + RefundStatus: "none", + DepositHoldStatus: model.DepositHoldStatusNone, + OfflineSettlementStatus: offlineSettlementStatusNone, + } +} + +func TestOwnerMayHideSettledHistory(t *testing.T) { + if !ownerMayHideOrder(settledHistoryOrder(), false, "") { + t.Fatal("已结算完成的订单应允许号主隐藏") + } + cancelled := settledHistoryOrder() + cancelled.Status = orderStatusCancelled + cancelled.SettlementStatus = settlementStatusUnsettled + if !ownerMayHideOrder(cancelled, false, "") { + t.Fatal("已取消且没有在途退款的订单应允许号主隐藏") + } +} + +func TestOwnerMayHideBlocksUnfinishedOrders(t *testing.T) { + cases := []struct { + name string + edit func(*model.RentalOrder) + dispute bool + dist string + }{ + {name: "租用中", edit: func(order *model.RentalOrder) { order.Status = orderStatusRenting }}, + {name: "退款审核中", edit: func(order *model.RentalOrder) { order.RefundStatus = refundStatusPendingReview }}, + {name: "押金暂扣", edit: func(order *model.RentalOrder) { order.DepositHoldStatus = model.DepositHoldStatusHeld }}, + {name: "线下结算未完成", edit: func(order *model.RentalOrder) { order.OfflineSettlementStatus = offlineSettlementStatusPending }}, + {name: "进行中争议", dispute: true}, + {name: "分销尚未释放", dist: "pending"}, + {name: "已经隐藏", edit: func(order *model.RentalOrder) { + now := time.Now() + order.OwnerHiddenAt = &now + }}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + order := settledHistoryOrder() + if tc.edit != nil { + tc.edit(&order) + } + if ownerMayHideOrder(order, tc.dispute, tc.dist) { + t.Fatal("该订单不应允许号主隐藏") + } + }) + } +} diff --git a/backend/internal/modules/order/queries.go b/backend/internal/modules/order/queries.go index 725aead..34cca55 100644 --- a/backend/internal/modules/order/queries.go +++ b/backend/internal/modules/order/queries.go @@ -14,8 +14,9 @@ import ( func (r *Repository) ListForUser(ctx context.Context, userID uint64, page, pageSize int, siteCode ...string) (*UserPaginatedResult, error) { page, pageSize = normalizePagination(page, pageSize) - base := r.baseQuery(ctx).Where("o.renter_id = ? OR o.owner_id = ?", userID, userID) - countBase := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.renter_id = ? OR o.owner_id = ?", userID, userID) + ownerVisible := "NOT (o.owner_id = ? AND o.owner_hidden_at IS NOT NULL)" + base := r.baseQuery(ctx).Where("o.renter_id = ? OR o.owner_id = ?", userID, userID).Where(ownerVisible, userID) + countBase := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.renter_id = ? OR o.owner_id = ?", userID, userID).Where(ownerVisible, userID) var code string if len(siteCode) > 0 { @@ -46,6 +47,16 @@ func (r *Repository) ListForUser(ctx context.Context, userID uint64, page, pageS if err != nil { return nil, err } + ownerOrderIDs := make([]uint64, 0, len(rows)) + for _, row := range rows { + if row.OwnerID == userID { + ownerOrderIDs = append(ownerOrderIDs, row.ID) + } + } + signals, err := loadOwnerHideSignals(db, ownerOrderIDs) + if err != nil { + return nil, err + } items := make([]UserOrderListItemDTO, 0, len(rows)) paymentTimeoutMinutes := pendingPaymentTimeoutMinutes(db) for _, row := range rows { @@ -54,7 +65,12 @@ func (r *Repository) ListForUser(ctx context.Context, userID uint64, page, pageS value := row.CreatedAt.Add(time.Duration(paymentTimeoutMinutes) * time.Minute) deadline = &value } - items = append(items, row.toUserListItem(userID, deadline)) + item := row.toUserListItem(userID, deadline) + if item.Role == "owner" { + _, disputed := signals.disputed[row.ID] + item.CanHide = ownerMayHideOrder(row.RentalOrder, disputed, signals.dist[row.ID]) + } + items = append(items, item) } return &UserPaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil } @@ -63,6 +79,7 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer page, pageSize := normalizePagination(query.Page, query.PageSize) base := r.baseQuery(ctx). Where("o.owner_id = ?", userID). + Where("o.owner_hidden_at IS NULL"). Where("o.status IN ?", sellerHandoffStatuses()) if query.Status != "" { base = base.Where("o.status = ?", query.Status) @@ -98,7 +115,7 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer } func (r *Repository) sellerHandoffMetrics(ctx context.Context, userID uint64, siteCode ...string) (SellerHandoffMetrics, error) { - base := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ?", userID) + base := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ? AND o.owner_hidden_at IS NULL", userID) if len(siteCode) > 0 && siteCode[0] != "" { base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", siteCode[0]) } @@ -372,7 +389,9 @@ func (r *Repository) FindLatestAdminByListing(ctx context.Context, listingID uin func (r *Repository) FindForUser(ctx context.Context, userID uint64, orderID uint64, siteCode ...string) (*OrderDTO, error) { var row orderRow db := r.db.WithContext(ctx) - query := r.baseQuery(ctx).Where("o.id = ? AND (o.renter_id = ? OR o.owner_id = ?)", orderID, userID, userID) + query := r.baseQuery(ctx). + Where("o.id = ? AND (o.renter_id = ? OR o.owner_id = ?)", orderID, userID, userID). + Where("NOT (o.owner_id = ? AND o.owner_hidden_at IS NOT NULL)", userID) var code string if len(siteCode) > 0 { diff --git a/backend/internal/modules/order/repository_integration_test.go b/backend/internal/modules/order/repository_integration_test.go index 506aa74..d7d0895 100644 --- a/backend/internal/modules/order/repository_integration_test.go +++ b/backend/internal/modules/order/repository_integration_test.go @@ -2625,3 +2625,132 @@ func TestLatestOwnerIncomeQueryIsSingleBatchStatement(t *testing.T) { t.Fatalf("应只取所需列,避免读取 content/evidence_urls 大字段,实际 SQL:\n%s", sql) } } + +func TestHideForOwnerRemovesSellerViewOnly(t *testing.T) { + db := setupOrderTestDB(t) + repo := NewRepository(db) + ctx := context.Background() + + owner := model.User{Phone: "13900007801"} + renter := model.User{Phone: "13900007802"} + if err := db.Create(&owner).Error; err != nil { + t.Fatalf("create owner: %v", err) + } + if err := db.Create(&renter).Error; err != nil { + t.Fatalf("create renter: %v", err) + } + account := model.GameAccount{OwnerID: owner.ID, ServerRegion: "QQ", LoginPlatform: "PC", Title: "隐藏测试号"} + if err := db.Create(&account).Error; err != nil { + t.Fatalf("create account: %v", err) + } + listing := model.RentalListing{ + ListingNo: "LST-HIDE-OWNER", + OwnerID: owner.ID, + AccountID: account.ID, + Status: listingStatusCompleted, + ReviewStatus: listingReviewStatusApproved, + PriceCent: 10000, + } + if err := db.Create(&listing).Error; err != nil { + t.Fatalf("create listing: %v", err) + } + history := model.RentalOrder{ + OrderNo: "ORD-HIDE-HISTORY", + ListingID: listing.ID, + AccountID: account.ID, + OwnerID: owner.ID, + RenterID: renter.ID, + Status: orderStatusCompleted, + SettlementStatus: settlementStatusSettled, + RefundStatus: "none", + DepositHoldStatus: model.DepositHoldStatusNone, + OfflineSettlementStatus: offlineSettlementStatusNone, + RentAmountCent: 10000, + OwnerRentAmountCent: 8000, + } + active := model.RentalOrder{ + OrderNo: "ORD-HIDE-ACTIVE", + ListingID: listing.ID, + AccountID: account.ID, + OwnerID: owner.ID, + RenterID: renter.ID, + Status: orderStatusRenting, + SettlementStatus: settlementStatusUnsettled, + RefundStatus: "none", + DepositHoldStatus: model.DepositHoldStatusNone, + RentAmountCent: 10000, + } + if err := db.Create(&history).Error; err != nil { + t.Fatalf("create history order: %v", err) + } + if err := db.Create(&active).Error; err != nil { + t.Fatalf("create active order: %v", err) + } + + before, err := repo.ListForUser(ctx, owner.ID, 1, 20) + if err != nil { + t.Fatalf("list before hide: %v", err) + } + var historyItem *UserOrderListItemDTO + for i := range before.Items { + if before.Items[i].ID == history.ID { + historyItem = &before.Items[i] + } + } + if historyItem == nil || !historyItem.CanHide || historyItem.Role != "owner" { + t.Fatalf("号主列表应标出可删除的历史单,got %#v", historyItem) + } + + if err := repo.HideForOwner(ctx, renter.ID, history.ID); !errors.Is(err, ErrPermissionDenied) { + t.Fatalf("租客隐藏应拒绝,got %v", err) + } + if err := repo.HideForOwner(ctx, owner.ID, active.ID); !errors.Is(err, ErrOrderCannotHide) { + t.Fatalf("进行中订单应拒绝隐藏,got %v", err) + } + if err := repo.HideForOwner(ctx, owner.ID, history.ID); err != nil { + t.Fatalf("号主隐藏历史单: %v", err) + } + if err := repo.HideForOwner(ctx, owner.ID, history.ID); err != nil { + t.Fatalf("重复隐藏应成功: %v", err) + } + + ownerList, err := repo.ListForUser(ctx, owner.ID, 1, 20) + if err != nil { + t.Fatalf("list owner after hide: %v", err) + } + if ownerList.Total != 1 || len(ownerList.Items) != 1 || ownerList.Items[0].ID != active.ID { + t.Fatalf("号主列表应只剩进行中订单,got total=%d items=%v", ownerList.Total, ownerList.Items) + } + renterList, err := repo.ListForUser(ctx, renter.ID, 1, 20) + if err != nil { + t.Fatalf("list renter after hide: %v", err) + } + seenHistory := false + for _, item := range renterList.Items { + if item.ID == history.ID { + seenHistory = true + if item.CanHide { + t.Fatal("租客视角不应出现删除入口") + } + } + } + if !seenHistory { + t.Fatal("租客仍应看到被号主隐藏的订单") + } + if _, err := repo.FindForUser(ctx, owner.ID, history.ID); !IsNotFound(err) { + t.Fatalf("号主打开已隐藏订单应不存在,got %v", err) + } + if _, err := repo.FindForUser(ctx, renter.ID, history.ID); err != nil { + t.Fatalf("租客仍应打开订单: %v", err) + } + if _, err := repo.FindAdmin(ctx, history.ID); err != nil { + t.Fatalf("后台仍应打开订单: %v", err) + } + var saved model.RentalOrder + if err := db.First(&saved, history.ID).Error; err != nil { + t.Fatalf("订单行应保留: %v", err) + } + if saved.OwnerHiddenAt == nil || saved.Status != orderStatusCompleted { + t.Fatalf("隐藏只写时间,订单状态应保持完成,got hidden=%v status=%s", saved.OwnerHiddenAt, saved.Status) + } +} diff --git a/backend/internal/modules/order/service.go b/backend/internal/modules/order/service.go index 0bf949a..cf81d44 100644 --- a/backend/internal/modules/order/service.go +++ b/backend/internal/modules/order/service.go @@ -34,6 +34,7 @@ var ( ErrDepositHoldAmountEmpty = errors.New("deposit hold amount empty") ErrOfflineSettlementCannotMark = errors.New("offline settlement cannot mark") ErrInvalidSellerHandoffStatus = errors.New("invalid seller handoff status") + ErrOrderCannotHide = errors.New("order cannot hide") ) const internalOrderHours = 24 @@ -63,6 +64,16 @@ func (s *Service) Cancel(ctx context.Context, userID uint64, orderID uint64) err return s.repo.Cancel(ctx, userID, orderID) } +func (s *Service) HideForOwner(ctx context.Context, userID uint64, orderID uint64) error { + if s.repo == nil { + return ErrDependencyUnavailable + } + if orderID == 0 { + return ErrOrderCannotHide + } + return s.repo.HideForOwner(ctx, userID, orderID) +} + func (s *Service) Pay(ctx context.Context, userID uint64, orderID uint64) error { if s.repo == nil { return ErrDependencyUnavailable diff --git a/backend/internal/router/router.go b/backend/internal/router/router.go index 2d87ea1..ee85881 100644 --- a/backend/internal/router/router.go +++ b/backend/internal/router/router.go @@ -529,6 +529,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine { orderRoutes.POST("/:id/start-payment", paymentHandler.Start) orderRoutes.GET("/:id/query-payment", paymentHandler.Query) orderRoutes.POST("/:id/cancel", orderHandler.Cancel) + orderRoutes.POST("/:id/hide", orderHandler.HideForOwner) orderRoutes.POST("/:id/handoff", orderHandler.SubmitHandoff) orderRoutes.GET("/:id/handoff-records", orderHandler.HandoffRecords) orderRoutes.POST("/:id/confirm-receive", orderHandler.ConfirmReceive) diff --git a/backend/migrations/000078_rental_order_owner_hidden_at.sql b/backend/migrations/000078_rental_order_owner_hidden_at.sql new file mode 100644 index 0000000..3a0a70e --- /dev/null +++ b/backend/migrations/000078_rental_order_owner_hidden_at.sql @@ -0,0 +1,12 @@ +-- +goose Up + +-- 号主可从自己的订单列表隐藏已结束订单。行数据保留,租客、后台和结算不受影响。 +ALTER TABLE rental_orders + ADD COLUMN owner_hidden_at DATETIME(6) NULL COMMENT '号主从自己的订单列表隐藏的时间' AFTER source_track_code, + ADD KEY idx_rental_orders_owner_hidden (owner_id, owner_hidden_at); + +-- +goose Down + +ALTER TABLE rental_orders + DROP KEY idx_rental_orders_owner_hidden, + DROP COLUMN owner_hidden_at; diff --git a/frontend/src/features/orders/api/orders.ts b/frontend/src/features/orders/api/orders.ts index 37a2555..2ca588b 100644 --- a/frontend/src/features/orders/api/orders.ts +++ b/frontend/src/features/orders/api/orders.ts @@ -94,6 +94,7 @@ export interface UserOrderListItem { deposit_waived_amount_cent: number status: OrderStatus handoff_status: HandoffStatus + can_hide?: boolean payment_deadline_at?: string created_at: string } @@ -385,6 +386,11 @@ export async function cancelOrder(id: number) { return data.data } +export async function hideOwnerOrder(id: number) { + const { data } = await apiClient.post>(`/orders/${id}/hide`) + return data.data +} + export async function submitHandoff(id: number, content: string) { const { data } = await apiClient.post>(`/orders/${id}/handoff`, { content, diff --git a/frontend/src/features/orders/views/MobileOrdersView.vue b/frontend/src/features/orders/views/MobileOrdersView.vue index 72a94f1..d1347e1 100644 --- a/frontend/src/features/orders/views/MobileOrdersView.vue +++ b/frontend/src/features/orders/views/MobileOrdersView.vue @@ -2,11 +2,12 @@ import { readError } from '@/shared/utils/error' import { onMounted, ref, computed, watch } from 'vue' import { useRouter, useRoute } from 'vue-router' -import { showToast } from 'vant' +import { showConfirmDialog, showToast } from 'vant' import MobileBottomNav from '@/components/MobileBottomNav.vue' import { fetchOrders, + hideOwnerOrder, startOrderPayment, type UserOrderListItem, } from '@/features/orders/api/orders' @@ -51,6 +52,7 @@ const rentalOrders = ref([]) const crashOrders = ref([]) const activeTab = ref('all') const payingOrderId = ref(null) +const hidingOrderId = ref(null) const rentalTotal = ref(0) const rentalPage = ref(1) const rentalPageSize = 20 @@ -213,6 +215,32 @@ function goDetail(item: UnifiedOrderItem) { router.push(`/m/orders/${item.id}`) } +async function handleHideOwnerOrder(order: UserOrderListItem) { + try { + await showConfirmDialog({ + title: '删除这条历史订单', + message: '只从你的订单列表移除,订单和款项记录仍会保留。', + confirmButtonText: '删除', + cancelButtonText: '取消', + }) + } catch { + return + } + hidingOrderId.value = order.id + try { + await hideOwnerOrder(order.id) + showToast({ message: '已从你的订单列表移除', icon: 'passed' }) + if (rentalOrders.value.filter(item => item.id !== order.id).length === 0 && rentalPage.value > 1) { + rentalPage.value -= 1 + } + await loadOrders() + } catch (error) { + showToast({ message: readError(error, '删除失败'), icon: 'cross' }) + } finally { + hidingOrderId.value = null + } +} + async function handlePay(order: UserOrderListItem) { const payWay = await selectPayWay() if (!payWay) return @@ -378,6 +406,18 @@ async function copyListingCode(order: UserOrderListItem) { {{ formatDateMinute(item.createdAt) }} + + 删除 +