Compare commits
56 Commits
Author | SHA1 | Date |
---|---|---|
|
021fb429ce | 4 days ago |
|
a9f45e334d | 1 month ago |
|
488b33ae50 | 1 month ago |
|
6dbf9cfb56 | 1 month ago |
|
108becd2cd | 1 month ago |
|
73e1dcdb4c | 1 month ago |
|
baae505831 | 1 month ago |
|
16b08311fa | 1 month ago |
|
e0e7c3c84f | 2 months ago |
|
87f24c40fa | 2 months ago |
|
bed6b81753 | 2 months ago |
|
171dd7514a | 2 months ago |
|
a0ea6507a3 | 2 months ago |
|
40cd81f9a7 | 2 months ago |
|
876216458e | 2 months ago |
|
8a0f919a42 | 2 months ago |
|
020c9fc3e9 | 2 months ago |
|
b2e539a4d2 | 2 months ago |
|
fee1185406 | 2 months ago |
|
e297d36256 | 2 months ago |
|
667574ec34 | 2 months ago |
|
185db1ec80 | 2 months ago |
|
6dc82a0a01 | 2 months ago |
|
4724b13a2d | 2 months ago |
|
f532f138ff | 2 months ago |
|
3b51ae8d08 | 2 months ago |
|
a6f7884e6e | 2 months ago |
|
928e27913d | 2 months ago |
|
94363df0fc | 2 months ago |
|
621d3a2446 | 2 months ago |
|
8f12fc8747 | 2 months ago |
|
397c886aea | 2 months ago |
|
459db55453 | 2 months ago |
|
6317c24a75 | 2 months ago |
|
c9e13385dc | 2 months ago |
|
a02fa37f17 | 2 months ago |
|
ccbd0be1cd | 2 months ago |
|
c7d3cf5746 | 2 months ago |
|
23b1d2c81b | 2 months ago |
|
7c08e8bfe6 | 2 months ago |
|
1e46cf6e63 | 2 months ago |
|
17cedf14d9 | 2 months ago |
|
2fae92fa2a | 2 months ago |
|
08aa01e33c | 2 months ago |
|
17a85122b1 | 2 months ago |
|
1b86ab1192 | 2 months ago |
|
be31c3983d | 2 months ago |
|
5551b2e362 | 3 months ago |
|
7cfd79a0d2 | 3 months ago |
|
dcb185be5a | 3 months ago |
|
c3547538fd | 3 months ago |
|
cb598ecba1 | 3 months ago |
|
a32943fffb | 3 months ago |
|
a7b24d206d | 3 months ago |
|
f8eef38944 | 3 months ago |
|
d1ee551a4e | 4 months ago |
@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Select } from 'antd';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { HotelStars as options } from '../../libs/ht';
|
||||||
|
|
||||||
|
const HotelStars = (props) => {
|
||||||
|
const { mode, value, onChange, show_all, ...extProps } = props;
|
||||||
|
const _show_all = ['tags', 'multiple'].includes(mode) ? false : show_all;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
mode={mode || null}
|
||||||
|
allowClear
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder="星级"
|
||||||
|
value={value || undefined}
|
||||||
|
onChange={(value) => {
|
||||||
|
if (typeof onChange === 'function') {
|
||||||
|
onChange(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
labelInValue={false}
|
||||||
|
{...extProps}
|
||||||
|
options={options}
|
||||||
|
>
|
||||||
|
{_show_all ? (
|
||||||
|
<Select.Option key="-1" value="ALL">
|
||||||
|
ALL
|
||||||
|
</Select.Option>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 酒店星级
|
||||||
|
*/
|
||||||
|
export default observer(HotelStars);
|
@ -0,0 +1,181 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { stores_Context } from '../config';
|
||||||
|
import { Row, Col, Table, Space, Typography, Divider } from 'antd';
|
||||||
|
import SearchForm from './../components/search/SearchForm';
|
||||||
|
import { VSTag, TableExportBtn } from './../components/Data';
|
||||||
|
import { CruiseAgency } from './../libs/ht';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
export default observer((props) => {
|
||||||
|
const { date_picker_store: searchFormStore } = useContext(stores_Context);
|
||||||
|
const { HotelCruiseStore, date_picker_store } = useContext(stores_Context);
|
||||||
|
const { loading, dataSource, summaryRow } = HotelCruiseStore.cruise;
|
||||||
|
|
||||||
|
const { formValues, siderBroken } = searchFormStore;
|
||||||
|
|
||||||
|
const tableSorter = (a, b, colName) => a[colName] - b[colName];
|
||||||
|
const tableExportDataRow = (col1, col2) => [col1, col2].filter((r) => r).join(' VS ');
|
||||||
|
const tableProps = {
|
||||||
|
size: 'small',
|
||||||
|
bordered: true,
|
||||||
|
pagination: false,
|
||||||
|
columns: [
|
||||||
|
{ title: '产品',
|
||||||
|
sorter: (a, b) => a.ProductName.localeCompare(b.ProductName, 'zh-CN'),children: [{ title: summaryRow.ProductName, dataIndex: 'ProductName', key: 'ProductName' }] },
|
||||||
|
{
|
||||||
|
title: '房间数',
|
||||||
|
sorter: (a, b) => tableSorter(a, b, 'TotalNum'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{summaryRow.TotalNum}
|
||||||
|
{summaryRow.TotalNumPercent ? <Text type="secondary"> VS {summaryRow.CPTotalNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{summaryRow.TotalNumPercent && <VSTag diffPercent={summaryRow.TotalNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
titleX: tableExportDataRow(summaryRow.TotalNum, summaryRow.CPTotalNum),
|
||||||
|
dataExport: (v, r) => tableExportDataRow(r.TotalNum, r.CPTotalNum),
|
||||||
|
dataIndex: 'TotalNum',
|
||||||
|
key: 'TotalNum',
|
||||||
|
render: (v, r) => (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{v}
|
||||||
|
{r.CPTotalNum ? <Text type="secondary"> VS {r.CPTotalNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{r.CPTotalNum && <VSTag diffPercent={r.TotalNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '人数',
|
||||||
|
sorter: (a, b) => tableSorter(a, b, 'TotalPersonNum'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{summaryRow.TotalPersonNum}
|
||||||
|
{summaryRow.TotalPersonNumPercent ? <Text type="secondary"> VS {summaryRow.CPTotalPersonNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{summaryRow.TotalPersonNumPercent && <VSTag diffPercent={summaryRow.TotalPersonNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
titleX: tableExportDataRow(summaryRow.TotalPersonNum, summaryRow.CPTotalPersonNum),
|
||||||
|
dataExport: (v, r) => tableExportDataRow(r.TotalPersonNum, r.CPTotalPersonNum),
|
||||||
|
dataIndex: 'TotalPersonNum',
|
||||||
|
key: 'TotalPersonNum',
|
||||||
|
render: (v, r) => (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{v}
|
||||||
|
{r.CPTotalPersonNum ? <Text type="secondary"> VS {r.CPTotalPersonNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{r.CPTotalNum && <VSTag diffPercent={r.TotalPersonNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总利润',
|
||||||
|
sorter: (a, b) => tableSorter(a, b, 'TotalProfit'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{summaryRow.TotalProfit}
|
||||||
|
{summaryRow.TotalProfitPercent ? <Text type="secondary"> VS {summaryRow.CPTotalProfit}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{summaryRow.TotalProfitPercent && <VSTag diffPercent={summaryRow.TotalProfitPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
titleX: tableExportDataRow(summaryRow.TotalProfit, summaryRow.CPTotalProfit),
|
||||||
|
dataExport: (v, r) => tableExportDataRow(r.TotalProfit, r.CPTotalProfit),
|
||||||
|
dataIndex: 'TotalProfit',
|
||||||
|
key: 'TotalProfit',
|
||||||
|
render: (v, r) => (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{v}
|
||||||
|
{r.CPTotalProfit ? <Text type="secondary"> VS {r.CPTotalProfit}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{r.CPTotalNum && <VSTag diffPercent={r.TotalProfitPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// { title: '单订船', dataIndex: '', key: '' },
|
||||||
|
// { title: '订单含行程', dataIndex: '', key: '' },
|
||||||
|
// { title: '国籍', dataIndex: '', key: '' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
|
||||||
|
<Col md={24} lg={24} xxl={24}>
|
||||||
|
<SearchForm
|
||||||
|
defaultValue={{
|
||||||
|
initialValue: {
|
||||||
|
...date_picker_store.formValues,
|
||||||
|
...HotelCruiseStore.searchValues,
|
||||||
|
},
|
||||||
|
// 'countryArea',
|
||||||
|
shows: [
|
||||||
|
'DepartmentList',
|
||||||
|
'orderStatus',
|
||||||
|
'dates',
|
||||||
|
'keyword',
|
||||||
|
'cruiseDirection',
|
||||||
|
'agency',
|
||||||
|
'cruiseBookType',
|
||||||
|
'country', // 'roomsRange', 'personRange'
|
||||||
|
],
|
||||||
|
sort: { keyword: 101, agency: 110, cruiseDirection: 102, country: 104 },
|
||||||
|
fieldProps: {
|
||||||
|
keyword: { placeholder: '产品名', col: 4 },
|
||||||
|
DepartmentList: { show_all: true, mode: 'multiple' },
|
||||||
|
orderStatus: { show_all: true },
|
||||||
|
cruiseDirection: { show_all: true },
|
||||||
|
agency: { defaultOptions: CruiseAgency, autoGet: false },
|
||||||
|
// years: { hide_vs: false },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onSubmit={(_err, obj, form) => {
|
||||||
|
HotelCruiseStore.setSearchValues(obj, form);
|
||||||
|
HotelCruiseStore.getCruiseData(obj);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<section>
|
||||||
|
<Divider orientation="right" >
|
||||||
|
<TableExportBtn label={'游船'} {...{ columns: tableProps.columns, dataSource }} />
|
||||||
|
</Divider>
|
||||||
|
<Table {...tableProps} {...{ loading, dataSource }} rowKey={(record) => record.ProductName} />
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,147 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { Row, Col, Typography, Space, Table, Divider } from 'antd';
|
||||||
|
import { stores_Context } from '../config';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import 'moment/locale/zh-cn';
|
||||||
|
import SearchForm from '../components/search/SearchForm';
|
||||||
|
import { TableExportBtn } from '../components/Data';
|
||||||
|
import * as comm from '../utils/commons';
|
||||||
|
|
||||||
|
const HostCaseCount = () => {
|
||||||
|
const { customer_store, date_picker_store } = useContext(stores_Context);
|
||||||
|
const host_case_data = customer_store.host_case_data;
|
||||||
|
|
||||||
|
const columnsList = [
|
||||||
|
{
|
||||||
|
title: '团数',
|
||||||
|
dataIndex: 'TotalGroupNum',
|
||||||
|
key: 'TotalGroupNum',
|
||||||
|
sorter: (a, b) => parseInt(a.TotalGroupNum) - parseInt(b.TotalGroupNum),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '人数',
|
||||||
|
dataIndex: 'TotalPersonNum',
|
||||||
|
key: 'TotalPersonNum',
|
||||||
|
sorter: (a, b) => parseInt(a.TotalPersonNum) - parseInt(b.TotalPersonNum),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '计费团天数',
|
||||||
|
dataIndex: 'TotalDays',
|
||||||
|
key: 'TotalDays',
|
||||||
|
sorter: (a, b) => parseInt(a.TotalDays) - parseInt(b.TotalDays),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '交易额',
|
||||||
|
dataIndex: 'TotalPrice',
|
||||||
|
key: 'TotalPrice',
|
||||||
|
sorter: (a, b) => parseInt(a.TotalPrice) - parseInt(b.TotalPrice),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 筛选函数
|
||||||
|
const getFiltersData=(filterData,filterKey)=>{
|
||||||
|
return comm.uniqWith(filterData.map(rr => ({ text: rr[filterKey], value: rr[filterKey] })),
|
||||||
|
(a, b) => JSON.stringify(a) === JSON.stringify(b)).sort((a, b) => a.text.localeCompare(b.text));
|
||||||
|
};
|
||||||
|
// 小组筛选菜单项
|
||||||
|
const allOPIGroup = getFiltersData(host_case_data.summaryData,"GroupBy");
|
||||||
|
// 顾问筛选菜单项
|
||||||
|
const allOPIConsultant = getFiltersData(host_case_data.counselorData,"GroupBy");
|
||||||
|
// 明细表顾问名筛选菜单项
|
||||||
|
const allOPIDetailConsultant = getFiltersData(host_case_data.singleDetailData,"OPI_Name");
|
||||||
|
const summaryColumnsList = [{
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'GroupBy',
|
||||||
|
key: 'GroupBy',
|
||||||
|
}, ...columnsList];
|
||||||
|
const groupColumnsList = [{
|
||||||
|
title: '组名',
|
||||||
|
dataIndex: 'GroupBy',
|
||||||
|
key: 'GroupBy',
|
||||||
|
filters: allOPIGroup,
|
||||||
|
onFilter: (value, record) => record.GroupBy === value,
|
||||||
|
filterSearch: true,
|
||||||
|
}, ...columnsList];
|
||||||
|
const counselorColumnsList = [{
|
||||||
|
title: '顾问名',
|
||||||
|
dataIndex: 'GroupBy',
|
||||||
|
key: 'GroupBy',
|
||||||
|
filters: allOPIConsultant,
|
||||||
|
onFilter: (value, record) => record.GroupBy === value,
|
||||||
|
filterSearch: true,
|
||||||
|
}, ...columnsList];
|
||||||
|
const singleDetailColumnsList = [{
|
||||||
|
title: '团名',
|
||||||
|
dataIndex: 'GroupBy',
|
||||||
|
key: 'GroupBy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '顾问名',
|
||||||
|
dataIndex: 'OPI_Name',
|
||||||
|
key: 'OPI_Name',
|
||||||
|
filters: allOPIDetailConsultant,
|
||||||
|
onFilter: (value, record) => record.OPI_Name === value,
|
||||||
|
filterSearch: true,
|
||||||
|
},
|
||||||
|
...columnsList.slice(1)];
|
||||||
|
|
||||||
|
const renderRow=(rowColumns,rowDataSource,title)=>{
|
||||||
|
return(
|
||||||
|
<Row>
|
||||||
|
<Col span={24}>
|
||||||
|
<Typography.Title level={3}>{title}</Typography.Title>
|
||||||
|
<Divider orientation="right" plain>
|
||||||
|
<TableExportBtn label={title} {...{ columns: rowColumns, dataSource: rowDataSource }} />
|
||||||
|
</Divider>
|
||||||
|
<Table
|
||||||
|
sticky
|
||||||
|
id={`${rowColumns}`}
|
||||||
|
dataSource={rowDataSource}
|
||||||
|
columns={rowColumns}
|
||||||
|
size="small"
|
||||||
|
rowKey={(record) => record.key}
|
||||||
|
loading={host_case_data.loading}
|
||||||
|
pagination={false}
|
||||||
|
scroll={{ x: 1000 }}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }}>
|
||||||
|
<Row gutter={16} className={date_picker_store.siderBroken ? "" : "sticky-top"} >
|
||||||
|
<Col className="gutter-row" span={24}>
|
||||||
|
<SearchForm
|
||||||
|
defaultValue={{
|
||||||
|
initialValue: {
|
||||||
|
...date_picker_store.formValues,
|
||||||
|
...host_case_data.searchValues,
|
||||||
|
},
|
||||||
|
shows: ['DepartmentList', 'dates'],
|
||||||
|
fieldProps: {
|
||||||
|
DepartmentList: { show_all: false, mode: 'multiple' },
|
||||||
|
dates: { hide_vs: true },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onSubmit={(_err, obj, form) => {
|
||||||
|
customer_store.setSearchValues(obj, form,"host_case_data");
|
||||||
|
customer_store.getHostCaseData("1");
|
||||||
|
customer_store.getHostCaseData("2");
|
||||||
|
customer_store.getHostCaseData("3");
|
||||||
|
customer_store.getHostCaseData("4");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{renderRow(summaryColumnsList,host_case_data.summaryData,'东道主项目汇总')}
|
||||||
|
{renderRow(groupColumnsList,host_case_data.groupData,'东道主项目小组统计')}
|
||||||
|
{renderRow(counselorColumnsList,host_case_data.counselorData,'东道主项目顾问统计')}
|
||||||
|
{renderRow(singleDetailColumnsList,host_case_data.singleDetailData,'单团明细')}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default observer(HostCaseCount);
|
@ -0,0 +1,171 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { stores_Context } from '../config';
|
||||||
|
import { Row, Col, Table, Space, Typography, Divider } from 'antd';
|
||||||
|
import SearchForm from './../components/search/SearchForm';
|
||||||
|
import { VSTag, TableExportBtn } from './../components/Data';
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
export default observer((props) => {
|
||||||
|
const { date_picker_store: searchFormStore } = useContext(stores_Context);
|
||||||
|
const { date_picker_store, HotelCruiseStore } = useContext(stores_Context);
|
||||||
|
const { loading, dataSource, summaryRow } = HotelCruiseStore.hotel;
|
||||||
|
|
||||||
|
const { formValues, siderBroken } = searchFormStore;
|
||||||
|
|
||||||
|
const tableSorter = (a, b, colName) => a[colName] - b[colName];
|
||||||
|
const tableExportDataRow = (col1, col2) => [col1, col2].filter((r) => r).join(' VS ');
|
||||||
|
|
||||||
|
const tableProps = {
|
||||||
|
size: 'small',
|
||||||
|
bordered: true,
|
||||||
|
pagination: false,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '目的地',
|
||||||
|
sorter: (a, b) => a.CityName.localeCompare(b.CityName, 'zh-CN'),
|
||||||
|
children: [{ title: summaryRow.CityName, dataIndex: 'CityName', key: 'CityName' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总间夜',
|
||||||
|
sorter: (a, b) => tableSorter(a, b, 'TotalNum'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{summaryRow.TotalNum}
|
||||||
|
{summaryRow.TotalNumPercent ? <Text type="secondary"> VS {summaryRow.CPTotalNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{summaryRow.TotalNumPercent && <VSTag diffPercent={summaryRow.TotalNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
titleX: tableExportDataRow(summaryRow.TotalNum, summaryRow.CPTotalNum),
|
||||||
|
dataIndex: 'TotalNum',
|
||||||
|
key: 'TotalNum',
|
||||||
|
dataExport: (v, r) => tableExportDataRow(r.TotalNum, r.CPTotalNum),
|
||||||
|
render: (v, r) => (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{v}
|
||||||
|
{r.CPTotalNum ? <Text type="secondary"> VS {r.CPTotalNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{r.CPTotalNum && <VSTag diffPercent={r.TotalNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '主推',
|
||||||
|
sorter: (a, b) => tableSorter(a, b, 'RecomendNum'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{summaryRow.RecomendNum}
|
||||||
|
{summaryRow.RecomendNumPercent ? <Text type="secondary"> VS {summaryRow.CPRecomendNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{summaryRow.RecomendNumPercent && <VSTag diffPercent={summaryRow.RecomendNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
titleX: tableExportDataRow(summaryRow.RecomendNum, summaryRow.CPRecomendNum),
|
||||||
|
dataIndex: 'RecomendNum',
|
||||||
|
key: 'RecomendNum',
|
||||||
|
dataExport: (v, r) => tableExportDataRow(r.RecomendNum, r.CPRecomendNum),
|
||||||
|
render: (v, r) => (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{v}
|
||||||
|
{r.CPRecomendNum ? <Text type="secondary"> VS {r.CPRecomendNum}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{r.CPRecomendNum && <VSTag diffPercent={r.RecomendNumPercent} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '使用比例',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{summaryRow.RecommendRate_100}
|
||||||
|
{summaryRow.RecommendRateDelta ? <Text type="secondary"> VS {summaryRow.CPRecommendRate_100}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
{summaryRow.RecommendRateDelta && <VSTag diffPercent={summaryRow.RecommendRateDelta} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
titleX: tableExportDataRow(summaryRow.RecommendRate_100, summaryRow.CPRecommendRate_100),
|
||||||
|
dataIndex: 'RecommendRate_100',
|
||||||
|
key: 'RecommendRate_100',
|
||||||
|
dataExport: (v, r) => tableExportDataRow(r.RecommendRate_100, r.CPRecommendRate_100),
|
||||||
|
render: (v, r) => (
|
||||||
|
<>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<Text strong>
|
||||||
|
{v}
|
||||||
|
{r.RecommendRateDelta !== undefined && <Text type="secondary"> VS {r.CPRecommendRate_100}</Text>}
|
||||||
|
</Text>
|
||||||
|
{r.RecommendRateDelta !== undefined && <VSTag diffPercent={r.RecommendRateDelta} />}
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
|
||||||
|
<Col md={24} lg={24} xxl={24}>
|
||||||
|
<SearchForm
|
||||||
|
defaultValue={{
|
||||||
|
initialValue: {
|
||||||
|
...date_picker_store.formValues,
|
||||||
|
...HotelCruiseStore.searchValues,
|
||||||
|
},
|
||||||
|
// 'countryArea', 'DateType', 'dates', 'hotelRecommandRate',
|
||||||
|
shows: ['DepartmentList', 'countryArea', 'orderStatus', 'hotelBookType', 'hotelStar', 'DateType', 'dates'],
|
||||||
|
sort: { DateType: 101, dates: 102 },
|
||||||
|
fieldProps: {
|
||||||
|
DepartmentList: { show_all: true, mode: 'multiple' },
|
||||||
|
countryArea: { show_all: true },
|
||||||
|
orderStatus: { show_all: true },
|
||||||
|
hotelBookType: { show_all: true },
|
||||||
|
hotelRecommandRate: { show_all: true },
|
||||||
|
// years: { hide_vs: false },
|
||||||
|
DateType: { disabledKeys: ['applyDate'] },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onSubmit={(_err, obj, form) => {
|
||||||
|
HotelCruiseStore.setSearchValues(obj, form);
|
||||||
|
HotelCruiseStore.getHotelData(obj);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<section>
|
||||||
|
<Divider orientation="right" >
|
||||||
|
<TableExportBtn label={'酒店'} {...{ columns: tableProps.columns, dataSource }} />
|
||||||
|
</Divider>
|
||||||
|
<Table {...tableProps} bordered {...{ loading, dataSource }} rowKey={(record) => record.CityName} />
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
@ -1,69 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { observer } from 'mobx-react';
|
|
||||||
import { stores_Context } from '../config';
|
|
||||||
import moment from 'moment';
|
|
||||||
import { SlackOutlined, SketchOutlined, AntCloudOutlined, RedditOutlined, GithubOutlined } from '@ant-design/icons';
|
|
||||||
import { Row, Col, Table, Select, Space, Typography, Progress, Spin, Divider, Button, Switch } from 'antd';
|
|
||||||
import SearchForm from './../components/search/SearchForm';
|
|
||||||
|
|
||||||
export default observer((props) => {
|
|
||||||
const { sale_store, date_picker_store: searchFormStore } = useContext(stores_Context);
|
|
||||||
|
|
||||||
const { formValues, siderBroken } = searchFormStore;
|
|
||||||
|
|
||||||
const riskTableProps = {
|
|
||||||
loading: false,
|
|
||||||
// sticky: true,
|
|
||||||
// scroll: { x: 1000, y: 400 },
|
|
||||||
pagination: false,
|
|
||||||
columns: [
|
|
||||||
{ title: '客人姓名', dataIndex: 'WebCode', key: 'WebCode' },
|
|
||||||
{ title: '团号', dataIndex: 'o_id', key: 'o_id' },
|
|
||||||
{ title: '表单内容', dataIndex: 'COLI_LineClass', key: 'COLI_LineClass' },
|
|
||||||
{ title: '顾问', dataIndex: 'SourceType', key: 'SourceType' },
|
|
||||||
{ title: '预定时间', dataIndex: 'applyDate', key: 'applyDate' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
|
|
||||||
<Col md={24} lg={24} xxl={24}>
|
|
||||||
<SearchForm
|
|
||||||
defaultValue={{
|
|
||||||
initialValue: {
|
|
||||||
...formValues,
|
|
||||||
...sale_store.searchValues,
|
|
||||||
},
|
|
||||||
shows: ['DepartmentList', 'WebCode', 'dates'],
|
|
||||||
fieldProps: {
|
|
||||||
DepartmentList: { show_all: false, mode: 'multiple', col: 5 },
|
|
||||||
WebCode: { show_all: false, mode: 'multiple', col: 5 },
|
|
||||||
dates: { hide_vs: true },
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
onSubmit={(_err, obj, form, str) => {
|
|
||||||
sale_store.setSearchValues(obj, form);
|
|
||||||
// pageRefresh(obj);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<section>
|
|
||||||
<h3>>24H回复</h3>
|
|
||||||
<Table {...riskTableProps} bordered />
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3>首次报价周期>48h</h3>
|
|
||||||
<Table {...riskTableProps} bordered />
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3>报价次数<1</h3>
|
|
||||||
<Table {...riskTableProps} bordered />
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3>报价次数<2</h3>
|
|
||||||
<Table {...riskTableProps} bordered />
|
|
||||||
</section>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
@ -0,0 +1,397 @@
|
|||||||
|
import React, { useContext, useEffect } from 'react';
|
||||||
|
import { NavLink, useParams } from 'react-router-dom';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { stores_Context, DATE_FORMAT, SMALL_DATETIME_FORMAT } from '../../config';
|
||||||
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Row, Col, Table, Divider, Button, Popover, Tooltip } from 'antd';
|
||||||
|
import { fixTo2Decimals } from '../../utils/commons';
|
||||||
|
import MixFieldsDetail from '../../components/MixFieldsDetail';
|
||||||
|
|
||||||
|
const COLOR_SETS = [
|
||||||
|
'#FFFFFF',
|
||||||
|
// "#5B8FF9",
|
||||||
|
// "#FF6B3B",
|
||||||
|
'#9FB40F',
|
||||||
|
'#76523B',
|
||||||
|
'#DAD5B5',
|
||||||
|
'#E19348',
|
||||||
|
'#F383A2',
|
||||||
|
];
|
||||||
|
const transparentHex = '1A';
|
||||||
|
const percentageRender = (val) => (val ? `${val}%` : '');
|
||||||
|
const numberConvert10K = (number, scale = 10) => {
|
||||||
|
return fixTo2Decimals((number/(1000*scale)));
|
||||||
|
};
|
||||||
|
const retPropsMinRatesSet = { 'CH': 12, 'AH': 8, 'default': 10 }; //
|
||||||
|
|
||||||
|
export default observer((props) => {
|
||||||
|
const { opisn, opi_name } = useParams();
|
||||||
|
|
||||||
|
const { sale_store, SalesCRMDataStore, date_picker_store: searchFormStore } = useContext(stores_Context);
|
||||||
|
|
||||||
|
const { formValues, siderBroken } = searchFormStore;
|
||||||
|
const { searchValues, searchValuesToSub, resetData, results, process, risk } = SalesCRMDataStore;
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Promise.allSettled([
|
||||||
|
// 结果指标
|
||||||
|
SalesCRMDataStore.get90n180Data({ opisn, groupType: 'operator', groupDateType: '' }),
|
||||||
|
// 结果: 全年业绩
|
||||||
|
SalesCRMDataStore.getResultData({
|
||||||
|
opisn,
|
||||||
|
Date1: searchValues.date.clone().startOf('year').format(DATE_FORMAT),
|
||||||
|
Date2: searchValues.date.clone().endOf('year').format(SMALL_DATETIME_FORMAT),
|
||||||
|
groupType: 'overview',
|
||||||
|
// groupType: 'operator',
|
||||||
|
groupDateType: 'month',
|
||||||
|
}),
|
||||||
|
// 过程
|
||||||
|
SalesCRMDataStore.getProcessData({ opisn, groupType: 'operator', groupDateType: '' }),
|
||||||
|
// 违规明细
|
||||||
|
SalesCRMDataStore.getRiskDetailData({ opisn }),
|
||||||
|
]);
|
||||||
|
}, [opisn]);
|
||||||
|
|
||||||
|
const dataFields = (suffix, colRootIndex) => [
|
||||||
|
{
|
||||||
|
key: 'ConfirmRates' + suffix,
|
||||||
|
title: '成行率',
|
||||||
|
dataIndex: [suffix, 'ConfirmRates'],
|
||||||
|
width: '5em',
|
||||||
|
// CH个人成行率<12%, AH个人成行率<8%刷红
|
||||||
|
render: (val, r) => ({
|
||||||
|
props: { style: { color: val < (retPropsMinRatesSet?.[r?.retProps || 'default'] || retPropsMinRatesSet.default) ? 'red' : 'green', backgroundColor: COLOR_SETS[colRootIndex]+transparentHex } },
|
||||||
|
children: val ? `${val}%` : '',
|
||||||
|
}),
|
||||||
|
sorter: (a, b) => (a.groupType === 'overview' ? -1 : b.groupType === 'overview' ? 0 : a[suffix].ConfirmRates - b[suffix].ConfirmRates),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'SumML' + suffix,
|
||||||
|
title: '业绩/万',
|
||||||
|
dataIndex: [suffix, 'SumML'],
|
||||||
|
width: '5em',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[colRootIndex]+transparentHex } },
|
||||||
|
children: numberConvert10K(_),
|
||||||
|
}),
|
||||||
|
sorter: (a, b) => (a.groupType === 'overview' ? -1 : b.groupType === 'overview' ? 0 : a[suffix].SumML - b[suffix].SumML),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ConfirmOrder' + suffix,
|
||||||
|
title: '团数',
|
||||||
|
dataIndex: [suffix, 'ConfirmOrder'],
|
||||||
|
width: '5em',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[colRootIndex]+transparentHex } },
|
||||||
|
children: _,
|
||||||
|
}),
|
||||||
|
sorter: (a, b) => (a.groupType === 'overview' ? -1 : b.groupType === 'overview' ? 0 : a[suffix].ConfirmOrder - b[suffix].ConfirmOrder),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'SumOrder' + suffix,
|
||||||
|
title: '订单数',
|
||||||
|
dataIndex: [suffix, 'SumOrder'],
|
||||||
|
width: '5em',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[colRootIndex]+transparentHex } },
|
||||||
|
children: _,
|
||||||
|
}),
|
||||||
|
sorter: (a, b) => (a.groupType === 'overview' ? -1 : b.groupType === 'overview' ? 0 : a[suffix].SumOrder - b[suffix].SumOrder),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ResumeOrder' + suffix,
|
||||||
|
title: '老客户团数',
|
||||||
|
dataIndex: [suffix, 'ResumeOrder'],
|
||||||
|
width: '5em',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[colRootIndex]+transparentHex } },
|
||||||
|
children: _,
|
||||||
|
}),
|
||||||
|
sorter: (a, b) => (a.groupType === 'overview' ? -1 : b.groupType === 'overview' ? 0 : a[suffix].ResumeOrder - b[suffix].ResumeOrder),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ResumeRates' + suffix,
|
||||||
|
title: '老客户成行率',
|
||||||
|
dataIndex: [suffix, 'ResumeRates'],
|
||||||
|
width: '5em',
|
||||||
|
render: (val, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[colRootIndex]+transparentHex } },
|
||||||
|
children: val ? `${val}%` : ''
|
||||||
|
}),
|
||||||
|
sorter: (a, b) => (a.groupType === 'overview' ? -1 : b.groupType === 'overview' ? 0 : a[suffix].ResumeRates - b[suffix].ResumeRates),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const dashboardTableProps = {
|
||||||
|
rowKey: 'groupsKey',
|
||||||
|
pagination: false,
|
||||||
|
size: 'small',
|
||||||
|
showSorterTooltip: false,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'groupsLabel',
|
||||||
|
key: 'name',
|
||||||
|
width: '5em',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (<>前90 -30天<br/>{searchValues.date90.Date1} 至 {searchValues.date90.Date2}</>),
|
||||||
|
key: 'date',
|
||||||
|
children: dataFields('result90', 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (<>前180 -50天<br/>{searchValues.date180.Date1} 至 {searchValues.date180.Date2}</>),
|
||||||
|
key: 'department',
|
||||||
|
children: dataFields('result180', 1),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rowClassName: (record, rowIndex) => {
|
||||||
|
return record.groupType === 'overview' ? 'ant-tag-blue' : '';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const activityTableProps = {
|
||||||
|
rowKey: 'groupsKey',
|
||||||
|
pagination: false,
|
||||||
|
size: 'small',
|
||||||
|
rowClassName: (record, rowIndex) => {
|
||||||
|
return record.groupType === 'operator' ? '' : 'ant-tag-blue';
|
||||||
|
},
|
||||||
|
showSorterTooltip: false,
|
||||||
|
columns: [
|
||||||
|
{ title: '', dataIndex: 'groupsLabel', key: 'groupsLabel', width: '6rem' }, // 维度: 顾问
|
||||||
|
{
|
||||||
|
title: '顾问动作',
|
||||||
|
key: 'date',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
首次响应率24H{' '}
|
||||||
|
<Tooltip title="达到24H内回复的订单数/总订单数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'firstTouch24',
|
||||||
|
key: 'firstTouch24',
|
||||||
|
render: percentageRender,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
48H内报价率{' '}
|
||||||
|
<Tooltip title="达到48H内报价的订单数/总订单数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'firstQuote48',
|
||||||
|
key: 'firstQuote48',
|
||||||
|
render: percentageRender,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
一次报价率{' '}
|
||||||
|
<Tooltip title="首次报价的订单数/总订单数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'quote1',
|
||||||
|
key: 'quote1',
|
||||||
|
render: percentageRender,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
二次报价率{' '}
|
||||||
|
<Tooltip title="二次报价的订单数/一次报价后回复数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'quote2',
|
||||||
|
key: 'quote2',
|
||||||
|
render: percentageRender,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
>50条会话{' '}
|
||||||
|
<Tooltip title=">50条会话的订单数/总订单">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'turnsGT50',
|
||||||
|
key: 'turnsGT50',
|
||||||
|
render: percentageRender,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
违规数{' '}
|
||||||
|
<Tooltip title="未遵循24H回复的订单数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'violations',
|
||||||
|
key: 'violations',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '客人回复',
|
||||||
|
key: 'department',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
首次回复率24H{' '}
|
||||||
|
<Tooltip title="达到24H内回复的订单数/总订单数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'firstReply24',
|
||||||
|
key: 'firstReply24',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[1] + transparentHex } },
|
||||||
|
children: percentageRender(_),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
48H内报价回复率{' '}
|
||||||
|
<Tooltip title="48H内报价后的回复数/报价的订单数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'replyQuote48',
|
||||||
|
key: 'replyQuote48',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[1] + transparentHex } },
|
||||||
|
children: percentageRender(_),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
一次报价回复率{' '}
|
||||||
|
<Tooltip title="一次报价后回复率/订单总数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'replyQuote1',
|
||||||
|
key: 'replyQuote1',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[1] + transparentHex } },
|
||||||
|
children: percentageRender(_),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: () => (
|
||||||
|
<>
|
||||||
|
二次报价回复率{' '}
|
||||||
|
<Tooltip title="二次报价后回复数/一次报价后回复数">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
dataIndex: 'replyQuote2',
|
||||||
|
key: 'replyQuote2',
|
||||||
|
render: (_, r) => ({
|
||||||
|
props: { style: { backgroundColor: COLOR_SETS[1] + transparentHex } },
|
||||||
|
children: percentageRender(_),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const riskTableProps = {
|
||||||
|
loading: risk.loading,
|
||||||
|
sticky: true,
|
||||||
|
// scroll: { x: 1000, y: 400 },
|
||||||
|
pagination: false,
|
||||||
|
rowKey: (row) => row.coli_id,
|
||||||
|
columns: [
|
||||||
|
{ title: '客人姓名', dataIndex: 'guest_name', key: 'guest_name', width: '6rem' },
|
||||||
|
{ title: '团号', dataIndex: 'coli_id', key: 'coli_id', width: '6rem' },
|
||||||
|
{
|
||||||
|
title: '表单内容',
|
||||||
|
dataIndex: 'coli_contents',
|
||||||
|
key: 'coli_contents',
|
||||||
|
width: '6rem',
|
||||||
|
render: (text, record) => (
|
||||||
|
<Popover
|
||||||
|
title={`${record.coli_id} ${record.guest_name}`}
|
||||||
|
content={<pre dangerouslySetInnerHTML={{ __html: text }} style={{ whiteSpace: 'pre-wrap', wordWrap: 'break-word' }} />}
|
||||||
|
trigger={['click']}
|
||||||
|
placement="right"
|
||||||
|
overlayStyle={{ width: '500px', maxHeight: '500px' }}
|
||||||
|
autoAdjustOverflow={false}
|
||||||
|
>
|
||||||
|
<Button type="link" size="small">
|
||||||
|
表单内容
|
||||||
|
</Button>
|
||||||
|
</Popover>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ title: '顾问', dataIndex: 'opi_name', key: 'opi_name', width: '6rem' },
|
||||||
|
{ title: '预定时间', dataIndex: 'coli_applydate', key: 'coli_applydate', width: '6rem' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const chartsConfig = {
|
||||||
|
colFields: ['ConfirmOrder', 'SumOrder'],
|
||||||
|
lineFields: ['SumML', 'ConfirmRates'],
|
||||||
|
seriesField: null,
|
||||||
|
xField: 'groupDateVal',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
|
||||||
|
<Col md={24} lg={12} xxl={14}>
|
||||||
|
<NavLink to={-1}>返回</NavLink>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<section>
|
||||||
|
<h2>结果指标 @ {searchValues.date.format(DATE_FORMAT)}</h2>
|
||||||
|
<Table {...dashboardTableProps} bordered dataSource={results[`operator_${opisn}`]} loading={results.loading} sticky />
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>全年每月业绩 @ {searchValues.date.format('YYYY')}</h3>
|
||||||
|
<MixFieldsDetail {...chartsConfig} dataSource={results[`operator_byDate_${opisn}`] || []} />
|
||||||
|
</section>
|
||||||
|
<Divider />
|
||||||
|
<section>
|
||||||
|
<h2>过程指标 @ {searchValuesToSub.Date1} 至 {searchValuesToSub.Date2}</h2>
|
||||||
|
<Table {...activityTableProps} bordered dataSource={process[`operator_${opisn}`]} loading={process.loading} sticky />
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>违规明细</h2>
|
||||||
|
<h3>>24H回复</h3>
|
||||||
|
<Table {...riskTableProps} bordered dataSource={risk.byLostType?.lostTouch24 || []} />
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>首次报价周期>48h</h3>
|
||||||
|
<Table {...riskTableProps} bordered dataSource={risk.byLostType?.lostQuote48 || []} />
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>报价次数<1</h3>
|
||||||
|
<Table {...riskTableProps} bordered dataSource={risk.byLostType?.lostQuote1 || []} />
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>报价次数<2</h3>
|
||||||
|
<Table {...riskTableProps} bordered dataSource={risk.byLostType?.lostQuote2 || []} />
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
Loading…
Reference in New Issue