Files
Situation-Awareness-Platfor…/src/views/Jyh/security/components/IndustryDistribution.vue

257 lines
6.1 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="index-module__NV_5cW__chartCard">
<h3 class="chartCard__title">行业分布</h3>
<div class="chartCard__container">
<div class="num-empty" v-if="computedIsEmpty"></div>
<div v-else class="industry-distribution-container">
<div class="chart-container" ref="chartDiv"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue';
import * as echarts from 'echarts';
import { industryDistributionPage1 } from '@/api/jyh/situation';
// 定义数据类型
interface IndustryData {
value: number;
name: string;
}
// 定义配色方案
const industryColorPalette = [
'#00f0ff', '#00b03e', '#ffeb00', '#ffab00',
'#ff5100', '#c0232a', '#a262f2', '#379bff'
];
// 内部数据
const internalData = ref<IndustryData[]>([]);
// 响应式数据
const chartDiv = ref<HTMLDivElement | null>(null);
let myChart: echarts.ECharts | null = null;
// 计算 isEmpty 状态
const computedIsEmpty = computed(() => {
return internalData.value.length === 0;
});
// 初始化图表
const initChart = () => {
if (!chartDiv.value || computedIsEmpty.value) return;
// 销毁已存在的图表实例
if (myChart) {
myChart.dispose();
}
myChart = echarts.init(chartDiv.value);
// 构建图例数据,对于较长的名称才在图例中显示数值
const legendData = internalData.value.map(item => ({
name: item.name,
icon: 'circle'
}));
const option: echarts.EChartsOption = {
tooltip: {
trigger: 'item',
formatter: (params: any) => `${params.name}: ${params.value} (${params.percent}%)`
},
legend: {
bottom: '0',
textStyle: { fontSize: 10 },
itemWidth: 10,
itemHeight: 10,
orient: 'horizontal',
padding: [5, 0, 0, 0],
data: legendData
},
series: [
{
name: '行业分布',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '45%'],
data: internalData.value,
label: {
show: true,
formatter: '{b}\n{d}%',
fontSize: 10,
rich: {
b: {
fontSize: 10,
lineHeight: 12
},
d: {
fontSize: 10,
lineHeight: 12
}
}
},
itemStyle: {
color: (params: any) => {
return industryColorPalette[params.dataIndex % industryColorPalette.length];
}
}
}
],
grid: { left: 0, bottom: 0, top: 0, right: 0 }
};
myChart.setOption(option);
};
// 响应式处理
const handleResize = () => {
if (myChart) {
myChart.resize();
}
};
// 获取行业分布数据
const fetchIndustryData = async () => {
try {
const response = await industryDistributionPage1();
const businessData = response.data; // Axios响应格式业务数据在response.data中
if (businessData.code === 200 && businessData.data) {
internalData.value = businessData.data;
} else {
console.error('获取行业分布数据失败:', businessData.msg || '未知错误');
internalData.value = [
{ value: 25.8, name: '人工智能' },
{ value: 18.4, name: '云计算' },
{ value: 15.6, name: '大数据' },
{ value: 12.2, name: '物联网' },
{ value: 9.6, name: '网络安全' },
{ value: 7.1, name: '区块链' },
{ value: 6.4, name: '工业互联网' },
{ value: 4.9, name: '移动开发' }
];
}
} catch (error) {
console.error('请求行业分布数据时发生错误:', error);
internalData.value = [
{ value: 25.8, name: '人工智能' },
{ value: 18.4, name: '云计算' },
{ value: 15.6, name: '大数据' },
{ value: 12.2, name: '物联网' },
{ value: 9.6, name: '网络安全' },
{ value: 7.1, name: '区块链' },
{ value: 6.4, name: '工业互联网' },
{ value: 4.9, name: '移动开发' }
];
}
};
// 生命周期钩子
onMounted(async () => {
await fetchIndustryData(); // 获取行业分布数据
await nextTick();
initChart();
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
if (myChart) {
myChart.dispose();
}
});
</script>
<style lang="scss" scoped>
.index-module__NV_5cW__chartCard {
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
background: #ffffffe6;
border: 1px solid #ffffff4d;
border-radius: 1rem;
padding: 1.5rem;
box-shadow: 0 4px 16px #00000014;
transition: all 0.3s;
}
/* 列表卡片特殊样式 */
.index-module__NV_5cW__chartCard.list-card {
padding: 1.5rem;
}
.index-module__NV_5cW__chartCard:hover {
border-color: #3b82f64d;
transform: translateY(-4px);
box-shadow: 0 8px 24px #0000001f;
}
.chartCard__wide {
grid-column: 1 / -1; /* 跨列显示 */
}
.chartCard__title {
color: #333;
font-size: 1.1rem;
font-weight: 600;
margin: 0 0 1rem 0;
text-align: left;
}
.chartCard__container {
width: 100%;
height: 300px; /* 图表高度 */
position: relative;
}
/* 列表容器样式:隐藏原生滚动条(可选,视觉更美观) */
.chartCard__container.list-container {
height: auto;
max-height: 300px; /* 限制列表高度,超出滚动 */
overflow-y: auto;
padding: 0 0.5rem;
/* 隐藏滚动条 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
/* 隐藏webkit内核浏览器的滚动条 */
.chartCard__container.list-container::-webkit-scrollbar {
display: none;
}
.num-empty {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.industry-distribution-container {
width: 100%;
height: 100%;
position: relative;
}
.chart-container {
width: 100%;
height: 100%;
min-height: 300px;
}
/* 响应式样式 */
@media (max-width: 1024px) {
.chartCard__container {
height: 250px; /* 移动端图表高度调整 */
}
}
@media (max-width: 480px) {
.chartCard__container {
height: 200px; /* 小屏移动端图表高度调整 */
}
}
</style>