<template>
|
<div class="art-full-height flex flex-col gap-6">
|
<section class="grid gap-6 md:grid-cols-2 xl:grid-cols-4" v-loading="sectionLoading.summary">
|
<div
|
v-for="item in overviewCards"
|
:key="item.key"
|
class="art-card flex cursor-pointer items-start justify-between rounded-3xl px-7 py-6"
|
@click="navigateTo(item.route)"
|
>
|
<div class="min-w-0 pr-6">
|
<p class="text-sm font-medium text-g-700">{{ item.title }}</p>
|
<ArtCountTo
|
class="mt-3 block text-[2.3rem] font-semibold leading-none text-g-900"
|
:target="item.total"
|
:duration="1200"
|
/>
|
<div class="mt-4 flex items-center gap-2 text-sm">
|
<span class="text-g-500">{{ item.badgeText }}</span>
|
<span class="text-g-600">{{ item.subtitle }}</span>
|
</div>
|
</div>
|
<div
|
class="flex size-13 shrink-0 items-center justify-center rounded-2xl"
|
:class="item.iconBoxClass"
|
>
|
<ArtSvgIcon :icon="item.icon" class="text-2xl" :class="item.iconClass" />
|
</div>
|
</div>
|
</section>
|
|
<section class="grid gap-6 xl:grid-cols-[0.92fr_1.08fr]">
|
<div class="art-card h-98 p-5 box-border" v-loading="sectionLoading.summary">
|
<div class="art-card-header">
|
<div class="title">
|
<h4>异常入口</h4>
|
<p>聚合现有异常相关真实业务页</p>
|
</div>
|
</div>
|
|
<div class="mt-3 grid gap-3">
|
<button
|
v-for="item in entryItems"
|
:key="item.key"
|
class="flex items-center justify-between rounded-2xl border border-[var(--art-border-color)] bg-[var(--art-main-bg-color)] px-4 py-4 text-left transition hover:border-[var(--el-color-primary-light-5)]"
|
type="button"
|
@click="navigateTo(item.route)"
|
>
|
<div class="flex min-w-0 items-center gap-3">
|
<div
|
class="flex size-11 shrink-0 items-center justify-center rounded-2xl bg-[var(--el-color-primary-light-9)]"
|
>
|
<ArtSvgIcon :icon="item.icon" class="text-xl text-[var(--el-color-primary)]" />
|
</div>
|
<div class="min-w-0">
|
<p class="truncate text-sm font-medium text-[var(--art-gray-900)]">{{
|
item.title
|
}}</p>
|
<p class="mt-1 truncate text-xs text-g-500">{{ item.description }}</p>
|
</div>
|
</div>
|
<div class="pl-3 text-right">
|
<p class="text-2xl font-semibold text-[var(--art-gray-900)]">{{ item.count }}</p>
|
<p class="mt-1 text-xs text-g-500">条记录</p>
|
</div>
|
</button>
|
</div>
|
</div>
|
|
<div class="art-card h-98 p-5 box-border" v-loading="sectionLoading.summary">
|
<div class="art-card-header">
|
<div class="title">
|
<h4>最近异常动态</h4>
|
<p>来自盘点差异、质检、冻结库存、库位调整</p>
|
</div>
|
</div>
|
|
<div class="mt-3 h-[calc(100%-3.75rem)] overflow-hidden">
|
<ElScrollbar>
|
<div
|
v-for="item in activityItems"
|
:key="item.key"
|
class="flex items-start gap-4 border-b border-g-300 py-4 last:border-b-0"
|
>
|
<div class="flex flex-col items-center pt-1">
|
<span class="size-3 rounded-full bg-[var(--el-color-danger)]"></span>
|
<span class="mt-2 min-h-10 w-px bg-[var(--art-border-color)]"></span>
|
</div>
|
<div class="min-w-0 flex-1">
|
<div class="flex items-center gap-2">
|
<p class="truncate text-base font-medium text-[var(--art-gray-900)]">{{
|
item.title
|
}}</p>
|
<ElTag size="small" effect="light" type="danger">{{ item.source }}</ElTag>
|
</div>
|
<p class="mt-2 text-sm text-g-600">{{ item.summary }}</p>
|
<p class="mt-2 text-xs text-g-500">{{ item.time }}</p>
|
</div>
|
<ElButton text type="primary" @click="navigateTo(item.route)">查看</ElButton>
|
</div>
|
|
<ElEmpty v-if="!activityItems.length" description="暂无异常动态" :image-size="88" />
|
</ElScrollbar>
|
</div>
|
</div>
|
</section>
|
</div>
|
</template>
|
|
<script setup>
|
import { useRouter } from 'vue-router'
|
import { withRequestGuard } from '@/utils/sys/requestGuard'
|
import { fetchCheckDiffPage } from '@/api/check-diff'
|
import { fetchQlyInspectPage } from '@/api/qly-inspect'
|
import { fetchFreezePage } from '@/api/freeze'
|
import { fetchLocRevisePage } from '@/api/loc-revise'
|
import {
|
ABNORMAL_PAGE_TITLE,
|
buildAbnormalActivityItems,
|
buildAbnormalEntryItems,
|
buildAbnormalOverviewCards,
|
createAbnormalOverviewState,
|
normalizeSummaryResponse
|
} from './abnormalPage.helpers'
|
|
defineOptions({ name: 'AbnormalManage' })
|
|
const router = useRouter()
|
const sectionLoading = reactive({
|
summary: false
|
})
|
const overviewState = ref(createAbnormalOverviewState())
|
|
const overviewCards = computed(() => buildAbnormalOverviewCards(overviewState.value))
|
const entryItems = computed(() => buildAbnormalEntryItems(overviewState.value))
|
const activityItems = computed(() => buildAbnormalActivityItems(overviewState.value))
|
|
onMounted(() => {
|
document.title = `${ABNORMAL_PAGE_TITLE} - RSF Design`
|
void loadOverview()
|
})
|
|
async function loadOverview() {
|
sectionLoading.summary = true
|
|
const [checkDiffResponse, qlyInspectResponse, freezeResponse, locReviseResponse] =
|
await Promise.all([
|
withRequestGuard(fetchCheckDiffPage({ current: 1, pageSize: 5 }), {
|
records: [],
|
total: 0
|
}),
|
withRequestGuard(fetchQlyInspectPage({ current: 1, pageSize: 5 }), {
|
records: [],
|
total: 0
|
}),
|
withRequestGuard(fetchFreezePage({ current: 1, pageSize: 5 }), { records: [], total: 0 }),
|
withRequestGuard(fetchLocRevisePage({ current: 1, pageSize: 5 }), { records: [], total: 0 })
|
])
|
|
overviewState.value = {
|
checkDiff: normalizeSummaryResponse(checkDiffResponse),
|
qlyInspect: normalizeSummaryResponse(qlyInspectResponse),
|
freeze: normalizeSummaryResponse(freezeResponse),
|
locRevise: normalizeSummaryResponse(locReviseResponse)
|
}
|
|
sectionLoading.summary = false
|
}
|
|
function navigateTo(path) {
|
if (!path) return
|
router.push(path)
|
}
|
</script>
|