diff --git a/src/config/character.config.js b/src/config/character.config.js index d71a6f2..b6de13a 100644 --- a/src/config/character.config.js +++ b/src/config/character.config.js @@ -718,6 +718,38 @@ export default { value: 4, }, ], + sectionType: [ + { + label: "全部", + value: -1 + }, + { + label: "200以内", + value: 1 + }, + { + label: "200-500", + value: 2 + }, + { + label: "500以上", + value: 3 + } + ], + vipType: [ + { + label: "全部", + value: -1 + }, + { + label: "非会员", + value: 0 + }, + { + label: "会员", + value: 1 + }, + ] } //商户名称 export const merchantName = [ diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/echarts.config.js b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/echarts.config.js index 8816fe0..d4ca7a5 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/echarts.config.js +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/echarts.config.js @@ -1,4 +1,4 @@ -const colorList = ['#3AA9FF', '#F997DF'] +const colorList = ['#3AA9FF', '#F997DF', '#F9EF97'] import utils from "@/config/utils" export default { @@ -73,4 +73,69 @@ export default { } ] }, + lineChartOption: { + title: { + text: '' + }, + tooltip: { + trigger: 'axis' + }, + legend: { + icon: 'rect', + top: '5%', + left: 'center', + itemHeight: 6, + itemGap: 20, + textStyle: { + color: '#fff' + } + }, + grid: { + top: '15%', + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: { + type: 'category', + boundaryGap: false, + 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: 'line', + stack: 'Total', + symbolSize: 1, + symbol: 'circle', + showSymbol: false, + smooth: true, + lineStyle: { + width: 3 + }, + data: [] + } + ] + } } \ No newline at end of file diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/index.jsx b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/index.jsx index afab685..16ae0e9 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/index.jsx +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/Overview/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef } from 'react' +import React, { useEffect, useState, useImperativeHandle, forwardRef } from 'react' import ajax from "@/services" import { Tabs } from 'antd' import ReactEcharts from "echarts-for-react"; @@ -6,7 +6,7 @@ import EchartsConfig from './echarts.config' import utils from "@/config/utils" import './index.scss' -const Overview = function(props) { +const Overview = forwardRef((props, ref) => { const { formData } = props @@ -15,6 +15,7 @@ const Overview = function(props) { const [activeTab, setActiveTab] = useState('parkRank') const [moneyPieChartOption, setMoneyPieChartOption] = useState({...EchartsConfig.pieChartOption}) const [itemPieChartOption, setItemPieChartOption] = useState({...EchartsConfig.pieChartOption}) + const [trendLineChartOption, setTrendLineChartOption] = useState({...EchartsConfig.lineChartOption}) const ajaxGetData = () => { ajax.getIncomeOverviewData({...formData}).then(res => { @@ -92,6 +93,51 @@ const Overview = function(props) { }) } + const initTrendLineChart = (data) => { + let [title, stack1, stack2, stack3] = [[], [], [], []] + data.map(item => { + title.push(item.name) + stack1.push(item.park1) + stack2.push(item.park2) + stack3.push(item.park3) + }) + + setTrendLineChartOption({ + ...trendLineChartOption, + xAxis: { + ...trendLineChartOption.xAxis, + data: [...title] + }, + series: [ + { + ...trendLineChartOption.series[0], + name: '一类区', + type: 'line', + stack: 'Total', + data: [...stack1] + }, + { + ...trendLineChartOption.series[0], + name: '二类区', + type: 'line', + stack: 'Total', + data: [...stack2] + }, + { + ...trendLineChartOption.series[0], + name: '三类区', + type: 'line', + stack: 'Total', + data: [...stack3] + } + ] + }) + } + + useImperativeHandle(ref, () => ({ + ajaxGetData + })) + useEffect(() => { ajaxGetData() }, []) @@ -103,6 +149,9 @@ const Overview = function(props) { if (yisaData.items) { initItemPieChart(yisaData.items, '个') } + if (yisaData.trend) { + initTrendLineChart(yisaData.trend) + } }, [yisaData]) return ( @@ -160,12 +209,17 @@ const Overview = function(props) {
-
欠费金额趋势
-
+
欠费金额趋势图
+
+ +
) -} +}) export default Overview \ No newline at end of file diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.jsx b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.jsx index 58bc945..a2c01c1 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.jsx +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.jsx @@ -1,11 +1,170 @@ -import React from 'react' +import React, { useEffect, useState, useImperativeHandle, forwardRef } from 'react' +import { Table, Pagination, Button } from 'antd' +import { ResultFlowResult, ExportBtnNew } from '@/components' +import { dictionary } from "@/config/common" +import ajax from "@/services" +import './index.scss' + +const ParkArrear = forwardRef((props, ref) => { + const { + formData + } = props + const [tableLoading, setTableLoading] = useState(false) + const [pageInfo, setPageInfo] = useState({ + pn: 1, + length: 10 + }) + const [exportData, setExportData] = useState({ + start: 1, + end: 10 + }) + const [resultData, setResultData] = useState({ + list: [], + totalRecords: 0 + }) + + const tableColumns = [ + { + title: "序号", + width: 60, + align: 'center', + render: (text, record, index) => index + 1, + }, + { + title: "停车场名称", + align: 'center', + dataIndex: "name", + }, + { + title: "区域", + align: 'center', + dataIndex: "area", + }, + { + title: "累计营收金额", + align: 'center', + dataIndex: "ljys", + }, + { + title: "累计实收金额", + align: 'center', + dataIndex: "ljss", + }, + { + title: "现存欠费金额", + align: 'center', + dataIndex: "xcqfje", + }, + { + title: "现存欠费订单", + align: 'center', + dataIndex: 'xcqfdd' + }, + { + title: '欠费金额占比', + align: 'center', + dataIndex: 'ratio', + render: (text, record) => { + return text + '%' + } + } + ] + + const paginationProps = { + className: "pagination-common", + showQuickJumper: true, + showSizeChanger: true, + current: pageInfo.pn, + total: resultData?.totalRecords, + pageSize: pageInfo.length, + pageSizeOptions: Array.from( + new Set([...[15], ...(dictionary?.pageSizeOptions || [])]) + ), + onChange: (current, size) => { + setPageInfo({ + ...pageInfo, + ...{ pn: current, length: size } + }); + } + } + + const ajaxGetTableData = (data) => { + setTableLoading(true) + ajax.getIncomeParkArrearData({ + ...data + }).then(res => { + if (res.status == 20000) { + setTableLoading(false) + setResultData({ + list: res.data, + totalRecords: res.totalRecords + }) + setExportData({ + ...exportData, + start: 1, + end: res.totalRecords + }) + } + }) + } + + const getData = (newPageInfo) => { + setPageInfo({ + ...newPageInfo + }) + ajaxGetTableData({ + ...formData, + ...newPageInfo + }) + } + + useImperativeHandle(ref, () => ({ + getData + })) + + useEffect(() => { + ajaxGetTableData({ + ...formData, + ...pageInfo + }) + }, [JSON.stringify(pageInfo)]) -const ParkArrear = function(props) { return (
- ParkArrear +
+
共查询到{ resultData.totalRecords || 0 }条结果
+
+ 导出} + modalType="noImg" + totalRecords={resultData.totalRecords} + exportUrl="/api/dataAnalysis/arrearsPark/export" + postdata={{ + formData: {...formData, ...pageInfo} + }} + imgno={false} + /> +
+
+
+ + row.id} + dataSource={resultData?.list || []} + columns={tableColumns} + pagination={false} + scroll={{y: 585}} + loading={tableLoading} + /> + + + ) -} +}) export default ParkArrear \ No newline at end of file diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.scss b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.scss index e69de29..26bef27 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.scss +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/ParkArrear/index.scss @@ -0,0 +1,40 @@ +@import "@/assets/css/mixin.scss"; + +.park-table-title { + margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; + .park-table-info { + span { + color: var(--color-primary); + } + } + .park-table-export { + + } +} +.park-arrear-container { + height: 100%; + display: flex; + flex-direction: column; + .park-table-title { + height: 25px; + } + .park-table-content { + flex: 1; + .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; + } + .ant-table-fixed-header .ant-table-tbody tr:nth-child(2n+1) > td { + + } + } + } +} \ No newline at end of file diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.jsx b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.jsx index 24e7736..250e6cf 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.jsx +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.jsx @@ -1,11 +1,300 @@ -import React from 'react' +import React, {useEffect, useState, useImperativeHandle, forwardRef} from 'react' +import { ResultFlowResult, ExportBtnNew } from '@/components' +import { Table, Pagination, Button, Modal } from 'antd' +import { dictionary } from "@/config/common" +import ajax from "@/services" +import './index.scss' -const PlateArrear = function(props) { + +const PlateArrear = forwardRef((props, ref) => { + const { + formData + } = props + const [tableLoading, setTableLoading] = useState(false) + const [detailVisble, setDetailVisible] = useState(false) + const [detailPlate, setDetailPlate] = useState('') + const [pageInfo, setPageInfo] = useState({ + pn: 1, + length: 10 + }) + const [exportData, setExportData] = useState({ + start: 1, + end: 10 + }) + const [resultData, setResultData] = useState({ + list: [], + totalRecords: 0 + }) + + const handleDetail = (data) => { + setDetailPlate(data.plate) + setDetailVisible(true) + } + + const tableColumns = [ + { + title: "序号", + width: 60, + align: 'center', + render: (text, record, index) => index + 1, + }, + { + title: "车牌号", + align: 'center', + dataIndex: "plate", + }, + { + title: "手机号", + align: 'center', + dataIndex: "phone", + }, + { + title: "欠费金额", + align: 'center', + dataIndex: "money", + }, + { + title: '操作', + width: 200, + align: 'center', + render: (text, record) => { + return ( + + ) + } + } + ] + + const paginationProps = { + className: "pagination-common", + showQuickJumper: true, + showSizeChanger: true, + current: pageInfo.pn, + total: resultData?.totalRecords, + pageSize: pageInfo.length, + pageSizeOptions: Array.from( + new Set([...[15], ...(dictionary?.pageSizeOptions || [])]) + ), + onChange: (current, size) => { + setPageInfo({ + ...pageInfo, + ...{ pn: current, length: size } + }); + } + } + + const ajaxGetTableData = (data) => { + setTableLoading(true) + ajax.getIncomePlateArrearData({ + ...data + }).then(res => { + if (res.status == 20000) { + setTableLoading(false) + setResultData({ + list: res.data, + totalRecords: res.totalRecords + }) + setExportData({ + ...exportData, + start: 1, + end: res.totalRecords + }) + } + }) + } + + const getData = (newPageInfo) => { + setPageInfo({ + ...newPageInfo + }) + ajaxGetTableData({ + ...formData, + ...newPageInfo + }) + } + + useImperativeHandle(ref, () => ({ + getData + })) + + useEffect(() => { + ajaxGetTableData({ + ...formData, + ...pageInfo + }) + }, [JSON.stringify(pageInfo)]) return (
- PlateArrear +
+
共查询到{ resultData.totalRecords || 0 }条结果
+
+ 导出} + modalType="noImg" + totalRecords={resultData.totalRecords} + exportUrl="/api/dataAnalysis/arrearsPlate/export" + postdata={{ + formData: {...formData, ...pageInfo} + }} + imgno={false} + /> +
+
+
+ +
row.id} + dataSource={resultData?.list || []} + columns={tableColumns} + pagination={false} + scroll={{y: 585}} + loading={tableLoading} + /> + + + + setDetailVisible(false)} + onCancel={() => setDetailVisible(false)} + /> ) +}) + +const ModalDetail = (props) => { + const { + visible, + onOk, + plate_number, + onCancel + } = props + + const [tableLoading, setTableLoading] = useState(false) + const [resultData, setResultData] = useState({ + list: [], + totalRecords: 0 + }) + const [formData, setFormData] = useState({ + pn: 1, + length: 10, + plate_number: plate_number + }) + const [pageInfo, setPageInfo] = useState({ + pn: 1, + length: 10 + }) + + const tableColumns = [ + { + title: "车牌号", + align: 'center', + dataIndex: "plate", + }, + { + title: "停车场", + align: 'center', + dataIndex: "park", + }, + { + title: "入场时间", + align: 'center', + dataIndex: "entry_time", + }, + { + title: "出场时间", + align: 'center', + dataIndex: "leave_time", + }, + { + title: "停车时长", + align: 'center', + dataIndex: "duration", + }, + { + title: "欠费金额", + align: 'center', + dataIndex: "money", + }, + ] + + const paginationProps = { + className: "pagination-common", + showQuickJumper: true, + showSizeChanger: true, + current: pageInfo.pn, + total: resultData?.totalRecords, + pageSize: pageInfo.length, + pageSizeOptions: Array.from( + new Set([...[15], ...(dictionary?.pageSizeOptions || [])]) + ), + onChange: (current, size) => { + setPageInfo({ + ...pageInfo, + ...{ pn: current, length: size } + }); + } + } + + const ajaxGetDetailData = () => { + setTableLoading(true) + ajax.getPlateArrearData({...formData, ...pageInfo}).then(res => { + if (res.status == 20000) { + setTableLoading(false) + setResultData({ + list: res.data, + totalRecords: res.totalRecords + }) + } + }) + } + + useEffect(() => { + setFormData({ + pn: 1, + length: 10, + plate_number: plate_number + }) + }, [plate_number]) + + useEffect(() => { + ajaxGetDetailData() + }, [JSON.stringify(formData), JSON.stringify(pageInfo)]) + + return ( + +
+
欠费总分析详情
+ +
row.id} + dataSource={resultData?.list || []} + columns={tableColumns} + pagination={false} + scroll={{y: 200}} + loading={tableLoading} + /> + + + + + ) } export default PlateArrear \ No newline at end of file diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.scss b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.scss index e69de29..b6ea73d 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.scss +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/PlateArrear/index.scss @@ -0,0 +1,56 @@ +@import "@/assets/css/mixin.scss"; + +.park-table-title { + margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; + .park-table-info { + span { + color: var(--color-primary); + } + } + .park-table-export { + + } +} +.plate-arrear-container { + height: 100%; + display: flex; + flex-direction: column; + .park-table-title { + height: 25px; + } + .park-table-content { + flex: 1; + .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; + } + .ant-table-fixed-header .ant-table-tbody tr:nth-child(2n+1) > td { + + } + } + } +} + +.detail-modal { + .ant-modal-body { + padding-top: 0; + padding-bottom: 5px; + .detail-title { + margin-bottom: 10px; + } + .ant-table-thead>tr>th { + background-color: #616b83; + } + .ant-table-body { + @include scrollBar(var(--color-user-list-bg), #3B97FF); + } + } +} \ No newline at end of file diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/index.scss b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/index.scss index 166a676..e4bd7df 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/index.scss +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/index.scss @@ -85,6 +85,11 @@ $color-primary : var(--color-primary); height: 36px; background: var(--button-default-bg); } + + .btn-export { + width: 90px; + height: 36px; + } .submit { width: calc(100% - 100px); diff --git a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/loadable.jsx b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/loadable.jsx index 24e9a8b..922b541 100644 --- a/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/loadable.jsx +++ b/src/pages/DataAnalysisPrediction/ParkingIncomeAly/ArrearageAly/loadable.jsx @@ -1,6 +1,6 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { ResultFlowResult } from "@/components"; -import { Select, Input, Button, Table, message, Pagination, DatePicker, Modal, Cascader, Tooltip, Tabs } from "antd"; +import { Select, Input, Button, Table, message, Pagination, DatePicker, Cascader, Tooltip, Tabs } from "antd"; import { useSessionStorageState } from "ahooks"; import { dictionary } from "@/config/common"; import { useNavigate } from "react-router-dom"; @@ -22,10 +22,19 @@ function ArrearageAly(props) { park_text: "", pay_merchant_id: 0 } + const defaultNewData = { + section: -1, + plate_number: "", + is_vip: -1 + } const [formData, setFormData] = useState({...defaultData}) + const [formDataNew, setFormDataNew] = useState({...defaultNewData}) const [areaList, setAreaList] = useState([]) const [loading, setLoading] = useState(false) const [activeTab, setActiveTab] = useState(1) + const overviewRef = useRef(null) + const parkRef = useRef(null) + const plateRef = useRef(null) const tabItems = [ { @@ -54,7 +63,19 @@ function ArrearageAly(props) { } const handleSearch = () => { - + if (activeTab == 1) { + overviewRef.current.ajaxGetData() + } else if (activeTab == 2) { + parkRef.current.getData({ + pn: 1, + length: 10 + }) + } else if (activeTab == 3) { + plateRef.current.getData({ + pn: 1, + length: 10 + }) + } } useEffect(() => { @@ -66,46 +87,86 @@ function ArrearageAly(props) {
查询条件
-
- - { - setFormData({ ...formData, region: v ? v : null }); - }} - /> -
-
- - - setFormData({ ...formData, park_text: e.target.value }) - } - /> -
+ { + activeTab == 3 ? ( + <> +
+ + + setFormDataNew({ ...formDataNew, plate_number: e.target.value }) + } + /> +
+
+ + setFormData({...formData, pay_merchant_id: v})} + placeholder="请选择计费类型" + /> +
+
+ + + setFormData({ ...formData, park_text: e.target.value }) + } + /> +
+ + ) + }
diff --git a/src/services/DataAnalysisPrediction/ParkingIncomeAly/index.js b/src/services/DataAnalysisPrediction/ParkingIncomeAly/index.js index 44b1833..8d3fcbe 100644 --- a/src/services/DataAnalysisPrediction/ParkingIncomeAly/index.js +++ b/src/services/DataAnalysisPrediction/ParkingIncomeAly/index.js @@ -7,5 +7,33 @@ export default { type: 'post', data }) + }, + getIncomeParkArrearData: function(data) { + return ajax({ + url: '/api/dataAnalysis/arrearsPark', + type: 'post', + data + }) + }, + parkArrearExport: function(data) { + return ajax({ + url: '/api/dataAnalysis/arrearsPark/export', + type: 'post', + data + }) + }, + getIncomePlateArrearData: function(data) { + return ajax({ + url: '/api/dataAnalysis/arrearsPlate', + type: 'post', + data + }) + }, + getPlateArrearData: function(data) { + return ajax({ + url: '/api/dataAnalysis/arrearsPlate/details', + type: 'post', + data + }) } }