8 天以前 fdd158306bf6dc3584f5110a385323f4a8dfb463
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<script lang="ts" setup>
import type { MesBagCodeHomeApi } from '#/api/mes/bag-code-home';
import type { MesTraceCrossRegionApi } from '#/api/mes/trace-cross-region';
 
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
 
import { Page } from '@vben/common-ui';
 
import { Col, Row, message } from 'ant-design-vue';
 
import { getBagCodeHomeSummary } from '#/api/mes/bag-code-home';
import { getTraceCrossRegionSummary } from '#/api/mes/trace-cross-region';
import { getTraceConsumerScanSummary } from '#/api/mes/trace-consumer-scan';
 
import { defaultSummary } from './data';
import AlertPanel from './modules/alert-panel.vue';
import BagCodeStatusChart from './modules/bag-code-status-chart.vue';
import BatchStatusChart from './modules/batch-status-chart.vue';
import BusinessFlow from './modules/business-flow.vue';
import KpiCards from './modules/kpi-cards.vue';
import ScanRegionChart from './modules/scan-region-chart.vue';
import Shortcuts from './modules/shortcuts.vue';
import TrendChart from './modules/trend-chart.vue';
 
defineOptions({ name: 'DashboardBagCodeHome' });
 
const router = useRouter();
const summary = ref<MesBagCodeHomeApi.Summary>(defaultSummary); // 首页汇总统计
const crossRegion = ref<MesTraceCrossRegionApi.Summary>({}); // 窜货预警汇总
const scanTotal = ref(0); // 累计扫码次数
 
/** 跳转到目标页面(按路由 name,未加载时提示) */
async function handleNavigate(name: string) {
  try {
    await router.push({ name });
  } catch {
    message.warning('当前菜单尚未加载,请从左侧菜单进入对应页面');
  }
}
 
/** 加载首页汇总统计、窜货预警汇总、消费者扫码汇总 */
async function loadSummary() {
  summary.value = await getBagCodeHomeSummary();
  crossRegion.value = await getTraceCrossRegionSummary();
  const scan = await getTraceConsumerScanSummary();
  scanTotal.value = scan.total ?? 0;
}
 
onMounted(() => {
  loadSummary();
});
</script>
 
<template>
  <Page>
    <div class="agri-dashboard">
      <!-- 第一行:业务全链路 -->
      <BusinessFlow
        :cross-region-total="crossRegion.total ?? 0"
        :scan-total="scanTotal"
        :summary="summary"
        @navigate="handleNavigate"
      />
 
      <!-- 第二行:全链路 KPI 总览 -->
      <KpiCards :scan-total="scanTotal" :summary="summary" @navigate="handleNavigate" />
 
      <!-- 第三行:袋码生成趋势 + 消费者扫码地区分布 -->
      <Row :gutter="16" class="mb-4">
        <Col :lg="12" :md="24" :sm="24" :xl="12" :xs="24" class="mb-4">
          <TrendChart />
        </Col>
        <Col :lg="12" :md="24" :sm="24" :xl="12" :xs="24" class="mb-4">
          <ScanRegionChart />
        </Col>
      </Row>
 
      <!-- 第四行:批次/袋码状态分布 + 待办与预警 -->
      <Row :gutter="16" class="mb-4">
        <Col :lg="6" :md="12" :sm="24" :xl="6" :xs="24" class="mb-4">
          <BatchStatusChart :list="summary.batchStatusList" />
        </Col>
        <Col :lg="6" :md="12" :sm="24" :xl="6" :xs="24" class="mb-4">
          <BagCodeStatusChart :list="summary.bagCodeStatusList" />
        </Col>
        <Col :lg="12" :md="24" :sm="24" :xl="12" :xs="24" class="mb-4">
          <AlertPanel :cross-region="crossRegion" :summary="summary" @navigate="handleNavigate" />
        </Col>
      </Row>
 
      <!-- 第五行:按业务域分组的快捷入口 -->
      <Shortcuts @navigate="handleNavigate" />
    </div>
  </Page>
</template>
 
<style lang="scss">
/* 农业翠绿玻璃拟态首页主题 —— 对齐登录页 `agri-auth` 色调,采用更清淡的浅色玻璃与高级渐变 */
.agri-dashboard {
  position: relative;
  padding: 1rem;
  border-radius: 1.25rem;
  background:
    radial-gradient(900px 480px at 8% 0%, rgba(110, 231, 183, 0.42), transparent 55%),
    radial-gradient(800px 420px at 96% 100%, rgba(6, 95, 70, 0.12), transparent 60%),
    linear-gradient(160deg, #f0fdf9 0%, #dcf7ea 50%, #c7f0d9 100%);
  isolation: isolate;
  color: #0f5c49;
 
  /* 高级白玻璃卡片:内描边 + 磨砂 + 柔和层次阴影 */
  .ant-card {
    color: #135746;
    background: linear-gradient(160deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.55));
    border: 1px solid rgba(16, 185, 129, 0.18);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.8),
      0 12px 30px rgba(6, 78, 59, 0.08);
    backdrop-filter: blur(14px);
  }
 
  .ant-card-head {
    border-bottom-color: rgba(16, 185, 129, 0.14);
  }
 
  .ant-card-head-title,
  .ant-card-head-title .anticon {
    color: #0f766e;
  }
 
  .ant-card:hover {
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.9),
      0 18px 44px rgba(6, 78, 59, 0.14);
    border-color: rgba(16, 185, 129, 0.34);
  }
 
  /* 覆盖 App 浅色主题的语义色:统一为柔和墨绿 */
  .text-muted-foreground {
    color: rgba(15, 78, 60, 0.62);
  }
 
  .text-2xl.font-bold {
    color: #047857;
  }
}
</style>