手动同步改为异步任务并前端轮询状态

This commit is contained in:
2026-07-04 12:10:33 +08:00
parent ab14eb9c30
commit 46013a2b2f
4 changed files with 98 additions and 23 deletions
+40 -7
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import {
BarChart3,
TrendingUp,
@@ -24,6 +24,7 @@ export function StockOverview({ role }: StockOverviewProps) {
const [loading, setLoading] = useState(true)
const [syncing, setSyncing] = useState(false)
const [error, setError] = useState('')
const pollRef = useRef<number | null>(null)
const canSync = canManageUsers(role)
@@ -43,20 +44,52 @@ export function StockOverview({ role }: StockOverviewProps) {
useEffect(() => {
fetchAll()
return () => {
if (pollRef.current) {
window.clearInterval(pollRef.current)
}
}
}, [])
const startPolling = () => {
if (pollRef.current) {
window.clearInterval(pollRef.current)
}
pollRef.current = window.setInterval(async () => {
try {
const j = await api.stockSyncStatus()
setJob(j)
if (!j || j.status !== 'running') {
if (pollRef.current) {
window.clearInterval(pollRef.current)
pollRef.current = null
}
setSyncing(false)
await fetchAll()
if (j?.status === 'failed') {
setError(j.error_message || '同步失败')
}
}
} catch (err: any) {
if (pollRef.current) {
window.clearInterval(pollRef.current)
pollRef.current = null
}
setSyncing(false)
setError(err?.message || '轮询同步状态失败')
}
}, 2000)
}
const handleSync = async () => {
setSyncing(true)
setError('')
try {
const res = await api.triggerStockSync()
await fetchAll()
// eslint-disable-next-line no-console
console.log('synced', res.records_count, 'records')
await api.triggerStockSync()
startPolling()
} catch (err: any) {
setError(err?.message || '同步失败')
} finally {
setSyncing(false)
setError(err?.message || '同步失败')
}
}
+2 -2
View File
@@ -58,7 +58,7 @@ export interface SyncJob {
records_count: number
started_at: string
finished_at?: string
error_message: string
error_message?: string
trigger_by: string
}
@@ -147,5 +147,5 @@ export const api = {
stockSyncStatus: () => request<SyncJob | null>('/api/stocks/sync/status'),
triggerStockSync: () =>
request<{ records_count: number }>('/api/admin/stocks/sync', { method: 'POST' }),
request<{ job: SyncJob }>('/api/admin/stocks/sync', { method: 'POST' }),
}