fix(selfop): preserve warehouse navigation and refine overview presentation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, onActivated, onDeactivated, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import AdminPage from '@/shared/components/AdminPage.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
|
||||
@@ -54,6 +54,7 @@ const fence = new RequestFence()
|
||||
const detailFence = new RequestFence()
|
||||
const actionFence = new RequestFence()
|
||||
const retryIntent = new RetryIntent()
|
||||
let active = false
|
||||
const warehouses = computed(() => overview.value?.warehouses.filter(row => !warehouseCode.value || row.warehouseCode === warehouseCode.value) ?? [])
|
||||
const fields = computed<QueryField[]>(() => [{ key: 'warehouseCode', label: '仓库', type: 'select', width: 230, placeholder: '全部仓库采集状态', options: [...new Map((overview.value?.warehouses ?? []).map(row => [row.warehouseCode, { label: row.warehouseName || row.warehouseCode, value: row.warehouseCode }])).values()] }])
|
||||
const hasSyntheticSamples = computed(() => warehouses.value.some(item => item.warehouseCode.startsWith('SELFOP-TEST-')))
|
||||
@@ -100,11 +101,12 @@ function blockReason(value: string | null | undefined) { return value ? reasonsT
|
||||
function budgetName(key: string) { return ({ pages: '分页HTTP', detailHttp: '详情HTTP', http: '全部HTTP保留额度', confirmedHttp: '已确认真实HTTP', distinctDetails: '不同详情对象', maxPages: '分页HTTP上限', maxPageSize: '每页数量上限', maxDistinctDetails: '不同详情对象上限', maxDetailHttp: '详情HTTP上限', maxInventoryPagesPerWarehouse: '每仓库存页上限', maxHttp: '全部HTTP上限' } as Record<string, string>)[key] ?? '其他保护额度' }
|
||||
function limitFor(used: string, value: Validation | null) { const key = ({ pages: 'maxPages', detailHttp: 'maxDetailHttp', http: 'maxHttp', confirmedHttp: 'maxHttp', distinctDetails: 'maxDistinctDetails' } as Record<string, string>)[used]; return key ? value?.budgetLimits?.[key] : null }
|
||||
async function read() {
|
||||
if (!canList.value) return false
|
||||
if (!active || !canList.value) return false
|
||||
const request = fence.begin()
|
||||
loading.value = !overview.value
|
||||
try {
|
||||
const nextOverview = await analyticsApi.overview(sourceAccount, undefined, request.signal)
|
||||
if (!request.current()) return false
|
||||
const tasks = warehouseCode.value ? await analyticsApi.tasks({ ...scope.value, current: current.value, size: size.value, ...upperBound.value }, request.signal) : null
|
||||
if (!request.current()) return false
|
||||
overview.value = nextOverview
|
||||
@@ -117,13 +119,14 @@ async function read() {
|
||||
finally { if (request.current()) loading.value = false }
|
||||
}
|
||||
async function selectTask(task: Task, reset = true) {
|
||||
if (!task.taskNo || task.warehouseCode !== warehouseCode.value) return
|
||||
if (!active || !task.taskNo || task.warehouseCode !== warehouseCode.value) return
|
||||
if (reset) { taskOpen.value = true; actionFence.cancel(); submitting.value = false; selected.value = task; selectedDetail.value = null; attempts.value = []; attemptsPage.value = 1; attemptsUpperBound.value = null; reason.value = ''; confirming.value = false; actionFeedback.value = '' }
|
||||
const request = detailFence.begin()
|
||||
detailLoading.value = true
|
||||
detailError.value = ''
|
||||
try {
|
||||
const detail = await analyticsApi.task(scope.value, task.taskNo, request.signal)
|
||||
if (!request.current()) return
|
||||
const history = await analyticsApi.runs({ ...scope.value, taskNo: task.taskNo, current: attemptsPage.value, size: attemptsSize.value, ...attemptsUpperBound.value }, request.signal)
|
||||
if (!request.current()) return
|
||||
if (detail.task.taskNo !== task.taskNo || detail.task.warehouseCode !== warehouseCode.value) throw new Error('任务归属不匹配')
|
||||
@@ -157,13 +160,21 @@ const poller = new RuntimePoller(async () => { const busy = await read(); if (se
|
||||
function visibility() { poller.setVisible(!document.hidden) }
|
||||
function refresh() { upperBound.value = null; current.value = 1; void read() }
|
||||
function openAnalysis(path: string) { void router.push({ path, query: { warehouseCode: warehouseCode.value } }) }
|
||||
watch([() => route.path, () => route.query], () => {
|
||||
if (route.path && route.path !== '/self-operated/collection') return
|
||||
filters.value.warehouseCode = typeof route.query.warehouseCode === 'string' ? route.query.warehouseCode : ''
|
||||
})
|
||||
watch(warehouseCode, () => { configOpen.value = false; taskOpen.value = false; fence.cancel(); detailFence.cancel(); actionFence.cancel(); selected.value = null; rows.value = []; total.value = 0; attempts.value = []; upperBound.value = null; confirming.value = false; submitting.value = false; reason.value = ''; actionFeedback.value = ''; current.value = 1; void read() })
|
||||
watch(taskOpen, open => { if (!open) { detailFence.cancel(); detailLoading.value = false; selected.value = null; selectedDetail.value = null; attempts.value = []; confirming.value = false; reason.value = ''; actionFeedback.value = '' } })
|
||||
watch([current, size], () => { void read() })
|
||||
watch([attemptsPage, attemptsSize], () => { if (selected.value) void selectTask(selected.value, false) })
|
||||
watch(reason, () => { confirming.value = false })
|
||||
onMounted(() => { visibility(); poller.start(); document.addEventListener('visibilitychange', visibility) })
|
||||
onUnmounted(() => { poller.stop(); actionFence.cancel(); document.removeEventListener('visibilitychange', visibility) })
|
||||
function resume() { if (active) return; active = true; visibility(); poller.start() }
|
||||
function suspend() { active = false; poller.stop(); actionFence.cancel(); configOpen.value = false; taskOpen.value = false; loading.value = false; detailLoading.value = false; submitting.value = false }
|
||||
onMounted(() => { resume(); document.addEventListener('visibilitychange', visibility) })
|
||||
onActivated(resume)
|
||||
onDeactivated(suspend)
|
||||
onUnmounted(() => { suspend(); document.removeEventListener('visibilitychange', visibility) })
|
||||
</script>
|
||||
<template>
|
||||
<AdminPage class="admin-density">
|
||||
|
||||
Reference in New Issue
Block a user