fix: 账号页闪烁/浏览类型/截图复制/时区统一
This commit is contained in:
@@ -59,7 +59,6 @@ const editForm = reactive({
|
||||
|
||||
const browseTypeOptions = [
|
||||
{ label: '应读', value: '应读' },
|
||||
{ label: '未读', value: '未读' },
|
||||
{ label: '注册前未读', value: '注册前未读' },
|
||||
]
|
||||
|
||||
@@ -80,8 +79,13 @@ function normalizeAccountPayload(acc) {
|
||||
}
|
||||
|
||||
function replaceAccounts(list) {
|
||||
for (const key of Object.keys(accountsById)) delete accountsById[key]
|
||||
for (const acc of list || []) normalizeAccountPayload(acc)
|
||||
const nextList = Array.isArray(list) ? list : []
|
||||
const nextIds = new Set(nextList.map((acc) => String(acc?.id || '')))
|
||||
|
||||
for (const existingId of Object.keys(accountsById)) {
|
||||
if (!nextIds.has(existingId)) delete accountsById[existingId]
|
||||
}
|
||||
for (const acc of nextList) normalizeAccountPayload(acc)
|
||||
}
|
||||
|
||||
function ensureBrowseTypeDefaults() {
|
||||
@@ -138,8 +142,9 @@ function showRuntimeProgress(acc) {
|
||||
return true
|
||||
}
|
||||
|
||||
async function refreshStats() {
|
||||
statsLoading.value = true
|
||||
async function refreshStats(options = {}) {
|
||||
const silent = Boolean(options?.silent)
|
||||
if (!silent) statsLoading.value = true
|
||||
try {
|
||||
const data = await fetchRunStats()
|
||||
stats.today_completed = Number(data?.today_completed || 0)
|
||||
@@ -150,7 +155,7 @@ async function refreshStats() {
|
||||
} catch (e) {
|
||||
if (e?.response?.status === 401) window.location.href = '/login'
|
||||
} finally {
|
||||
statsLoading.value = false
|
||||
if (!silent) statsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,6 +461,41 @@ function bindSocket() {
|
||||
let unbindSocket = null
|
||||
let statsTimer = null
|
||||
|
||||
const shouldPollStats = computed(() => {
|
||||
// 仅在“真正执行中”才轮询(排队中不轮询,避免空转导致页面闪烁)
|
||||
return accounts.value.some((acc) => {
|
||||
if (!acc?.is_running) return false
|
||||
const statusText = String(acc.status || '')
|
||||
if (statusText.includes('排队')) return false
|
||||
return true
|
||||
})
|
||||
})
|
||||
|
||||
function stopStatsPolling() {
|
||||
if (!statsTimer) return
|
||||
window.clearInterval(statsTimer)
|
||||
statsTimer = null
|
||||
}
|
||||
|
||||
function startStatsPolling() {
|
||||
if (statsTimer) return
|
||||
statsTimer = window.setInterval(() => refreshStats({ silent: true }), 10_000)
|
||||
}
|
||||
|
||||
function syncStatsPolling(prevRunning = null) {
|
||||
const running = shouldPollStats.value
|
||||
|
||||
// 任务从“运行中 -> 空闲”时,补拉一次统计以确保最终数据正确,再停止轮询
|
||||
if (prevRunning === true && running === false) refreshStats({ silent: true }).catch(() => {})
|
||||
|
||||
if (running) startStatsPolling()
|
||||
else stopStatsPolling()
|
||||
}
|
||||
|
||||
watch(shouldPollStats, (running, prevRunning) => {
|
||||
syncStatsPolling(prevRunning)
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
if (!userStore.vipInfo) {
|
||||
userStore.refreshVipInfo().catch(() => {
|
||||
@@ -467,12 +507,12 @@ onMounted(async () => {
|
||||
|
||||
await refreshAccounts()
|
||||
await refreshStats()
|
||||
statsTimer = window.setInterval(refreshStats, 10_000)
|
||||
syncStatsPolling()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (unbindSocket) unbindSocket()
|
||||
if (statsTimer) window.clearInterval(statsTimer)
|
||||
stopStatsPolling()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -565,7 +605,7 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-skeleton v-if="loading || statsLoading" :rows="5" animated />
|
||||
<el-skeleton v-if="loading" :rows="5" animated />
|
||||
<template v-else>
|
||||
<el-empty v-if="accounts.length === 0" description="暂无账号,点击右上角添加" />
|
||||
<div v-else class="grid">
|
||||
|
||||
Reference in New Issue
Block a user