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

266 lines
8.0 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':
// 本周:从周一到今天
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 }) => {
2025-08-28 11:06:02 +08:00
const defaultNoData = {
dimensions: props.chartConfig.option.dataset.dimensions,
source: [{
[props.chartConfig.option.dataset.dimensions[0]]: "无数据",
[props.chartConfig.option.dataset.dimensions[1]]: 0
2025-08-28 11:06:02 +08:00
}],
};
try {
const res: any = await axiosInstance.get(
2025-09-03 14:50:26 +08:00
`/awjt/space/getNumberByAlarmLevel/${props.chartConfig.option.secneID}`,
2025-08-28 10:33:55 +08:00
{
params: { startTime, endTime },
2025-08-28 10:33:55 +08:00
responseType: 'json',
baseURL: ''
2025-08-28 10:33:55 +08:00
}
);
2025-08-28 11:06:02 +08:00
// 检查 API 响应状态和数据是否有效且非空
if (res.state === true && res.value && res.value.length > 0) {
console.log(res)
return {
2025-08-28 11:06:02 +08:00
dimensions: props.chartConfig.option.dataset.dimensions,
source: res.value,
};
} else {
console.warn('API调用成功但数据为空或状态异常显示默认无数据。', res)
2025-08-28 11:06:02 +08:00
return defaultNoData;
}
} catch (error) {
2025-08-28 10:33:55 +08:00
console.error('获取图表数据失败:', error)
2025-08-28 11:06:02 +08:00
return defaultNoData;
}
};
const handleBorderSelectChange = async (newValue: string) => {
props.chartConfig.option.selectOption.selectValue = newValue;
const { startTime, endTime } = generateTimeRange(newValue);
const fetchedData = await fetchAlarmData({ startTime, endTime });
2025-08-28 11:06:02 +08:00
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>
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>