|
|
@ -8,6 +8,7 @@ import { |
|
|
|
AutoComplete, |
|
|
|
Table, |
|
|
|
Select, |
|
|
|
Progress, |
|
|
|
Modal, |
|
|
|
} from "antd"; |
|
|
|
import { |
|
|
@ -18,6 +19,8 @@ import { |
|
|
|
} from "@ant-design/icons"; |
|
|
|
import { json, useLocation, useNavigate } from "react-router-dom"; |
|
|
|
import ReactEcharts from "echarts-for-react"; |
|
|
|
import * as echarts from "echarts"; |
|
|
|
import "echarts-gl"; |
|
|
|
|
|
|
|
import { |
|
|
|
ImgError, |
|
|
@ -53,6 +56,7 @@ import { time } from "echarts"; |
|
|
|
let timer = null; |
|
|
|
let qftimer = null; |
|
|
|
let crtimer = null; |
|
|
|
let option = null; |
|
|
|
const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
return { |
|
|
|
user: state.user, |
|
|
@ -219,6 +223,14 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
income: 0, |
|
|
|
memberTotal: 0, |
|
|
|
}); |
|
|
|
//左侧数据储存 区 |
|
|
|
const [LeftDataTopqu, setLeftDataTopqu] = useState({ |
|
|
|
offRoadParks: 0, |
|
|
|
offRoadBerth: 0, |
|
|
|
roadParks: 0, |
|
|
|
roadBerth: 0, |
|
|
|
memberTotal: 0, |
|
|
|
}); |
|
|
|
const [LeftDataOther, setLeftDataOther] = useState({ |
|
|
|
usage: 0, |
|
|
|
turnoverRate: 0, |
|
|
@ -239,19 +251,19 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
status: "", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "近7日交易订单数", |
|
|
|
text: "昨日交易订单数", |
|
|
|
value: "orderTotal", |
|
|
|
img: Lf3, |
|
|
|
status: "单", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "近7日收入", |
|
|
|
text: "昨日收入", |
|
|
|
value: "income", |
|
|
|
img: Lf4, |
|
|
|
status: "元", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "近7日泊位利用率", |
|
|
|
text: "昨日泊位利用率", |
|
|
|
value: "usage", |
|
|
|
img: Lf5, |
|
|
|
status: "%", |
|
|
@ -266,7 +278,61 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
other: true, |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "近7日泊位周转率", |
|
|
|
text: "昨泊位周转率", |
|
|
|
value: "turnoverRate", |
|
|
|
img: Lf6, |
|
|
|
status: "次", |
|
|
|
other: true, |
|
|
|
url: "/dataAlyPrediction/parkTurnoverAly", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "注册会员", |
|
|
|
value: "memberTotal", |
|
|
|
img: Lf7, |
|
|
|
status: "", |
|
|
|
}, |
|
|
|
]); |
|
|
|
//区域 |
|
|
|
const [LeftShowqu, setLeftShowqu] = useState([ |
|
|
|
{ |
|
|
|
text: "停车场总数", |
|
|
|
value: "offRoadParks", |
|
|
|
img: Lf1, |
|
|
|
status: "", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "停车场泊位总数", |
|
|
|
value: "offRoadBerth", |
|
|
|
img: Lf2, |
|
|
|
status: "", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "路段总数", |
|
|
|
value: "roadParks", |
|
|
|
img: Lf3, |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "路段泊位总数", |
|
|
|
value: "roadBerth", |
|
|
|
img: Lf2, |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "昨日泊位利用率", |
|
|
|
value: "usage", |
|
|
|
img: Lf5, |
|
|
|
status: "%", |
|
|
|
other: true, |
|
|
|
url: "/dataAlyPrediction/parkUsageAly", |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "出入场流率", |
|
|
|
value: "flowrate", |
|
|
|
img: Lf5, |
|
|
|
status: "%", |
|
|
|
other: true, |
|
|
|
}, |
|
|
|
{ |
|
|
|
text: "昨泊位周转率", |
|
|
|
value: "turnoverRate", |
|
|
|
img: Lf6, |
|
|
|
status: "次", |
|
|
@ -339,6 +405,14 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
const [HoShow, setHoShow] = useState(false); |
|
|
|
//欠费弹框是否出现 |
|
|
|
const [Qf, setQf] = useState(false); |
|
|
|
|
|
|
|
//右侧top |
|
|
|
const [DataTop, setDataTop] = useState([ |
|
|
|
{ |
|
|
|
name: "", |
|
|
|
rate: "", |
|
|
|
}, |
|
|
|
]); |
|
|
|
//文字展示 |
|
|
|
const [Text, setText] = useState(""); |
|
|
|
//右侧时间切换 |
|
|
@ -504,10 +578,16 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
const SelectDay = (str, val) => { |
|
|
|
if (str == 1) { |
|
|
|
setDaySel(val); |
|
|
|
if (CarRoad[CarShow].type == 1) { |
|
|
|
GetComplaintType(RoadSelect, val); |
|
|
|
} |
|
|
|
} else if (str == 2) { |
|
|
|
setDaySet(val); |
|
|
|
if (CarRoad[CarShow].type == 2) { |
|
|
|
GetincomeType(RoadSelect, val); |
|
|
|
} else { |
|
|
|
GetParkingEvaluate(RoadSelect, val); |
|
|
|
} |
|
|
|
} else if (str == 3) { |
|
|
|
setDaySes(val); |
|
|
|
GetRevenueAnalysis(RoadSelect, val); |
|
|
@ -624,29 +704,298 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
}, |
|
|
|
}); |
|
|
|
}; |
|
|
|
const getRingOption = ( |
|
|
|
datas = [ |
|
|
|
{ |
|
|
|
key: "1星", |
|
|
|
value: 0, |
|
|
|
// 生成扇形的曲面参数方程,用于 series-surface.parametricEquation |
|
|
|
function getParametricEquation( |
|
|
|
startRatio, |
|
|
|
endRatio, |
|
|
|
isSelected, |
|
|
|
isHovered, |
|
|
|
k, |
|
|
|
h |
|
|
|
) { |
|
|
|
// 计算 |
|
|
|
let midRatio = (startRatio + endRatio) / 2; |
|
|
|
|
|
|
|
let startRadian = startRatio * Math.PI * 2; |
|
|
|
let endRadian = endRatio * Math.PI * 2; |
|
|
|
let midRadian = midRatio * Math.PI * 2; |
|
|
|
|
|
|
|
// 如果只有一个扇形,则不实现选中效果。 |
|
|
|
if (startRatio === 0 && endRatio === 1) { |
|
|
|
isSelected = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3) |
|
|
|
k = typeof k !== "undefined" ? k : 1 / 3; |
|
|
|
|
|
|
|
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0) |
|
|
|
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0; |
|
|
|
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0; |
|
|
|
|
|
|
|
// 计算高亮效果的放大比例(未高亮,则比例为 1) |
|
|
|
let hoverRate = isHovered ? 1.05 : 1; |
|
|
|
|
|
|
|
// 返回曲面参数方程 |
|
|
|
return { |
|
|
|
u: { |
|
|
|
min: -Math.PI, |
|
|
|
max: Math.PI * 3, |
|
|
|
step: Math.PI / 32, |
|
|
|
}, |
|
|
|
{ |
|
|
|
key: "2星", |
|
|
|
value: 0, |
|
|
|
|
|
|
|
v: { |
|
|
|
min: 0, |
|
|
|
max: Math.PI * 2, |
|
|
|
step: Math.PI / 20, |
|
|
|
}, |
|
|
|
{ |
|
|
|
key: "3星", |
|
|
|
value: 0, |
|
|
|
|
|
|
|
x: function (u, v) { |
|
|
|
if (u < startRadian) { |
|
|
|
return ( |
|
|
|
offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate |
|
|
|
); |
|
|
|
} |
|
|
|
if (u > endRadian) { |
|
|
|
return ( |
|
|
|
offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate |
|
|
|
); |
|
|
|
} |
|
|
|
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate; |
|
|
|
}, |
|
|
|
{ |
|
|
|
key: "4星", |
|
|
|
value: 0, |
|
|
|
|
|
|
|
y: function (u, v) { |
|
|
|
if (u < startRadian) { |
|
|
|
return ( |
|
|
|
offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate |
|
|
|
); |
|
|
|
} |
|
|
|
if (u > endRadian) { |
|
|
|
return ( |
|
|
|
offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate |
|
|
|
); |
|
|
|
} |
|
|
|
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate; |
|
|
|
}, |
|
|
|
|
|
|
|
z: function (u, v) { |
|
|
|
if (u < -Math.PI * 0.5) { |
|
|
|
return Math.sin(u); |
|
|
|
} |
|
|
|
if (u > Math.PI * 2.5) { |
|
|
|
return Math.sin(u) * h * 0.1; |
|
|
|
} |
|
|
|
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1; |
|
|
|
}, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 生成模拟 3D 饼图的配置项 |
|
|
|
function getPie3D(pieData, internalDiameterRatio) { |
|
|
|
let series = []; |
|
|
|
let sumValue = 0; |
|
|
|
let startValue = 0; |
|
|
|
let endValue = 0; |
|
|
|
let legendData = []; |
|
|
|
let k = |
|
|
|
typeof internalDiameterRatio !== "undefined" |
|
|
|
? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) |
|
|
|
: 1 / 3; |
|
|
|
|
|
|
|
// 为每一个饼图数据,生成一个 series-surface 配置 |
|
|
|
for (let i = 0; i < pieData.length; i++) { |
|
|
|
sumValue += pieData[i].value; |
|
|
|
|
|
|
|
let seriesItem = { |
|
|
|
name: |
|
|
|
typeof pieData[i].name === "undefined" |
|
|
|
? `series${i}` |
|
|
|
: pieData[i].name, |
|
|
|
type: "surface", |
|
|
|
parametric: true, |
|
|
|
wireframe: { |
|
|
|
show: false, |
|
|
|
}, |
|
|
|
pieData: pieData[i], |
|
|
|
pieStatus: { |
|
|
|
selected: false, |
|
|
|
hovered: false, |
|
|
|
k: k, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
if (typeof pieData[i].itemStyle != "undefined") { |
|
|
|
let itemStyle = {}; |
|
|
|
|
|
|
|
typeof pieData[i].itemStyle.color != "undefined" |
|
|
|
? (itemStyle.color = pieData[i].itemStyle.color) |
|
|
|
: null; |
|
|
|
typeof pieData[i].itemStyle.opacity != "undefined" |
|
|
|
? (itemStyle.opacity = pieData[i].itemStyle.opacity) |
|
|
|
: null; |
|
|
|
|
|
|
|
seriesItem.itemStyle = itemStyle; |
|
|
|
} |
|
|
|
series.push(seriesItem); |
|
|
|
} |
|
|
|
|
|
|
|
// 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数, |
|
|
|
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。 |
|
|
|
for (let i = 0; i < series.length; i++) { |
|
|
|
endValue = startValue + series[i].pieData.value; |
|
|
|
|
|
|
|
series[i].pieData.startRatio = startValue / sumValue; |
|
|
|
series[i].pieData.endRatio = endValue / sumValue; |
|
|
|
series[i].parametricEquation = getParametricEquation( |
|
|
|
series[i].pieData.startRatio, |
|
|
|
series[i].pieData.endRatio, |
|
|
|
false, |
|
|
|
false, |
|
|
|
k, |
|
|
|
series[i].pieData.value |
|
|
|
); |
|
|
|
|
|
|
|
startValue = endValue; |
|
|
|
|
|
|
|
legendData.push(series[i].name); |
|
|
|
} |
|
|
|
|
|
|
|
// 补充一个透明的圆环,用于支撑高亮功能的近似实现。 |
|
|
|
series.push({ |
|
|
|
name: "mouseoutSeries", |
|
|
|
type: "surface", |
|
|
|
parametric: true, |
|
|
|
wireframe: { |
|
|
|
show: false, |
|
|
|
}, |
|
|
|
itemStyle: { |
|
|
|
opacity: 0, |
|
|
|
}, |
|
|
|
parametricEquation: { |
|
|
|
u: { |
|
|
|
min: 0, |
|
|
|
max: Math.PI * 2, |
|
|
|
step: Math.PI / 20, |
|
|
|
}, |
|
|
|
v: { |
|
|
|
min: 0, |
|
|
|
max: Math.PI, |
|
|
|
step: Math.PI / 20, |
|
|
|
}, |
|
|
|
x: function (u, v) { |
|
|
|
return Math.sin(v) * Math.sin(u) + Math.sin(u); |
|
|
|
}, |
|
|
|
y: function (u, v) { |
|
|
|
return Math.sin(v) * Math.cos(u) + Math.cos(u); |
|
|
|
}, |
|
|
|
z: function (u, v) { |
|
|
|
return Math.cos(v) > 0 ? 0.1 : -0.1; |
|
|
|
}, |
|
|
|
}, |
|
|
|
}); |
|
|
|
|
|
|
|
// 准备待返回的配置项,把准备好的 legendData、series 传入。 |
|
|
|
let option = { |
|
|
|
//animation: false, |
|
|
|
// title: { |
|
|
|
// text: "{a|" + sum(datas.map((ele) => ele.value)) + "}{c|次}", |
|
|
|
// x: "center", |
|
|
|
// y: "center", |
|
|
|
// subtext: "评价总数", |
|
|
|
// subtextStyle: { |
|
|
|
// color: "#fff", |
|
|
|
// fontSize: 14, |
|
|
|
// }, |
|
|
|
// textStyle: { |
|
|
|
// rich: { |
|
|
|
// a: { |
|
|
|
// fontSize: 30, |
|
|
|
// color: "#4DC3FF", |
|
|
|
// }, |
|
|
|
|
|
|
|
// c: { |
|
|
|
// fontSize: 14, |
|
|
|
// color: "#4DC3FF", |
|
|
|
// // padding: [5,0] |
|
|
|
// }, |
|
|
|
// }, |
|
|
|
// }, |
|
|
|
// }, |
|
|
|
legend: { |
|
|
|
type: "scroll", |
|
|
|
//right: "5%", |
|
|
|
top: "bottom", |
|
|
|
bottom: "center", |
|
|
|
data: legendData, |
|
|
|
itemWidth: 18, |
|
|
|
itemHeight: 12, |
|
|
|
textStyle: { |
|
|
|
fontSize: 14, |
|
|
|
color: "white", |
|
|
|
}, |
|
|
|
}, |
|
|
|
tooltip: { |
|
|
|
formatter: (params) => { |
|
|
|
if (params.seriesName !== "mouseoutSeries") { |
|
|
|
return `${ |
|
|
|
params.seriesName |
|
|
|
}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${ |
|
|
|
params.color |
|
|
|
};"></span>${option.series[params.seriesIndex].pieData.value}(次)`; |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
xAxis3D: { |
|
|
|
min: -1, |
|
|
|
max: 1, |
|
|
|
}, |
|
|
|
yAxis3D: { |
|
|
|
min: -1, |
|
|
|
max: 1, |
|
|
|
}, |
|
|
|
zAxis3D: { |
|
|
|
min: -1, |
|
|
|
max: 1, |
|
|
|
}, |
|
|
|
grid3D: { |
|
|
|
show: false, |
|
|
|
boxHeight: 10, |
|
|
|
viewControl: { |
|
|
|
//3d效果可以放大、旋转等,请自己去查看官方配置 |
|
|
|
alpha: 40, |
|
|
|
// beta: 40, |
|
|
|
rotateSensitivity: 0, |
|
|
|
zoomSensitivity: 0, |
|
|
|
panSensitivity: 0, |
|
|
|
autoRotate: false, |
|
|
|
}, |
|
|
|
//后处理特效可以为画面添加高光、景深、环境光遮蔽(SSAO)、调色等效果。可以让整个画面更富有质感。 |
|
|
|
postEffect: { |
|
|
|
//配置这项会出现锯齿,请自己去查看官方配置有办法解决 |
|
|
|
enable: true, |
|
|
|
bloom: { |
|
|
|
enable: true, |
|
|
|
bloomIntensity: 0.1, |
|
|
|
}, |
|
|
|
SSAO: { |
|
|
|
enable: true, |
|
|
|
quality: "medium", |
|
|
|
radius: 2, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
series: series, |
|
|
|
}; |
|
|
|
return option; |
|
|
|
} |
|
|
|
|
|
|
|
const getRingOption = ( |
|
|
|
datas = [ |
|
|
|
{ |
|
|
|
key: "5星", |
|
|
|
key: "1星", |
|
|
|
value: 0, |
|
|
|
}, |
|
|
|
] |
|
|
|
], |
|
|
|
type |
|
|
|
) => { |
|
|
|
// 获取所有地区名称 |
|
|
|
|
|
|
@ -657,12 +1006,13 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
value: ele.value, |
|
|
|
}; |
|
|
|
}) || []; |
|
|
|
if (type == 2) { |
|
|
|
setRightTwo({ |
|
|
|
title: { |
|
|
|
text: "{a|" + sum(datas.map((ele) => ele.value)) + "}{c|次}", |
|
|
|
text: "{a|" + sum(datas.map((ele) => ele.value)) + "}", |
|
|
|
x: "center", |
|
|
|
y: "center", |
|
|
|
subtext: "评价总数", |
|
|
|
subtext: "营业收入", |
|
|
|
subtextStyle: { |
|
|
|
color: "#fff", |
|
|
|
fontSize: 14, |
|
|
@ -685,7 +1035,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
tooltip: { |
|
|
|
trigger: "item", |
|
|
|
formatter: (params) => { |
|
|
|
return `<div class="ttopi">${params.marker} ${params.name} ${params.value}次 ${params.percent}%</div>`; |
|
|
|
return `<div class="ttopi">${params.marker} ${params.name} ${params.value} ${params.percent}%</div>`; |
|
|
|
}, |
|
|
|
}, |
|
|
|
legend: { |
|
|
@ -694,7 +1044,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
top: "bottom", |
|
|
|
bottom: "center", |
|
|
|
//data: areaNames, |
|
|
|
data: ["1星", "2星", "3星", "4星", "5星"], |
|
|
|
data: datas.map((ele) => ele.key), |
|
|
|
itemWidth: 18, |
|
|
|
itemHeight: 12, |
|
|
|
textStyle: { |
|
|
@ -735,6 +1085,156 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
y2: 20, |
|
|
|
}, |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// 传入数据生成 option |
|
|
|
option = getPie3D([...arrRight], 0.59); |
|
|
|
var myChart = echarts.init(document.getElementById("ecsdf")); |
|
|
|
myChart.setOption(option); |
|
|
|
let selectedIndex = ""; |
|
|
|
let hoveredIndex = ""; |
|
|
|
|
|
|
|
// 监听点击事件,实现选中效果(单选) |
|
|
|
// myChart.on("click", function (params) { |
|
|
|
// // 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。 |
|
|
|
// let isSelected = !option.series[params.seriesIndex].pieStatus.selected; |
|
|
|
// let isHovered = option.series[params.seriesIndex].pieStatus.hovered; |
|
|
|
// let k = option.series[params.seriesIndex].pieStatus.k; |
|
|
|
// let startRatio = option.series[params.seriesIndex].pieData.startRatio; |
|
|
|
// let endRatio = option.series[params.seriesIndex].pieData.endRatio; |
|
|
|
|
|
|
|
// // 如果之前选中过其他扇形,将其取消选中(对 option 更新) |
|
|
|
// if (selectedIndex !== "" && selectedIndex !== params.seriesIndex) { |
|
|
|
// option.series[selectedIndex].parametricEquation = |
|
|
|
// getParametricEquation( |
|
|
|
// option.series[selectedIndex].pieData.startRatio, |
|
|
|
// option.series[selectedIndex].pieData.endRatio, |
|
|
|
// false, |
|
|
|
// false, |
|
|
|
// k, |
|
|
|
// option.series[selectedIndex].pieData.value |
|
|
|
// ); |
|
|
|
// option.series[selectedIndex].pieStatus.selected = false; |
|
|
|
// } |
|
|
|
|
|
|
|
// // 对当前点击的扇形,执行选中/取消选中操作(对 option 更新) |
|
|
|
// option.series[params.seriesIndex].parametricEquation = |
|
|
|
// getParametricEquation( |
|
|
|
// startRatio, |
|
|
|
// endRatio, |
|
|
|
// isSelected, |
|
|
|
// isHovered, |
|
|
|
// k, |
|
|
|
// option.series[selectedIndex].pieData.value |
|
|
|
// ); |
|
|
|
// option.series[params.seriesIndex].pieStatus.selected = isSelected; |
|
|
|
|
|
|
|
// // 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex |
|
|
|
// isSelected ? (selectedIndex = params.seriesIndex) : null; |
|
|
|
|
|
|
|
// // 使用更新后的 option,渲染图表 |
|
|
|
// myChart.setOption(option); |
|
|
|
// }); |
|
|
|
|
|
|
|
// 监听 mouseover,近似实现高亮(放大)效果 |
|
|
|
myChart.on("mouseover", function (params) { |
|
|
|
// 准备重新渲染扇形所需的参数 |
|
|
|
let isSelected; |
|
|
|
let isHovered; |
|
|
|
let startRatio; |
|
|
|
let endRatio; |
|
|
|
let k; |
|
|
|
|
|
|
|
// 如果触发 mouseover 的扇形当前已高亮,则不做操作 |
|
|
|
if (hoveredIndex === params.seriesIndex) { |
|
|
|
return; |
|
|
|
|
|
|
|
// 否则进行高亮及必要的取消高亮操作 |
|
|
|
} else { |
|
|
|
// 如果当前有高亮的扇形,取消其高亮状态(对 option 更新) |
|
|
|
if (hoveredIndex !== "") { |
|
|
|
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。 |
|
|
|
isSelected = option.series[hoveredIndex].pieStatus.selected; |
|
|
|
isHovered = false; |
|
|
|
startRatio = option.series[hoveredIndex].pieData.startRatio; |
|
|
|
endRatio = option.series[hoveredIndex].pieData.endRatio; |
|
|
|
k = option.series[hoveredIndex].pieStatus.k; |
|
|
|
|
|
|
|
// 对当前点击的扇形,执行取消高亮操作(对 option 更新) |
|
|
|
option.series[hoveredIndex].parametricEquation = |
|
|
|
getParametricEquation( |
|
|
|
startRatio, |
|
|
|
endRatio, |
|
|
|
isSelected, |
|
|
|
isHovered, |
|
|
|
k, |
|
|
|
option.series[hoveredIndex].pieData.value |
|
|
|
); |
|
|
|
option.series[hoveredIndex].pieStatus.hovered = isHovered; |
|
|
|
|
|
|
|
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空 |
|
|
|
hoveredIndex = ""; |
|
|
|
} |
|
|
|
|
|
|
|
// 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新) |
|
|
|
if (params.seriesName !== "mouseoutSeries") { |
|
|
|
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。 |
|
|
|
isSelected = option.series[params.seriesIndex].pieStatus.selected; |
|
|
|
isHovered = true; |
|
|
|
startRatio = option.series[params.seriesIndex].pieData.startRatio; |
|
|
|
endRatio = option.series[params.seriesIndex].pieData.endRatio; |
|
|
|
k = option.series[params.seriesIndex].pieStatus.k; |
|
|
|
|
|
|
|
// 对当前点击的扇形,执行高亮操作(对 option 更新) |
|
|
|
option.series[params.seriesIndex].parametricEquation = |
|
|
|
getParametricEquation( |
|
|
|
startRatio, |
|
|
|
endRatio, |
|
|
|
isSelected, |
|
|
|
isHovered, |
|
|
|
k, |
|
|
|
option.series[params.seriesIndex].pieData.value + 5 |
|
|
|
); |
|
|
|
option.series[params.seriesIndex].pieStatus.hovered = isHovered; |
|
|
|
|
|
|
|
// 记录上次高亮的扇形对应的系列号 seriesIndex |
|
|
|
hoveredIndex = params.seriesIndex; |
|
|
|
} |
|
|
|
|
|
|
|
// 使用更新后的 option,渲染图表 |
|
|
|
myChart.setOption(option); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 修正取消高亮失败的 bug |
|
|
|
myChart.on("globalout", function () { |
|
|
|
if (hoveredIndex !== "") { |
|
|
|
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。 |
|
|
|
let isSelected = option.series[hoveredIndex].pieStatus.selected; |
|
|
|
let isHovered = false; |
|
|
|
let k = option.series[hoveredIndex].pieStatus.k; |
|
|
|
let startRatio = option.series[hoveredIndex].pieData.startRatio; |
|
|
|
let endRatio = option.series[hoveredIndex].pieData.endRatio; |
|
|
|
|
|
|
|
// 对当前点击的扇形,执行取消高亮操作(对 option 更新) |
|
|
|
option.series[hoveredIndex].parametricEquation = |
|
|
|
getParametricEquation( |
|
|
|
startRatio, |
|
|
|
endRatio, |
|
|
|
isSelected, |
|
|
|
isHovered, |
|
|
|
k, |
|
|
|
option.series[hoveredIndex].pieData.value |
|
|
|
); |
|
|
|
option.series[hoveredIndex].pieStatus.hovered = isHovered; |
|
|
|
|
|
|
|
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空 |
|
|
|
hoveredIndex = ""; |
|
|
|
} |
|
|
|
|
|
|
|
// 使用更新后的 option,渲染图表 |
|
|
|
myChart.setOption(option); |
|
|
|
}); |
|
|
|
} |
|
|
|
}; |
|
|
|
//右下 |
|
|
|
const getRevenueOption = ( |
|
|
@ -856,6 +1356,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
setCarShow(index + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
setText(""); |
|
|
|
setRoadSelect("1"); |
|
|
|
}; |
|
|
|
//底部车场类型切换 |
|
|
@ -890,6 +1391,26 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
} |
|
|
|
); |
|
|
|
}; |
|
|
|
//车场总数 单独提供给区大屏 |
|
|
|
const GetParkinfo = () => { |
|
|
|
ajax.ParkingOverview.GetParkinfo({ |
|
|
|
areaType: CarRoad[CarShow].type, |
|
|
|
value: CarRoad[CarShow].value, |
|
|
|
}).then( |
|
|
|
(res) => { |
|
|
|
if (parseInt(res?.status) === 20000) { |
|
|
|
setLeftDataTopqu({ ...res?.data }); |
|
|
|
} else { |
|
|
|
message.error(res?.message); |
|
|
|
} |
|
|
|
setLoading(true); |
|
|
|
}, |
|
|
|
(err) => { |
|
|
|
console.log(err); |
|
|
|
setLoading(true); |
|
|
|
} |
|
|
|
); |
|
|
|
}; |
|
|
|
//获取左边数据(7日利用率和周转) |
|
|
|
const GetUseInfo = (val) => { |
|
|
|
ajax.ParkingOverview.GetUseInfo({ |
|
|
@ -1051,6 +1572,51 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
} |
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
//获取收费top5 |
|
|
|
const GetrateRank = () => { |
|
|
|
ajax.ParkingOverview.GetrateRank({ |
|
|
|
areaType: CarRoad[CarShow].type, |
|
|
|
value: CarRoad[CarShow].value, |
|
|
|
}).then( |
|
|
|
(res) => { |
|
|
|
if (parseInt(res?.status) === 20000) { |
|
|
|
setDataTop(res?.data); |
|
|
|
// getRevenueOption(res.data || []); |
|
|
|
} else { |
|
|
|
message.error(res?.message); |
|
|
|
} |
|
|
|
setLoading(true); |
|
|
|
}, |
|
|
|
(err) => { |
|
|
|
console.log(err); |
|
|
|
setLoading(true); |
|
|
|
} |
|
|
|
); |
|
|
|
}; |
|
|
|
//概览-营收分析类型占比 |
|
|
|
const GetincomeType = (val, item) => { |
|
|
|
ajax.ParkingOverview.GetincomeType({ |
|
|
|
type: val, |
|
|
|
dateType: item, |
|
|
|
areaType: CarRoad[CarShow].type, |
|
|
|
value: CarRoad[CarShow].value, |
|
|
|
}).then( |
|
|
|
(res) => { |
|
|
|
if (parseInt(res?.status) === 20000) { |
|
|
|
// setZata(res?.data); |
|
|
|
getRingOption(res?.data, 2); |
|
|
|
} else { |
|
|
|
message.error(res?.message); |
|
|
|
} |
|
|
|
setLoading(true); |
|
|
|
}, |
|
|
|
(err) => { |
|
|
|
console.log(err); |
|
|
|
setLoading(true); |
|
|
|
} |
|
|
|
); |
|
|
|
}; |
|
|
|
//获取收入分析 |
|
|
|
const GetRevenueAnalysis = (val, item) => { |
|
|
|
ajax.ParkingOverview.GetRevenueAnalysis({ |
|
|
@ -1073,7 +1639,8 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
setLoading(true); |
|
|
|
} |
|
|
|
); |
|
|
|
}; //获取车场评价 |
|
|
|
}; |
|
|
|
//获取车场评价 |
|
|
|
const GetParkingEvaluate = (val, item) => { |
|
|
|
ajax.ParkingOverview.GetParkingEvaluate({ |
|
|
|
type: val, |
|
|
@ -1084,7 +1651,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
(res) => { |
|
|
|
if (parseInt(res?.status) === 20000) { |
|
|
|
// setZata(res?.data); |
|
|
|
getRingOption(res?.data); |
|
|
|
getRingOption(res?.data, 1); |
|
|
|
} else { |
|
|
|
message.error(res?.message); |
|
|
|
} |
|
|
@ -1095,7 +1662,8 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
setLoading(true); |
|
|
|
} |
|
|
|
); |
|
|
|
}; //获取客诉类型分析 |
|
|
|
}; |
|
|
|
//获取客诉类型分析 |
|
|
|
const GetComplaintType = (val, item) => { |
|
|
|
ajax.ParkingOverview.GetComplaintType({ |
|
|
|
type: val, |
|
|
@ -1207,12 +1775,19 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
setDaySet("1"); |
|
|
|
setDaySes("1"); |
|
|
|
getMapData(RoadSelect); |
|
|
|
GetDataStatic(RoadSelect); |
|
|
|
GetOverviewData(RoadSelect); |
|
|
|
// GetDataStatic(RoadSelect); |
|
|
|
GetUseInfo(RoadSelect); |
|
|
|
GetRevenueAnalysis(RoadSelect, "1"); |
|
|
|
GetParkingEvaluate(RoadSelect, "1"); |
|
|
|
if (CarRoad[CarShow].type == 2) { |
|
|
|
GetrateRank(); |
|
|
|
GetincomeType(RoadSelect, "1"); |
|
|
|
GetOverviewData(RoadSelect); |
|
|
|
} else { |
|
|
|
GetComplaintType(RoadSelect, "1"); |
|
|
|
// GetincomeType(RoadSelect, "1"); |
|
|
|
GetParkinfo(); |
|
|
|
GetParkingEvaluate(RoadSelect, "1"); |
|
|
|
} |
|
|
|
}, [RoadSelect, CarShow]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
@ -1237,7 +1812,8 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
<div className="left_home"> |
|
|
|
<div className="pkh_title">停车业务概览</div> |
|
|
|
<div className="dlex_f"> |
|
|
|
{LeftShow.map((ele) => { |
|
|
|
{CarRoad[CarShow].type == 2 |
|
|
|
? LeftShow.map((ele) => { |
|
|
|
return ( |
|
|
|
<div |
|
|
|
className={ele?.url ? "curpoin lf_s" : "lf_s"} |
|
|
@ -1245,7 +1821,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
if (ele?.url) { |
|
|
|
window.location = `/#${ele.url}`; |
|
|
|
} |
|
|
|
if (ele.text == "泊位总数") { |
|
|
|
if (ele.text == "停车场泊位总数") { |
|
|
|
getData(FormData); |
|
|
|
setBoOpenClass({ |
|
|
|
width: 1632, |
|
|
@ -1277,6 +1853,47 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
}) |
|
|
|
: LeftShowqu.map((ele) => { |
|
|
|
return ( |
|
|
|
<div |
|
|
|
className={ele?.url ? "curpoin lf_s" : "lf_s"} |
|
|
|
onClick={() => { |
|
|
|
if (ele?.url) { |
|
|
|
window.location = `/#${ele.url}`; |
|
|
|
} |
|
|
|
// if (ele.text == "停车场泊位总数") { |
|
|
|
// getData(FormData); |
|
|
|
// setBoOpenClass({ |
|
|
|
// width: 1632, |
|
|
|
// title: "泊位列表", |
|
|
|
// type: 1, |
|
|
|
// }); |
|
|
|
// setBoOpen(true); |
|
|
|
// } |
|
|
|
}} |
|
|
|
key={ele.text} |
|
|
|
> |
|
|
|
<img src={ele.img} alt="" /> |
|
|
|
<div className="lf_num"> |
|
|
|
<div className="pldf"> |
|
|
|
<p |
|
|
|
title={ |
|
|
|
ele.other |
|
|
|
? LeftDataOther[ele.value] |
|
|
|
: LeftDataTopqu[ele.value] |
|
|
|
} |
|
|
|
> |
|
|
|
{ele.other |
|
|
|
? LeftDataOther[ele.value] |
|
|
|
: LeftDataTopqu[ele.value]} |
|
|
|
</p> |
|
|
|
<i>{ele.status}</i> |
|
|
|
</div> |
|
|
|
<span>{ele.text}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
})} |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -1363,16 +1980,15 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
) : ( |
|
|
|
"" |
|
|
|
)} |
|
|
|
{Text && ( |
|
|
|
// CarRoad[CarShow].type == 1 && |
|
|
|
{ |
|
|
|
<div className="left_content"> |
|
|
|
<p> |
|
|
|
<SoundOutlined /> |
|
|
|
</p> |
|
|
|
{Text} |
|
|
|
<div>{Text}</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
<div className="show_c"> |
|
|
|
} |
|
|
|
{/* <div className="show_c"> |
|
|
|
<div className="lf_num"> |
|
|
|
<div className="pldf"> |
|
|
|
<p title={Zata?.income}>{Zata?.income}</p> |
|
|
@ -1387,7 +2003,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
</div> |
|
|
|
<span>今日服务车次数</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> */} |
|
|
|
<div className="right_ssdf"> |
|
|
|
<div className="c_t"> |
|
|
|
{MapS.map((ele) => { |
|
|
@ -1435,6 +2051,33 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
{HoShow ? <i></i> : ""} |
|
|
|
</div> |
|
|
|
<div className="right_home"> |
|
|
|
{CarRoad[CarShow].type == 2 ? ( |
|
|
|
<div> |
|
|
|
<div className="pkh_title">收费员排行Top5</div> |
|
|
|
<div className="tfff"> |
|
|
|
{DataTop.map((ele, index) => { |
|
|
|
return ( |
|
|
|
<div className="topph" key={ele.name + index}> |
|
|
|
<div className="nol"> |
|
|
|
<p>No.{index + 1}</p> |
|
|
|
<span></span> |
|
|
|
</div> |
|
|
|
<div className="nor"> |
|
|
|
<div className="trr"> |
|
|
|
<span>{ele.name || "--"}</span> |
|
|
|
<span>{ele.rate || 0}</span> |
|
|
|
</div> |
|
|
|
<Progress |
|
|
|
showInfo={false} |
|
|
|
percent={ele.rate.slice(0, ele.rate.length - 1) || 0} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
})} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) : ( |
|
|
|
<div> |
|
|
|
<div className="pkh_title"> |
|
|
|
客诉类型分析 |
|
|
@ -1467,15 +2110,18 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
style={{ height: "180px", width: "100%" }} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
<div> |
|
|
|
<div className="pkh_title"> |
|
|
|
车场服务评价 |
|
|
|
{CarRoad[CarShow].type == 2 ? "营业收入分析" : "车场服务评价"} |
|
|
|
{CarRoad[CarShow].type == 1 && ( |
|
|
|
<Tooltip |
|
|
|
placement="bottom" |
|
|
|
title={<span>统计范围内用户对车场进行评价的不同分值占比</span>} |
|
|
|
> |
|
|
|
<i>?</i> |
|
|
|
</Tooltip> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
<div className="day_select"> |
|
|
|
{Dayfour.map((ele) => { |
|
|
@ -1492,10 +2138,14 @@ const ParkingOverview = connect(function mapStateToProps(state) { |
|
|
|
); |
|
|
|
})} |
|
|
|
</div> |
|
|
|
{CarRoad[CarShow].type == 1 ? ( |
|
|
|
<div id="ecsdf" style={{ height: "180px", width: "100%" }}></div> |
|
|
|
) : ( |
|
|
|
<ReactEcharts |
|
|
|
option={RightTwo} |
|
|
|
style={{ height: "180px", width: "100%" }} |
|
|
|
/> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<div className="pkh_title"> |
|
|
|