<script lang="ts" setup>
|
import { computed, onMounted, ref } from 'vue';
|
import { useRouter } from 'vue-router';
|
|
import { Page } from '@vben/common-ui';
|
|
import { Col, Row } from 'ant-design-vue';
|
|
import { getHomeSummary } from '#/api/mes/home';
|
|
import { useHomeAccess } from '#/utils/use-home-access';
|
|
import { defaultSummary } from './data';
|
import AiInsights from './modules/ai-insights.vue';
|
import AlertPanel from './modules/alert-panel.vue';
|
import BizCards from './modules/biz-cards.vue';
|
import KpiCards from './modules/kpi-cards.vue';
|
import ProductionTrend from './modules/production-trend.vue';
|
import QuickActions from './modules/quick-actions.vue';
|
|
defineOptions({ name: 'DashboardAnalytics' });
|
|
const router = useRouter();
|
const summary = ref(defaultSummary);
|
|
const { canQuery, canSeeMenu } = useHomeAccess();
|
|
/** 首页各模块的接口权限都是 mes:home:query,取不到数就先别请求(否则弹「没有该操作权限」) */
|
const canViewSummary = computed(() => canQuery('mes:home:query'));
|
|
/** MES 生产 KPI:数据取自首页汇总接口,且对应菜单开着才渲染 */
|
const showKpi = computed(
|
() =>
|
canViewSummary.value &&
|
['MesProWorkOrder', 'MesProFeedback', 'MesQcIqc', 'MesDvMachinery'].some(
|
(name) => canSeeMenu(name),
|
),
|
);
|
|
/** 生产趋势:数据来自生产报工 */
|
const showTrend = computed(
|
() => canViewSummary.value && canSeeMenu('MesProFeedback'),
|
);
|
|
/** 工单状态分布 + 维修预警 */
|
const showAlert = computed(
|
() =>
|
canViewSummary.value &&
|
(canSeeMenu('MesProWorkOrder') || canSeeMenu('MesDvRepair')),
|
);
|
|
/** 生产趋势和预警面板同一行,两块都没开就整行不渲染 */
|
const showMonitorRow = computed(() => showTrend.value || showAlert.value);
|
|
/** AI 分析块里「N 个工单可分析」取的也是首页汇总接口,取不到数就别显示这个假数字 */
|
const showAiInsights = computed(() => canViewSummary.value);
|
|
const greeting = computed(() => {
|
const hour = new Date().getHours();
|
if (hour < 6) return '夜深了';
|
if (hour < 9) return '早上好';
|
if (hour < 12) return '上午好';
|
if (hour < 14) return '中午好';
|
if (hour < 18) return '下午好';
|
return '晚上好';
|
});
|
|
const today = computed(() => {
|
const d = new Date();
|
const weekNames = ['日', '一', '二', '三', '四', '五', '六'];
|
return `${d.getFullYear()}年${d.getMonth() + 1}月${d.getDate()}日 星期${weekNames[d.getDay()]}`;
|
});
|
|
function handleNavigate(name: string) {
|
router.push({ name });
|
}
|
|
async function loadSummary() {
|
if (!canViewSummary.value) return;
|
summary.value = await getHomeSummary();
|
}
|
|
onMounted(() => {
|
loadSummary();
|
});
|
</script>
|
|
<template>
|
<Page auto-content-height>
|
<!-- 欢迎栏 -->
|
<div class="glass-card mb-6 flex items-center justify-between rounded-2xl p-6">
|
<div>
|
<h1 class="bg-gradient-to-r from-blue-600 via-purple-600 to-pink-500 bg-clip-text text-2xl font-bold text-transparent dark:from-blue-400 dark:via-purple-400 dark:to-pink-400">
|
{{ greeting }},欢迎回来
|
</h1>
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ today }}</p>
|
</div>
|
<div class="hidden items-center gap-2 sm:flex">
|
<div class="flex items-center gap-1.5 rounded-full bg-emerald-50 px-3 py-1.5 text-xs font-medium text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-400">
|
<span class="relative flex size-2">
|
<span class="absolute inline-flex size-full animate-ping rounded-full bg-emerald-400 opacity-75" />
|
<span class="relative inline-flex size-2 rounded-full bg-emerald-500" />
|
</span>
|
系统运行中
|
</div>
|
</div>
|
</div>
|
|
<!-- MES 生产 KPI -->
|
<KpiCards v-if="showKpi" :summary="summary" @navigate="handleNavigate" />
|
|
<!-- ERP/WMS/BPM 经营 KPI -->
|
<BizCards @navigate="handleNavigate" />
|
|
<!-- AI 智能分析 -->
|
<AiInsights
|
v-if="showAiInsights"
|
:active-order-count="summary.workOrderActiveCount"
|
@navigate="handleNavigate"
|
/>
|
|
<!-- 生产趋势 + 预警面板 -->
|
<Row v-if="showMonitorRow" :gutter="16" class="mb-4">
|
<Col
|
v-if="showTrend"
|
:lg="showAlert ? 14 : 24"
|
:md="24"
|
:sm="24"
|
:xl="showAlert ? 14 : 24"
|
:xs="24"
|
class="mb-4"
|
>
|
<div class="glass-card rounded-2xl p-5">
|
<h3 class="mb-4 text-base font-semibold text-gray-800 dark:text-gray-100">
|
生产趋势(近7天)
|
</h3>
|
<ProductionTrend />
|
</div>
|
</Col>
|
<Col
|
v-if="showAlert"
|
:lg="showTrend ? 10 : 24"
|
:md="24"
|
:sm="24"
|
:xl="showTrend ? 10 : 24"
|
:xs="24"
|
class="mb-4"
|
>
|
<AlertPanel
|
:repair-active-count="summary.repairActiveCount"
|
@navigate="handleNavigate"
|
/>
|
</Col>
|
</Row>
|
|
<!-- 快捷操作 -->
|
<Row :gutter="16" class="mb-4">
|
<Col :span="24">
|
<QuickActions @navigate="handleNavigate" />
|
</Col>
|
</Row>
|
</Page>
|
</template>
|
|
<style scoped>
|
.glass-card {
|
background: linear-gradient(135deg, rgba(255,255,255,0.8), rgba(255,255,255,0.5));
|
backdrop-filter: blur(20px);
|
-webkit-backdrop-filter: blur(20px);
|
border: 1px solid rgba(255,255,255,0.6);
|
box-shadow:
|
0 8px 32px rgba(0,0,0,0.04),
|
0 2px 8px rgba(0,0,0,0.02),
|
inset 0 1px 0 rgba(255,255,255,0.8);
|
}
|
|
.dark .glass-card {
|
background: linear-gradient(135deg, rgba(30,30,50,0.7), rgba(20,20,40,0.5));
|
border: 1px solid rgba(255,255,255,0.08);
|
box-shadow:
|
0 8px 32px rgba(0,0,0,0.3),
|
0 2px 8px rgba(0,0,0,0.2),
|
inset 0 1px 0 rgba(255,255,255,0.05);
|
}
|
</style>
|