bonus-ui/src/views/screen/wsScreen/components/center/index.vue

385 lines
11 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="middle-warp">
<div class="top-btns">
<div class="btn" :class="{ active: btnIndex == 1 }" @click="handleBtn(1)">总价值数</div>
<div class="btn" :class="{ active: btnIndex == 2 }" @click="handleBtn(2)">在库装备数</div>
<div class="btn" :class="{ active: btnIndex == 3 }" @click="handleBtn(3)">机械化率</div>
</div>
<!-- 外层容器用于加阴影 -->
<div class="map-wrapper">
<!-- 倾斜层实现 3D 倾斜效果 -->
<div class="map-tilt">
<div ref="mapChart" class="map-container"></div>
</div>
</div>
<!-- 点击城市显示详情 -->
<div v-if="selectedCity && btnIndex == 1" class="city-tooltip">
<div class="city-name">{{ selectedCity.cityName }}</div>
<div
>装备价值: <span class="num">{{ selectedCity.totalValue }}</span
><span class="unit"> 元</span></div
>
<div
>装备数量: <span class="num">{{ selectedCity.totalEquipmentQuantity }}</span
><span class="unit"> 台</span></div
>
<div
>配置率: <span class="num">{{ selectedCity.configRate || 0 }}</span
><span class="unit"> %</span></div
>
<div
>线路数量: <span class="num">{{ selectedCity.lineNum }}</span
><span class="unit"> 台</span></div
>
<div
>变电数量: <span class="num">{{ selectedCity.substationNum }}</span
><span class="unit"> 台</span></div
>
<div
>电缆数量: <span class="num">{{ selectedCity.cableNum }}</span
><span class="unit"> </span></div
>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import anhuiMapJson from '../anhui.json'
import labelBg from '../../img/value-bg.png'
import { getUnitEquipmentConfigurationApi, getEquipmentNumberApi, getMechanizationRateApi } from '@/api/wsScreen'
export default {
data() {
return {
btnIndex: 1,
myChart: null,
selectedCity: null,
cityData: [],
}
},
created() {
this.getInfo()
},
methods: {
handleBtn(index) {
this.btnIndex = index
this.cityData = []
this.getInfo()
},
async getInfo() {
try {
let res = null
if (this.btnIndex == 1) {
res = await getUnitEquipmentConfigurationApi()
if (!res.data) return
this.cityData = res.data.map((item) => {
let value = item.location.split(',')
value.push(item.totalValue)
// console.log('🚀 ~ getInfo ~ value:', value)
return {
...item,
value,
}
})
} else if (this.btnIndex == 2) {
res = await getEquipmentNumberApi()
this.cityData = res.data.map((item) => {
let value = item.location.split(',')
value.push(item.num)
// console.log('🚀 ~ getInfo ~ value:', value)
return {
...item,
value,
deptName: item.name,
}
})
} else if (this.btnIndex == 3) {
// res = await getMechanizationRateApi()
}
setTimeout(() => {
console.log('🚀 ~ 地图数据 ~ this.cityData:', this.cityData)
this.initMap()
}, 300)
console.log('🚀 ~ 地图数据 ~ res:', res)
} catch (error) {
console.log('🚀 ~ 地图数据 ~ error:', error)
// this.initMap()
}
},
initMap() {
echarts.registerMap('anhui', anhuiMapJson)
this.myChart = echarts.init(this.$refs.mapChart)
const seriesData = this.cityData
const option = {
backgroundColor: 'transparent',
geo: {
map: 'anhui',
roam: false,
zoom: 1.1,
aspectScale: 1.5,
center: [117.227239, 31.820586],
label: { show: false },
itemStyle: {
areaColor: '#1B3452',
borderColor: '#5A9BD9',
borderWidth: 1.5,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowBlur: 10,
},
emphasis: {
itemStyle: { areaColor: '#4C7DBF' },
},
},
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
data: seriesData,
symbol: 'circle',
symbolSize: 16,
label: {
show: true,
// 保持文字阴影等样式(可按需调整)
color: '#fff',
fontSize: 15,
textShadowColor: '#000',
textShadowBlur: 2,
// 使用富文本标签:{val|...} 表示 value 显示区,{name|...} 表示城市名
formatter: (params) => {
// console.log('🚀 ~ initMap ~ params:', params)
// 优先使用 params.data.value更可靠否则 fallback 到 params.value
const val = params.data && params.data.value !== undefined ? params.data.value : params.value
let unit = ''
if (this.btnIndex === 1) {
unit = '亿'
} else if (this.btnIndex === 2) {
unit = '台'
} else if (this.btnIndex === 3) {
unit = '%'
}
return val !== undefined
? `{val|${val[2]} ${unit}}\n{name|${params.data.deptName}}`
: `{name|${params.data.deptName}}`
// 根据 params.name 匹配 seriesData 中的数据, 同一个城市如果有多条数据 则间隔一点距离展示
},
rich: {
// value 的背景图样式
val: {
// 关键backgroundColor 使用 image传入上面引入的 labelBg
backgroundColor: {
image: labelBg, // ← 确保上面已 import 或用 new URL 得到的 href
},
// 使背景块垂直居中、控制高度、内边距等
height: 28,
minWidth: 70,
lineHeight: 28,
padding: [0, 10], // 上右下左
align: 'center',
verticalAlign: 'middle',
color: '#fff',
fontSize: 18,
borderRadius: 14, // 圆角(如果背景图是纯图,这个可以省)
},
// 城市名样式(在 value 下方)
name: {
color: '#fff',
fontFamily: 'DS-TITLE',
fontSize: 16,
padding: [6, 0, 0, 0],
textShadowColor: '#000',
textShadowBlur: 2,
},
},
},
itemStyle: {
areaColor: '#1B3452',
borderColor: '#5A9BD9',
borderWidth: 1.5,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowBlur: 10,
},
emphasis: {
label: {
color: '#fff',
},
itemStyle: {
areaColor: '#4C7DBF',
},
},
data: seriesData,
},
],
}
this.myChart.setOption(option)
this.myChart.on('click', (params) => {
console.log('🚀 ~ initMap ~ params:', params)
// params.name去掉 市
let city = null
if (params.seriesType === 'scatter' && params.data) {
city =
params.data.deptName == '安徽送变电工程有限公司'
? '安徽送变电'
: params.data.cityName.replace(/市$/, '')
} else {
city = params.name.replace(/市$/, '')
}
this.$router.push({
path: '/screen/cityScreen',
query: {
cityName: city,
},
})
})
// 鼠标移入时展示
this.myChart.on('mouseover', (params) => {
// console.log('🚀 ~ initMap ~ params:', params)
let city = null
if (params.seriesType === 'scatter' && params.data) {
// console.log('🚀 ~ 当前坐标点信息 ~ params.data:', params.data)
city = params.data
} else {
this.selectedCity = null
city = this.cityData.find((c) => c.cityName === params.name)
}
this.selectedCity = city || null
})
// 鼠标移出时隐藏
this.myChart.on('mouseout', () => {
this.selectedCity = null
})
window.addEventListener('resize', () => {
this.myChart.resize()
})
},
},
beforeDestroy() {
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
},
}
</script>
<style lang="scss" scoped>
.middle-warp {
margin-top: 80px;
position: relative;
padding-top: 20px;
border-radius: 8px;
overflow: hidden;
}
.top-btns {
margin-left: -80px;
display: flex;
justify-content: center;
.btn:not(:last-child) {
margin-right: 80px;
}
.btn {
font-size: 28px;
text-align: center;
padding: 10px 20px;
font-family: DS-TITLE;
color: #ccc;
background-image: url('../../img/btn.png');
background-size: 100% 100%;
cursor: pointer;
}
.active {
background-image: url('../../img/btn-active.png');
background-size: 100% 100%;
}
}
// 外层容器:添加底部阴影
.map-wrapper {
margin-top: -21px;
position: relative;
filter: drop-shadow(0 20px 20px rgba(0, 0, 0, 0.3)); // 20px 柔和阴影
transform: translateZ(0); // 启用硬件加速
}
// 倾斜层:实现 15 度倾斜的 3D 效果
.map-tilt {
transform: rotateX(15deg);
transform-origin: bottom center;
perspective: 1200px; // 👈 增加景深,效果更立体
transition: transform 0.3s ease;
pointer-events: none;
height: 900px;
display: flex;
justify-content: center;
}
// 鼠标悬停时轻微动态效果(可选)
.middle-warp:hover .map-tilt {
transform: rotateX(12deg);
}
// 实际图表容器
.map-container {
width: 100%;
height: 900px;
background: transparent;
pointer-events: auto; // 图表本身可交互
display: flex;
align-items: center;
justify-content: center;
}
.city-tooltip {
position: absolute;
top: 20px;
right: 80px;
width: 288px;
height: 288px;
color: #fdfdfd;
padding: 12px;
border-radius: 6px;
font-size: 17px;
background-image: url('../../img/dialog.png');
background-size: 100% 100%;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
z-index: 10;
.city-name {
font-size: 25px;
font-family: DS-TITLE;
margin: -5px 0 10px;
}
div {
padding-bottom: 5px;
}
// 除了第一个和最后一个外,添加一个浅下边框
div:not(:first-child):not(:last-child) {
margin-bottom: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.num {
font-weight: 900;
}
.unit {
font-size: 12px;
color: #ccc;
}
}
</style>