feat: focus collection page on account activity and progress
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { Overview, Task } from '../types'
|
||||
import CollectionTaskProgress from './CollectionTaskProgress.vue'
|
||||
import { beijingTime, phaseText } from '../state'
|
||||
import { taskStateText } from '../collectionPresentation'
|
||||
|
||||
const props = defineProps<{ overview: Overview | null; loading?: boolean; stale?: boolean; visible?: boolean }>()
|
||||
defineEmits<{ refresh: [] }>()
|
||||
const activeStates = new Set(['RUNNING', 'APPLYING', 'READY', 'QUEUED', 'WAITING', 'WAITING_SOURCE', 'WAITING_UPSTREAM', 'RETRY_WAIT', 'YIELDED'])
|
||||
const tasks = computed(() => {
|
||||
const all = [props.overview?.accountActivity, ...(props.overview?.warehouses.flatMap(w => [...(w.activeTasks ?? []), w.sharedUpstream]) ?? [])]
|
||||
return [...new Map(all.filter((t): t is Task => Boolean(t && activeStates.has(t.taskStatus))).map(t => [t.taskNo, t])).values()]
|
||||
})
|
||||
const running = computed(() => tasks.value.filter(t => ['RUNNING', 'APPLYING'].includes(t.taskStatus)))
|
||||
const current = computed(() => running.value[0] ?? tasks.value[0] ?? null)
|
||||
const waiting = computed(() => tasks.value.filter(t => t.taskNo !== current.value?.taskNo && !['RUNNING', 'APPLYING'].includes(t.taskStatus)))
|
||||
const upcoming = computed(() => {
|
||||
const groups = new Map<string, number>()
|
||||
for (const task of waiting.value) {
|
||||
const name = `${task.warehouseCode || '账号'} · ${task.dataFamily === 'INVENTORY' ? '产品库存' : '出库销量'}`
|
||||
groups.set(name, (groups.get(name) ?? 0) + 1)
|
||||
}
|
||||
return [...groups].map(([name, count]) => ({ name, count }))
|
||||
})
|
||||
const nextStep = computed(() => {
|
||||
const phase = current.value?.progress?.phase
|
||||
if (['DIRECTORY', 'DISCOVERY'].includes(phase ?? '')) return '获取出库详情 → 各仓校验与归并 → 统计计算 → 发布结果'
|
||||
if (['DETAIL', 'DETAILS'].includes(phase ?? '')) return '各仓校验与归并 → 统计计算 → 发布结果'
|
||||
if (['INVENTORY', 'FETCH'].includes(phase ?? '')) return '库存完整性校验 → 统计计算 → 发布结果'
|
||||
if (['VALIDATE', 'VALIDATION', 'MERGE'].includes(phase ?? '')) return '统计计算 → 发布结果'
|
||||
if (['BUILD', 'BUILDING', 'BUILT'].includes(phase ?? '')) return '发布结果'
|
||||
if (['PUBLISH', 'PUBLISHED'].includes(phase ?? '')) return '本次发布完成后,由调度继续安排后续任务'
|
||||
return '等待调度确认下一步'
|
||||
})
|
||||
const scopeText = computed(() => current.value?.taskNo === props.overview?.accountActivity?.taskNo || current.value?.progress?.progressScope === 'ACCOUNT_SHARED' ? '领星账号 · 出库数据' : `${current.value?.warehouseCode || '领星账号'} · ${current.value?.dataFamily === 'INVENTORY' ? '产品库存' : '出库销量'}`)
|
||||
</script>
|
||||
<template>
|
||||
<section class="account-monitor" aria-label="领星账号运行进度">
|
||||
<header class="account-header"><div><h2>数据采集</h2><span>领星账号</span></div><el-button :loading="loading" @click="$emit('refresh')">刷新状态</el-button></header>
|
||||
<div class="account-body">
|
||||
<p v-if="stale" role="status">状态更新失败,以下保留最后一次读取的进度。</p>
|
||||
<template v-if="current">
|
||||
<div class="account-now"><div><span class="account-eyebrow">{{ running.length ? '正在进行' : '当前等待' }}</span><h3>{{ current.progress?.phase ? phaseText(current.progress.phase) : taskStateText(current) }}</h3><p>{{ scopeText }}<template v-if="current.queryFrom"> · {{ beijingTime(current.queryFrom) }} 至 {{ beijingTime(current.queryUntil) }}(结束时刻不含)</template></p></div><span class="account-status">{{ taskStateText(current) }}</span></div>
|
||||
<CollectionTaskProgress :key="current.taskNo" :task="current" compact :stale="stale" :visible="visible" :observed-at="overview?.observedAt" />
|
||||
<div class="account-next"><strong>后续处理</strong><span>{{ nextStep }}<small>流程参考,实际切换由调度确认。</small></span></div>
|
||||
<p v-if="running.length > 1">同时运行:<span v-for="task in running.slice(1)" :key="task.taskNo">{{ task.warehouseCode || '账号' }} · {{ phaseText(task.progress?.phase) }};</span></p>
|
||||
</template>
|
||||
<div v-else class="account-empty"><h3>{{ loading ? '正在读取采集状态…' : overview ? '当前没有正在运行的采集' : '尚未读取到采集状态' }}</h3><p>{{ overview?.collectionMode === 'OFF' ? '采集已关闭,已有报表仍可查看。' : '运行任务会在这里自动更新。' }}</p></div>
|
||||
<div v-if="overview" class="account-pending"><strong>已知待处理</strong><span v-for="group in upcoming" :key="group.name">{{ group.name }} <b>{{ group.count }}</b> 项</span><span v-if="!upcoming.length">当前摘要中暂无其他待处理项</span><small>仅当前活动摘要;完整队列数量及下一任务顺序尚未提供。</small></div>
|
||||
<footer><span>最近推进 {{ beijingTime(current?.progressUpdatedAt) }}</span><span>状态更新 {{ beijingTime(overview?.observedAt) }} · 北京时间</span></footer>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped>
|
||||
.account-monitor { background: var(--admin-surface, #fff); border: 1px solid var(--el-border-color-light); border-radius: var(--admin-radius); overflow: hidden; }
|
||||
.account-header, .account-header > div, .account-now, .account-next, .account-pending, footer { display: flex; align-items: center; gap: var(--admin-space-4); }
|
||||
.account-header { justify-content: space-between; padding: var(--admin-space-5) var(--admin-space-6); border-bottom: 1px solid var(--el-border-color-light); }
|
||||
h2, h3, p { margin: 0; }
|
||||
h2 { font-size: var(--admin-font-section); }
|
||||
h3 { font-size: 24px; margin: var(--admin-space-2) 0; }
|
||||
.account-body { max-width: 1180px; margin-inline: auto; padding: var(--admin-space-6); }
|
||||
.account-header span, p, footer, small { color: var(--el-text-color-secondary); font-size: var(--admin-font-caption); }
|
||||
.account-now { justify-content: space-between; align-items: flex-start; }
|
||||
.account-eyebrow { color: var(--el-color-primary); font-size: var(--admin-font-caption); }
|
||||
.account-status { color: var(--el-color-primary); background: var(--el-color-primary-light-9); padding: var(--admin-space-2) var(--admin-space-3); border-radius: var(--admin-radius); white-space: nowrap; }
|
||||
.account-next { padding: var(--admin-space-4); background: var(--el-fill-color-light); border-left: 3px solid var(--el-color-primary); }
|
||||
.account-next small { display: block; margin-top: var(--admin-space-2); }
|
||||
.account-pending { flex-wrap: wrap; margin-top: var(--admin-space-5); }
|
||||
.account-pending small { flex-basis: 100%; }
|
||||
footer { justify-content: space-between; margin-top: var(--admin-space-5); padding-top: var(--admin-space-4); border-top: 1px solid var(--el-border-color-light); }
|
||||
.account-empty { padding-block: var(--admin-space-6); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user