停车场项目web, 互联网仓库, 开发完成后, 需要将代码回传云桌面.
 
 
 
 

737 lines
30 KiB

import React, { useState, useEffect } from "react";
import { ResultFlowResult } from "@/components";
import { Select, Input, Button, Table, message, Pagination, DatePicker, Modal, Cascader, Tooltip } from "antd";
import { Icon } from "@/components"
import { useSessionStorageState } from "ahooks";
import { lineChartOption, ringChartOption } from "../echarts.config";
import moment from "moment";
import ReactEcharts from "echarts-for-react";
import "./index.scss";
import ajax from "@/services";
//停车时段分析
function ParkingAlyPeriod() {
// session缓存
const [defaultParams, setDefaultParams] = useSessionStorageState(
"formData_parkingAlyPeriod",
{ defaultValue: null }
);
//区域的下拉数据
const [areaList, setAreaList] = useState([]);
// 默认数据
const defaultData = {
start_time: moment().subtract('days').startOf('day').format("YYYY-MM-DD"),
end_time: moment().endOf("day").format("YYYY-MM-DD"),
date_type: '1',
};
// 分页数据
const [pageInfo, setPageInfo] = useState({
pn: defaultParams ? defaultParams?.pn : 1,
page_size: defaultParams ? defaultParams?.page_size : 15,
});
// 表单数据
const [formData, setFormData] = useState({
...defaultData,
...defaultParams,
});
// 搜索提交数据-存储
const [holdData, setHoldData] = useState(formData);
// 访问接口,isAjax改变时执行
const [isAjax, setIsAjax] = useState(false);
// 检索按钮加载状态
const [loading, setLoading] = useState(false);
// 表格加载状态
const [tabLoading, setTabLoading] = useState(false);
// 表格返回数据
const [resultData, setResultData] = useState({
total: 0,
list: [],
});
//出入场车流量分析
const [revenueData, setRevenueData] = useState({});
//停车饱和度趋势分析
const [parkData, setParkData] = useState({});
const [searchSelectList, setSearchSelectList] = useState([]); //搜索下拉数据
const [sessionTabList, setSessionTabList] = useSessionStorageState('parkingAlyPeriod', {
value: {
}
})
useEffect(() => {
if (sessionTabList && Object.values(sessionTabList).length > 0) {
setFormData({
...formData, ...sessionTabList
})
getCheck({
...sessionTabList
})
} else {
getCheck()
}
}, [isAjax])
useEffect(() => {
setSessionTabList({
...formData
})
}, [formData])
useEffect(() => {
getSelectList();
}, []);
// 访问接口,获取表格
// useEffect(() => {
// getData();
// }, [isAjax]);
//时间状态切换
const TimeChange = () => {
let e = formData.date_type;
let str = "day";
let mat = "YYYY-MM-DD";
if (e == 4) {
str = "year";
mat = "YYYY";
} else if (e == 3) {
str = "month";
mat = "YYYY-MM";
} else if (e == 2) {
str = "week";
mat = "YYYY-MM-DD";
}
return { str, mat };
};
//切换时间变化
const SetTimeNow = (e) => {
let start = "";
let end = "";
if (e == 4) {
start = moment().format("YYYY");
end = moment().format("YYYY");
} else if (e == 3) {
start = moment().startOf('month').format("YYYY-MM-DD");
end = moment().endOf("month").format("YYYY-MM-DD");
} else if (e == 2) {
start = moment().day(1).format("YYYY-MM-DD");
end = moment().day(7).format("YYYY-MM-DD");
} else {
start = moment().startOf("day").format("YYYY-MM-DD");
end = moment().endOf("day").format("YYYY-MM-DD");
}
setFormData({
...formData,
date_type: e,
start_time: start,
end_time: end,
});
};
//出入场车流量分析 折线图
const getRevenueOption = (data) => {
const areaNames = data[0].name ? [...new Set(data.map((item) => item.name))] : ['入场车次', '出场车次'];
// 获取所有横坐标
const dates = [...new Set(data.map((item) => item.hour))].sort(
(a, b) => a.hour - b.hour
);
// 构建数据对象
const seriesData = areaNames.map((areaName, index) => {
// 获取数据
const areaData = data[0].name ? data.filter((item) => item.name === areaName) : data
// 构建数据对象
return {
name: areaNames.length > 1 ? areaName : '',
type: "line",
itemStyle: {
label: {
show: true, //开启显示
position: 'top', //在上方显示
color: 'white',//字体颜色
fontSize: 10//字体大小
},
},
data: dates.map((item) => {
for (const { hour, total_in_records, total_out_records } of areaData) {
if (hour === item) return index == 1 ? total_in_records : total_out_records;
}
return 0;
}),
};
});
// 构建X轴数据
const xAxisData = dates.map((date) => {
return {
value: date,
align: "center",
lineStyle: {
color: "skyblue", // 设置线的颜色为天蓝色
shadowBlur: 6,
},
};
});
setRevenueData(lineChartOption(areaNames, xAxisData, "车次数(个)", seriesData));
};
//停车饱和趋势分析分析 折线图
const getParkOption = (data) => {
// data = [
// {
// "hour": 0,
// "occupancy_rate": "0.01%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 1,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 2,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 3,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 4,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 5,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 6,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 7,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 8,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 9,
// "occupancy_rate": "0.1%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 10,
// "occupancy_rate": "0.01%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 11,
// "occupancy_rate": "0.04%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 12,
// "occupancy_rate": "0.06%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 13,
// "occupancy_rate": "0.04%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 14,
// "occupancy_rate": "0.06%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 15,
// "occupancy_rate": "0.01%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 16,
// "occupancy_rate": "0.04%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 17,
// "occupancy_rate": "0.04%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 18,
// "occupancy_rate": "0.07%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 19,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 20,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 21,
// "occupancy_rate": "0.01%",
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 22,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// },
// {
// "hour": 23,
// "occupancy_rate": 0,
// "charge_type": "2",
// "charge_type_name": "二类区"
// }
// ]
const areaNames = data[0].charge_type_name ? [...new Set(data.map((item) => item.charge_type_name))] : [''];
// 获取所有横坐标
const dates = [...new Set(data.map((item) => item.hour))].sort(
(a, b) => a.hour - b.hour
);
// 构建数据对象
const seriesData = areaNames.map((areaName, index) => {
// 获取数据
const areaData = data[0].charge_type_name ? data.filter((item) => item.charge_type_name === areaName) : data
// 构建数据对象
return {
name: areaName,
type: "line",
itemStyle: {
label: {
show: true, //开启显示
position: 'top', //在上方显示
color: 'white',//字体颜色
fontSize: 10//字体大小
},
},
data: dates.map((item) => {
for (const { hour, occupancy_rate } of areaData) {
if (hour === item) return parseFloat(occupancy_rate);
}
return 0;
}),
};
});
// 构建X轴数据
const xAxisData = dates.map((date) => {
return {
value: date,
align: "center",
lineStyle: {
color: "skyblue", // 设置线的颜色为天蓝色
shadowBlur: 6,
},
};
});
setParkData(lineChartOption(areaNames, xAxisData, "饱和度", seriesData));
};
function getParkingIncome(data) {
ajax
.getParkingAlyPeriodLine(data)
.then((res) => {
if (res.status === 20000) {
getRevenueOption(res.data.list);
setResultData(res.data)
}
})
.catch((err) => console.error(err));
}
function getParkingData(data) {
ajax
.getParkingAlyPeriodParkLine(data)
.then((res) => {
if (res.status === 20000) {
getParkOption(res.data.list);
}
})
.catch((err) => console.error(err));
}
// 获取下拉数据
const getSelectList = () => {
ajax.getOperator().then((e) => {
setSearchSelectList([
...searchSelectList,
...e.data
])
})
};
// 携带参数处理
const getCheck = (v) => {
let postData = { ...formData };
if (!loading) {
postData = { ...holdData };
}
setDefaultParams({ ...postData, ...pageInfo });
if (moment(formData.end_time) - moment(formData.start_time) > 1000 * 31 * 24 * 3600) {
message.error("时间范围限制为31天!")
setLoading(false);
setTabLoading(false);
return
}
setLoading(false);
setTabLoading(false);
let params = { ...postData, ...v, ...pageInfo }
//请求接口
getParkingIncome(params)
getParkingData(params)
};
// 检索数据
const handleSearch = () => {
setLoading(true);
setPageInfo({ ...pageInfo, ...{ pn: 1 } });
setHoldData(formData);
setIsAjax(!isAjax);
};
// 导出
const handleExport = () => {
if (tableData.list.area_list?.length > 0) {
let { pn, page_size, ...params } = defaultParams;
ajax.getParkingAlyDurationParkingExp(defaultParams).then(
(res) => {
if (res) {
window.open(res.data.export_url)
} else {
message.error(res?.message);
}
},
(err) => {
console.log(err);
}
);
} else {
message.error("暂无数据");
}
};
// useEffect(() => {
// getParkingIncome();
// }, []);
//区域下拉框数据
useEffect(() => {
ajax
.getAreaTree()
.then((res) => {
if (res.status === 20000) {
setAreaList(res.data);
}
})
.catch((err) => {
console.error(err);
});
}, []);
return (
<>
<div className="edit-order-inquiry">
<div className="paid-search">
<div className="title">查询条件</div>
<div className="form-Wrap">
<div className="yisa-search">
<label>区域</label>
<Cascader
className="form-con"
popupClassName="start-exception-deal-cascader"
options={areaList}
placeholder="请选择区域"
expandTrigger="hover"
fieldNames={{
label: "name",
value: "id",
children: "children",
}}
value={formData.area_id}
onChange={(v, option) => {
setFormData({ ...formData, area_id: v ? v : null });
}}
/>
</div>
<div className="yisa-search">
<label>运营商</label>
<Select
className="form-con"
placeholder="请选择"
options={searchSelectList || []}
value={formData.operator_id}
onChange={(v) =>
setFormData({ ...formData, operator_id: v })
}
/>
</div>
<div className="yisa-search">
<label>车场类型</label>
<Select
className="form-con"
placeholder="请选择车场类型"
options={[
{
label: '全部',
value: '0',
},
{
label: '路内车场',
value: '1',
},
{
label: '路外车场',
value: '2',
},
]}
value={formData.car_parking_type}
onChange={(v) =>
setFormData({ ...formData, car_parking_type: v })
}
/>
</div>
<div className="yisa-search">
<label>停车场</label>
<Input
className="form-con"
placeholder="请输入"
value={formData?.road_name}
onChange={(e) =>
setFormData({ ...formData, road_name: e.target.value })
}
/>
</div>
<div className="yisa-search">
<label>日期
<div className="daf">
<Select
value={formData.date_type}
// style={{
// width: "100%",
// }}
placeholder="请选择"
options={[
{
value: "1",
label: "日",
},
{
value: "2",
label: "周",
},
{
value: "3",
label: "月",
},
]}
onChange={(e) => SetTimeNow(e)}
/>
</div>
</label>
<DatePicker
style={{ width: "100%" }}
// showTime
format={TimeChange().mat}
picker={TimeChange().str}
allowClear={false}
value={formData.start_time ? moment(formData.start_time) : null}
onChange={(date, dateString) => {
if (TimeChange().str == "week") {
setFormData({
...formData,
start_time: date
? moment(date).day(1).format("YYYY-MM-DD")
: null,
});
} else if (TimeChange().str == "day") {
if (date > moment(formData.end_time)) {
setFormData({
...formData,
end_time: dateString,
start_time: formData.end_time,
});
} else {
setFormData({
...formData,
start_time: dateString,
});
}
} else if (TimeChange().str == "month") {
setFormData({ ...formData, start_time: moment(date).format("YYYY-MM-DD"), end_time: moment(date).endOf("month").format("YYYY-MM-DD") });
} else {
setFormData({ ...formData, start_time: dateString });
}
}}
disabledDate={(current) => current > moment(formData.end_time)}
/>
</div>
<div className="yisa-search">
<label></label>
<DatePicker
style={{ width: "100%" }}
// showTime
format={TimeChange().mat}
picker={TimeChange().str}
allowClear={false}
value={formData.end_time ? moment(formData.end_time) : null}
onChange={(date, dateString) => {
if (TimeChange().str == "week") {
setFormData({
...formData,
end_time: date
? moment(date).day(7).format("YYYY-MM-DD")
: null,
});
} else if (TimeChange().str == "day") {
if (date < moment(formData.start_time)) {
setFormData({
...formData,
start_time: dateString,
end_time: formData.start_time,
});
} else {
setFormData({
...formData,
end_time: dateString,
});
}
} else if (TimeChange().str == "month") {
setFormData({ ...formData, start_time: moment(date).startOf('month').format("YYYY-MM-DD"), end_time: moment(date).format("YYYY-MM-DD") });
} else {
setFormData({ ...formData, end_time: dateString });
}
}}
disabledDate={(current) =>
current < moment(formData.start_time)
}
/>
</div>
<div className="form-btn">
<Button
className="reset"
onClick={() => setFormData(defaultData)}
>
重置
</Button>
<Button
className="submit"
type="primary"
onClick={handleSearch}
loading={loading}
>
查询
</Button>
</div>
</div>
</div>
<div className="paid-result period-result">
<div className="result">
<div className="result-hd">
<div className="result-header rea">
<div className="result-icon"><Icon type="shijian" /></div>
<div className="result-content">
<div className="title">停车高峰时段</div>
<div className="time">{resultData.peak_hours || "--"}</div>
</div>
</div>
<div className="result-header reb">
<div className="result-icon"><Icon type="shijian" /></div>
<div className="result-content">
<div className="title">入场压力时段</div>
<div className="time">{resultData.entry_pressure_hours || "--"}</div>
</div>
</div>
<div className="result-header rec">
<div className="result-icon"><Icon type="shijian" /></div>
<div className="result-content">
<div className="title">出场压力时段</div>
<div className="time">{resultData.exit_pressure_hours || "--"}</div>
</div>
</div>
</div>
<div className="result-box">
<div className="result-box-title">出入场车流量分析</div>
<Tooltip
placement="topLeft"
title={<span>展示所选日期内各时段的车辆出入场数量用来分析一天内入场车流量与出场车流量的变化情况</span>}
>
<i>?</i>
</Tooltip>
<ReactEcharts
option={revenueData}
style={{ height: "300px", width: "100%", overflow: "hidden" }}
/>
</div>
<div className="result-box">
<div className="result-box-title">停车饱和度趋势分析</div>
<Tooltip
placement="topLeft"
title={<span>展示所选日期内各个时间段的停车场饱和度变化情况用来分析停车高峰与低谷时段入场与出场压力较大的时段</span>}
>
<i>?</i>
</Tooltip>
<div className="bhd-select">
<Select
className="form-con"
placeholder="请选择"
defaultValue={'0'}
options={[
{
label: '按时间对比',
value: '0',
},
{
label: '按计费类型对比',
value: '1',
},
]}
value={formData.pay_me}
onChange={(v) =>
setFormData({ ...formData, pay_me: v })
}
/>
</div>
<ReactEcharts
option={parkData}
style={{ height: "300px", width: "100%", overflow: "hidden" }}
/>
</div>
</div>
</div>
</div>
</>
);
}
export default ParkingAlyPeriod;