新增退款待审核角标提醒

This commit is contained in:
yml2213
2026-08-28 23:10:07 +08:00
parent 41a5b49450
commit a9a9127076
8 changed files with 176 additions and 1 deletions
@@ -0,0 +1,89 @@
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { RouteLocationNormalizedLoaded } from 'vue-router'
import { fetchPendingRefundCount } from '@/features/orders/api/orders'
import { useAdminSessionStore } from '@/stores/adminSession'
export const pendingRefundCountChangedEvent = 'pending-refund-count-changed'
export function usePendingRefundCount(route: RouteLocationNormalizedLoaded) {
const adminSession = useAdminSessionStore()
const count = ref(0)
let timer: number | null = null
let requestID = 0
const label = computed(() => (count.value > 99 ? '99+' : String(count.value)))
const canReviewRefund = computed(
() => adminSession.isSuperAdmin || adminSession.hasPermission('order:close')
)
function stopPolling() {
if (timer === null) return
window.clearInterval(timer)
timer = null
}
async function refresh() {
if (!canReviewRefund.value) {
count.value = 0
return
}
const currentID = ++requestID
try {
const nextCount = await fetchPendingRefundCount()
if (currentID === requestID) count.value = nextCount
} catch {
// 角标加载失败时保持当前数字,避免影响后台其他操作。
}
}
function startPolling() {
stopPolling()
void refresh()
timer = window.setInterval(refresh, 30_000)
}
function handleVisibilityChange() {
if (document.hidden) {
stopPolling()
return
}
startPolling()
}
function handleCountChanged() {
void refresh()
}
onMounted(() => {
window.addEventListener(pendingRefundCountChangedEvent, handleCountChanged)
document.addEventListener('visibilitychange', handleVisibilityChange)
if (!document.hidden) startPolling()
})
onBeforeUnmount(() => {
stopPolling()
window.removeEventListener(pendingRefundCountChangedEvent, handleCountChanged)
document.removeEventListener('visibilitychange', handleVisibilityChange)
})
watch(canReviewRefund, canReview => {
if (canReview && !document.hidden) {
startPolling()
return
}
stopPolling()
count.value = 0
})
watch(
() => route.fullPath,
() => void refresh()
)
return {
pendingRefundCount: count,
pendingRefundLabel: label,
refreshPendingRefundCount: refresh,
}
}
@@ -14,6 +14,7 @@ import { formatCentWithSymbol } from '@/shared/utils/money'
import { orderStatusLabel, handoffStatusLabel } from '@/shared/utils/statusLabels'
import { readError } from '@/shared/utils/error'
import { adminPath } from '@/shared/utils/adminPath'
import { pendingRefundCountChangedEvent } from '@/features/admin/composables/usePendingRefundCount'
const router = useRouter()
const loading = ref(false)
@@ -46,6 +47,7 @@ async function handleApprove(row: Order) {
submitting.value = true
try {
await adminApproveRefund(row.id)
window.dispatchEvent(new Event(pendingRefundCountChangedEvent))
ElMessage.success(`退款审核通过,${row.order_no} 已发起退款`)
await loadOrders()
} catch (error) {
@@ -75,6 +77,7 @@ async function handleRejectRestore() {
submitting.value = true
try {
await adminRejectRefund(row.id, 'restore')
window.dispatchEvent(new Event(pendingRefundCountChangedEvent))
ElMessage.success(`退款已驳回,${row.order_no} 已恢复至待交接状态`)
rejectVisible.value = false
await loadOrders()
@@ -100,6 +103,7 @@ async function handleRejectClose() {
submitting.value = true
try {
await adminRejectRefund(row.id, 'close')
window.dispatchEvent(new Event(pendingRefundCountChangedEvent))
ElMessage.success(`退款已驳回,${row.order_no} 已关闭`)
rejectVisible.value = false
await loadOrders()