bonus-ui/src/views/home/components/provincial/Top2.vue

623 lines
20 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 style="position: relative">
<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
class="btn"
:class="{ active: btnIndex == item.id }"
v-for="(item, index) in btnList"
:key="item.id"
@click="handleBtn(item.id)"
>
<div class="num">
<span v-if="item.id == 4"
>{{ mechanizationTotal > 0 ? mechanizationTotal : equipData[item.key] || 0 }}%</span
>
<span v-else>{{ equipData[item.key] || 0 }}</span>
</div>
<div class="name">{{ item.name }}</div>
<img v-show="btnIndex == item.id" src="@/assets/images/top2-icon.png" class="icon" alt="" />
</div>
</div>
<el-radio-group v-model="radio" class="radio-box" v-if="btnIndex == 4" @input="handleRadio">
<el-radio :label="1">线路工程</el-radio>
<el-radio :label="2">变电工程</el-radio>
<el-radio :label="3">电缆工程</el-radio>
</el-radio-group>
<div class="map-box">
<div class="echarts" id="mapChart"></div>
</div>
</div>
</template>
<script>
import {
getUnitEquipmentConfigurationApi,
getEquipmentNumberApi,
getMechanizationRateApi,
getTotalEquipmentApi,
} from '@/api/wsScreen'
import * as echarts from 'echarts'
import 'echarts-gl'
let mapImg = require('./Map/assets/img/anhui.png')
import labelBg from './Map/assets/img/value-bg.png'
let mapJson = require('./Map/ah.json')
export default {
data() {
return {
btnIndex: 1,
cityData: [],
btnList: [
{ id: 1, name: '总价值(万元)', key: 'totalPrice' },
{ id: 2, name: '装备总量(台)', key: 'total' },
{ id: 3, name: '配置率(分)', key: 'configuration' },
{ id: 4, name: '机械化率', key: 'mechanization' },
],
equipData: {
totalPrice: 0, // 总价值
total: 0, // 装备总数
configuration: 0, // 配置率
mechanization: 0, // 机械化率
},
radio: 1,
// 机械化率总数
mechanizationTotal: 0,
}
},
created() {
this.getInfo()
},
methods: {
handleBtn(index) {
if (this.btnIndex == index) return
this.btnIndex = index
this.cityData = []
this.getInfo()
},
handleRadio(val) {
this.getInfo()
},
async getInfo() {
try {
const { data } = await getTotalEquipmentApi()
this.equipData.total = data.totalEquipmentQuantity || 0
this.equipData.totalPrice = data.totalValue || 0
this.equipData.configuration = data.configuration || 0
this.equipData.mechanization = data.mechanization || 0
let res = null
if (this.btnIndex == 1) {
res = await getUnitEquipmentConfigurationApi()
if (!res.data) return
res.data = res.data.filter((item) => item.location)
this.cityData = res.data.map((item) => {
let value = item.location.split(',')
value.push(item.totalValue)
// console.log('🚀 ~ getInfo ~ value:', value)
return {
...item,
value,
}
})
}
if (this.btnIndex == 4) {
let type = ''
switch (this.radio) {
case 1:
type = '线路'
break
case 2:
type = '变电'
break
case 3:
type = '电缆'
break
}
res = await getMechanizationRateApi({ type })
if (!res.data) return
this.mechanizationTotal = res.data.find((item) => item.dataType == 'total')?.mechanizationRate
res.data = res.data.filter((item) => item.cityName)
this.cityData = res.data.map((item) => {
return {
cityName: item.cityName,
mechanizationRate: item.mechanizationRate,
dataType: item.dataType,
companyName: item.companyName,
value: [0, 0, item.mechanizationRate],
}
})
} else if (this.btnIndex == 2 || this.btnIndex == 3) {
// res = await getEquipmentNumberApi()
res = await getUnitEquipmentConfigurationApi()
if (!res.data) return
res.data = res.data.filter((item) => item.location)
this.cityData = res.data.map((item) => {
let value = item.location.split(',')
value.push(item.num)
// console.log('🚀 ~ getInfo ~ value:', value)
return {
...item,
value,
}
})
}
this.$nextTick(() => {
console.log('🚀 ~ 地图数据 ~ this.cityData:', this.cityData)
this.initChart()
})
console.log('🚀 ~ 地图数据 ~ res:', res)
} catch (error) {
console.log('🚀 ~ 地图数据 ~ error:', error)
// this.initChart()
}
},
initChart(jsonData = mapJson) {
// 模拟数据
let arr = this.cityData.map((item) => {
return {
...item,
name: item.cityName,
}
})
echarts.registerMap('ah', jsonData)
const charEle = document.getElementById('mapChart')
const myChart = echarts.init(charEle)
// let tooltip = gzjhTooltip(arr)
const option = {
tooltip: {
show: true,
backgroundColor: 'rgba(0,0,0,0)',
borderWidth: 0,
padding: 0, // 👈 关键 1干掉外壳内边距
extraCssText: 'box-shadow:none;border-radius:0;', // 👈 关键 2干掉阴影 & 圆角
position: function (point, params, dom, rect, size) {
const tooltipWidth = size.contentSize[0]
const tooltipHeight = size.contentSize[1]
const viewHeight = size.viewSize[1]
let x = point[0] - tooltipWidth / 2
let y = 0
if (point[1] < viewHeight / 2) {
// 👆 地图上半部分 → tooltip 显示在鼠标下方(靠顶部)
y = point[1] + 10
} else {
// 👇 地图下半部分 → tooltip 显示在鼠标上方(靠底部)
y = point[1] - tooltipHeight - 10
}
return [x, y]
},
formatter: (e) => {
let n = e.name
let res = ''
arr.forEach((data) => {
if (data.cityName === n) {
// console.log('🚀 ~ 提示数据 ~ data:', data)
if (data.cityName === '合肥市') {
const hefeiList = arr.filter((item) => item.cityName === '合肥市')
res =
'<div>' +
this.renderOneCompany(hefeiList[0], this.btnIndex) +
this.renderOneCompany(hefeiList[1], this.btnIndex) +
'</div>'
} else {
res = this.renderOneCompany(data, this.btnIndex)
}
}
})
return res
},
},
geo3D: {
map: 'ah',
zoom: 1,
roam: false,
label: { show: false },
itemStyle: {
opacity: 0, //.01 // important!
},
emphasis: {
disabled: true,
},
regionHeight: 0,
shading: 'lambert',
viewControl: {
zoomSensitivity: false,
rotateSensitivity: 0,
projection: 'orthographic',
autoRotate: false,
autoRotateAfterStill: 1,
orthographicSize: 100,
minAlpha: 20, // 上下旋转的最小 alpha 值。即视角能旋转到达最上面的角度。[ default: 5 ]
maxAlpha: 90, // 上下旋转的最大 alpha 值。即视角能旋转到达最下面的角度。[ default: 90 ]
minBeta: -360, // 左右旋转的最小 beta 值。即视角能旋转到达最左的角度。[ default: -80 ]
maxBeta: 360, // 左右旋转的最大 beta 值。即视角能旋转到达最右的角度。[ default: 80 ]
animation: false, // 是否开启动画。[ default: true ]
animationDurationUpdate: 1000, // 过渡动画的时长。[ default: 1000 ]
animationEasingUpdate: 'cubicInOut', // 过渡动画的缓动效果。[ default: cubicInOut ]
},
light: {
//光照阴影
main: {
color: '#02fce7', //光照颜色
intensity: 0.5, //光照强度
shadow: true, //是否显示阴影
shadowQuality: 'ultra', //阴影质量 ultra //阴影亮度
alpha: 30,
beta: 90,
},
ambient: {
color: '#fff',
intensity: 1,
},
},
zlevel: -8,
},
// 要显示的散点数据
series: [
{
left: 0,
top: 6,
bottom: 22,
type: 'map3D',
map: 'ah',
roam: false,
data: arr,
itemStyle: {
// color: "#4b6f52",
color: 'transparent',
borderWidth: 1,
borderColor: '#FFF',
opacity: 1,
},
emphasis: {
disabled: false, // 👈 一定要打开
label: {
show: false,
color: '#fff',
},
itemStyle: {
color: 'rgba(44, 186, 178, 0.45)', // 👈 青绿色半透明背景
borderColor: '#FFF', // 👈 高亮描边
borderWidth: 1,
},
},
regionHeight: 0,
shading: 'lambert',
viewControl: {
zoomSensitivity: false,
rotateSensitivity: 0,
projection: 'orthographic',
autoRotate: false,
autoRotateAfterStill: 1,
orthographicSize: 92,
animation: false, // 是否开启动画。[ default: true ]
animationDurationUpdate: 1000, // 过渡动画的时长。[ default: 1000 ]
animationEasingUpdate: 'cubicInOut', // 过渡动画的缓动效果。[ default: cubicInOut ]
},
label: {
show: true,
color: '#FFF',
position: 'top',
fontSize: 12,
fontWeight: '600',
},
light: {
//光照阴影
main: {
color: 'rgb(14,70,82)', //光照颜色
intensity: 0.1, //光照强度
shadow: true, //是否显示阴影
shadowQuality: 'ultra', //阴影质量 ultra //阴影亮度
alpha: 30,
beta: 90,
},
ambient: {
color: '#fff',
intensity: 1,
},
},
zlevel: 1,
zoom: 1,
scaleLimit: {
// 限制缩放的比例
min: 1, // 最小缩放比例
max: 1, // 最大缩放比例
},
},
{
type: 'scatter3D',
data: arr,
symbol: 'circle',
symbolSize: 11,
coordinateSystem: 'geo3D',
tooltip: { show: false },
label: {
show: false,
// position: 'top', // 先指定一个基准位置(如 'top'
// offset: [0, -10], // 向上偏移 10pxx 方向 0y 方向 -10
// triggerEvent: true,
// formatter: (params) => {
// // console.log('🚀 ~ initChart ~ params:', params)
// const val = params.data.value || []
// let unit = ''
// if (this.btnIndex === 1) unit = '万元'
// else if (this.btnIndex === 2) unit = '台'
// else if (this.btnIndex === 3) unit = '%'
// return val.length
// ? `{val|${val[2]} ${unit}}\n{name|${params.data.deptAbbreviation}}`
// : `{name|${params.data.deptAbbreviation}}`
// },
// rich: {
// val: {
// backgroundColor: { image: labelBg },
// height: 28,
// minWidth: 70,
// lineHeight: 28,
// padding: [0, 10],
// align: 'center',
// verticalAlign: 'middle',
// color: '#fff',
// fontSize: 23,
// },
// name: {
// color: '#fff',
// fontFamily: 'DS-TITLE',
// fontSize: 21,
// padding: [6, 0, 0, 0],
// },
// },
},
// 红点样式
// itemStyle: {
// color: 'rgba(217, 94, 0, 1)',
// },
// zlevel: 1,
},
],
graphic: {
elements: [
{
type: 'image',
style: {
image: mapImg, // 图片的 URL
width: 456, // 图片宽度
height: 440, // 图片高度
// 位置根据实际需求调整
x: 0,
y: 0,
},
left: 'center',
top: 'center',
},
],
},
}
myChart.setOption(option)
// 监听地图绑定双击事件(双击进入地图下一级)
myChart.on('click', (params) => {
console.log('🚀 ~ 点击 ~ params-->:', params)
console.log('🚀 ~ initChart ~ params.data-->>:', params.data)
if (!params.data) return
this.$router.push({
path: '/equipment/manage/equipment-ledger',
query: {
parentId: params.data.parentId,
deptId: params.data.deptId,
},
})
if (params.seriesType === 'map3D' && params.data) {
let city =
params.data.deptName == '安徽送变电工程有限公司' ? '安徽送变电' : params.data.name.replace(/市$/, '')
console.log('🚀 ~ initChart ~ this.$router:', this.$router)
// this.$router.push({
// path: '/screen/cityScreen',
// query: {
// cityName: city,
// },
// })
// window.open(`${window.location.origin}/screen/cityScreen?cityName=${city}`, '_blank')
}
})
myChart.on('mouseover', (params) => {
// console.log('🚀 ~ 移入 ~ params:', params)
})
myChart.on('mouseout', () => {
// this.selectedCity = null
})
return myChart
},
renderOneCompany(data, btnIndex) {
if (btnIndex == 1) {
return (
"<div style='width:260px;background:url(" +
require('./Map/assets/img/dialog-2.png') +
") no-repeat;background-size:100% 100%;margin-right:-10px;padding-bottom:30px'>" +
"<div style='height:34px;display:flex;align-items:center;padding-left:10px;color:#fff;font-size:17px'>" +
data.deptName +
'</div>' +
this.renderItem('装备价值', data.totalValue, '万元') +
'</div>'
)
}
if (btnIndex == 2) {
return (
"<div style='width:260px;background:url(" +
require('./Map/assets/img/dialog.png') +
") no-repeat;background-size:100% 100%;margin-right:-10px;padding-bottom:30px'>" +
"<div style='height:34px;display:flex;align-items:center;padding-left:10px;color:#fff;font-size:17px'>" +
data.deptName +
'</div>' +
this.renderItem('装备总量', data.totalEquipmentQuantity, '台') +
this.renderItem('线路数量', data.lineNum, '台') +
this.renderItem('变电数量', data.substationNum, '台') +
this.renderItem('电缆数量', data.cableNum, '台') +
'</div>'
)
}
if (btnIndex == 3) {
return (
"<div style='width:260px;background:url(" +
require('./Map/assets/img/dialog.png') +
") no-repeat;background-size:100% 100%;margin-right:-10px;padding-bottom:30px'>" +
"<div style='height:34px;display:flex;align-items:center;padding-left:10px;color:#fff;font-size:17px'>" +
data.deptName +
'</div>' +
this.renderItem('总配置率', data.configRate, '分') +
this.renderItem('线路设备配置率', data.valueA, '分') +
this.renderItem('变电设备配置率', data.valueB, '分') +
this.renderItem('电缆设备配置率', data.valueC, '分') +
'</div>'
)
}
if (btnIndex == 4) {
let title = ''
if (this.radio == 1) {
title = '线路工程机械化率配置率'
} else if (this.radio == 2) {
title = '变电工程机械化率配置率'
} else if (this.radio == 3) {
title = '电缆工程机械化率配置率'
}
return (
"<div style='width:260px;background:url(" +
require('./Map/assets/img/dialog-2.png') +
") no-repeat;background-size:100% 100%;margin-right:-10px;padding-bottom:30px'>" +
"<div style='height:34px;display:flex;align-items:center;padding-left:10px;color:#fff;font-size:17px'>" +
data.companyName +
'</div>' +
this.renderItem(title, data.mechanizationRate, '%') +
'</div>'
)
}
},
renderItem(label, value, unit) {
return (
"<div style='width:260px;margin-top:10px;height:25px;display:flex;align-items:center;font-size:12px;color:#666;margin-left:20px'>" +
'<div>' +
label +
'</div>' +
"<div style='margin-left:10px;font-size:16px'>" +
(value || 0) +
"<span style='font-size:12px'> " +
unit +
'</span>' +
'</div></div>'
)
},
},
}
</script>
<style lang="scss" scoped>
.num {
font-family: OPPOSans;
font-size: 24px;
line-height: 22px;
}
.name {
margin-top: 6px;
font-weight: 400;
font-size: 14px;
}
.icon {
width: 56px;
height: 54px;
position: absolute;
right: 0;
bottom: 0;
}
.top-btns {
display: flex;
flex-direction: column;
align-items: flex-start;
position: absolute;
z-index: 9;
.btn {
cursor: pointer;
width: 168px;
height: 80px;
background: #fff;
border-radius: 10px 10px 10px 10px;
margin-bottom: 16px;
padding: 15px;
display: flex;
flex-direction: column;
justify-content: center;
color: #3f3f3f;
position: relative;
}
.active {
color: #fff;
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
}
}
.map-box {
width: 100%;
height: 440px;
display: flex;
align-items: center;
justify-content: center;
}
.echarts {
width: 100%;
height: 100%;
}
// 多选框
.radio-box,
.circle-checkbox {
position: absolute;
right: -30px;
bottom: -10px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 99;
}
</style>
<style>
/* 圆圈外框 */
.circle-checkbox .el-checkbox__inner {
width: 16px;
height: 16px;
border-radius: 50%;
}
/* 选中状态背景 */
.circle-checkbox .el-checkbox__input.is-checked .el-checkbox__inner {
background-color: #3bc6c1;
border-color: #3bc6c1;
}
/* 中间的“点” */
.circle-checkbox .el-checkbox__inner::after {
content: '';
width: 6px;
height: 6px;
background: #fff;
border-radius: 50%;
position: absolute;
left: 3.6px;
top: 3.6px;
transform: none;
}
</style>