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

266 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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>
</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,
TitleComponent, GraphicComponent
} from 'echarts/components'
import axiosInstance from '@/api/axios'
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)
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':
// 本周:从周一到今天
startTime = new Date(now);
const dayOfWeek = now.getDay(); // 0(周日) to 6(周六)
const diffToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // 周日需要调整为上周一
startTime.setDate(startTime.getDate() + diffToMonday);
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 }) => {
const defaultNoData = {
dimensions: props.chartConfig.option.dataset.dimensions,
source: [{
[props.chartConfig.option.dataset.dimensions[0]]: "无数据",
[props.chartConfig.option.dataset.dimensions[1]]: 0
}],
};
try {
const res: any = await axiosInstance.get(
`/awjt/space/getNumberByAlarmLevel/${props.chartConfig.option.sceneCode}`,
{
params: { startTime, endTime },
responseType: 'json',
baseURL: ''
}
);
// 检查 API 响应状态和数据是否有效且非空
if (res.state === true && res.value && res.value.length > 0) {
console.log(res)
return {
dimensions: props.chartConfig.option.dataset.dimensions,
source: res.value,
};
} else {
console.warn('API调用成功但数据为空或状态异常显示默认无数据。', res)
return defaultNoData;
}
} catch (error) {
console.error('获取图表数据失败:', error)
return defaultNoData;
}
};
const handleBorderSelectChange = async (newValue: string) => {
props.chartConfig.option.selectOption.selectValue = newValue;
const { startTime, endTime } = generateTimeRange(newValue);
const fetchedData = await fetchAlarmData({ startTime, endTime });
dataHandle(fetchedData);
};
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>
<style lang="scss" scoped>
@include go(border-box) {
width: 100%;
height: 100%;
}
.chart {
// position: relative;
z-index: 2;
width: 100%;
height: 100%;
}
</style>