Browse Source

feat(): 城市收入分析page

tags/PMS_Frontend_v1.0.6-develop
wanghx 1 year ago
parent
commit
6e7caed585
  1. 101
      src/config/character.config.js
  2. 254
      src/pages/DataAnalysisPrediction/ParkingIncomeAly/CityIncomeAly/index.scss
  3. 478
      src/pages/DataAnalysisPrediction/ParkingIncomeAly/CityIncomeAly/loadable.jsx
  4. 9
      src/services/DataAnalysisPrediction/ParkingIncomeAly/index.js

101
src/config/character.config.js

@ -1024,3 +1024,104 @@ export const stackBarChartOption = {
data: []
}]
}
export const barChartOption = {
// color: colorList,
grid: {
top: '15%',
left: '0%',
right: '4%',
bottom: '3%',
containLabel: true
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
textStyle: {
color: "#fff"
}
}
},
legend: {
icon: 'rect',
top: '5%',
left: 'center',
itemHeight: 6,
itemGap: 20,
textStyle: {
color: '#fff'
}
},
calculable: true,
xAxis: {
type: 'category',
boundaryGap: true,
data: [],
axisLabel: {
color: 'rgba(255, 255, 255, .65)'
}
},
yAxis: {
type: 'value',
axisLine: {
show: false
},
axisLabel: {
color: 'rgba(255, 255, 255, .65)'
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#fff',
opacity: .15
}
}
},
series: [{
name: "",
type: "bar",
barMaxWidth: 12,
barGap: "10%",
itemStyle: {
barBorderRadius: [2, 2, 0, 0],
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#99EBFF'
}, {
offset: 1, color: '#3AA9FF'
}],
globalCoord: false
}
},
data: []
}, {
name: "",
type: "bar",
barMaxWidth: 12,
barGap: "10%",
itemStyle: {
barBorderRadius: [2, 2, 0, 0],
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#FFB8B8'
}, {
offset: 1, color: '#F481F8'
}],
globalCoord: false
}
},
data: []
}]
}

254
src/pages/DataAnalysisPrediction/ParkingIncomeAly/CityIncomeAly/index.scss

