go-viee-fetch-Demo/src/packages/components/Charts/ConfinedSpace/PieCircleCommen/index.vue

256 lines
7.6 KiB
Vue
Raw Normal View History

<template>
2025-08-27 10:01:26 +08:00
<div class="go-border-box">
<SmallBaorder01 :titleText="option.titleText" :title-option="option.titleOption"
:select-option="option.selectOption" :header-option="option.headerOption" @change="handleBorderSelectChange"
:selectStyleConfig="selectStyleOption
">
<v-chart class=" chart" ref="vChartRef" :theme="themeColor" :init-options="initOptions" :option="option"
autoresize> </v-chart>
</SmallBaorder01>
2025-08-27 10:01:26 +08:00
</div>
</template>
<script setup lang="ts">
import { computed, PropType, watch, onMounted } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { mergeTheme } from '@/packages/public/chart'
import config, { includes, selectStyleOption } from './config'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import SmallBaorder01 from '../SmallBorder01Co/index.vue'
import {
DatasetComponent,
GridComponent,
TooltipComponent,
LegendComponent,
2025-08-27 10:01:26 +08:00
TitleComponent, GraphicComponent
} from 'echarts/components'
import axiosInstance from '@/api/axios'
2025-08-27 10:01:26 +08:00
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
2025-08-27 10:01:26 +08:00
use([
DatasetComponent,
CanvasRenderer,
PieChart,
GridComponent,
TooltipComponent,
LegendComponent,
TitleComponent,
GraphicComponent
])
// const option = computed(() => {
// return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
// })
const option = computed(() => {
const merged = mergeTheme(props.chartConfig.option, props.themeSetting, includes);
const dataset = merged.dataset || {};
const total = calculateTotal(dataset);
merged.title.text = total;
// 每次都创建新的formatter函数
merged.legend = {
...merged.legend,
formatter: (name: string) => {
const item = dataset.source?.find((it: any) => it[dataset.dimensions?.[0]] === name);
if (!item) return name;
const value = item[dataset.dimensions?.[1]] ?? 0;
const percentage = calculatePercentage(value, total);
return `{title|${name}}\n{detail|${value}\t${percentage}}`;
}
};
// 更新tooltip formatter
merged.tooltip = {
...merged.tooltip,
formatter: (params: any) => {
const name = params.name;
const item = dataset.source?.find((it: any) => it[dataset.dimensions?.[0]] === name);
if (!item) return `${name}: 0(0.0%)`;
const value = item[dataset.dimensions?.[1]] ?? 0;
const percentage = calculatePercentage(value, total);
return `${name}: ${value}(${percentage})`;
}
};
return merged;
});
// 总数计算
const calculateTotal = (data: any) => {
if (!data || !data.source) return 0
return data.source.reduce((total: number, item: any) => {
return total + (item[data.dimensions[1]] || 0)
}, 0)
}
// 计算百分比
const calculatePercentage = (value: number, total: number) => {
if (total === 0) return '0.0%';
const percentage = (value / total * 100).toFixed(1);
return `${percentage}%`;
};
// 处理数据更新
const dataHandle = (newData: any) => {
if (!newData) return
props.chartConfig.option.dataset = newData;
}
// 辅助函数:格式化日期为 YYYY-MM-DD HH:mm:ss 格式
function formatDateTime(date: Date): string {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始所以+1
const day = date.getDate().toString().padStart(2, '0');
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
const seconds = date.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 聚合函数:根据周期生成时间范围
function generateTimeRange(period: string): { startTime: string; endTime: string } {
const now = new Date();
let startTime: Date;
let endTime: Date;
endTime = new Date(now);
endTime.setDate(endTime.getDate() + 1); // 移动到明天
endTime.setHours(0, 0, 0, 0); // 设置为明天的 00:00:00
switch (period) {
case 'day':
startTime = new Date(now);
startTime.setHours(0, 0, 0, 0);
break;
case 'week':
// 本周7 天前的 00:00:00
startTime = new Date(now);
startTime.setDate(startTime.getDate() - 7);
startTime.setHours(0, 0, 0, 0);
break;
case 'month':
// 当月:本月第一天的 00:00:00
startTime = new Date(now.getFullYear(), now.getMonth(), 1);
startTime.setHours(0, 0, 0, 0);
break;
case 'quarter':
// 本季度:当前季度第一天的 00:00:00
const currentMonth = now.getMonth();
const quarterStartMonth = Math.floor(currentMonth / 3) * 3; // 计算当前季度的起始月份 (0, 3, 6, 9)
startTime = new Date(now.getFullYear(), quarterStartMonth, 1);
startTime.setHours(0, 0, 0, 0);
break;
case 'year':
// 当年:当年第一天的 00:00:00
startTime = new Date(now.getFullYear(), 0, 1); // 月份 0 代表一月
startTime.setHours(0, 0, 0, 0);
break;
default:
// 如果传入的周期不匹配,默认使用 'day' 的逻辑
console.warn(`未知周期类型: ${period},默认使用 'day'`);
startTime = new Date(now);
startTime.setHours(0, 0, 0, 0);
break;
}
return {
startTime: formatDateTime(startTime),
endTime: formatDateTime(endTime),
};
}
const fetchAlarmData = async ({ startTime, endTime }: { startTime: string; endTime: string }) => {
try {
const res = await axiosInstance({
method: 'GET',
url: `/space/getNumberByAlarmLevel`,
params: { startTime, endTime },
responseType: 'json',
});
if (res && (res as any).value && Array.isArray((res as any).value)) {
return {
dimensions: props.chartConfig.option.dataset.dimensions, // 保持原有的维度配置
source: (res as any).value,
};
} else {
console.warn('API returned unexpected data structure:', res);
return undefined;
}
} catch (error) {
console.error('Error fetching alarm data:', error);
return undefined; // 返回 undefined 表示获取失败
}
};
const handleBorderSelectChange = async (newValue: string) => {
props.chartConfig.option.selectOption.selectValue = newValue;
const { startTime, endTime } = generateTimeRange(newValue);
const fetchedData = await fetchAlarmData({ startTime, endTime });
if (fetchedData) {
dataHandle(fetchedData);
} else {
dataHandle(undefined); // 清空图表或显示默认状态
}
};
watch(
() => props.chartConfig.option.dataset,
(newData) => {
try {
dataHandle(newData)
} catch (error) {
console.error('数据处理错误:', error)
}
},
{
immediate: true,
deep: true
}
)
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
props.chartConfig.option.dataset = newData
dataHandle(newData)
})
onMounted(async () => {
const timeRange = generateTimeRange(option.value.selectOption.selectValue);
const fetchedData = await fetchAlarmData(timeRange);
dataHandle(fetchedData);
})
</script>
2025-08-27 10:01:26 +08:00
<style lang="scss" scoped>
@include go(border-box) {
width: 100%;
height: 100%;
}
.chart {
// position: relative;
z-index: 2;
width: 100%;
height: 100%;
}
2025-08-27 10:01:26 +08:00
</style>