From 2587b50c5efa005b5b2cd63ed19e541e2e7c4c29 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Fri, 22 Sep 2023 16:49:36 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 15 ++++++- src/components/Scatter.jsx | 42 ++++++++++++++++++++ src/stores/Distribution.js | 35 ++++++++++++++--- src/views/Detail.jsx | 80 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 src/components/Scatter.jsx create mode 100644 src/views/Detail.jsx diff --git a/src/App.jsx b/src/App.jsx index 1ce1708..718dd76 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -10,9 +10,9 @@ import { DollarOutlined, AreaChartOutlined, WechatOutlined, - UserOutlined, FlagOutlined, PieChartOutlined + UserOutlined, FlagOutlined, PieChartOutlined, BarChartOutlined } from '@ant-design/icons'; -import { Layout, Menu, Image, Spin } from 'antd'; +import { Layout, Menu, Image, Badge } from 'antd'; import { BrowserRouter, Route, Routes, NavLink } from 'react-router-dom'; import Home from './views/Home'; import Dashboard from './views/Dashboard'; @@ -37,6 +37,7 @@ import { observer } from 'mobx-react'; import ExchangeRate from './charts/ExchangeRate'; import KPI from './views/KPI'; import Distribution from './views/Distribution'; +import Detail from './views/Detail'; const App = () => { const { Content, Footer, Sider } = Layout; @@ -123,6 +124,15 @@ const App = () => { }, { key: 'kpi', label: 目标, icon: }, { key: 'distribution', label: 统计分布, icon: }, + { + key: 'detail', + label: ( + + 统计分析 + + ), + icon: , + }, ]; return ( @@ -165,6 +175,7 @@ const App = () => { } /> } /> } /> + } /> }> } /> } /> diff --git a/src/components/Scatter.jsx b/src/components/Scatter.jsx new file mode 100644 index 0000000..3ef84a2 --- /dev/null +++ b/src/components/Scatter.jsx @@ -0,0 +1,42 @@ +import { useEffect, useState } from 'react'; +import { observer } from 'mobx-react'; +import { sortBy, merge } from '../utils/commons'; +import { dataFieldAlias } from '../libs/ht'; +import { Mix, Scatter } from '@ant-design/plots'; + +export default observer((props) => { + const { dataSource, ...extProps } = props; + const config = merge( + { + appendPadding: 10, + // xField: 'Revenue (Millions)', + // yField: 'Rating', + shape: 'circle', + // colorField: 'Genre', + size: 4, + yAxis: { + nice: true, + line: { + style: { + stroke: '#aaa', + }, + }, + }, + xAxis: { + min: -100, + grid: { + line: { + style: { + stroke: '#eee', + }, + }, + }, + line: { + style: { + stroke: '#aaa', + }, + }, + }, + }, extProps); + return ; +}); diff --git a/src/stores/Distribution.js b/src/stores/Distribution.js index e583983..5f62d6c 100644 --- a/src/stores/Distribution.js +++ b/src/stores/Distribution.js @@ -1,6 +1,6 @@ import { makeAutoObservable, runInAction, toJS } from 'mobx'; import * as req from '../utils/request'; -import { isEmpty, sortBy } from '../utils/commons'; +import { isEmpty, pick, sortBy } from '../utils/commons'; const modelMapper = { 'tourDays': { url: '/service-Analyse2/GetTradeApartByTourDays' }, @@ -17,7 +17,10 @@ class Distribution { makeAutoObservable(this); } - async getData(param){ + /** + * 各个类型的分布 + */ + getApartData = async (param) => { const mkey = this.curTab; this[mkey] = { loading: true, dataSource: [] }; const json = await req.fetchJSON(modelMapper[mkey].url, param); @@ -30,10 +33,29 @@ class Distribution { }); } return this[mkey]; + }; - } + /** + * 明细 + */ + getDetailData = async (param) => { + this.detailData.loading = true; + const json = await req.fetchJSON('/service-Analyse2/GetTradeApartDetail', param); + if (json.errcode === 0) { + runInAction(() => { + this.detailData.loading = false; + this.detailData.dataSource = json.result; + const daysData = json.result.filter(ele => ele.confirmDays).map(row => pick(row, ['o_id', 'tourdays', 'applyDays', 'personNum', 'country', 'startDate'])); + this.scatterDays = daysData; + }); + } + return this.detailData; + }; + + resetData = () => { + // this.detailData = { loading: false, dataSource: [] }; + // this.scatterDays = []; - resetData() { this.tourDays = { loading: false, dataSource: [] }; this.PML = { loading: false, dataSource: [] }; this.ConfirmDays = { loading: false, dataSource: [] }; @@ -41,7 +63,7 @@ class Distribution { this.PersonNum = { loading: false, dataSource: [] }; this.destination = { loading: false, dataSource: [] }; this.GlobalDestination = { loading: false, dataSource: [] }; - } + }; curTab = 'tourDays'; setCurTab(v) { @@ -50,6 +72,9 @@ class Distribution { pageLoading = false; + detailData = { loading: false, dataSource: [], }; + scatterDays = []; + tourDays = { loading: false, dataSource: [] }; PML = { loading: false, dataSource: [] }; ConfirmDays = { loading: false, dataSource: [] }; diff --git a/src/views/Detail.jsx b/src/views/Detail.jsx new file mode 100644 index 0000000..dc97d35 --- /dev/null +++ b/src/views/Detail.jsx @@ -0,0 +1,80 @@ +import { useContext, useEffect, useMemo } from 'react'; +import { observer } from "mobx-react"; +import { stores_Context } from '../config'; +import { Row, Col, Spin, Space, Radio, Tabs, Table } from 'antd'; +import { empty } from '../utils/commons'; +import { dataFieldAlias } from '../libs/ht'; +import Scatter from './../components/Scatter'; +import SearchForm from './../components/search/SearchForm'; + +export default observer((props) => { + const { date_picker_store: searchFormStore, DistributionStore } = useContext(stores_Context); + const { formValues, formValuesToSub } = searchFormStore; + const { curTab, scatterDays, detailData } = DistributionStore; + + const detailRefresh = (obj) => { + DistributionStore.getDetailData({ + ...(obj || formValuesToSub), + }); + }; + + useEffect(() => { + if (empty(detailData.dataSource)) { + detailRefresh(); + } + }, []); + + const ScatterConfig = { + xField: 'startDate', + yField: 'tourdays', + colorField: 'country', + size: 4, + // xAxis: { + // min: 0, + // max: 30, + // }, + yAxis: { + min: 0, + max: 10, + }, + // quadrant: { + // xBaseline: 15, + // yBaseline: 5, + // }, + tooltip: false, + legend: { + position: 'right-top', + }, + }; + return ( + <> + + {/* style={{ margin: '-16px -8px', padding: 0 }} */} + + { + detailRefresh(obj); + }} + /> + + + +
+ + + +
+ + ); +});