| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- <template>
- <div class="confidentiality-position-chart">
- <!-- 标题区域 -->
- <div class="chart-header">
- <div class="main-title">
- <img src="@/assets/images/warning.png" alt="warning" class="warning-icon" />
- <span class="title-text">今日抓拍记录</span>
- <span class="record-count">{{ todayCount }}</span>
- <span class="title-text">条</span>
- </div>
- <!-- <div class="subtitle">近7日抓拍记录变化折线图</div> -->
- </div>
- <!-- 图表区域 -->
- <div ref="chartRef" class="chart-container"></div>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, onMounted, onUnmounted, nextTick } from 'vue';
- import * as echarts from 'echarts';
- import { getTodayCaptureRecordCount, getRecentDaysCaptureRecordCount } from '@/api/security-confidentiality-position';
- const chartRef = ref<HTMLDivElement | null>(null);
- let chartInstance: echarts.ECharts | null = null;
- const todayCount = ref<number>(0);
- // 初始化图表
- const initChart = async () => {
- if (!chartRef.value) return;
- // 获取数据
- try {
- const [todayRes, recentRes] = await Promise.all([
- getTodayCaptureRecordCount(),
- getRecentDaysCaptureRecordCount(7),
- ]);
- todayCount.value = todayRes || 0;
- // 销毁旧实例
- if (chartInstance) {
- chartInstance.dispose();
- }
- // 初始化图表实例
- chartInstance = echarts.init(chartRef.value);
- // 处理数据
- const dates = recentRes.map((item) => {
- const date = new Date(item.date);
- const month = String(date.getMonth() + 1).padStart(2, '0');
- const day = String(date.getDate()).padStart(2, '0');
- return `${month}.${day}`;
- });
- const counts = recentRes.map((item) => item.count);
- // 找到最大值用于高亮显示
- const maxCount = Math.max(...counts, 0);
- const maxIndex = counts.indexOf(maxCount);
- const option: echarts.EChartsOption = {
- grid: {
- left: '2%',
- right: '2%',
- top: '25%',
- bottom: '0%',
- containLabel: true,
- },
- xAxis: {
- type: 'category',
- data: dates,
- axisLine: {
- show: false,
- },
- axisTick: {
- show: false,
- },
- axisLabel: {
- color: '#666',
- fontSize: 12,
- margin: 10,
- },
- },
- yAxis: {
- name: '近7日抓拍记录变化折线图',
- nameGap: 26,
- type: 'value',
- axisLine: {
- show: false,
- },
- axisTick: {
- show: false,
- },
- axisLabel: {
- color: '#666',
- fontSize: 12,
- },
- splitLine: {
- lineStyle: {
- color: '#f0f0f0',
- type: 'dashed',
- },
- },
- nameTextStyle: {
- verticalAlign: 'bottom',
- padding: [0, 0, 5, 80],
- },
- },
- series: [
- {
- name: '抓拍记录',
- type: 'line',
- data: counts,
- smooth: true,
- symbol: 'circle',
- symbolSize: 6,
- lineStyle: {
- color: '#ff8c00',
- width: 2,
- },
- itemStyle: {
- color: '#ff8c00',
- },
- markPoint:
- maxCount > 0
- ? {
- data: [
- {
- type: 'max',
- name: '最大值',
- coord: [maxIndex, maxCount],
- symbolSize: 0,
- label: {
- show: true,
- position: 'top',
- color: '#ff8c00',
- fontSize: 14,
- fontWeight: 'bold',
- formatter: maxCount.toString(),
- },
- },
- ],
- }
- : undefined,
- },
- ],
- tooltip: {
- trigger: 'axis',
- backgroundColor: 'rgba(0, 0, 0, 0.6)',
- borderColor: 'transparent',
- textStyle: {
- color: '#fff',
- },
- formatter: (params: any) => {
- const data = params[0];
- return `${data.axisValue}<br/>抓拍记录: ${data.value}条`;
- },
- },
- };
- chartInstance.setOption(option);
- // 响应式处理
- window.addEventListener('resize', handleResize);
- } catch (error) {
- console.error('Failed to load chart data:', error);
- todayCount.value = 0;
- }
- };
- // 处理窗口大小变化
- const handleResize = () => {
- if (chartInstance) {
- chartInstance.resize();
- }
- };
- onMounted(async () => {
- await nextTick();
- initChart();
- });
- onUnmounted(() => {
- window.removeEventListener('resize', handleResize);
- if (chartInstance) {
- chartInstance.dispose();
- }
- });
- </script>
- <style scoped lang="scss">
- .confidentiality-position-chart {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 5px 20px;
- .chart-header {
- width: 100%;
- // display: flex;
- // flex-direction: column;
- // align-items: center;
- margin-bottom: 8px;
- .main-title {
- display: flex;
- align-items: baseline;
- justify-content: center;
- height: 30px;
- gap: 8px;
- .warning-icon {
- position: relative;
- top: 3px;
- width: 20px;
- height: 20px;
- }
- .title-text {
- line-height: 20px;
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- }
- .record-count {
- line-height: 30px;
- font-size: 24px;
- font-weight: 600;
- color: #ff5f53;
- }
- }
- }
- .chart-container {
- width: 100%;
- height: 153px;
- flex: 1;
- }
- }
- </style>
|