@ -1,5 +1,259 @@
@import "@/assets/css/mixin.scss";
$color-container-bg : var(--color-container-bg);
$color-user-list-bg : var(--color-user-list-bg);
$color-text : var(--color-text);
$color-primary : var(--color-primary);
.parking-container {
display: flex;
padding-top: 10px;
height: 100%;
.parking-container-left {
display: block;
width: 375px;
padding: 10px 10px 20px 20px;
}
.parking-container-right {
width: calc(100% - 375px);
padding-bottom: 15px;
padding: 20px;
background: var(--color-user-list-bg);
border-top-left-radius: 20px;
box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.08);
display: flex;
flex-direction: column;
.ant-tabs .ant-tabs-nav-wrap .ant-tabs-nav-list {
width: unset;
}
.ant-tabs-tab {
padding: unset;
}
.parking-content {
height: 100%;
display: flex;
flex-direction: column;
.parking-tabs {
margin-bottom: 10px;
}
.parking-wrapper {
flex: 1;
}
}
}
}
.parking-container {
.yisa-search {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 24px;
label {
color: var(--color-search-list-item-text);
flex: 0 0 27%;
max-width: 27%;
text-align: right;
padding-right: 8px;
}
.form-con {
flex: 1;
width: 220px;
}
}
.form-btn {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
// margin: 40px 0px 0px;
padding: 0 3px;
.ant-btn+.ant-btn {
margin-left: 10px;
}
.ant-btn span {
font-size: 16px;
font-family: Microsoft YaHei, Microsoft YaHei-Regular;
font-weight: 400;
text-align: center;
color: #ffffff;
}
.reset {
width: 90px;
height: 36px;
background: var(--button-default-bg);
}
.btn-export {
width: 90px;
height: 36px;
}
.submit {
width: calc(100% - 100px);
height: 36px;
}
}
.ant-select-selector,
.ant-picker,
.ant-input {
background-color: var(--color-search-list-item-bg) !important;
box-shadow: none !important;
color: var(--color-search-list-item-value);
border-color: var(--color-search-list-item-bd) !important;
}
.ant-picker {
width: 100%;
}
.parking-search {
.title {
width: 100%;
font-size: 16px;
font-family: Microsoft YaHei, Microsoft YaHei-Bold;
font-weight: 700;
text-align: left;
color: var(--color-text);
margin-bottom: 20px;
}
}
.form-Wrap {
display: flex;
flex-direction: column;
}
}
.ant-cascader-menu {
width: 260px;
}
.parking-container-right {
.export-container {
margin-bottom: 10px;
text-align: right;
}
.parking-item {
height: 350px;
}
.park-table-content {
margin-top: 20px;
.park-table {
flex: 1;
.ant-table-body {
@include scrollBar(var(--color-user-list-bg), #3B97FF);
}
.ant-table-fixed-header .ant-table-tbody tr:nth-child(2n+1) > td {
background: unset !important;
background-color: #3e4557 !important;
}
}
}
}
.parking-item {
color: #fff;
background: #3e4557;
border-radius: 4px;
display: flex;
flex-direction: column;
padding: 20px;
&-title {
height: 18px;
display: flex;
align-items: center;
position: relative;
text-indent: .5rem;
font-size: 16px;
font-weight: 700;
user-select: none;
&::before {
position: absolute;
content: "";
height: 100%;
width: 4px;
left: -2px;
background: var(--color-menu-selected-text-item);
}
}
&-content {
flex: 1;
.echarts-for-react {
height: 100% !important;
}
}
}
.parking-bottom {
display: flex;
margin-top: 20px;
min-height: 0;
flex: 1;
.parking-item {
flex: 1;
height: 100% !important;
&:nth-child(2) {
margin: 0 20px;
}
&:last-child {
.parking-item-title {
margin-bottom: 10px;
}
}
}
.parking-item-content {
min-height: 0;
overflow-y: hidden;
&:hover {
overflow-y: auto;
@include scrollBar(var(--color-user-list-bg), #3B97FF);
}
}
.item-tab-content {
flex: 1;
margin-top: 10px;
display: flex;
flex-direction: column;
user-select: none;
padding-right: 10px;
.rank-item {
display: flex;
justify-content: space-between;
align-items: center;
height: 30px;
margin-bottom: 5px;
font-size: 16px;
.rank-left {
display: flex;
font-weight: 700;
.rank-no {
width: 25px;
height: 25px;
margin: 0 5px;
margin-right: 10px;
text-align: center;
}
}
&:nth-child(1) {
.rank-no {
background: url('@/assets/images/icon-rank-1.png') no-repeat 100% 100%;
background-size: 100% 100%;
}
}
&:nth-child(2) {
.rank-no {
background: url('@/assets/images/icon-rank-2.png') no-repeat 100% 100%;
background-size: 100% 100%;
}
}
&:nth-child(3) {
.rank-no {
background: url('@/assets/images/icon-rank-3.png') no-repeat 100% 100%;
background-size: 100% 100%;
}
}
}
}
}

478
src/pages/DataAnalysisPrediction/ParkingIncomeAly/CityIncomeAly/loadable.jsx

@ -1,15 +1,469 @@
import React, { useState, useRef, useEffect } from "react";
// import { message, Pagination, Table, Space, Modal, } from "antd";
// import { dictionary, utils } from "@/config/common";
// import moment from 'moment'
// import { useSessionStorageState, useUpdateEffect, useSize, useUpdate } from 'ahooks';
// import ajax from "@/services"
// import { FormInput, FormSelect, OptionPanel, ResultPanel, FormSliderPicker, AreaCascader, ImgResize, ImgZoom, } from "@/components"
// import "./index.scss";
// import errorImg from "@/assets/images/layout/error.png"
// import { useLocation } from "react-router-dom";
function CityIncomeAly() {
return <div>CityIncomeAly</div>
import React, { useState, useRef, useEffect } from "react"
import { Select, Input, Button, Table, message, Pagination, DatePicker, Cascader, Tooltip } from "antd"
import { dictionary } from "@/config/common"
import ReactEcharts from "echarts-for-react"
import { barChartOption, pieChartOption } from "@/config/character.config"
import utils from "@/config/utils"
import ajax from "@/services"
import moment from "moment"
import './index.scss'
function CityIncomeAly(props) {
const {
} = props
const [loading, setLoading] = useState(false)
const defaultFormData = {
region: [],
operator_id: "0",
park_type: 0,
date_type: "day",
start_time: "",
end_time: "",
park_bussiness_type: 0
}
const [formData, setFormData] = useState({
...defaultFormData
})
const [pageInfo, setPageInfo] = useState({
pn: 1,
length: 10
})
const [resultData, setResultDate] = useState({
list: [],
totalRecords: 0
})
const [barOption, setBarOption] = useState({...barChartOption})
const [ysPieChartOption, setYsPieChartOption] = useState({...pieChartOption})
const [ssPieChartOption, setSsPieChartOption] = useState({...pieChartOption})
const [rankData, setRankData] = useState([])
const [areaList, setAreaList] = useState([])
const [Yunying, setYunying] = useState([])
const ajaxGetAreaData = () => {
ajax.getAreaTree().then((res) => {
if (res.status === 20000) {
setAreaList(res.data);
}
}).catch((err) => {
console.error(err)
});
}
const ajaxGetOperatorData = () => {
ajax.getAllOperator().then((res) => {
if (parseInt(res?.status) === 20000) {
setYunying(res.data);
} else {
message.error(res?.message);
}
}).catch(err => {
console.log(err)
})
}
const ajaxGetListData = () => {
setLoading(true)
ajax.getCityRevenueAlyData({...formData}).then(res => {
if (res.status == 20000) {
initBarChart([...res.data.trend])
initPieChart([...res.data.ysAmount], 'ys' , '元')
initPieChart([...res.data.ssAmount], 'ss', '元')
setRankData([...res.data.rank])
}
setLoading(false)
})
}
const initBarChart = (data) => {
setBarOption({
...barChartOption,
xAxis: {
...barChartOption.xAxis,
data: [...data.map(item => item.name)]
},
yAxis: {
...barChartOption.yAxis,
axisLabel: {
...barChartOption.yAxis.axisLabel,
formatter: '{value} 元'
}
},
series: [
{
...barChartOption.series[0],
name: '应收',
data: [...data.map(item => item.ys)]
},
{
...barChartOption.series[1],
name: '实收',
data: [...data.map(item => item.ss)]
}
]
})
}
const initPieChart = (data, chartName, unit) => {
let total = 0
data.map((item) => {
total += item.value
})
if (chartName == 'ys') {
setYsPieChartOption({
...ysPieChartOption,
title: {
...ysPieChartOption.title,
text: `总应收金额:${utils.parseFormatNum(total)}${unit}`
},
tooltip: {
...ysPieChartOption.tooltip,
formatter: (params) => {
return `
<div>
${params.marker}
${params.name}:
&nbsp;&nbsp;
${utils.parseFormatNum(params?.value || 0)}
${unit}
</div>
`
}
},
series: [
{
...ysPieChartOption.series[0],
data: data
}
]
})
} else {
setSsPieChartOption({
...ssPieChartOption,
title: {
...ssPieChartOption.title,
text: `总实收金额:${utils.parseFormatNum(total)}${unit}`
},
tooltip: {
...ssPieChartOption.tooltip,
formatter: (params) => {
return `
<div>
${params.marker}
${params.name}:
&nbsp;&nbsp;
${utils.parseFormatNum(params?.value || 0)}
${unit}
</div>
`
}
},
series: [
{
...ssPieChartOption.series[0],
data: data
}
]
})
}
}
const TimeChange = () => {
let e = formData.date_type;
let str = "day";
let mat = "YYYY-MM-DD";
if (e == "year") {
str = "year";
mat = "YYYY";
} else if (e == "month") {
str = "month";
mat = "YYYY-MM";
} else if (e == "week") {
str = "week";
mat = "YYYY-MM-DD";
}
return { str, mat };
}
const SetTimeNow = (e) => {
let start = "";
let end = "";
if (e == 'year') {
start = moment().format("YYYY");
end = moment().format("YYYY");
} else if (e == 'month') {
start = moment().format("YYYY-MM");
end = moment().format("YYYY-MM");
} else if (e == 'week') {
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 handleReset = () => {
setFormData({
...defaultFormData
})
}
const handleSearch = () => {
ajaxGetListData()
}
useEffect(() => {
ajaxGetAreaData()
ajaxGetOperatorData()
ajaxGetListData()
}, [])
return (
<div className="arrearage-container parking-container">
<div className="parking-container-left">
<div className="parking-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.region}
onChange={(v, option) => {
setFormData({ ...formData, region: v ? v : null });
}}
/>
</div>
<div className="yisa-search">
<label>车场业务类型</label>
<Select
value={formData.park_bussiness_type}
style={{
width: "100%",
}}
placeholder="请选择"
options={sysConfig.businessRoad}
onChange={(e) =>
setFormData({
...formData,
park_bussiness_type: e,
})
}
/>
</div>
<div className="yisa-search">
<label>运营商</label>
<Select
value={formData.operator_id}
style={{
width: "100%",
}}
placeholder="请选择"
options={Yunying}
onChange={(e) =>
setFormData({
...formData,
operator_id: e,
})
}
/>
</div>
<div className="yisa-search">
<label>车场类型</label>
<Select
className="form-con"
value={formData.park_type}
options={dictionary.parkType}
onChange={(v) => setFormData({...formData, park_type: v})}
placeholder="请选择车场类型"
/>
</div>
<div className="yisa-search">
<label>
<div className="daf">
<Select
value={formData.date_type}
placeholder="请选择"
options={[
{
value: "day",
label: "日",
},
{
value: "week",
label: "周",
},
{
value: "month",
label: "月",
},
{
value: "year",
label: "年",
},
]}
onChange={(e) => SetTimeNow(e)}
/>
</div>
</label>
<DatePicker
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 {
setFormData({ ...formData, start_time: dateString });
}
}}
disabledDate={(current) => current > moment(formData.end_time)}
/>
</div>
<div className="yisa-search">
<label></label>
<DatePicker
style={{ width: "100%" }}
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 {
setFormData({ ...formData, end_time: dateString });
}
}}
disabledDate={(current) =>
current < moment(formData.start_time)
}
/>
</div>
<div className="form-btn">
<Button
className="reset"
onClick={handleReset}
>
重置
</Button>
<Button
className="submit"
type="primary"
onClick={handleSearch}
>
查询
</Button>
</div>
</div>
</div>
</div>
<div className="parking-container-right">
<div className="parking-item">
<div className="parking-item-title">订单收入对比</div>
<div className="parking-item-content">
<ReactEcharts
option={barOption}
style={{ overflow: "hidden" }}
/>
</div>
</div>
<div className="parking-bottom">
<div className="parking-item">
<div className="parking-item-title">应收金额对比</div>
<div className="parking-item-content">
<ReactEcharts
option={ysPieChartOption}
style={{ overflow: "hidden" }}
/>
</div>
</div>
<div className="parking-item">
<div className="parking-item-title">实收金额对比</div>
<div className="parking-item-content">
<ReactEcharts
option={ssPieChartOption}
style={{ overflow: "hidden" }}
/>
</div>
</div>
<div className="parking-item">
<div className="parking-item-title">金额实缴率排行榜</div>
<div className="parking-item-content">
<div className="item-tab-content">
{
rankData && rankData.map((item, index) => (
<div className="rank-item" key={index}>
<div className="rank-left">
<div className="rank-no">{index+1 > 3 ? (index+1) : ''}</div>
<div className="rank-label">{item.name}</div>
</div>
<div className="rank-right">
<div className="rank-value">{utils.parseFormatNum(item.value || 0)}</div>
</div>
</div>
))
}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default CityIncomeAly;

9
src/services/DataAnalysisPrediction/ParkingIncomeAly/index.js

@ -77,5 +77,12 @@ export default {
type: 'post',
data
})
}
},
getCityRevenueAlyData: function(data) {
return ajax({
url: '/api/dataAnalysis/cityRevenueAnalysis',
type: 'post',
data
})
},
}
Loading…
Cancel
Save