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/Distribution.jsx

246 lines
8.6 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useContext, useEffect } from 'react';
import { observer } from 'mobx-react';
import { stores_Context } from '../config';
import { Row, Col, Spin, Tabs, Table, Space, Typography, Divider } from 'antd';
import { RingProgress } from '@ant-design/plots';
import SearchForm from './../components/search/SearchForm';
import { empty } from '../utils/commons';
import { dataFieldAlias } from '../libs/ht';
import { VSTag, TableExportBtn } from './../components/Data';
import MixYnQ from './../components/MixYnQ';
import './kpi.css';
const { Text } = Typography;
const apartOptions = [
{ key: 'tourDays', value: 'tourDays', label: '团天数' },
{ key: 'PML', value: 'PML', label: '单团毛利' },
{ key: 'ConfirmDays', value: 'ConfirmDays', label: '成团周期' },
{ key: 'ApplyDays', value: 'ApplyDays', label: '预定周期' },
{ key: 'PersonNum', value: 'PersonNum', label: '人等' },
{ key: 'destination', value: 'destination', label: '国内目的地', },
{ key: 'GlobalDestination', value: 'GlobalDestination', label: '海外目的地', },
{ key: 'destinationCountry', value: 'destinationCountry', label: '目的地国籍', },
{ key: 'guestCountry', value: 'guestCountry', label: '客人国籍', },
];
// 注意TdCell要提到DataTable作用域外声明
const TdCell = (tdprops) => {
// onMouseEnter, onMouseLeave在数据量多的时候会严重阻塞表格单元格渲染严重影响性能
const { onMouseEnter, onMouseLeave, ...restProps } = tdprops;
return <td {...restProps} />;
};
export default observer(() => {
const { date_picker_store: searchFormStore, DistributionStore } = useContext(stores_Context);
const { formValues, formValuesToSub, siderBroken } = searchFormStore;
const { curTab, dateStringQ, dateStringY } = DistributionStore;
const pageRefresh = (obj) => {
DistributionStore.getApartData({
...(obj || formValuesToSub),
});
};
useEffect(() => {
DistributionStore.setFormDates(formValuesToSub);
DistributionStore.resetData();
return () => {};
}, [formValuesToSub]);
const onTabsChange = (tab) => {
DistributionStore.setCurTab(tab);
if (empty(DistributionStore[tab].dataSource)) {
pageRefresh();
}
};
const RingProgressConfig = {
height: 60,
width: 60,
autoFit: false,
color: ['#5B8FF9', '#E8EDF3'],
};
const RingProgressConfigY = {
height: 50,
width: 50,
autoFit: false,
// color: ['#f6bd16', '#E8EDF3'],
color: ['#61ddaa', '#E8EDF3'], // #7cb305
innerRadius: 0.90,
};
const RingProgressConfigQ = {
height: 50,
width: 50,
autoFit: false,
color: ['#f6bd16', '#E8EDF3'],
innerRadius: 0.90,
};
const columns = [
{ title: '#', dataIndex: 'label' },
{
title: '预定',
dataIndex: 'SumOrder',
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>{v}</Text>
<span>
<span>同比: </span> <VSTag diffPercent={r.SumOrderToY} diffData={r.SumOrderDiffY} />
</span>
<span>
<span>环比: </span> <VSTag diffPercent={r.SumOrderToQ} diffData={r.SumOrderDiffQ} />
</span>
</Space>
</>
),
},
{
title: '团数',
dataIndex: 'ConfirmOrder',
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>{v}</Text>
<span>
<span>同比: </span> <VSTag diffPercent={r.ConfirmOrderToY} diffData={r.ConfirmOrderDiffY} />
</span>
<span>
<span>环比: </span> <VSTag diffPercent={r.ConfirmOrderToQ} diffData={r.ConfirmOrderDiffQ} />
</span>
</Space>
</>
),
},
{
title: '业绩',
dataIndex: 'SumML',
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>{dataFieldAlias.SumML.formatter(v)}</Text>
<span>
<span>同比: </span> <VSTag diffPercent={r.SumMLToY} diffData={dataFieldAlias.SumML.formatter(r.SumMLDiffY)} />
</span>
<span>
<span>环比: </span> <VSTag diffPercent={r.SumMLToQ} diffData={dataFieldAlias.SumML.formatter(r.SumMLDiffQ)} />
</span>
</Space>
</>
),
},
{
title: '团数占比',
dataIndex: 'ConfirmOrderPercent',
render: (v, r) => v ? <RingProgress {...RingProgressConfig} percent={v / 100} /> : '-',
},
{
title: '业绩占比',
dataIndex: 'SumMLPercent',
render: (v, r) => v ? <RingProgress {...RingProgressConfig} percent={v / 100} /> : '-',
},
{
title: () => <><div>去年同期</div><div>{dateStringY}</div></>,
titleX: ['去年同期', dateStringY], // 给导出按钮用
align: 'center',
children: [
{
title: '团数占比',
titleX: '团数占比',
width: 90,
dataIndex: ['resultToY', 'ConfirmOrderPercent'], // 'ConfirmOrderPercent',
render: (v, r) => r.resultToY.ConfirmOrderPercent ? <RingProgress {...RingProgressConfigY} percent={r.resultToY.ConfirmOrderPercent / 100} /> : '-',
},
{
title: '业绩占比',
titleX: '业绩占比',
width: 90,
dataIndex: ['resultToY', 'SumMLPercent'], // 'SumMLPercent',
render: (v, r) => r.resultToY.SumMLPercent ? <RingProgress {...RingProgressConfigY} percent={r.resultToY.SumMLPercent / 100} /> : '-',
},
],
},
{
title: () => <><div>上个时间段</div><div>{dateStringQ}</div></>,
titleX: ['上个时间段', dateStringY], // 给导出按钮用
align: 'center',
children: [
{
title: '团数占比',
titleX: '团数占比',
width: 90,
dataIndex: ['resultToQ', 'ConfirmOrderPercent'], // 'ConfirmOrderPercent',
render: (v, r) => r.resultToQ.ConfirmOrderPercent ? <RingProgress {...RingProgressConfigQ} percent={r.resultToQ.ConfirmOrderPercent / 100} /> : '-',
},
{
title: '业绩占比',
titleX: '业绩占比',
width: 90,
dataIndex: ['resultToQ', 'SumMLPercent'], // 'SumMLPercent',
render: (v, r) => r.resultToQ.SumMLPercent ? <RingProgress {...RingProgressConfigQ} percent={r.resultToQ.SumMLPercent / 100} /> : '-',
},
],
},
];
const chartsConfig = {
xField: 'label',
yFields: ['ConfirmOrder','SumML'],
seriesField: null,
};
return (
<>
<Row gutter={16} className={siderBroken ? "" : "sticky-top"} >
<Col className="gutter-row" span={24}>
<SearchForm
defaultValue={{
initialValue: {
...formValues,
},
shows: ['DateType', 'DepartmentList', 'WebCode', 'IncludeTickets', 'dates', 'operator'],
fieldProps: {
DepartmentList: { show_all: true },
WebCode: { show_all: true },
dates: { hide_vs: true },
},
}}
onSubmit={(_err, obj) => {
pageRefresh(obj);
}}
/>
</Col>
</Row>
<section>
<Tabs
onChange={onTabsChange}
type="card"
items={apartOptions.map((ele) => {
return {
...ele,
children: (
<Spin spinning={DistributionStore.pageLoading}>
<MixYnQ {...chartsConfig} dataSource={DistributionStore[curTab].dataSource} />
<Divider orientation="right" plain>
<TableExportBtn label={`统计分布-${ele.label}`} {...{ columns, dataSource: DistributionStore[curTab].dataSource }} />
</Divider>
<Table
id="table_to_xlsx_sale"
components={{ body: { cell: TdCell } }}
dataSource={DistributionStore[curTab].dataSource}
columns={columns}
size="small"
rowKey={(record) => record.label}
loading={DistributionStore[curTab].loading}
pagination={false}
scroll={{ x: '100%' }}
/>
</Spin>
),
};
})}
/>
</section>
</>
);
});