You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dashboard/src/views/Home.jsx

325 lines
12 KiB
JavaScript

import { useContext, useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { Row, Col, Spin, Space, Radio, Table, Button } from 'antd';
import { CheckCircleTwoTone, MoneyCollectTwoTone, FlagTwoTone, SmileTwoTone } from '@ant-design/icons';
import { stores_Context } from '../config';
import StatisticCard2 from '../components/StatisticCard2';
import Bullet from '../components/BulletWithSort';
import Waterfall from '../components/Waterfall';
import MixTBWithKPI from './../components/MixTBWithKPI';
import Donut from './../components/Donut';
import MapCountry from './../components/MapCountry';
import LineWithKPI from '../components/LineWithKPI';
import DataFieldRadio from '../components/DataFieldRadio';
import { datePartOptions } from './../components/DateGroupRadio/date';
import SearchForm from './../components/search/SearchForm';
import { empty, cloneDeep, isEmpty } from './../utils/commons';
import { dataFieldAlias } from './../libs/ht';
import './home.css';
const topSeries = [
{ key: 'dept', value: 'dept', label: '小组', graphVisible: true },
{ key: 'operator', value: 'operator', label: '顾问', graphVisible: true },
{ key: 'destination', value: 'destination', label: '目的地', graphVisible: true },
{ key: 'GuestGroupType', value: 'GuestGroupType', label: '客群类别', graphVisible: false },
{ key: 'country', value: 'country', label: '国籍', graphVisible: true },
{ key: 'webcode', value: 'webcode', label: '站点', graphVisible: false },
{ key: 'bizarea', value: 'bizarea', label: '国境', graphVisible: false },
];
const allGroupTypes = [
{ key: 'overview', value: 'overview', label: '总额' },
...topSeries,
];
// const iconSets = [CheckCircleTwoTone, <MoneyCollectTwoTone />, <FlagTwoTone />, <ClockCircleTwoTone />, <DashboardTwoTone />,<SmileTwoTone />,];
const iconSets = [CheckCircleTwoTone, MoneyCollectTwoTone, FlagTwoTone, SmileTwoTone];
export default observer(() => {
// const navigate = useNavigate();
const { TradeStore, date_picker_store: searchFormStore } = useContext(stores_Context);
const { searchValues, sideData, summaryData, BuData, topData, timeData, timeLineKey, targetTableProps, timeDiffData, groupKey } = TradeStore;
const { formValues } = searchFormStore;
useEffect(() => {
if (empty(summaryData.dataSource)) {
// pageRefresh();
}
return () => {};
}, []);
const [topSeriesSet, setTopSeriesSet] = useState(topSeries);
const [overviewFlag, setOverviewFlag] = useState(true);
const [groupTypeVal, setGroupTypeVal] = useState('overview');
const pageRefresh = (queryData) => {
const _overviewFlag = queryData.DepartmentList.toLowerCase() === 'all' || queryData.DepartmentList.toLowerCase().includes(',');
const groupType = _overviewFlag ? 'overview' : 'dept';
queryData.groupType = groupType;
setGroupTypeVal(groupType);
setDiffGroupKey('overview');
TradeStore.resetData();
TradeStore.fetchSummaryData(Object.assign({}, queryData, { groupType }));
TradeStore.fetchTradeDataByDate(queryData);
TradeStore.fetchTradeDataDiffByDate(queryData);
// // TradeStore.fetchTradeDataByBU(queryData);
TradeStore.fetchTradeDataByMonth(queryData);
const topSeriesF = _overviewFlag ? topSeries : topSeries.filter((ele) => ele.key !== 'dept');
setTopSeriesSet(topSeriesF);
setOverviewFlag(_overviewFlag);
for (const iterator of topSeriesF) {
TradeStore.fetchTradeDataByType(iterator.key, queryData);
}
};
const layoutProps = {
gutter: { xs: 8, sm: 8, lg: 16 },
lg: { span: 6 },
sm: { span: 12 },
xs: { span: 24 },
};
const layoutProps3 = {
gutter: { xs: 8, sm: 8, lg: 16 },
lg: { span: 8 },
sm: { span: 12 },
xs: { span: 24 },
};
const [valueKey, setValueKey] = useState('SumML');
const [BulletConfig, setBulletConfig] = useState({
measureField: 'SumML', //
rangeField: 'SumMLRange', //
targetField: 'MLKPIvalue', //
xField: 'groupsLabel',
});
const handleChangeValueKey = (key) => {
setValueKey(key);
setBulletConfig({
measureField: key,
rangeField: `${key}Range`,
// targetField: `${key}KPI`,
targetField: dataFieldAlias[key].nestkey.v,
xField: 'groupsLabel',
});
};
const WaterfallConfig = {
xField: 'groupDateVal',
yField: 'SumML',
seriesField: 'groupsLabel',
meta: {
groupDateVal: {
alias: '月份',
// type: 'cat',
},
},
label: {
formatter: (v) => ((summaryData.kpi?.value || 0) === 0 ? dataFieldAlias.SumML?.formatter(v.SumML) || v.SumML : ((v.SumML / summaryData.kpi.value) * 100).toFixed(2) + '%'),
},
};
const BUConfig = {
measureField: 'SumML', //
rangeField: 'SumMLRange', //
targetField: 'MLKPIvalue', //
xField: 'groupsLabel',
layout: 'vertical',
xAxis: {
line: null,
label: {
autoHide: true,
autoRotate: false,
},
},
legend: false,
};
const lineConfigSet = {
// data: orders_data.data,
padding: 'auto',
xField: 'groupDateVal',
yField: 'SumML',
seriesField: 'groupsLabel',
xAxis: {
type: 'cat',
},
point: {
size: 4,
shape: 'cicle',
},
legend: false,
meta: {
...cloneDeep(dataFieldAlias),
},
};
const [timeDataField, setTimeDataField] = useState('SumML');
const [lineConfig, setLineConfig] = useState(cloneDeep(lineConfigSet));
const handleChangetimeDataField = (key) => {
setTimeDataField(key);
setLineConfig({
...cloneDeep(lineConfig),
yField: key,
});
};
const [dateField, setDateField] = useState(timeLineKey);
const handleChangeDateType = ({ target: { value } }) => {
setDateField(value);
TradeStore.setTimeLineKey(value);
if (!isEmpty(TradeStore.searchPayloadHome)) {
TradeStore.fetchTradeDataByDate({ groupType: groupTypeVal });
TradeStore.fetchTradeDataDiffByDate({ groupType: diffGroupKey });
}
};
const [diffGroupKey, setDiffGroupKey] = useState(groupKey);
const handleChangeDiffType = ({ target: { value } }) => {
// console.log('diffGroupKey', diffGroupKey, value);
setDiffGroupKey(value);
TradeStore.setGroupKey(value);
if (!isEmpty(TradeStore.searchPayloadHome)) {
TradeStore.fetchTradeDataDiffByDate({ groupType: value });
}
};
const [showDiff, setShowDiff] = useState(false);
return (
<>
<Row gutter={16} className="sticky-top">
<Col className="gutter-row" span={24}>
<SearchForm
defaultValue={{
initialValue: {
...formValues,
...searchValues,
},
shows: ['DateType', 'DepartmentList', 'WebCode', 'IncludeTickets', 'years'],
fieldProps: {
DepartmentList: { show_all: true },
WebCode: { show_all: true },
years: { hide_vs: false },
},
}}
onSubmit={(_err, obj, form, str) => {
TradeStore.setSearch(obj, form);
pageRefresh(obj);
}}
/>
</Col>
</Row>
<section>
<Space>
<h2>
年度业绩<span style={{ fontSize: 'small' }}> =传统+商务</span>
</h2>
</Space>
<Spin spinning={summaryData.loading}>
<Row gutter={layoutProps.gutter}>
{/* {summaryData.dataSource.map((item, i) => (
<Col {...layoutProps} key={item.title}>
<StatisticCard {...item} showProgress={item.hasKPI} icon={iconSets[i]} />
</Col>
))} */}
{summaryData.dataSource.map((item, i) => (
<Col {...layoutProps} key={item.title} lg={{ span: item?.col || layoutProps.lg.span }}>
<StatisticCard2 {...item} showProgress={item.hasKPI} icon={iconSets[i]} />
</Col>
))}
</Row>
</Spin>
</section>
<section>
<Space gutter={16} size={'small'}>
<h3>{showDiff === false ? '走势' : '对比'}</h3>
<DataFieldRadio value={timeDataField} onChange={handleChangetimeDataField} />
<Radio.Group options={datePartOptions} optionType="button" onChange={handleChangeDateType} value={dateField} />
{searchValues.yearDiff && (
<Button type="link" size={'small'} onClick={() => setShowDiff(!showDiff)}>
{showDiff === false ? '显示对比' : '返回本期走势'}
</Button>
)}
</Space>
{showDiff === false ? (
<Spin spinning={timeData.loading}>
<MixTBWithKPI dataSource={timeData.dataSource} summaryData={timeData.origin?.summaryRows || []} {...lineConfig} />
</Spin>
) : (
<Spin spinning={timeDiffData.loading}>
<Space gutter={16} size={'small'}>
<h3>分类对比</h3>
<Radio.Group options={allGroupTypes} optionType="button" onChange={handleChangeDiffType} value={diffGroupKey} />
</Space>
<LineWithKPI
dataSource={timeDiffData.dataSource}
showKPI={false}
{...lineConfig}
{...{ appendPadding: 10, legend: { position: 'right-top', title: { text: '虚线: 对比年份' } }, point: false }}
/>
</Spin>
)}
</section>
<section>
<h3>市场 (仅传统订单) </h3>
<Spin spinning={sideData.loading}>
<Row gutter={layoutProps3.gutter}>
<Col {...layoutProps3}>
<>
<Donut {...{ angleField: 'SumML', colorField: 'groupsLabel' }} title={formValues.DepartmentList?.label} dataSource={sideData.yearData} />
</>
{/* {overviewFlag ? (
<>
<Bullet {...BUConfig} dataSource={BuData?.dataSource || []} />
<h3 style={{ textAlign: 'center' }}>{`各事业部总业绩`}</h3>
</>
) : (
<><Donut {...{angleField: 'SumML', colorField: 'groupsLabel'}} title={formValues.DepartmentList?.label} dataSource={sideData.yearData} /></>
)} */}
</Col>
{Object.keys(sideData.dataSource)
.sort()
.map((key) => (
<Col {...layoutProps3} key={key}>
<Waterfall key={key} {...WaterfallConfig} title={key} dataSource={sideData.dataSource[key]} line={summaryData.kpi} />
<h3 style={{ textAlign: 'center' }}>{`${key}每月业绩`}</h3>
</Col>
))}
</Row>
</Spin>
</section>
<section>
<h3>
英语区目标客户
<Spin spinning={topData?.GuestGroupType?.loading || false}>
<Table {...targetTableProps} pagination={false} rowKey={'groupsLabel'} />
</Spin>
</h3>
</section>
<section>
<Space>
<h3>TOP</h3>
<div>
<DataFieldRadio value={valueKey} onChange={handleChangeValueKey} />
</div>
</Space>
<Row gutter={layoutProps3.gutter}>
{topSeriesSet.map((item) =>
item.graphVisible ? (
<Col {...layoutProps3} key={item.key}>
<Spin spinning={topData[item.key]?.loading || false}>
<h3 style={{ textAlign: 'center' }}>{item.label}</h3>
<Bullet {...BulletConfig} dataSource={topData[item.key]?.dataSource || []} itemLength={10} key={item.key} />
</Spin>
</Col>
) : null
)}
<Col key={'mapG'} flex={'1 0 600px'} >
<Spin spinning={topData?.country?.loading || false}>
<div id="topC" style={{ height: '700px' }}>
<MapCountry sourceField={'groupsLabel'} valueField={BUConfig.measureField} dataSource={topData?.country?.dataSource || []} />
</div>
</Spin>
</Col>
</Row>
</section>
</>
);
});