You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

657 lines
19 KiB

<template>
<div class="dashboard-container">
<div class="dashboard-body">
<!-- 左侧面板 -->
<div class="left-panel">
<!-- 数据概览 -->
<div class="dashboard-card">
<div class="card-title"><i class="el-icon-data-line"></i>预警信息统计</div>
<div class="data-overview">
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
</div>
</div>
<!-- 柱状图 -->
<div class="dashboard-card">
<div class="card-title"><i class="el-icon-s-data"></i> 设备状态监控</div>
<div class="chart-container">
<dv-scroll-board :config="scrollConfig" style="width:500px;height:280px" />
</div>
</div>
</div>
<!-- 中间地图面板 -->
<div class="map-panel">
<div class="dashboard-card" style="flex: 1;">
<div class="card-title"><i class="el-icon-map-location"></i> 智慧城市地理分布</div>
<div class="map-container" ref="mapChart"></div>
</div>
</div>
<!-- 右侧面板 -->
<div class="right-panel">
<!-- 实时数据 -->
<div class="dashboard-card">
<div class="card-title"><i class="el-icon-monitor"></i> 实时监测</div>
<div class="data-overview">
<div class="data-item">
<div class="data-label">交通流量</div>
<div class="data-value">86,542</div>
<div class="data-trend"> 12.5%</div>
</div>
<div class="data-item">
<div class="data-label">能耗指数</div>
<div class="data-value">2,356</div>
<div class="data-trend down"> 3.2%</div>
</div>
<div class="data-item">
<div class="data-label">空气质量</div>
<div class="data-value">优良</div>
<div class="data-trend"> 稳定</div>
</div>
<div class="data-item">
<div class="data-label">治安指数</div>
<div class="data-value">98.7%</div>
<div class="data-trend"> 0.5%</div>
</div>
</div>
</div>
<!-- 饼图 -->
<div class="dashboard-card">
<div class="card-title"><i class="el-icon-pie-chart"></i> 人口结构</div>
<div class="chart-container" ref="populationChart"></div>
</div>
</div>
</div>
</div>
</template>
<script>
import digital from './dashboard/digital'
export default {
components: {
digital
},
data() {
return {
scrollConfig:{
header: ['设备名称', '设备位置', 'CPU使用率','内存使用率'],
data: [
['行1列1', '行1列2', '行1列3', '行1列4', '行1列5', '行1列6','行1列7', '行1列8'],
['行2列1', '行2列2', '行2列3', '行2列4', '行2列5', '行2列6','行2列7', '行2列8'],
['行3列1', '行3列2', '行3列3', '行3列4', '行3列5', '行3列6','行3列7', '行3列8'],
['行4列1', '行4列2', '行4列3', '行4列4', '行4列5', '行4列6','行4列7', '行4列8'],
['行5列1', '行5列2', '行5列3', '行5列4', '行5列5', '行5列6','行5列7', '行5列8'],
['行6列1', '行6列2', '行6列3', '行6列4', '行6列5', '行6列6','行6列7', '行6列8'],
['行7列1', '行7列2', '行7列3', '行7列4', '行7列5', '行7列6','行7列7', '行7列8'],
['行8列1', '行8列2', '行8列3', '行8列4', '行8列5', '行8列6','行8列7', '行8列8'],
['行9列1', '行9列2', '行9列3', '行9列4', '行9列5', '行9列6','行9列7', '行9列8'],
['行10列1', '行10列2', '行10列3', '行10列4', '行10列5', '行10列6','行10列7', '行10列8']
]
},
currentTime: '',
currentDate: '',
districtRanking: [
{ name: '高新区', value: 856 },
{ name: '经济开发区', value: 732 },
{ name: '西湖区', value: 698 },
{ name: '东海区', value: 645 },
{ name: '滨江区', value: 587 }
],
industryChart: null,
populationChart: null,
economyChart: null,
mapChart: null
};
},
mounted() {
this.updateTime();
setInterval(this.updateTime, 1000);
this.$nextTick(() => {
this.initCharts();
});
// 窗口调整时重新渲染图表
window.addEventListener('resize', this.resizeCharts);
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeCharts);
},
methods: {
formatter1 (number) {
const numbers = number.toString().split('').reverse()
const segs = []
while (numbers.length) segs.push(numbers.splice(0, 3).join(''))
return segs.join(',').split('').reverse().join('')
},
updateTime() {
const now = new Date();
this.currentTime = now.toLocaleTimeString();
this.currentDate = now.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
});
},
initCharts() {
// 初始化产业分布柱状图
this.industryChart = echarts.init(this.$refs.industryChart);
this.industryChart.setOption({
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#4e9ff7',
textStyle: {
color: '#fff'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '10%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['高新技术', '制造业', '金融业', '服务业', '农业'],
axisLine: {
lineStyle: {
color: '#5d92d0'
}
},
axisLabel: {
color: '#3d3d3d'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#5d92d0'
}
},
axisLabel: {
color: '#3d3d3d'
},
splitLine: {
lineStyle: {
color: 'rgba(93, 146, 208, 0.2)'
}
}
},
series: [
{
name: '产值(亿元)',
type: 'bar',
data: [320, 185, 195, 150, 85],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#4e9ff7' },
{ offset: 1, color: '#8bd6ff' }
])
},
label: {
show: true,
position: 'top',
color: '#3d3d3d'
}
}
]
});
// 初始化人口结构饼图
this.populationChart = echarts.init(this.$refs.populationChart);
this.populationChart.setOption({
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#4e9ff7',
textStyle: {
color: '#fff'
}
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
textStyle: {
color: '#3d3d3d'
}
},
series: [
{
name: '人口结构',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#0a1d35',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold',
color: '#fff'
}
},
labelLine: {
show: false
},
data: [
{ value: 245, name: '0-18岁' },
{ value: 520, name: '19-35岁' },
{ value: 395, name: '36-60岁' },
{ value: 198, name: '60岁以上' }
],
color: ['#4e9ff7', '#5d92d0', '#6b88b2', '#7a7e95']
}
]
});
// 初始化经济趋势折线图
this.economyChart = echarts.init(this.$refs.economyChart);
this.economyChart.setOption({
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#4e9ff7',
textStyle: {
color: '#fff'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '10%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisLine: {
lineStyle: {
color: '#5d92d0'
}
},
axisLabel: {
color: '#3d3d3d'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#5d92d0'
}
},
axisLabel: {
color: '#3d3d3d',
formatter: '{value} 亿'
},
splitLine: {
lineStyle: {
color: 'rgba(93, 146, 208, 0.2)'
}
}
},
series: [
{
name: 'GDP增长',
type: 'line',
smooth: true,
data: [320, 332, 301, 334, 390, 330, 320, 342, 361, 384, 410, 432],
itemStyle: {
color: '#4e9ff7'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(78, 159, 247, 0.6)' },
{ offset: 1, color: 'rgba(78, 159, 247, 0.1)' }
])
},
markPoint: {
data: [
{ type: 'max', name: '最高值' },
{ type: 'min', name: '最低值' }
]
}
}
]
});
// 初始化地图
this.mapChart = echarts.init(this.$refs.mapChart);
this.mapChart.setOption({
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#4e9ff7',
textStyle: {
color: '#fff'
},
formatter: function(params) {
return `${params.name}<br/>发展指数: ${params.value}`;
}
},
visualMap: {
min: 0,
max: 1000,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#fee090', '#fdae61', '#f46d43', '#d73027']
},
textStyle: {
color: '#3d3d3d'
}
},
series: [
{
name: '发展指数',
type: 'map',
map: 'china',
emphasis: {
label: {
show: true,
color: '#fff'
},
itemStyle: {
areaColor: '#3498db'
}
},
data: [
{ name: '北京', value: 1000 },
{ name: '天津', value: 800 },
{ name: '上海', value: 950 },
{ name: '重庆', value: 700 },
{ name: '河北', value: 600 },
{ name: '山西', value: 550 },
{ name: '辽宁', value: 650 },
{ name: '吉林', value: 580 },
{ name: '江苏', value: 850 },
{ name: '浙江', value: 820 },
{ name: '安徽', value: 630 },
{ name: '福建', value: 720 },
{ name: '江西', value: 590 },
{ name: '山东', value: 780 },
{ name: '河南', value: 680 },
{ name: '湖北', value: 710 },
{ name: '湖南', value: 690 },
{ name: '广东', value: 900 },
{ name: '海南', value: 620 },
{ name: '四川', value: 730 },
{ name: '贵州', value: 580 },
{ name: '云南', value: 610 },
{ name: '陕西', value: 670 },
{ name: '甘肃', value: 540 },
{ name: '青海', value: 500 },
{ name: '台湾', value: 750 },
{ name: '内蒙古', value: 560 },
{ name: '广西', value: 610 },
{ name: '宁夏', value: 530 },
{ name: '新疆', value: 550 },
{ name: '西藏', value: 480 },
{ name: '香港', value: 880 },
{ name: '澳门', value: 780 },
{ name: '黑龙江', value: 610 }
],
itemStyle: {
areaColor: 'rgba(93, 146, 208, 0.3)',
borderColor: '#5d92d0',
borderWidth: 1
}
}
]
});
},
resizeCharts() {
if (this.industryChart) this.industryChart.resize();
if (this.populationChart) this.populationChart.resize();
if (this.economyChart) this.economyChart.resize();
if (this.mapChart) this.mapChart.resize();
},
refreshData() {
this.$message({
message: '数据刷新中...',
type: 'info',
customClass: 'message-box'
});
// 模拟数据刷新
setTimeout(() => {
this.$message({
message: '数据已更新到最新状态',
type: 'success',
customClass: 'message-box'
});
// 这里可以添加实际的数据更新逻辑
this.initCharts();
}, 1000);
}
}
}
</script>
<style lang="scss" scoped>
.dashboard-container {
width: 100%;
// height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
}
.dashboard-body {
flex: 1;
display: flex;
gap: 20px;
}
.left-panel, .right-panel {
width: 35%;
display: flex;
flex-direction: column;
gap: 20px;
}
.map-panel {
flex: 1;
display: flex;
flex-direction: column;
}
.dashboard-card {
border-radius: 10px;
box-shadow: 0 4px 25px rgba(0, 0, 0, 0.4);
padding: 15px;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
border: 1px solid rgba(100, 180, 246, 0.15);
backdrop-filter: blur(5px);
}
// .dashboard-card::before {
// content: '';
// position: absolute;
// top: 0;
// left: 0;
// right: 0;
// height: 3px;
// background: linear-gradient(90deg, #4e9ff7, #8bd6ff);
// }
.card-title {
font-size: 16px;
margin-bottom: 15px;
display: flex;
align-items: center;
color: #3d3d3d;
font-weight: bold;
}
.card-title i {
margin-right: 8px;
font-size: 18px;
}
.chart-container {
flex: 1;
width: 100%;
min-height: 200px;
}
.map-container {
flex: 1;
width: 100%;
border-radius: 8px;
overflow: hidden;
}
.data-overview {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.data-item {
flex: 1;
min-width: 45%;
text-align: center;
padding: 15px 10px;
background: rgba(38, 84, 139, 0.3);
border-radius: 8px;
transition: all 0.3s ease;
}
.data-item:hover {
background: rgba(38, 84, 139, 0.5);
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.data-value {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
color: #3d3d3d;
}
.data-label {
font-size: 14px;
color: #3d3d3d;
}
.data-trend {
font-size: 12px;
color: #3d3d3d;
}
.data-trend.down {
color: #3d3d3d;
}
.footer {
text-align: center;
padding: 15px;
color: #3d3d3d;
font-size: 14px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
height: 50px;
}
/* 动画效果 */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.dashboard-card {
animation: fadeIn 0.8s ease-out;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.left-panel, .right-panel {
width: 30%;
}
}
@media (max-width: 992px) {
.dashboard-body {
flex-direction: column;
}
.left-panel, .right-panel {
width: 100%;
flex-direction: row;
}
.dashboard-card {
flex: 1;
}
.map-panel {
order: -1;
height: 400px;
}
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: rgba(78, 159, 247, 0.5);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(78, 159, 247, 0.7);
}
</style>