liu
2026-09-30 b1e27feae0b951218fd2f0b0561f9be4c8b67771
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
<script lang="ts" setup>
import type { EchartsUIType } from '@vben/plugins/echarts';
 
import type { ArchiveStatApi } from '#/api/archive/stat';
 
import { computed, onMounted, ref } from 'vue';
 
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
 
import { Spin } from 'ant-design-vue';
 
import { getArchiveStatOverview } from '#/api/archive/stat';
 
import { buildBarOption, buildPieOption, STAT_CARDS } from './data';
 
/** 档案统计 */
defineOptions({ name: 'ArchiveStat' });
 
const loading = ref(false);
const overview = ref<ArchiveStatApi.StatOverview>({});
 
const categoryChartRef = ref<EchartsUIType>();
const secretChartRef = ref<EchartsUIType>();
const carrierChartRef = ref<EchartsUIType>();
 
const { renderEcharts: renderCategory } = useEcharts(categoryChartRef);
const { renderEcharts: renderSecret } = useEcharts(secretChartRef);
const { renderEcharts: renderCarrier } = useEcharts(carrierChartRef);
 
/** 卡片取值 */
const cards = computed(() =>
  STAT_CARDS.map((card) => ({
    ...card,
    value: (overview.value[card.key] as number | undefined) ?? 0,
  })),
);
 
async function loadData() {
  loading.value = true;
  try {
    const data = await getArchiveStatOverview();
    overview.value = data;
    await Promise.all([
      renderCategory(
        buildPieOption(
          '按分类分布',
          (data.byCategory ?? []).map((item) => ({
            name: item.name ?? '未命名',
            value: item.total ?? 0,
          })),
        ),
      ),
      renderSecret(
        buildBarOption(
          '按密级分布',
          (data.bySecretLevel ?? []).map((item) => ({
            name: item.name ?? '未设置',
            value: item.total ?? 0,
          })),
        ),
      ),
      renderCarrier(
        buildPieOption(
          '按载体分布',
          (data.byCarrierType ?? []).map((item) => ({
            name: item.name ?? '未设置',
            value: item.total ?? 0,
          })),
        ),
      ),
    ]);
  } finally {
    loading.value = false;
  }
}
 
onMounted(loadData);
</script>
 
<template>
  <Page auto-content-height>
    <Spin :spinning="loading" tip="加载中...">
      <div class="space-y-4">
        <!-- 统计卡片 -->
        <div class="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4">
          <ContentWrap
            v-for="card in cards"
            :key="card.key"
            class="flex items-center justify-between"
          >
            <div>
              <p class="text-sm text-gray-500">{{ card.label }}</p>
              <p
                class="mt-1 text-2xl font-semibold"
                :style="{ color: card.color }"
              >
                {{ card.value }}
              </p>
            </div>
            <span
              class="inline-block h-10 w-1 rounded"
              :style="{ backgroundColor: card.color }"
            />
          </ContentWrap>
        </div>
 
        <!-- 分布图表 -->
        <div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
          <ContentWrap>
            <EchartsUI class="h-72 w-full" ref="categoryChartRef" />
          </ContentWrap>
          <ContentWrap>
            <EchartsUI class="h-72 w-full" ref="secretChartRef" />
          </ContentWrap>
        </div>
        <ContentWrap>
          <EchartsUI class="h-72 w-full" ref="carrierChartRef" />
        </ContentWrap>
      </div>
    </Spin>
  </Page>
</template>