优化号主交接超时卡死问题
- 号主交接超时(owner_timeout)后允许补提交交接说明,避免临时延误导致订单卡死 - 后台新增"重置交接"动作,可将超时订单恢复为待号主交接并刷新计时 - 交接超时改以进入待交接时刻为基准计算,新增 handoff_started_at 字段 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ae11dd7b8d
commit
8192344027
@@ -275,7 +275,7 @@ func (j *Job) handleOwnerSubmitTimeout(ctx context.Context, now time.Time, cfg t
|
|||||||
}
|
}
|
||||||
var rows []model.RentalOrder
|
var rows []model.RentalOrder
|
||||||
err := j.db.WithContext(ctx).
|
err := j.db.WithContext(ctx).
|
||||||
Where("status = ? AND handoff_status = ? AND created_at <= ?", "pending_handoff", "pending_owner", now.Add(-time.Duration(cfg.OwnerSubmitTimeoutMinutes)*time.Minute)).
|
Where("status = ? AND handoff_status = ? AND COALESCE(handoff_started_at, created_at) <= ?", "pending_handoff", "pending_owner", now.Add(-time.Duration(cfg.OwnerSubmitTimeoutMinutes)*time.Minute)).
|
||||||
Order("id ASC").
|
Order("id ASC").
|
||||||
Limit(100).
|
Limit(100).
|
||||||
Find(&rows).Error
|
Find(&rows).Error
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type RentalOrder struct {
|
|||||||
OwnerID uint64 `gorm:"not null;index" json:"owner_id"`
|
OwnerID uint64 `gorm:"not null;index" json:"owner_id"`
|
||||||
RenterID uint64 `gorm:"not null;index" json:"renter_id"`
|
RenterID uint64 `gorm:"not null;index" json:"renter_id"`
|
||||||
RentedAt *time.Time `json:"rented_at"`
|
RentedAt *time.Time `json:"rented_at"`
|
||||||
|
HandoffStartedAt *time.Time `json:"handoff_started_at"`
|
||||||
EstimatedDurationHours int `gorm:"not null;default:24" json:"estimated_duration_hours"`
|
EstimatedDurationHours int `gorm:"not null;default:24" json:"estimated_duration_hours"`
|
||||||
RentAmountCent int64 `gorm:"not null;default:0" json:"-"`
|
RentAmountCent int64 `gorm:"not null;default:0" json:"-"`
|
||||||
OwnerRentAmountCent int64 `gorm:"not null;default:0" json:"-"`
|
OwnerRentAmountCent int64 `gorm:"not null;default:0" json:"-"`
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"hfb_sys/backend/internal/modules/notification"
|
"hfb_sys/backend/internal/modules/notification"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Repository) AdminClose(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
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 模块走渠道原路退回。
|
// AdminRefund 触发后台人工退款,退款由 payment 模块走渠道原路退回。
|
||||||
func (r *Repository) AdminRefund(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
|
func (r *Repository) AdminRefund(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
|
||||||
var order model.RentalOrder
|
var order model.RentalOrder
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const (
|
|||||||
handoffStatusPendingOwnerCheckout = "pending_owner_checkout"
|
handoffStatusPendingOwnerCheckout = "pending_owner_checkout"
|
||||||
handoffStatusPendingRenterCheckout = "pending_renter_checkout"
|
handoffStatusPendingRenterCheckout = "pending_renter_checkout"
|
||||||
handoffStatusReturned = "returned"
|
handoffStatusReturned = "returned"
|
||||||
|
handoffStatusOwnerTimeout = "owner_timeout"
|
||||||
handoffStatusCancelled = "cancelled"
|
handoffStatusCancelled = "cancelled"
|
||||||
handoffStatusAdminClosed = "admin_closed"
|
handoffStatusAdminClosed = "admin_closed"
|
||||||
handoffStatusAdminAbnormal = "admin_abnormal"
|
handoffStatusAdminAbnormal = "admin_abnormal"
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ func (h *Handler) AdminMarkAbnormal(c *gin.Context) {
|
|||||||
h.adminAction(c, h.service.AdminMarkAbnormal, gin.H{"abnormal": true})
|
h.adminAction(c, h.service.AdminMarkAbnormal, gin.H{"abnormal": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) AdminResetHandoff(c *gin.Context) {
|
||||||
|
h.adminAction(c, h.service.AdminResetHandoff, gin.H{"reset": true})
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) AdminRefund(c *gin.Context) {
|
func (h *Handler) AdminRefund(c *gin.Context) {
|
||||||
orderID, ok := parseID(c)
|
orderID, ok := parseID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ func writeOrderError(c *gin.Context, err error) {
|
|||||||
response.Error(c, http.StatusConflict, "order_cannot_cancel", "当前订单不能取消")
|
response.Error(c, http.StatusConflict, "order_cannot_cancel", "当前订单不能取消")
|
||||||
case errors.Is(err, ErrOrderCannotHandoff):
|
case errors.Is(err, ErrOrderCannotHandoff):
|
||||||
response.Error(c, http.StatusConflict, "order_cannot_handoff", "当前订单不能交接")
|
response.Error(c, http.StatusConflict, "order_cannot_handoff", "当前订单不能交接")
|
||||||
|
case errors.Is(err, ErrOrderCannotResetHandoff):
|
||||||
|
response.Error(c, http.StatusConflict, "order_cannot_reset_handoff", "仅号主交接超时的订单可重置交接")
|
||||||
case errors.Is(err, ErrOrderCannotReceive):
|
case errors.Is(err, ErrOrderCannotReceive):
|
||||||
response.Error(c, http.StatusConflict, "order_cannot_receive", "当前订单不能确认收号")
|
response.Error(c, http.StatusConflict, "order_cannot_receive", "当前订单不能确认收号")
|
||||||
case errors.Is(err, ErrOrderCannotReturn):
|
case errors.Is(err, ErrOrderCannotReturn):
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ func (r *Repository) SubmitHandoff(ctx context.Context, userID uint64, orderID u
|
|||||||
if order.OwnerID != userID {
|
if order.OwnerID != userID {
|
||||||
return ErrPermissionDenied
|
return ErrPermissionDenied
|
||||||
}
|
}
|
||||||
if order.Status != orderStatusPendingHandoff || order.HandoffStatus != handoffStatusPendingOwner {
|
// 号主交接超时(owner_timeout)后仍允许补提交,避免临时延误导致订单卡死。
|
||||||
|
if order.Status != orderStatusPendingHandoff ||
|
||||||
|
(order.HandoffStatus != handoffStatusPendingOwner && order.HandoffStatus != handoffStatusOwnerTimeout) {
|
||||||
return ErrOrderCannotHandoff
|
return ErrOrderCannotHandoff
|
||||||
}
|
}
|
||||||
|
lateSubmit := order.HandoffStatus == handoffStatusOwnerTimeout
|
||||||
record := model.HandoffRecord{
|
record := model.HandoffRecord{
|
||||||
OrderID: order.ID,
|
OrderID: order.ID,
|
||||||
FromUserID: order.OwnerID,
|
FromUserID: order.OwnerID,
|
||||||
@@ -35,11 +38,15 @@ func (r *Repository) SubmitHandoff(ctx context.Context, userID uint64, orderID u
|
|||||||
}
|
}
|
||||||
order.HandoffStatus = handoffStatusPendingRenterConfirm
|
order.HandoffStatus = handoffStatusPendingRenterConfirm
|
||||||
orderID := order.ID
|
orderID := order.ID
|
||||||
|
renterContent := "请查看交接记录,确认账号可正常登录后点击确认收号。"
|
||||||
|
if lateSubmit {
|
||||||
|
renterContent = "号主已补交交接说明,请查看交接记录,确认账号可正常登录后点击确认收号。"
|
||||||
|
}
|
||||||
if err := notification.Append(tx, notification.Entry{
|
if err := notification.Append(tx, notification.Entry{
|
||||||
UserID: order.RenterID,
|
UserID: order.RenterID,
|
||||||
Type: "handoff",
|
Type: "handoff",
|
||||||
Title: "号主已提交交接说明",
|
Title: "号主已提交交接说明",
|
||||||
Content: "请查看交接记录,确认账号可正常登录后点击确认收号。",
|
Content: renterContent,
|
||||||
BizType: "order",
|
BizType: "order",
|
||||||
BizID: &orderID,
|
BizID: &orderID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|||||||
@@ -177,8 +177,10 @@ func (r *Repository) ConfirmPaidFromChannelTx(tx *gorm.DB, orderID uint64) (uint
|
|||||||
|
|
||||||
// 租客已通过外部渠道付款,这里不写租客钱包流水。
|
// 租客已通过外部渠道付款,这里不写租客钱包流水。
|
||||||
orderID = order.ID
|
orderID = order.ID
|
||||||
|
now := time.Now()
|
||||||
order.Status = orderStatusPendingHandoff
|
order.Status = orderStatusPendingHandoff
|
||||||
order.HandoffStatus = handoffStatusPendingOwner
|
order.HandoffStatus = handoffStatusPendingOwner
|
||||||
|
order.HandoffStartedAt = &now
|
||||||
markAssetsRented(listing, account)
|
markAssetsRented(listing, account)
|
||||||
conv, err := chat.EnsureOrderConversation(tx, *order)
|
conv, err := chat.EnsureOrderConversation(tx, *order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ var (
|
|||||||
ErrChannelPaymentRequired = errors.New("channel payment required")
|
ErrChannelPaymentRequired = errors.New("channel payment required")
|
||||||
ErrOrderCannotCancel = errors.New("order cannot cancel")
|
ErrOrderCannotCancel = errors.New("order cannot cancel")
|
||||||
ErrOrderCannotHandoff = errors.New("order cannot handoff")
|
ErrOrderCannotHandoff = errors.New("order cannot handoff")
|
||||||
|
ErrOrderCannotResetHandoff = errors.New("order cannot reset handoff")
|
||||||
ErrOrderCannotReceive = errors.New("order cannot receive")
|
ErrOrderCannotReceive = errors.New("order cannot receive")
|
||||||
ErrOrderCannotReturn = errors.New("order cannot return")
|
ErrOrderCannotReturn = errors.New("order cannot return")
|
||||||
ErrOrderCannotComplete = errors.New("order cannot complete")
|
ErrOrderCannotComplete = errors.New("order cannot complete")
|
||||||
@@ -185,6 +186,16 @@ func (s *Service) AdminMarkAbnormal(ctx context.Context, adminID uint64, orderID
|
|||||||
return s.repo.AdminMarkAbnormal(ctx, adminID, orderID, req, meta)
|
return s.repo.AdminMarkAbnormal(ctx, adminID, orderID, req, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) AdminResetHandoff(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
||||||
|
if s.repo == nil {
|
||||||
|
return ErrDependencyUnavailable
|
||||||
|
}
|
||||||
|
if orderID == 0 || req.Reason == "" {
|
||||||
|
return ErrOrderCannotResetHandoff
|
||||||
|
}
|
||||||
|
return s.repo.AdminResetHandoff(ctx, adminID, orderID, req, meta)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) AdminRefund(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
|
func (s *Service) AdminRefund(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
|
|||||||
@@ -487,6 +487,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
|
|||||||
adminRoutes.GET("/orders/:id/handoff-records", requirePerm("order:view"), orderHandler.AdminHandoffRecords)
|
adminRoutes.GET("/orders/:id/handoff-records", requirePerm("order:view"), orderHandler.AdminHandoffRecords)
|
||||||
adminRoutes.POST("/orders/:id/close", requirePerm("order:close"), orderHandler.AdminClose)
|
adminRoutes.POST("/orders/:id/close", requirePerm("order:close"), orderHandler.AdminClose)
|
||||||
adminRoutes.POST("/orders/:id/mark-abnormal", requirePerm("order:mark_abnormal"), orderHandler.AdminMarkAbnormal)
|
adminRoutes.POST("/orders/:id/mark-abnormal", requirePerm("order:mark_abnormal"), orderHandler.AdminMarkAbnormal)
|
||||||
|
adminRoutes.POST("/orders/:id/reset-handoff", requirePerm("order:mark_abnormal"), orderHandler.AdminResetHandoff)
|
||||||
adminRoutes.POST("/orders/:id/refund", requirePerm("order:close"), orderHandler.AdminRefund)
|
adminRoutes.POST("/orders/:id/refund", requirePerm("order:close"), orderHandler.AdminRefund)
|
||||||
adminRoutes.GET("/orders/:id/refund-status", requirePerm("order:view"), orderHandler.AdminRefundStatus)
|
adminRoutes.GET("/orders/:id/refund-status", requirePerm("order:view"), orderHandler.AdminRefundStatus)
|
||||||
adminRoutes.GET("/listings", requirePerm("listing:view"), listingHandler.ListAdmin)
|
adminRoutes.GET("/listings", requirePerm("listing:view"), listingHandler.ListAdmin)
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
-- +goose Up
|
||||||
|
|
||||||
|
-- 新增进入“待号主交接”的时间,用于精确计算号主交接超时(以支付完成时刻为基准,而非订单创建时刻)。
|
||||||
|
ALTER TABLE rental_orders
|
||||||
|
ADD COLUMN handoff_started_at DATETIME NULL COMMENT '进入待号主交接的时间,用于计算交接超时' AFTER rented_at;
|
||||||
|
|
||||||
|
-- 历史数据兜底:已进入交接及之后阶段的订单,用 created_at 回填,避免基准缺失。
|
||||||
|
UPDATE rental_orders
|
||||||
|
SET handoff_started_at = created_at
|
||||||
|
WHERE handoff_started_at IS NULL
|
||||||
|
AND status NOT IN ('pending_payment', 'cancelled');
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
|
||||||
|
ALTER TABLE rental_orders DROP COLUMN handoff_started_at;
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
adminMarkOrderAbnormal,
|
adminMarkOrderAbnormal,
|
||||||
adminRefundOrder,
|
adminRefundOrder,
|
||||||
adminRefundStatus,
|
adminRefundStatus,
|
||||||
|
adminResetHandoff,
|
||||||
fetchAdminHandoffRecords,
|
fetchAdminHandoffRecords,
|
||||||
fetchAdminOrder,
|
fetchAdminOrder,
|
||||||
type HandoffRecord,
|
type HandoffRecord,
|
||||||
@@ -28,7 +29,7 @@ const submitting = ref(false)
|
|||||||
const order = ref<Order | null>(null)
|
const order = ref<Order | null>(null)
|
||||||
const handoffRecords = ref<HandoffRecord[]>([])
|
const handoffRecords = ref<HandoffRecord[]>([])
|
||||||
const paymentRecords = ref<AdminPayment[]>([])
|
const paymentRecords = ref<AdminPayment[]>([])
|
||||||
const actionType = ref<'close' | 'abnormal' | ''>('')
|
const actionType = ref<'close' | 'abnormal' | 'reset' | ''>('')
|
||||||
const reason = ref('')
|
const reason = ref('')
|
||||||
const refundStatus = ref<RefundStatus | null>(null)
|
const refundStatus = ref<RefundStatus | null>(null)
|
||||||
const listingCode = computed(() =>
|
const listingCode = computed(() =>
|
||||||
@@ -37,10 +38,20 @@ const listingCode = computed(() =>
|
|||||||
const refunding = ref(false)
|
const refunding = ref(false)
|
||||||
|
|
||||||
const snapshotText = computed(() => JSON.stringify(order.value?.account_snapshot || {}, null, 2))
|
const snapshotText = computed(() => JSON.stringify(order.value?.account_snapshot || {}, null, 2))
|
||||||
const actionTitle = computed(() => (actionType.value === 'close' ? '客服关闭订单' : '标记订单异常'))
|
const actionTitle = computed(() => {
|
||||||
|
if (actionType.value === 'close') return '客服关闭订单'
|
||||||
|
if (actionType.value === 'reset') return '重置交接(给号主再次机会)'
|
||||||
|
return '标记订单异常'
|
||||||
|
})
|
||||||
const canOperate = computed(
|
const canOperate = computed(
|
||||||
() => !!order.value && !['completed', 'cancelled', 'closed'].includes(order.value.status)
|
() => !!order.value && !['completed', 'cancelled', 'closed'].includes(order.value.status)
|
||||||
)
|
)
|
||||||
|
const canResetHandoff = computed(
|
||||||
|
() =>
|
||||||
|
!!order.value &&
|
||||||
|
order.value.status === 'pending_handoff' &&
|
||||||
|
order.value.handoff_status === 'owner_timeout'
|
||||||
|
)
|
||||||
|
|
||||||
onMounted(loadOrder)
|
onMounted(loadOrder)
|
||||||
|
|
||||||
@@ -64,7 +75,7 @@ async function loadRefundStatus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openAction(type: 'close' | 'abnormal') {
|
function openAction(type: 'close' | 'abnormal' | 'reset') {
|
||||||
actionType.value = type
|
actionType.value = type
|
||||||
reason.value = ''
|
reason.value = ''
|
||||||
}
|
}
|
||||||
@@ -76,6 +87,9 @@ async function submitAction() {
|
|||||||
if (actionType.value === 'close') {
|
if (actionType.value === 'close') {
|
||||||
await adminCloseOrder(order.value.id, reason.value)
|
await adminCloseOrder(order.value.id, reason.value)
|
||||||
ElMessage.success('订单已关闭')
|
ElMessage.success('订单已关闭')
|
||||||
|
} else if (actionType.value === 'reset') {
|
||||||
|
await adminResetHandoff(order.value.id, reason.value)
|
||||||
|
ElMessage.success('交接已重置,等待号主重新提交')
|
||||||
} else {
|
} else {
|
||||||
await adminMarkOrderAbnormal(order.value.id, reason.value)
|
await adminMarkOrderAbnormal(order.value.id, reason.value)
|
||||||
ElMessage.success('订单已标记异常')
|
ElMessage.success('订单已标记异常')
|
||||||
@@ -197,6 +211,9 @@ function formatHandoffRecordType(type: string) {
|
|||||||
<RouterLink :to="adminPath('orders')">
|
<RouterLink :to="adminPath('orders')">
|
||||||
<el-button>返回列表</el-button>
|
<el-button>返回列表</el-button>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
<el-button v-if="canResetHandoff" type="success" @click="openAction('reset')"
|
||||||
|
>重置交接</el-button
|
||||||
|
>
|
||||||
<el-button type="warning" :disabled="!canOperate" @click="openAction('abnormal')"
|
<el-button type="warning" :disabled="!canOperate" @click="openAction('abnormal')"
|
||||||
>标记异常</el-button
|
>标记异常</el-button
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -321,6 +321,13 @@ export async function adminMarkOrderAbnormal(id: number, reason: string) {
|
|||||||
return data.data
|
return data.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function adminResetHandoff(id: number, reason: string) {
|
||||||
|
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/reset-handoff`, {
|
||||||
|
reason,
|
||||||
|
})
|
||||||
|
return data.data
|
||||||
|
}
|
||||||
|
|
||||||
export async function adminRefundStatus(id: number) {
|
export async function adminRefundStatus(id: number) {
|
||||||
const { data } = await apiClient.get<ApiResponse<RefundStatus>>(
|
const { data } = await apiClient.get<ApiResponse<RefundStatus>>(
|
||||||
`/admin/orders/${id}/refund-status`
|
`/admin/orders/${id}/refund-status`
|
||||||
|
|||||||
Reference in New Issue
Block a user