Merge branch 'main' of github.com:hainatravel-it/dashboard

main
ybc 3 months ago
commit cb994aff29

4
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "haina-dashboard", "name": "haina-dashboard",
"version": "2.13.2", "version": "2.14.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "haina-dashboard", "name": "haina-dashboard",
"version": "2.13.2", "version": "2.14.0",
"dependencies": { "dependencies": {
"@ant-design/charts": "^1.4.2", "@ant-design/charts": "^1.4.2",
"@ant-design/pro-components": "^2.6.16", "@ant-design/pro-components": "^2.6.16",

@ -1,6 +1,6 @@
{ {
"name": "haina-dashboard", "name": "haina-dashboard",
"version": "2.13.2", "version": "2.14.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/charts": "^1.4.2", "@ant-design/charts": "^1.4.2",

@ -58,6 +58,8 @@ import Hotel from './views/Hotel';
import HostCaseCount from './views/HostCaseCount'; import HostCaseCount from './views/HostCaseCount';
import TrainsUpsell from './views/biz/reports/TrainsUpsell'; import TrainsUpsell from './views/biz/reports/TrainsUpsell';
import HostCaseReport from './views/HostCaseReport'; import HostCaseReport from './views/HostCaseReport';
import ToBOrder from './views/toB/ToBOrder';
import ToBOrderSub from './views/toB/ToBOrderSub';
const App = () => { const App = () => {
const { Content, Footer, Sider, } = Layout; const { Content, Footer, Sider, } = Layout;
@ -93,6 +95,11 @@ const App = () => {
label: <NavLink to="/orders">订单数据</NavLink>, label: <NavLink to="/orders">订单数据</NavLink>,
// icon: <FileProtectOutlined />, // icon: <FileProtectOutlined />,
}, },
{
key: 'tob_orders',
label: <NavLink to="/tob_orders">分销订单</NavLink>,
// icon: <FileProtectOutlined />,
},
{ {
key: 22, key: 22,
label: <NavLink to="/dashboard">仪表盘</NavLink>, label: <NavLink to="/dashboard">仪表盘</NavLink>,
@ -105,11 +112,13 @@ const App = () => {
], ],
}, },
{ {
key: 20, label: '商务市场', icon: <RocketOutlined />, key: 20,
label: '商务市场',
icon: <RocketOutlined />,
children: [ children: [
{ key: 201, label: <NavLink to="/biz_orders">订单数据</NavLink> }, { key: 201, label: <NavLink to="/biz_orders">订单数据</NavLink> },
{ key: 202, label: <NavLink to="/trains">火车票Upsell</NavLink> }, { key: 202, label: <NavLink to="/trains">火车票Upsell</NavLink> },
] ],
}, },
{ {
key: 5, key: 5,
@ -147,11 +156,8 @@ const App = () => {
label: '财务', label: '财务',
icon: <DollarOutlined />, icon: <DollarOutlined />,
children: [ children: [
{ // { key: 41, label: <NavLink to="/credit_card_bill"></NavLink> },
key: 41, // { key: 42, label: <NavLink to="/exchange_rate"></NavLink> },
label: <NavLink to="/credit_card_bill">信用卡账单</NavLink>,
},
{ key: 42, label: <NavLink to="/exchange_rate">汇率</NavLink> },
{ key: 'service_person_num', label: <NavLink to="/service_person_num">服务人数</NavLink> }, { key: 'service_person_num', label: <NavLink to="/service_person_num">服务人数</NavLink> },
], ],
}, },
@ -261,6 +267,8 @@ const App = () => {
<Route path="/:page/pivot" element={<DataPivot />} /> <Route path="/:page/pivot" element={<DataPivot />} />
<Route path="/orders/meeting-2024-GH" element={<Meeting2024GH />} /> <Route path="/orders/meeting-2024-GH" element={<Meeting2024GH />} />
<Route path="/orders/meeting-2025-GH" element={<Meeting2025GH />} /> <Route path="/orders/meeting-2025-GH" element={<Meeting2025GH />} />
<Route path="/tob_orders" element={<ToBOrder />} />
<Route path="/tob_orders_sub/:ordertype/:ordertype_sub/:ordertype_title" element={<ToBOrderSub />} />
<Route path="/biz_orders" element={<BizOrder />} /> <Route path="/biz_orders" element={<BizOrder />} />
<Route path="/biz_orders_sub/:ordertype/:ordertype_sub/:ordertype_title" element={<BizOrderSub />} /> <Route path="/biz_orders_sub/:ordertype/:ordertype_sub/:ordertype_title" element={<BizOrderSub />} />
<Route path="/trains" element={<TrainsUpsell />} /> <Route path="/trains" element={<TrainsUpsell />} />

@ -6,13 +6,24 @@ import { stores_Context } from '../config';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import SearchForm from './../components/search/SearchForm'; import SearchForm from './../components/search/SearchForm';
import LineWithAvg from '../components/LineWithAvg'; import LineWithAvg from '../components/LineWithAvg';
import { flow } from 'mobx'; import { toJS } from 'mobx';
import { TableExportBtn } from '../components/Data'; import { TableExportBtn, RenderVSDataCell } from '../components/Data';
import useCustomerRelationsStore from '../zustand/CustomerRelations';
import { useShallow } from 'zustand/shallow';
import { fixTo2Decimals, isEmpty } from '@haina/utils-commons';
const Customer_care_regular = () => { const Customer_care_regular = () => {
const { orders_store, date_picker_store, customer_store } = useContext(stores_Context); const { date_picker_store, customer_store } = useContext(stores_Context);
const regular_data = customer_store.regular_data; const regular_data = customer_store.regular_data;
const [loading, loading2, searchValues, searchValuesToSub] = useCustomerRelationsStore(useShallow((state) => [state.loading, state.loading2, state.searchValues, state.searchValuesToSub]));
const [setSearchValues] = useCustomerRelationsStore(useShallow((state) => [state.setSearchValues]));
const [regular] = useCustomerRelationsStore(useShallow((state) => [state.regular]));
const getRegularCustomer = useCustomerRelationsStore((state) => state.getRegularCustomer);
const columns = [ const columns = [
{ {
title: '订单号', title: '订单号',
@ -205,13 +216,14 @@ const Customer_care_regular = () => {
return ( return (
<div> <div>
<Row gutter={16} className={date_picker_store.siderBroken ? '' : 'sticky-top'}> <Row gutter={16} className={toJS(date_picker_store.siderBroken) ? '' : 'sticky-top'}>
<Col className="gutter-row" span={24}> <Col className="gutter-row" span={24}>
<SearchForm <SearchForm
defaultValue={{ defaultValue={{
initialValue: { initialValue: {
...date_picker_store.formValues, ...toJS(date_picker_store.formValues),
...regular_data.searchValues, // ...toJS(regular_data.searchValues),
...searchValues,
}, },
shows: ['DateType', 'DepartmentList', 'WebCode', 'dates', 'IncludeTickets'], shows: ['DateType', 'DepartmentList', 'WebCode', 'dates', 'IncludeTickets'],
fieldProps: { fieldProps: {
@ -222,21 +234,25 @@ const Customer_care_regular = () => {
}} }}
onSubmit={async (_err, obj, form, str) => { onSubmit={async (_err, obj, form, str) => {
customer_store.setSearchValues(obj, form, 'regular_data'); customer_store.setSearchValues(obj, form, 'regular_data');
regular_data.data_compare=[]; setSearchValues(obj, form);
if (obj.DateDiff1 && obj.DateDiff2){ getRegularCustomer({ ...obj, IsDetail: 0 });
regular_data.isCompareLine=true; getRegularCustomer({ ...obj, IsDetail: 1 });
regular_data.showCompareSum=true;
await customer_store.regular_customer_order(); // regular_data.data_compare=[];
customer_store.regular_customer_order(false,true); // if (obj.DateDiff1 && obj.DateDiff2){
// customer_store.regular_customer_order(true,false,true); // regular_data.isCompareLine=true;
// customer_store.regular_customer_order(true,true,true); // regular_data.showCompareSum=true;
} // await customer_store.regular_customer_order();
else{ // customer_store.regular_customer_order(false,true);
regular_data.isCompareLine=false; // // customer_store.regular_customer_order(true,false,true);
regular_data.showCompareSum=false; // customer_store.regular_customer_order(true,true,true);
customer_store.regular_customer_order(); // }
// customer_store.regular_customer_order(true); // else{
} // regular_data.isCompareLine=false;
// regular_data.showCompareSum=false;
// customer_store.regular_customer_order();
// customer_store.regular_customer_order(true);
// }
}} }}
/> />
</Col> </Col>
@ -247,8 +263,8 @@ const Customer_care_regular = () => {
</Col> </Col>
<Col span={24}> <Col span={24}>
<Table <Table
dataSource={regular_data.data} dataSource={regular.data}
loading={regular_data.loading} loading={loading}
columns={[ columns={[
{ {
title: '统计条目', title: '统计条目',
@ -259,7 +275,7 @@ const Customer_care_regular = () => {
title: () => ( title: () => (
<> <>
订单数{' '} 订单数{' '}
<Tooltip key='total_data_tips_title' title="总订单: 当同时勾选老客户和推荐时, 将重复计数"> <Tooltip key="total_data_tips_title" title="总订单: 当同时勾选老客户和推荐时, 将重复计数">
<InfoCircleOutlined /> <InfoCircleOutlined />
</Tooltip> </Tooltip>
</> </>
@ -268,10 +284,15 @@ const Customer_care_regular = () => {
key: 'OrderNum', key: 'OrderNum',
render: (text, record, index) => ( render: (text, record, index) => (
<> <>
<span>{text}</span>&nbsp;&nbsp; <RenderVSDataCell showDiffData={!isEmpty(searchValuesToSub.DateDiff1)} data1={record.OrderNum} data2={record.diff?.OrderNum} />
{<Tooltip key='total_data_tips' title={regular_data.total_data_tips}> {index === 0 && regular.total_data_tips !== '' && (
{index === 0 && regular_data.total_data_tips!=='' && <InfoCircleOutlined className='ant-tag-gold' />} <>
</Tooltip>} &nbsp;&nbsp;
<Tooltip key="total_data_tips" title={regular.total_data_tips}>
<InfoCircleOutlined className="ant-tag-gold" />
</Tooltip>
</>
)}
</> </>
), ),
}, },
@ -279,46 +300,84 @@ const Customer_care_regular = () => {
title: '订单数占比', title: '订单数占比',
dataIndex: 'OrderRate', dataIndex: 'OrderRate',
key: 'OrderRate', key: 'OrderRate',
render: (text) => typeof text === 'number'?<span>{parseFloat((text * 100).toFixed(2))}%</span>:text, render: (text, record) => (
<RenderVSDataCell
showDiffData={!isEmpty(searchValuesToSub.DateDiff1)}
data1={fixTo2Decimals(record.OrderRate * 100)}
data2={fixTo2Decimals(record.diff?.OrderRate * 100)}
dataSuffix="%"
/>
),
}, },
{ {
title: '订单数占比(市场)', title: '订单数占比(市场)',
dataIndex: 'OrderRate2', dataIndex: 'OrderRate2',
key: 'OrderRate2', key: 'OrderRate2',
render: (text) => typeof text === 'number'?<span>{parseFloat((text * 100).toFixed(2))}%</span>:text, render: (text, record) => (
<RenderVSDataCell
showDiffData={!isEmpty(searchValuesToSub.DateDiff1)}
data1={fixTo2Decimals(record.OrderRate2 * 100)}
data2={fixTo2Decimals(record.diff?.OrderRate2 * 100)}
dataSuffix="%"
/>
),
}, },
{ {
title: '成行数', title: '成行数',
dataIndex: 'SUCOrderNum', dataIndex: 'SUCOrderNum',
key: 'SUCOrderNum', key: 'SUCOrderNum',
render: (text, record) => <RenderVSDataCell showDiffData={!isEmpty(searchValuesToSub.DateDiff1)} data1={record.SUCOrderNum} data2={record.diff?.SUCOrderNum} />,
}, },
{ {
title: '成行率', title: '成行率',
dataIndex: 'SUCRate', dataIndex: 'SUCRate',
key: 'SUCRate', key: 'SUCRate',
render: (text) => typeof text === 'number'?<span>{Math.round(text * 100)}%</span>:text, render: (text, record) => (
<RenderVSDataCell
showDiffData={!isEmpty(searchValuesToSub.DateDiff1)}
data1={fixTo2Decimals(record.SUCRate * 100)}
data2={fixTo2Decimals(record.diff?.SUCRate * 100)}
dataSuffix="%"
/>
),
}, },
{ {
title: '毛利', title: '毛利',
dataIndex: 'ML', dataIndex: 'ML',
key: 'ML', key: 'ML',
render: (text, record) => <RenderVSDataCell showDiffData={!isEmpty(searchValuesToSub.DateDiff1)} data1={record.ML} data2={record.diff?.ML} />,
}, },
{ {
title: '毛利占比', title: '毛利占比',
dataIndex: 'OrderMLRate', dataIndex: 'OrderMLRate',
key: 'OrderMLRate', key: 'OrderMLRate',
render: (text) => typeof text === 'number'?<span>{parseFloat((text * 100).toFixed(2))}%</span>:text, render: (text, record) => (
<RenderVSDataCell
showDiffData={!isEmpty(searchValuesToSub.DateDiff1)}
data1={fixTo2Decimals(record.OrderMLRate * 100)}
data2={fixTo2Decimals(record.diff?.OrderMLRate * 100)}
dataSuffix="%"
/>
),
}, },
{ {
title: '毛利占比(市场)', title: '毛利占比(市场)',
dataIndex: 'OrderMLRate2', dataIndex: 'OrderMLRate2',
key: 'OrderMLRate2', key: 'OrderMLRate2',
render: (text) => typeof text === 'number'?<span>{parseFloat((text * 100).toFixed(2))}%</span>:text, render: (text, record) => (
<RenderVSDataCell
showDiffData={!isEmpty(searchValuesToSub.DateDiff1)}
data1={fixTo2Decimals(record.OrderMLRate2 * 100)}
data2={fixTo2Decimals(record.diff?.OrderMLRate2 * 100)}
dataSuffix="%"
/>
),
}, },
{ {
title: '人数(含成人+儿童)', title: '人数(含成人+儿童)',
dataIndex: 'PersonNum', dataIndex: 'PersonNum',
key: 'PersonNum', key: 'PersonNum',
render: (text, record) => <RenderVSDataCell showDiffData={!isEmpty(searchValuesToSub.DateDiff1)} data1={record.PersonNum} data2={record.diff?.PersonNum} />,
}, },
]} ]}
size="small" size="small"
@ -327,65 +386,38 @@ const Customer_care_regular = () => {
/> />
</Col> </Col>
<Col span={24} >
<div style={{height: '100%'}}>
<>
<dialog open={false} style={{
// position: 'fixed',
// top: 0,
// left: '200px',
// width: 'calc(100vw - 200px)',
// height: '100vh',
width: 'inherit',
height: 'inherit',
background: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
border: 'none',
zIndex: 2,
margin: 0,
padding: 0
}}>
<div style={{
background: 'white',
padding: '20px',
borderRadius: '8px',
textAlign: 'center'
}}>
维护中, 暂不可用, 敬请期待
</div>
</dialog></>
<Col span={24}> <Col span={24}>
<LineWithAvg dataSource={regular_data.pivotData} loading={regular_data.detail_loading} xField={regular_data.pivotX} yField={regular_data.pivotY} <div style={{ height: '100%' }}>
seriesField='_ylabel' showCompareSum={regular_data.showCompareSum} solidLineTime={regular_data.solidLineTime} solidLineCompareTime={regular_data.solidLineCompareTime} <Col span={24}>
solidLineDash={regular_data.solidLineDash} isCompareLine={regular_data.isCompareLine}/> <LineWithAvg
</Col> dataSource={regular.pivotData}
loading={loading2}
xField={regular.pivotX}
yField={regular.pivotY}
seriesField="_ylabel"
showCompareSum={false}
solidLineTime={false}
solidLineCompareTime={false}
solidLineDash={false}
isCompareLine={false}
/>
</Col>
<Col span={24}> <Col span={24}>
<Divider orientation="right" plain> <Divider orientation="right" plain>
<a <a
onClick={() => { onClick={() => {
const wb = utils.table_to_book(document.getElementById('table_to_xlsx').getElementsByTagName('table')[0]); const wb = utils.table_to_book(document.getElementById('table_to_xlsx').getElementsByTagName('table')[0]);
writeFileXLSX(wb, '老客户.xlsx'); writeFileXLSX(wb, '老客户.xlsx');
}} }}
> >
导出下表 导出下表
</a> </a>
<TableExportBtn btnTxt='导出详情' label={'老客户-详情'} columns={export_columns} dataSource={regular_data.data_detail} style={{ marginLeft: '10px' }} /> <TableExportBtn btnTxt="导出详情" label={'老客户-详情'} columns={export_columns} dataSource={regular.details} style={{ marginLeft: '10px' }} />
</Divider> </Divider>
<Table <Table id="table_to_xlsx" pagination={false} loading={loading2} dataSource={regular.details} scroll={{ x: 1200 }} columns={columns} size="small" rowKey={(record) => record.COLI_ID} />
id="table_to_xlsx" </Col>
pagination={false} </div>
loading={regular_data.detail_loading}
dataSource={regular_data.data_detail}
scroll={{ x: 1200 }}
columns={columns}
size="small"
rowKey={(record) => record.COLI_ID}
/>
</Col>
</div>
</Col> </Col>
</Row> </Row>
</div> </div>

@ -36,8 +36,9 @@ export const VSTag = (props) => {
* @property {string} dataSuffix * @property {string} dataSuffix
*/ */
export const VSDataTag = ({ diffPercent=0, diffData=0, data1=0, data2=0, dataSuffix='' }) => { export const VSDataTag = ({ diffPercent=0, diffData=0, data1=0, data2=0, dataSuffix='' }) => {
const _diffPercent = diffPercent || (data2) ? fixTo2Decimals((data1-data2)/data2*100) : 100; const _diffPercent = diffPercent || ((data2) ? fixTo2Decimals((data1-data2)/data2*100) : 100);
const _diffData = diffData || isNaN(data2) ? fixTo2Decimals(data1-0) : (fixTo2Decimals(data1-data2)); const _diffPercentSuffix = String(_diffPercent).includes('%') ? '' : '%';
const _diffData = diffData || (isNaN(data2) ? fixTo2Decimals(data1-0) : (fixTo2Decimals(data1-data2)));
const CaretIcon = parseInt(_diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined; const CaretIcon = parseInt(_diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined;
const tagColor = parseInt(_diffPercent) < 0 ? 'gold' : 'lime'; const tagColor = parseInt(_diffPercent) < 0 ? 'gold' : 'lime';
// parseInt(_diffPercent) === 0 ? ( // parseInt(_diffPercent) === 0 ? (
@ -50,14 +51,30 @@ export const VSDataTag = ({ diffPercent=0, diffData=0, data1=0, data2=0, dataSuf
</div> </div>
{_diffData !== 0 && ( {_diffData !== 0 && (
<Tag icon={<CaretIcon />} color={tagColor}> <Tag icon={<CaretIcon />} color={tagColor}>
{_diffPercent} {_diffPercent}<span>{_diffPercentSuffix}</span>&nbsp;&nbsp;<span>{_diffData}{dataSuffix}</span>
<span>%</span>&nbsp;&nbsp;<span>{_diffData}{dataSuffix}</span>
</Tag> </Tag>
)} )}
</span> </span>
); );
}; };
/**
* 表格中显示数据对比
*
* @property {boolean | undefined} [showDiffData=false]
* @property {number} [diffPercent=0]
* @property {number} diffData
* @property {number} data1
* @property {number} data2
* @property {string} dataSuffix
*/
export const RenderVSDataCell = ({ showDiffData=false, data1, data2, dataSuffix = '', ...props }) => {
if (showDiffData) {
return <VSDataTag data1={data1} data2={data2} dataSuffix={dataSuffix} {...props} />;
}
return <div>{data1}{dataSuffix}</div>;
};
/** /**
* 导出表格数据存为xlsx * 导出表格数据存为xlsx
* @property label 文件名字 * @property label 文件名字

@ -58,7 +58,7 @@ const ParetoChart = ({ data, xField, yField, thresholds = { A: 80, B: 90 }, titl
Cumulative: { Cumulative: {
// min: 0, // min: 0,
label: { label: {
formatter: (val) => `${val}%`, formatter: (val) => `${val}`,
}, },
}, },
}, },

@ -1,6 +1,11 @@
import { Tag } from "antd"; import { Tag } from "antd";
import { CaretUpOutlined, CaretDownOutlined } from "@ant-design/icons"; import { CaretUpOutlined, CaretDownOutlined } from "@ant-design/icons";
/**
* 显示对比标签
* @deprecated
* 使用组件: VSTag VSDataTag RenderVSDataCell
*/
export function show_vs_tag(vs, vs_diff, data1, data2) { export function show_vs_tag(vs, vs_diff, data1, data2) {
let tag = "-"; let tag = "-";
if (parseInt(vs) < 0) { if (parseInt(vs) < 0) {

@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import { toJS } from 'mobx'; import { toJS } from 'mobx';
import 'moment/locale/zh-cn'; import 'moment/locale/zh-cn';
import SearchForm from './../components/search/SearchForm'; import SearchForm from './../components/search/SearchForm';
import { TableExportBtn, VSDataTag } from './../components/Data'; import { TableExportBtn, RenderVSDataCell } from './../components/Data';
import useCustomerServicesStore from '../zustand/CustomerServices'; import useCustomerServicesStore from '../zustand/CustomerServices';
import { useShallow } from 'zustand/shallow'; import { useShallow } from 'zustand/shallow';
import { fixTo2Decimals } from "@haina/utils-commons"; import { fixTo2Decimals } from "@haina/utils-commons";
@ -19,13 +19,6 @@ const TdCell = (tdprops) => {
return <td {...restProps} />; return <td {...restProps} />;
}; };
const DataRenderCell = ({ data1, data2, dataSuffix = '', showDiffData }) => {
if (showDiffData) {
return <VSDataTag data1={data1} data2={data2} dataSuffix={dataSuffix} />;
}
return <div>{data1}{dataSuffix}</div>;
};
const AgentGroupCount = () => { const AgentGroupCount = () => {
const { customerServicesStore, date_picker_store } = useContext(stores_Context); const { customerServicesStore, date_picker_store } = useContext(stores_Context);
const [loading, searchValues, setSearchValues, searchValuesToSub] = useCustomerServicesStore(useShallow((state) => [state.loading, state.searchValues, state.setSearchValues, state.searchValuesToSub])); const [loading, searchValues, setSearchValues, searchValuesToSub] = useCustomerServicesStore(useShallow((state) => [state.loading, state.searchValues, state.setSearchValues, state.searchValuesToSub]));
@ -53,9 +46,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'GroupCount'), sorter: (a, b) => sorter(a, b, 'GroupCount'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.GroupCount} data2={total1.diff?.GroupCount} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.GroupCount, title: <RenderVSDataCell data1={total1.GroupCount} data2={total1.diff?.GroupCount} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.GroupCount,
dataIndex: 'GroupCount', dataIndex: 'GroupCount',
render: (text, r) => <DataRenderCell data1={r.GroupCount} data2={r.diff?.GroupCount} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.GroupCount} data2={r.diff?.GroupCount} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -65,9 +58,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'PersonNum'), sorter: (a, b) => sorter(a, b, 'PersonNum'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.PersonNum} data2={total1.diff?.PersonNum} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.PersonNum, title: <RenderVSDataCell data1={total1.PersonNum} data2={total1.diff?.PersonNum} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.PersonNum,
dataIndex: 'PersonNum', dataIndex: 'PersonNum',
render: (text, r) => <DataRenderCell data1={r.PersonNum} data2={r.diff?.PersonNum} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.PersonNum} data2={r.diff?.PersonNum} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -77,9 +70,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'GroupDays'), sorter: (a, b) => sorter(a, b, 'GroupDays'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.GroupDays} data2={total1.diff?.GroupDays} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.GroupDays, title: <RenderVSDataCell data1={total1.GroupDays} data2={total1.diff?.GroupDays} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.GroupDays,
dataIndex: 'GroupDays', dataIndex: 'GroupDays',
render: (text, r) => <DataRenderCell data1={r.GroupDays} data2={r.diff?.GroupDays} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.GroupDays} data2={r.diff?.GroupDays} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -89,9 +82,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'totalcost'), sorter: (a, b) => sorter(a, b, 'totalcost'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.totalcost} data2={total1.diff?.totalcost} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.totalcost, title: <RenderVSDataCell data1={total1.totalcost} data2={total1.diff?.totalcost} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.totalcost,
dataIndex: 'totalcost', dataIndex: 'totalcost',
render: (text, r) => <DataRenderCell data1={r.totalcost} data2={r.diff?.totalcost} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.totalcost} data2={r.diff?.totalcost} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -101,9 +94,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'FKBTS'), sorter: (a, b) => sorter(a, b, 'FKBTS'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.FKBTS} data2={total1.diff?.FKBTS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.FKBTS, title: <RenderVSDataCell data1={total1.FKBTS} data2={total1.diff?.FKBTS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.FKBTS,
dataIndex: 'FKBTS', dataIndex: 'FKBTS',
render: (text, r) => <DataRenderCell data1={r.FKBTS} data2={r.diff?.FKBTS} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.FKBTS} data2={r.diff?.FKBTS} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -113,9 +106,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'DDZTS'), sorter: (a, b) => sorter(a, b, 'DDZTS'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.DDZTS} data2={total1.diff?.DDZTS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.DDZTS, title: <RenderVSDataCell data1={total1.DDZTS} data2={total1.diff?.DDZTS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.DDZTS,
dataIndex: 'DDZTS', dataIndex: 'DDZTS',
render: (text, r) => <DataRenderCell data1={r.DDZTS} data2={r.diff?.DDZTS} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.DDZTS} data2={r.diff?.DDZTS} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -125,9 +118,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'DDZCases'), sorter: (a, b) => sorter(a, b, 'DDZCases'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.DDZCases} data2={total1.diff?.DDZCases} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.DDZCases, title: <RenderVSDataCell data1={total1.DDZCases} data2={total1.diff?.DDZCases} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.DDZCases,
dataIndex: 'DDZCases', dataIndex: 'DDZCases',
render: (text, r) => <DataRenderCell data1={r.DDZCases} data2={r.diff?.DDZCases} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.DDZCases} data2={r.diff?.DDZCases} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -137,9 +130,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'DDZRate'), sorter: (a, b) => sorter(a, b, 'DDZRate'),
children: [ children: [
{ {
title: <DataRenderCell data1={fixTo2Decimals(total1.DDZRate*100)} data2={fixTo2Decimals(total1.diff?.DDZRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.DDZRate, title: <RenderVSDataCell data1={fixTo2Decimals(total1.DDZRate*100)} data2={fixTo2Decimals(total1.diff?.DDZRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.DDZRate,
dataIndex: 'DDZRate', dataIndex: 'DDZRate',
render: (text, r) => <DataRenderCell data1={fixTo2Decimals(r.DDZRate*100)} data2={fixTo2Decimals(r.diff?.DDZRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={fixTo2Decimals(r.DDZRate*100)} data2={fixTo2Decimals(r.diff?.DDZRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -149,9 +142,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'ZWHP'), sorter: (a, b) => sorter(a, b, 'ZWHP'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.ZWHP} data2={total1.diff?.ZWHP} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.ZWHP, title: <RenderVSDataCell data1={total1.ZWHP} data2={total1.diff?.ZWHP} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.ZWHP,
dataIndex: 'ZWHP', dataIndex: 'ZWHP',
render: (text, r) => <DataRenderCell data1={r.ZWHP} data2={r.diff?.ZWHP} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.ZWHP} data2={r.diff?.ZWHP} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -161,9 +154,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'ZWHPCases'), sorter: (a, b) => sorter(a, b, 'ZWHPCases'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.ZWHPCases} data2={total1.diff?.ZWHPCases} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.ZWHPCases, title: <RenderVSDataCell data1={total1.ZWHPCases} data2={total1.diff?.ZWHPCases} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.ZWHPCases,
dataIndex: 'ZWHPCases', dataIndex: 'ZWHPCases',
render: (text, r) => <DataRenderCell data1={r.ZWHPCases} data2={r.diff?.ZWHPCases} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.ZWHPCases} data2={r.diff?.ZWHPCases} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -173,9 +166,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'ZWHPRate'), // parseInt(a.ZWHPRate) - parseInt(b.ZWHPRate), sorter: (a, b) => sorter(a, b, 'ZWHPRate'), // parseInt(a.ZWHPRate) - parseInt(b.ZWHPRate),
children: [ children: [
{ {
title: <DataRenderCell data1={fixTo2Decimals(total1.ZWHPRate*100)} data2={fixTo2Decimals(total1.diff?.ZWHPRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.ZWHPRate, title: <RenderVSDataCell data1={fixTo2Decimals(total1.ZWHPRate*100)} data2={fixTo2Decimals(total1.diff?.ZWHPRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.ZWHPRate,
dataIndex: 'ZWHPRate', dataIndex: 'ZWHPRate',
render: (text, r) => <DataRenderCell data1={fixTo2Decimals(r.ZWHPRate*100)} data2={fixTo2Decimals(r.diff?.ZWHPRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={fixTo2Decimals(r.ZWHPRate*100)} data2={fixTo2Decimals(r.diff?.ZWHPRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -185,9 +178,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'BMS'), sorter: (a, b) => sorter(a, b, 'BMS'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.BMS} data2={total1.diff?.BMS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.BMS, title: <RenderVSDataCell data1={total1.BMS} data2={total1.diff?.BMS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.BMS,
dataIndex: 'BMS', dataIndex: 'BMS',
render: (text, r) => <DataRenderCell data1={r.BMS} data2={r.diff?.BMS} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.BMS} data2={r.diff?.BMS} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -197,9 +190,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'BMRate'), // parseInt(a.BMRate) - parseInt(b.BMRate), sorter: (a, b) => sorter(a, b, 'BMRate'), // parseInt(a.BMRate) - parseInt(b.BMRate),
children: [ children: [
{ {
title: <DataRenderCell data1={fixTo2Decimals(total1.BMRate*100)} data2={fixTo2Decimals((total1.diff?.BMRate || 0)*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.BMRate, title: <RenderVSDataCell data1={fixTo2Decimals(total1.BMRate*100)} data2={fixTo2Decimals((total1.diff?.BMRate || 0)*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.BMRate,
dataIndex: 'BMRate', dataIndex: 'BMRate',
render: (text, r) => <DataRenderCell data1={fixTo2Decimals(r.BMRate*100)} data2={fixTo2Decimals(r.diff?.BMRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={fixTo2Decimals(r.BMRate*100)} data2={fixTo2Decimals(r.diff?.BMRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -209,9 +202,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'TS'), sorter: (a, b) => sorter(a, b, 'TS'),
children: [ children: [
{ {
title: <DataRenderCell data1={total1.TS} data2={total1.diff?.TS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.TS, title: <RenderVSDataCell data1={total1.TS} data2={total1.diff?.TS} showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.TS,
dataIndex: 'TS', dataIndex: 'TS',
render: (text, r) => <DataRenderCell data1={r.TS} data2={r.diff?.TS} showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={r.TS} data2={r.diff?.TS} showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },
@ -221,9 +214,9 @@ const AgentGroupCount = () => {
sorter: (a, b) => sorter(a, b, 'TSRate'), // parseInt(a.TSRate) - parseInt(b.TSRate), sorter: (a, b) => sorter(a, b, 'TSRate'), // parseInt(a.TSRate) - parseInt(b.TSRate),
children: [ children: [
{ {
title: <DataRenderCell data1={fixTo2Decimals(total1.TSRate*100)} data2={fixTo2Decimals(total1.diff?.TSRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.TSRate, title: <RenderVSDataCell data1={fixTo2Decimals(total1.TSRate*100)} data2={fixTo2Decimals(total1.diff?.TSRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, // total1.TSRate,
dataIndex: 'TSRate', dataIndex: 'TSRate',
render: (text, r) => <DataRenderCell data1={fixTo2Decimals(r.TSRate*100)} data2={fixTo2Decimals(r.diff?.TSRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />, render: (text, r) => <RenderVSDataCell data1={fixTo2Decimals(r.TSRate*100)} data2={fixTo2Decimals(r.diff?.TSRate*100)} dataSuffix='%' showDiffData={!!searchValuesToSub.DateDiff1} />,
}, },
], ],
}, },

@ -7,12 +7,11 @@ import { observer } from "mobx-react";
import * as config from "../config"; import * as config from "../config";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import * as comm from '@haina/utils-commons'; import * as comm from '@haina/utils-commons';
import { show_vs_tag } from './../utils/commons';
import { utils, writeFileXLSX } from "xlsx";
import DateGroupRadio from '../components/DateGroupRadio'; import DateGroupRadio from '../components/DateGroupRadio';
import SearchForm from './../components/search/SearchForm'; import SearchForm from './../components/search/SearchForm';
import { TableExportBtn } from './../components/Data'; import { TableExportBtn, RenderVSDataCell } from './../components/Data';
import ParetoChart from "../components/Pareto"; import ParetoChart from "../components/Pareto";
import { toJS } from 'mobx';
class Orders extends Component { class Orders extends Component {
static contextType = stores_Context; static contextType = stores_Context;
@ -24,229 +23,181 @@ class Orders extends Component {
format_data(data) { format_data(data) {
const { date_picker_store, orders_store } = this.context; const { date_picker_store, orders_store } = this.context;
const result = { dataSource: [], columns: [] }; const result = { dataSource: [], columns: [] };
if (!comm.emptyValue(data)) { if (!comm.isEmpty(data)) {
const ordercountTotal1 = data.ordercountTotal1; const rows1Map = data.ordercount1.reduce((a, row1) => ({ ...a, [row1.OrderTypeSN]: row1 }), {});
const ordercountTotal2 = data.ordercountTotal2; const rows2Map = data.ordercount2.reduce((a, row2) => ({ ...a, [row2.OrderTypeSN]: row2 }), {});
if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) { // Diff: elements in rows2 but not in rows1
// const diffKey = [...new Set(Object.keys(rows2Map).filter((x) => !new Set(Object.keys(rows1Map)).has(x)))];
result.columns = [ const withDiff1 = (structuredClone(toJS(data.ordercount1)) || []).map((r1) => ({ ...r1, diff: rows2Map[r1.OrderTypeSN] }));
{ withDiff1.push(
title: '#', ...diffKey.map((key) => ({
fixed: 'left', diff: rows2Map[key],
children: [ EOI_ObjSN: rows2Map[key].EOI_ObjSN,
{ OrderType: rows2Map[key].OrderType,
title: ( CJrate: 0,
<span> CJCount_vs: -100,
<div> CJPersonNum_vs: -100,
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)} CJrate_vs: -100,
</div> YJLY_vs: -100,
<div> OrderCount_vs: -100,
{date_picker_store.start_date_cp.format(config.DATE_FORMAT)}~{date_picker_store.end_date_cp.format(config.DATE_FORMAT)} CJCount_diff: -rows2Map[key].CJCount,
</div> CJPersonNum_diff: -rows2Map[key].CJPersonNum,
</span> CJrate_diff: -rows2Map[key].CJrate,
), YJLY_diff: -rows2Map[key].YJLY,
titleX: `${date_picker_store.start_date.format(config.DATE_FORMAT)}~${date_picker_store.end_date.format(config.DATE_FORMAT)} vs ${date_picker_store.start_date_cp.format( OrderCount_diff: -rows2Map[key].OrderCount,
config.DATE_FORMAT Ordervalue: 0,
)}~${date_picker_store.end_date_cp.format(config.DATE_FORMAT)}`, Ordervalue_diff: -rows2Map[key].Ordervalue,
dataIndex: 'OrderType', Ordervalue_vs: -100,
fixed: 'left', }))
render: (text, record) => <NavLink to={`/orders_sub/${orders_store.active_tab_key}/${record.OrderTypeSN}/${encodeURIComponent(record.OrderType)}`}>{text}</NavLink>, );
}, const showDiff = date_picker_store.start_date_cp && date_picker_store.end_date_cp;
], result.dataSource = withDiff1;
},
{
title: '数量',
children: [
{
title: show_vs_tag(ordercountTotal1.OrderCount_vs, ordercountTotal1.OrderCount_diff, ordercountTotal1.OrderCount, ordercountTotal2.OrderCount),
titleX: [ordercountTotal1.OrderCount, ordercountTotal2.OrderCount].join(' vs '),
dataIndex: 'OrderCount',
},
],
},
{
title: '成交数',
children: [
{
title: show_vs_tag(ordercountTotal1.CJCount_vs, ordercountTotal1.CJCount_diff, ordercountTotal1.CJCount, ordercountTotal2.CJCount),
titleX: [ordercountTotal1.CJCount, ordercountTotal2.CJCount].join(' vs '),
dataIndex: 'CJCount',
},
],
},
{
title: '成交人数',
children: [
{
title: show_vs_tag(ordercountTotal1.CJPersonNum_vs, ordercountTotal1.CJPersonNum_diff, ordercountTotal1.CJPersonNum, ordercountTotal2.CJPersonNum),
titleX: [ordercountTotal1.CJPersonNum, ordercountTotal2.CJPersonNum].join(' vs '),
dataIndex: 'CJPersonNum',
},
],
},
{
title: '成交率',
children: [
{
title: show_vs_tag(ordercountTotal1.CJrate_vs, ordercountTotal1.CJrate_diff, ordercountTotal1.CJrate, ordercountTotal2.CJrate),
titleX: [ordercountTotal1.CJrate, ordercountTotal2.CJrate].join(' vs '),
dataIndex: 'CJrate',
},
],
},
{
title: '成交毛利(预计)',
children: [
{
title: show_vs_tag(ordercountTotal1.YJLY_vs, ordercountTotal1.YJLY_diff, ordercountTotal1.YJLY, ordercountTotal2.YJLY),
titleX: [ordercountTotal1.YJLY, ordercountTotal2.YJLY].join(' vs '),
dataIndex: 'YJLY',
},
],
},
{ const ordercountTotal1 = data.ordercountTotal1;
title: '单个订单价值', const ordercountTotal2 = data.ordercountTotal2;
children: [ result.columns = [
{ {
title: show_vs_tag(ordercountTotal1.Ordervalue_vs, ordercountTotal1.Ordervalue_diff, ordercountTotal1.Ordervalue, ordercountTotal2.Ordervalue), title: '#',
titleX: [ordercountTotal1.Ordervalue, ordercountTotal2.Ordervalue].join(' vs '), fixed: 'left',
dataIndex: 'Ordervalue', children: [
}, {
], title: (
}, <span>
]; <div>
// 1.OrderType 2.OrderType {date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
let has_same_type = false; // 12 </div>
for (const item of data.ordercount1) { {showDiff ? <div>
has_same_type = false; {date_picker_store.start_date_cp.format(config.DATE_FORMAT)}~{date_picker_store.end_date_cp.format(config.DATE_FORMAT)}
// 12 </div> : null}
for (const item2 of data.ordercount2) { </span>
if (item.OrderType === item2.OrderType) { ),
has_same_type = true; titleX: showDiff ? `${date_picker_store.start_date.format(config.DATE_FORMAT)}~${date_picker_store.end_date.format(config.DATE_FORMAT)} vs ${date_picker_store.start_date_cp.format(
result.dataSource.push({ config.DATE_FORMAT
key: item.key, )}~${date_picker_store.end_date_cp.format(config.DATE_FORMAT)}` : `${date_picker_store.start_date.format(config.DATE_FORMAT)}~${date_picker_store.end_date.format(config.DATE_FORMAT)}`,
OrderType: item.OrderType, dataIndex: 'OrderType',
OrderTypeSN: item.OrderTypeSN, fixed: 'left',
OrderCount: show_vs_tag(item.OrderCount_vs, item.OrderCount_diff, item.OrderCount, item2.OrderCount), render: (text, record) => <NavLink to={`/orders_sub/${orders_store.active_tab_key}/${record.OrderTypeSN}/${encodeURIComponent(record.OrderType)}`}>{text}</NavLink>,
OrderCount_X: ([item.OrderCount, item2.OrderCount].join(' vs ')), },
CJCount: show_vs_tag(item.CJCount_vs, item.CJCount_diff, item.CJCount, item2.CJCount), ],
CJCount_X: ([item.CJCount, item2.CJCount].join(' vs ')), },
CJPersonNum: show_vs_tag(item.CJPersonNum_vs, item.CJPersonNum_diff, item.CJPersonNum, item2.CJPersonNum), {
CJPersonNum_X: ([item.CJPersonNum, item2.CJPersonNum].join(' vs ')), title: '数量',
CJrate: show_vs_tag(item.CJrate_vs, item.CJrate_diff, item.CJrate, item2.CJrate), children: [
CJrate_X: ([item.CJrate, item2.CJrate].join(' vs ')), {
YJLY: show_vs_tag(item.YJLY_vs, item.YJLY_diff, item.YJLY, item2.YJLY), title: (
YJLY_X: ([item.YJLY, item2.YJLY].join(' vs ')), <RenderVSDataCell
Ordervalue: show_vs_tag(item.Ordervalue_vs, item.Ordervalue_diff, item.Ordervalue, item2.Ordervalue), showDiffData={showDiff}
Ordervalue_X: ([item.Ordervalue, item2.Ordervalue].join(' vs ')), data1={ordercountTotal1?.OrderCount}
}); data2={ordercountTotal2?.OrderCount}
} diffPercent={ordercountTotal1?.OrderCount_vs}
} diffData={ordercountTotal1?.OrderCount_diff}
// 12 />
if (has_same_type === false) { ),
result.dataSource.push({ titleX: [ordercountTotal1.OrderCount, ordercountTotal2.OrderCount].join(' vs '),
key: item.key, dataIndex: 'OrderCount',
OrderType: item.OrderType, render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.OrderCount} diffPercent={r.OrderCount_vs} diffData={r.OrderCount_diff} />,
OrderTypeSN: item.OrderTypeSN, },
OrderCount: show_vs_tag(comm.formatPercent(item.OrderCount), item.OrderCount, item.OrderCount, 0), ],
OrderCount_X: ([item.OrderCount, 0].join(' vs ')), },
CJCount: show_vs_tag(comm.formatPercent(item.CJCount), item.CJCount, item.CJCount, 0), {
CJCount_X: ([item.CJCount, 0].join(' vs ')), title: '成交数',
CJPersonNum: show_vs_tag(comm.formatPercent(item.CJPersonNum), item.CJPersonNum, item.CJPersonNum, 0), children: [
CJPersonNum_X: ([item.CJPersonNum, 0].join(' vs ')), {
CJrate: show_vs_tag(item.CJrate, item.CJrate, item.CJrate, 0), title: (
CJrate_X: ([item.CJrate, 0].join(' vs ')), <RenderVSDataCell
YJLY: show_vs_tag(comm.formatPercent(item.YJLY), item.YJLY, item.YJLY, 0), showDiffData={showDiff}
YJLY_X: ([item.YJLY, 0].join(' vs ')), data1={ordercountTotal1?.CJCount}
Ordervalue: show_vs_tag(comm.formatPercent(item.Ordervalue), item.Ordervalue, item.Ordervalue, 0), data2={ordercountTotal2?.CJCount}
Ordervalue_X: ([item.Ordervalue, 0].join(' vs ')), diffPercent={ordercountTotal1?.CJCount_vs}
}); diffData={ordercountTotal1?.CJCount_diff}
} />
} ),
// 21 titleX: [ordercountTotal1.CJCount, ordercountTotal2.CJCount].join(' vs '),
for (const item2 of data.ordercount2) { dataIndex: 'CJCount',
has_same_type = false; render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJCount} diffPercent={r.CJCount_vs} diffData={r.CJCount_diff} />,
for (const item of data.ordercount1) { },
if (item.OrderType === item2.OrderType) { ],
has_same_type = true; },
} {
} title: '成交人数',
if (has_same_type === false) { children: [
result.dataSource.push({ {
key: item2.key, title: (
OrderType: item2.OrderType, <RenderVSDataCell
OrderTypeSN: item2.OrderTypeSN, showDiffData={showDiff}
OrderCount: show_vs_tag(comm.formatPercent(-item2.OrderCount), -item2.OrderCount, 0, item2.OrderCount), data1={ordercountTotal1?.CJPersonNum}
OrderCount_X: ([ 0, item2.OrderCount].join(' vs ')), data2={ordercountTotal2?.CJPersonNum}
CJCount: show_vs_tag(comm.formatPercent(-item2.CJCount), -item2.CJCount, 0, item2.CJCount), diffPercent={ordercountTotal1?.CJPersonNum_vs}
CJCount_X: ([ 0, item2.CJCount].join(' vs ')), diffData={ordercountTotal1?.CJPersonNum_diff}
CJPersonNum: show_vs_tag(comm.formatPercent(-item2.CJPersonNum), -item2.CJPersonNum, 0, item2.CJPersonNum), />
CJPersonNum_X: ([0, item2.CJPersonNum].join(' vs ')), ),
CJrate: show_vs_tag(-item2.CJrate, -item2.CJrate, 0, item2.CJrate), titleX: [ordercountTotal1.CJPersonNum, ordercountTotal2.CJPersonNum].join(' vs '),
CJrate_X: ([ 0, item2.CJrate].join(' vs ')), dataIndex: 'CJPersonNum',
YJLY: show_vs_tag(comm.formatPercent(-item2.YJLY), -item2.YJLY, 0, item2.YJLY), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJPersonNum} diffPercent={r.CJPersonNum_vs} diffData={r.CJPersonNum_diff} />,
YJLY_X: ([0, item2.YJLY].join(' vs ')), },
Ordervalue: show_vs_tag(comm.formatPercent(-item2.Ordervalue), -item2.Ordervalue, 0, item2.Ordervalue), ],
Ordervalue_X: ([ 0, item2.Ordervalue].join(' vs ')), },
}); {
} title: '成交率',
} children: [
} else { {
result.columns = [ title: (
{ <RenderVSDataCell
title: "#", showDiffData={showDiff}
fixed: 'left', data1={ordercountTotal1?.CJrate}
children: [ data2={ordercountTotal2?.CJrate}
{ diffPercent={ordercountTotal1?.CJrate_vs}
title: ( diffData={ordercountTotal1?.CJrate_diff}
<span> />
<div> ),
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)} titleX: [ordercountTotal1.CJrate, ordercountTotal2.CJrate].join(' vs '),
</div> dataIndex: 'CJrate',
</span> render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJrate} diffPercent={r.CJrate_vs} diffData={r.CJrate_diff} />,
), },
titleX: `${date_picker_store.start_date.format(config.DATE_FORMAT)}~${date_picker_store.end_date.format(config.DATE_FORMAT)}`, ],
fixed: 'left', },
dataIndex: "OrderType", {
render: (text, record) => <NavLink to={`/orders_sub/${orders_store.active_tab_key}/${record.OrderTypeSN}/${encodeURIComponent(record.OrderType)}`}>{text}</NavLink>, title: '成交毛利(预计)',
}, children: [
], {
}, title: (
{ <RenderVSDataCell
title: "数量", showDiffData={showDiff}
children: [{ title: ordercountTotal1.OrderCount, dataIndex: "OrderCount" }], data1={ordercountTotal1?.YJLY}
sorter: (a, b) => b.OrderCount - a.OrderCount, data2={ordercountTotal2?.YJLY}
}, diffPercent={ordercountTotal1?.YJLY_vs}
{ diffData={ordercountTotal1?.YJLY_diff}
title: "成交数", />
children: [{ title: ordercountTotal1.CJCount, dataIndex: "CJCount" }], ),
sorter: (a, b) => b.CJCount - a.CJCount, titleX: [ordercountTotal1.YJLY, ordercountTotal2.YJLY].join(' vs '),
}, dataIndex: 'YJLY',
{ render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.YJLY} diffPercent={r.YJLY_vs} diffData={r.YJLY_diff} />,
title: "成交人数", },
children: [{ title: ordercountTotal1.CJPersonNum, dataIndex: "CJPersonNum" }], ],
sorter: (a, b) => b.CJPersonNum - a.CJPersonNum, },
},
{ {
title: "成交率", title: '单个订单价值',
children: [{ title: ordercountTotal1.CJrate, dataIndex: "CJrate" }], children: [
sorter: (a, b) => parseInt(b.CJrate) - parseInt(a.CJrate), {
}, title: (
{ <RenderVSDataCell
title: "成交毛利(预计)", showDiffData={showDiff}
children: [{ title: ordercountTotal1.YJLY, dataIndex: "YJLY" }], data1={ordercountTotal1?.Ordervalue}
sorter: (a, b) => parseFloat(b.YJLY.replace(/,/g, "")) - parseFloat(a.YJLY.replace(/,/g, "")), data2={ordercountTotal2?.Ordervalue}
}, diffPercent={ordercountTotal1?.Ordervalue_vs}
diffData={ordercountTotal1?.Ordervalue_diff}
/>
),
titleX: [ordercountTotal1.Ordervalue, ordercountTotal2.Ordervalue].join(' vs '),
dataIndex: 'Ordervalue',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.Ordervalue} diffPercent={r.Ordervalue_vs} diffData={r.Ordervalue_diff} />,
},
],
},
];
return result;
{
title: "单个订单价值",
children: [{ title: ordercountTotal1.Ordervalue, dataIndex: "Ordervalue" }],
sorter: (a, b) => parseFloat(b.Ordervalue.replace(/,/g, "")) - parseFloat(a.Ordervalue.replace(/,/g, "")),
},
];
result.dataSource = data.ordercount1;
}
} }
return result; return result;
} }
@ -256,10 +207,10 @@ class Orders extends Component {
const table_data = orders_store.orderCountData_Form ? this.format_data(orders_store.orderCountData_Form) : []; const table_data = orders_store.orderCountData_Form ? this.format_data(orders_store.orderCountData_Form) : [];
const data_source = orders_store.orderCountData ? orders_store.orderCountData : []; const data_source = orders_store.orderCountData ? orders_store.orderCountData : [];
const avg_line_y = Math.round(orders_store.avgLine1); const avg_line_y = Math.round(orders_store.avgLine1);
const pie_data = comm.emptyValue(orders_store.orderCountData_Form) const pie_data = comm.isEmpty(orders_store.orderCountData_Form)
? [] ? []
: orders_store.orderCountData_Form.ordercount1.map((ele) => ({ ...ele, YJLYx: comm.price_to_number(ele.YJLY) })); // : orders_store.orderCountData_Form.ordercount1.map((ele) => ({ ...ele, YJLYx: comm.price_to_number(ele.YJLY) })); //
const pie_data2 = comm.emptyValue(orders_store.orderCountData_Form) const pie_data2 = comm.isEmpty(orders_store.orderCountData_Form)
? [] ? []
: orders_store.orderCountData_Form.ordercount2.map((ele) => ({ ...ele, YJLYx: comm.price_to_number(ele.YJLY) })); : orders_store.orderCountData_Form.ordercount2.map((ele) => ({ ...ele, YJLYx: comm.price_to_number(ele.YJLY) }));

@ -4,10 +4,10 @@ import { ContainerOutlined, BlockOutlined, SmileOutlined, MobileOutlined, Custom
import { Line, Pie } from '@ant-design/charts'; import { Line, Pie } from '@ant-design/charts';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import * as comm from '@haina/utils-commons'; import * as comm from '@haina/utils-commons';
import { show_vs_tag } from './../../utils/commons';
import DateGroupRadio from '../../components/DateGroupRadio'; import DateGroupRadio from '../../components/DateGroupRadio';
import SearchForm from '../../components/search/SearchForm'; import SearchForm from '../../components/search/SearchForm';
import { TableExportBtn } from '../../components/Data'; import { TableExportBtn } from '../../components/Data';
import { RenderVSDataCell } from './../../components/Data';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { toJS } from 'mobx'; import { toJS } from 'mobx';
@ -143,12 +143,18 @@ const BizOrder = observer(() => {
title: '数量', title: '数量',
children: [ children: [
{ {
title: !showDiff title: (
? result.ordercountTotal1?.OrderCount <RenderVSDataCell
: show_vs_tag(result.ordercountTotal1?.OrderCount_vs, result.ordercountTotal1?.OrderCount_diff, result.ordercountTotal1?.OrderCount, result.ordercountTotal2?.OrderCount), showDiffData={showDiff}
data1={result.ordercountTotal1?.OrderCount}
data2={result.ordercountTotal2?.OrderCount}
diffPercent={result.ordercountTotal1?.OrderCount_vs}
diffData={result.ordercountTotal1?.OrderCount_diff}
/>
),
titleX: [result.ordercountTotal1?.OrderCount, result.ordercountTotal2?.OrderCount].join(' vs '), titleX: [result.ordercountTotal1?.OrderCount, result.ordercountTotal2?.OrderCount].join(' vs '),
dataIndex: 'OrderCount', dataIndex: 'OrderCount',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.OrderCount_vs, r.OrderCount_diff, r.OrderCount, r.diff?.OrderCount)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.OrderCount} diffPercent={r.OrderCount_vs} diffData={r.OrderCount_diff} />,
}, },
], ],
}, },
@ -156,12 +162,18 @@ const BizOrder = observer(() => {
title: '成交数', title: '成交数',
children: [ children: [
{ {
title: !showDiff title: (
? result.ordercountTotal1?.CJCount <RenderVSDataCell
: show_vs_tag(result.ordercountTotal1?.CJCount_vs, result.ordercountTotal1?.CJCount_diff, result.ordercountTotal1?.CJCount, result.ordercountTotal2?.CJCount), showDiffData={showDiff}
data1={result.ordercountTotal1?.CJCount}
data2={result.ordercountTotal2?.CJCount}
diffPercent={result.ordercountTotal1?.CJCount_vs}
diffData={result.ordercountTotal1?.CJCount_diff}
/>
),
titleX: [result.ordercountTotal1?.CJCount, result.ordercountTotal2?.CJCount].join(' vs '), titleX: [result.ordercountTotal1?.CJCount, result.ordercountTotal2?.CJCount].join(' vs '),
dataIndex: 'CJCount', dataIndex: 'CJCount',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.CJCount_vs, r.CJCount_diff, r.CJCount, r.diff?.CJCount)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJCount} diffPercent={r.CJCount_vs} diffData={r.CJCount_diff} />,
}, },
], ],
}, },
@ -169,12 +181,18 @@ const BizOrder = observer(() => {
title: '成交人数', title: '成交人数',
children: [ children: [
{ {
title: !showDiff title: (
? result.ordercountTotal1?.CJPersonNum <RenderVSDataCell
: show_vs_tag(result.ordercountTotal1?.CJPersonNum_vs, result.ordercountTotal1?.CJPersonNum_diff, result.ordercountTotal1?.CJPersonNum, result.ordercountTotal2?.CJPersonNum), showDiffData={showDiff}
data1={result.ordercountTotal1?.CJPersonNum}
data2={result.ordercountTotal2?.CJPersonNum}
diffPercent={result.ordercountTotal1?.CJPersonNum_vs}
diffData={result.ordercountTotal1?.CJPersonNum_diff}
/>
),
titleX: [result.ordercountTotal1?.CJPersonNum, result.ordercountTotal2?.CJPersonNum].join(' vs '), titleX: [result.ordercountTotal1?.CJPersonNum, result.ordercountTotal2?.CJPersonNum].join(' vs '),
dataIndex: 'CJPersonNum', dataIndex: 'CJPersonNum',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.CJPersonNum_vs, r.CJPersonNum_diff, r.CJPersonNum, r.diff?.CJPersonNum)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJPersonNum} diffPercent={r.CJPersonNum_vs} diffData={r.CJPersonNum_diff} />,
}, },
], ],
}, },
@ -182,12 +200,18 @@ const BizOrder = observer(() => {
title: '成交率', title: '成交率',
children: [ children: [
{ {
title: !showDiff title: (
? result.ordercountTotal1?.CJrate <RenderVSDataCell
: show_vs_tag(result.ordercountTotal1?.CJrate_vs, result.ordercountTotal1?.CJrate_diff, result.ordercountTotal1?.CJrate, result.ordercountTotal2?.CJrate), showDiffData={showDiff}
data1={result.ordercountTotal1?.CJrate}
data2={result.ordercountTotal2?.CJrate}
diffPercent={result.ordercountTotal1?.CJrate_vs}
diffData={result.ordercountTotal1?.CJrate_diff}
/>
),
titleX: [result.ordercountTotal1?.CJrate, result.ordercountTotal2?.CJrate].join(' vs '), titleX: [result.ordercountTotal1?.CJrate, result.ordercountTotal2?.CJrate].join(' vs '),
dataIndex: 'CJrate', dataIndex: 'CJrate',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.CJrate_vs, r.CJrate_diff, r.CJrate, r.diff?.CJrate)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJrate} diffPercent={r.CJrate_vs} diffData={r.CJrate_diff} />,
}, },
], ],
}, },
@ -195,12 +219,18 @@ const BizOrder = observer(() => {
title: '成交毛利(预计)', title: '成交毛利(预计)',
children: [ children: [
{ {
title: !showDiff title: (
? result.ordercountTotal1?.YJLY <RenderVSDataCell
: show_vs_tag(result.ordercountTotal1?.YJLY_vs, result.ordercountTotal1?.YJLY_diff, result.ordercountTotal1?.YJLY, result.ordercountTotal2?.YJLY), showDiffData={showDiff}
data1={result.ordercountTotal1?.YJLY}
data2={result.ordercountTotal2?.YJLY}
diffPercent={result.ordercountTotal1?.YJLY_vs}
diffData={result.ordercountTotal1?.YJLY_diff}
/>
),
titleX: [result.ordercountTotal1?.YJLY, result.ordercountTotal2?.YJLY].join(' vs '), titleX: [result.ordercountTotal1?.YJLY, result.ordercountTotal2?.YJLY].join(' vs '),
dataIndex: 'YJLY', dataIndex: 'YJLY',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.YJLY_vs, r.YJLY_diff, r.YJLY, r.diff?.YJLY)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.YJLY} diffPercent={r.YJLY_vs} diffData={r.YJLY_diff} />,
}, },
], ],
}, },
@ -209,12 +239,18 @@ const BizOrder = observer(() => {
title: '单个订单价值', title: '单个订单价值',
children: [ children: [
{ {
title: !showDiff title: (
? result.ordercountTotal1?.Ordervalue <RenderVSDataCell
: show_vs_tag(result.ordercountTotal1?.Ordervalue_vs, result.ordercountTotal1?.Ordervalue_diff, result.ordercountTotal1?.Ordervalue, result.ordercountTotal2?.Ordervalue), showDiffData={showDiff}
data1={result.ordercountTotal1?.Ordervalue}
data2={result.ordercountTotal2?.Ordervalue}
diffPercent={result.ordercountTotal1?.Ordervalue_vs}
diffData={result.ordercountTotal1?.Ordervalue_diff}
/>
),
titleX: [result.ordercountTotal1?.Ordervalue, result.ordercountTotal2?.Ordervalue].join(' vs '), titleX: [result.ordercountTotal1?.Ordervalue, result.ordercountTotal2?.Ordervalue].join(' vs '),
dataIndex: 'Ordervalue', dataIndex: 'Ordervalue',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.Ordervalue_vs, r.Ordervalue_diff, r.Ordervalue, r.diff?.Ordervalue)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.Ordervalue} diffPercent={r.Ordervalue_vs} diffData={r.Ordervalue_diff} />,
}, },
], ],
}, },

@ -3,8 +3,8 @@ import { Row, Col, Table, Spin, Space, Divider } from 'antd';
import { Funnel, Pie, Sunburst } from '@ant-design/charts'; import { Funnel, Pie, Sunburst } from '@ant-design/charts';
import { isEmpty } from '@haina/utils-commons'; import { isEmpty } from '@haina/utils-commons';
import { show_vs_tag } from '../../../utils/commons';
import SearchForm from '../../../components/search/SearchForm'; import SearchForm from '../../../components/search/SearchForm';
import { RenderVSDataCell } from './../../../components/Data';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { toJS } from 'mobx'; import { toJS } from 'mobx';
@ -168,33 +168,33 @@ const TrainsUpsell = observer(({ ...props }) => {
{ {
title: '数量', title: '数量',
dataIndex: 'OrderCount', dataIndex: 'OrderCount',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.OrderCount_vs, r.OrderCount_diff, r.OrderCount, r.diff?.OrderCount)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.OrderCount} diffPercent={r.OrderCount_vs} diffData={r.OrderCount_diff} />,
}, },
{ {
title: '成交数', title: '成交数',
dataIndex: 'CJCount', dataIndex: 'CJCount',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.CJCount_vs, r.CJCount_diff, r.CJCount, r.diff?.CJCount)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJCount} diffPercent={r.CJCount_vs} diffData={r.CJCount_diff} />,
}, },
{ {
title: '成交人数', title: '成交人数',
dataIndex: 'CJPersonNum', dataIndex: 'CJPersonNum',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.CJPersonNum_vs, r.CJPersonNum_diff, r.CJPersonNum, r.diff?.CJPersonNum)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJPersonNum} diffPercent={r.CJPersonNum_vs} diffData={r.CJPersonNum_diff} />,
}, },
{ {
title: '成交率', title: '成交率',
dataIndex: 'CJrate', dataIndex: 'CJrate',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.CJrate_vs, r.CJrate_diff, r.CJrate, r.diff?.CJrate)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJrate} diffPercent={r.CJrate_vs} diffData={r.CJrate_diff} />,
}, },
{ {
title: '成交毛利(预计)', title: '成交毛利(预计)',
dataIndex: 'YJLY', dataIndex: 'YJLY',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.YJLY_vs, r.YJLY_diff, r.YJLY, r.diff?.YJLY)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.YJLY} diffPercent={r.YJLY_vs} diffData={r.YJLY_diff} />,
}, },
{ {
title: '单个订单价值', title: '单个订单价值',
dataIndex: 'Ordervalue', dataIndex: 'Ordervalue',
render: (text, r) => (!showDiff ? text : show_vs_tag(r.Ordervalue_vs, r.Ordervalue_diff, r.Ordervalue, r.diff?.Ordervalue)), render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.Ordervalue} diffPercent={r.Ordervalue_vs} diffData={r.Ordervalue_diff} />,
}, },
]; ];
return ( return (

@ -0,0 +1,366 @@
import { useContext } from 'react';
import { Row, Col, Tabs, Table, Divider, Spin, Checkbox, Space } from 'antd';
import { ContainerOutlined, BlockOutlined, SmileOutlined, MobileOutlined, CustomerServiceOutlined, IeOutlined } from '@ant-design/icons';
import { Line, Pie } from '@ant-design/charts';
import { NavLink } from 'react-router-dom';
import * as comm from '@haina/utils-commons';
import DateGroupRadio from '../../components/DateGroupRadio';
import SearchForm from '../../components/search/SearchForm';
import { TableExportBtn } from '../../components/Data';
import { RenderVSDataCell } from './../../components/Data';
import { observer } from 'mobx-react';
import { toJS } from 'mobx';
import { stores_Context } from '../../config';
import { useShallow } from 'zustand/shallow';
import useToBOrderStore, { orderCountDataMapper, orderCountDataFieldMapper } from '../../zustand/ToBOrder';
const ToBOrder = observer(() => {
const { date_picker_store: searchFormStore } = useContext(stores_Context);
const [searchValues, setSearchValues] = useToBOrderStore(useShallow((state) => [state.searchValues, state.setSearchValues]));
const [activeTab, setActiveTab] = useToBOrderStore(useShallow((state) => [state.activeTab, state.setActiveTab]));
const [loading, typeLoading, onTabChange] = useToBOrderStore(useShallow((state) => [state.loading, state.typeLoading,state.onTabChange]));
const orderCountDataRaw = useToBOrderStore((state) => state.orderCountDataRaw);
const [orderCountDataLines, avgLineValue] = useToBOrderStore(useShallow((state) => [state.orderCountDataLines, state.avgLineValue]));
const [onChangeDateGroup, activeDateGroupRadio] = useToBOrderStore(useShallow((state) => [state.onChangeDateGroup, state.activeDateGroupRadio]));
const orderCountDataByType = useToBOrderStore((state) => state.orderCountDataByType);
const result = orderCountDataByType[activeTab] || {};
const getToBOrderCount = useToBOrderStore((state) => state.getToBOrderCount);
const showDiff = !comm.isEmpty(searchFormStore.start_date_cp);
const avg_line_y = Math.round(avgLineValue);
const lineConfig = {
data: orderCountDataLines,
padding: 'auto',
xField: 'xField',
yField: 'yField',
seriesField: 'seriesField',
// xAxis: {
// type: "timeCat",
// },
point: {
size: 4,
shape: 'cicle',
},
annotations: [
{
type: 'text',
position: ['start', avg_line_y],
content: avg_line_y,
offsetX: -15,
style: {
fill: '#F4664A',
textBaseline: 'bottom',
},
},
{
type: 'line',
start: [-10, avg_line_y],
end: ['max', avg_line_y],
style: {
stroke: '#F4664A',
lineDash: [2, 2],
},
},
],
label: {}, //
legend: {
itemValue: {
formatter: (text, item) => {
const items = orderCountDataLines.filter((d) => d.seriesField === item.value); //
return items.length ? items.reduce((a, b) => a + b.yField, 0) : ''; //
},
},
},
tooltip: {
customItems: (originalItems) => {
// process originalItems,
return originalItems.map((ele) => ({ ...ele, name: ele.data?.seriesField || ele.data?.xField }));
},
title: (title, datum) => {
let ret = title;
switch (activeDateGroupRadio) {
case 'day':
ret = `${title} ${comm.getWeek(datum.xField)}`; //
break;
default:
break;
}
return ret;
},
},
// smooth: true,
};
const pieConfig = {
appendPadding: 10,
data: [],
angleField: 'OrderCount',
colorField: 'OrderType',
radius: 0.8,
label: {
type: 'outer',
content: '{name} {value} \t {percentage}',
},
legend: false, //
interactions: [
{
type: 'element-selected',
},
{
type: 'element-active',
},
],
};
const tableProps = {
dataSource: result?.ordercount1 || [], // table_data.dataSource,
columns: [
{
title: '#',
fixed: 'left',
children: [
{
title: (
<span>
<div>{result.ordercountTotal1?.groups}</div>
{showDiff ? <div>{result.ordercountTotal2?.groups}</div> : null}
</span>
),
titleX: `${result.ordercountTotal1?.groups}` + (showDiff ? ` vs ${result.ordercountTotal2?.groups}` : ''),
dataIndex: 'OrderType',
fixed: 'left',
render: (text, record) => <NavLink to={`/tob_orders_sub/${activeTab}/${record.OrderTypeSN}/${encodeURIComponent(record.OrderType)}`}>{text}</NavLink>,
},
],
},
{
title: '数量',
children: [
{
title: (
<RenderVSDataCell
showDiffData={showDiff}
data1={result.ordercountTotal1?.OrderCount}
data2={result.ordercountTotal2?.OrderCount}
diffPercent={result.ordercountTotal1?.OrderCount_vs}
diffData={result.ordercountTotal1?.OrderCount_diff}
/>
),
titleX: [result.ordercountTotal1?.OrderCount, result.ordercountTotal2?.OrderCount].join(' vs '),
dataIndex: 'OrderCount',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.OrderCount} diffPercent={r.OrderCount_vs} diffData={r.OrderCount_diff} />,
},
],
},
{
title: '成交数',
children: [
{
title: (
<RenderVSDataCell
showDiffData={showDiff}
data1={result.ordercountTotal1?.CJCount}
data2={result.ordercountTotal2?.CJCount}
diffPercent={result.ordercountTotal1?.CJCount_vs}
diffData={result.ordercountTotal1?.CJCount_diff}
/>
),
titleX: [result.ordercountTotal1?.CJCount, result.ordercountTotal2?.CJCount].join(' vs '),
dataIndex: 'CJCount',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJCount} diffPercent={r.CJCount_vs} diffData={r.CJCount_diff} />,
},
],
},
{
title: '成交人数',
children: [
{
title: (
<RenderVSDataCell
showDiffData={showDiff}
data1={result.ordercountTotal1?.CJPersonNum}
data2={result.ordercountTotal2?.CJPersonNum}
diffPercent={result.ordercountTotal1?.CJPersonNum_vs}
diffData={result.ordercountTotal1?.CJPersonNum_diff}
/>
),
titleX: [result.ordercountTotal1?.CJPersonNum, result.ordercountTotal2?.CJPersonNum].join(' vs '),
dataIndex: 'CJPersonNum',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJPersonNum} diffPercent={r.CJPersonNum_vs} diffData={r.CJPersonNum_diff} />,
},
],
},
{
title: '成交率',
children: [
{
title: (
<RenderVSDataCell
showDiffData={showDiff}
data1={result.ordercountTotal1?.CJrate}
data2={result.ordercountTotal2?.CJrate}
diffPercent={result.ordercountTotal1?.CJrate_vs}
diffData={result.ordercountTotal1?.CJrate_diff}
/>
),
titleX: [result.ordercountTotal1?.CJrate, result.ordercountTotal2?.CJrate].join(' vs '),
dataIndex: 'CJrate',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.CJrate} diffPercent={r.CJrate_vs} diffData={r.CJrate_diff} />,
},
],
},
{
title: '成交毛利(预计)',
children: [
{
title: (
<RenderVSDataCell
showDiffData={showDiff}
data1={result.ordercountTotal1?.YJLY}
data2={result.ordercountTotal2?.YJLY}
diffPercent={result.ordercountTotal1?.YJLY_vs}
diffData={result.ordercountTotal1?.YJLY_diff}
/>
),
titleX: [result.ordercountTotal1?.YJLY, result.ordercountTotal2?.YJLY].join(' vs '),
dataIndex: 'YJLY',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.YJLY} diffPercent={r.YJLY_vs} diffData={r.YJLY_diff} />,
},
],
},
{
title: '单个订单价值',
children: [
{
title: (
<RenderVSDataCell
showDiffData={showDiff}
data1={result.ordercountTotal1?.Ordervalue}
data2={result.ordercountTotal2?.Ordervalue}
diffPercent={result.ordercountTotal1?.Ordervalue_vs}
diffData={result.ordercountTotal1?.Ordervalue_diff}
/>
),
titleX: [result.ordercountTotal1?.Ordervalue, result.ordercountTotal2?.Ordervalue].join(' vs '),
dataIndex: 'Ordervalue',
render: (text, r) => <RenderVSDataCell showDiffData={showDiff} data1={text} data2={r.diff?.Ordervalue} diffPercent={r.Ordervalue_vs} diffData={r.Ordervalue_diff} />,
},
],
},
],
size: 'small',
pagination: false,
scroll: { x: 100 * 7 },
loading,
};
return (
<>
<div>
<Row gutter={16} className={toJS(searchFormStore.siderBroken) ? '' : 'sticky-top'}>
<Col className="gutter-row" span={24}>
<SearchForm
defaultValue={{
initialValue: {
...toJS(searchFormStore.formValues),
...searchValues,
},
//
shows: ['DateType', 'WebCode','IncludeTickets', 'DepartmentList', 'dates'],
fieldProps: {
DepartmentList: { show_all: false, mode: 'multiple' },
WebCode: { show_all: false, mode: 'multiple' },
years: { hide_vs: true },
},
}}
onSubmit={(_err, obj, form, str) => {
setSearchValues(obj, form);
getToBOrderCount(obj);
onTabChange(activeTab);
}}
/>
</Col>
</Row>
<Row gutter={[16, { sm: 16, lg: 32 }]}>
<Col span={24} style={{ textAlign: 'right' }}>
<DateGroupRadio
visible={orderCountDataLines.length !== 0}
dataRaw={orderCountDataRaw}
onChange={onChangeDateGroup}
value={activeDateGroupRadio}
dataMapper={orderCountDataMapper}
fieldMapper={orderCountDataFieldMapper}
/>
</Col>
<Col span={24}>
<Spin spinning={loading}>
<Line {...lineConfig} />
</Spin>
</Col>
<Col span={24}>
<Tabs
activeKey={activeTab}
onChange={(active_key) => onTabChange(active_key)}
items={[
{
key: 'customer_types',
label: (
<span>
<CustomerServiceOutlined />
分销客户
</span>
),
},
].map((ele) => {
return {
...ele,
children: (
<>
<Table sticky key={`table_to_xlsx_${ele.key}`} {...tableProps} loading={typeLoading} />
<Divider orientation="right" plain>
<TableExportBtn label={ele.key} {...{ columns: tableProps.columns, dataSource: tableProps.dataSource }} />
</Divider>
</>
),
};
})}
/>
</Col>
</Row>
<div>
<h3>各项占比</h3>
{/* <Checkbox
checked={true}
// onChange={(e) => setIsShowEmpty(e.target.checked)}
>
包含空值
</Checkbox> */}
</div>
<Spin spinning={typeLoading}>
<Row>
<Col sm={24} lg={12}>
<Pie {...pieConfig} data={result?.ordercount1 || []} innerRadius={0.6} statistic={{title: false,content:{content:'数量'}}} />
<Pie {...pieConfig} data={result?.ordercount1 || []} angleField='YJLYx' innerRadius={0.6} statistic={{title: false,content:{content:'预计毛利'}}} />
</Col>
{showDiff && <Col sm={24} lg={12}>
<Pie {...pieConfig} data={result?.ordercount2 || []} innerRadius={0.6} statistic={{title: false,content:{content:'数量'}}} />
<Pie {...pieConfig} data={result?.ordercount2 || []} angleField='YJLYx' innerRadius={0.6} statistic={{title: false,content:{content:'预计毛利'}}} />
</Col>}
</Row>
</Spin>
</div>
</>
);
});
export default ToBOrder;

@ -0,0 +1,280 @@
import { useContext, useEffect } from 'react';
import { Row, Col, Tabs, Table, Divider, Spin, Space } from 'antd';
import { ContainerOutlined, BlockOutlined, SmileOutlined, MobileOutlined } from '@ant-design/icons';
import { Line } from '@ant-design/charts';
import { NavLink, useParams } from 'react-router-dom';
import { getWeek } from '@haina/utils-commons';
import DateGroupRadio from '../../components/DateGroupRadio';
import SearchForm from '../../components/search/SearchForm';
import { TableExportBtn } from '../../components/Data';
import { observer } from 'mobx-react';
import { stores_Context } from '../../config';
import { useShallow } from 'zustand/shallow';
import useToBOrderStore, { orderCountDataMapper, orderCountDataFieldMapper } from '../../zustand/ToBOrder';
//
const addLineBreaksAtCommas = (text) => {
if (!text) return '';
return text.replace(/&amp;/g, '&').replace(//g, '\n').replace(/,/g, ',\n').replace(//g, '\n').replace(/;/g, ';\n');
};
const OrderDetailTable = ({ caption, dataSource, loading, ...props }) => {
const columns = [
{
title: '订单号',
dataIndex: 'COLI_ID',
key: 'COLI_ID',
},
{
title: '网站',
dataIndex: 'COLI_WebCode',
key: 'COLI_WebCode',
},
{
title: '成行',
dataIndex: 'COLI_Success',
key: 'COLI_Success',
render: (text, record) => <span>{text == 1 ? '是' : '否'}</span>,
sorter: (a, b) => b.COLI_Success - a.COLI_Success,
},
// {
// title: "(//)",
// dataIndex: "COLI_PersonNum",
// key: "COLI_PersonNum",
// render: (text, record) => (
// <span>
// {record.COLI_PersonNum}/{record.COLI_ChildNum}/{record.COLI_BabyNum}
// </span>
// ),
// },
{
title: '预计利润',
dataIndex: 'CGI_YJLY',
key: 'CGI_YJLY',
},
{
title: '预定时间',
dataIndex: 'COLI_ApplyDate',
key: 'COLI_ApplyDate',
},
{
title: '出发日期',
dataIndex: 'CGI_ArriveDate',
key: 'CGI_ArriveDate',
},
// {
// title: '',
// dataIndex: 'COLI_CustomerRequest',
// key: 'COLI_CustomerRequest',
// ellipsis: true,
// },
{
title: '订单内容',
dataIndex: 'COLI_OrderDetailText',
key: 'COLI_OrderDetailText',
ellipsis: true,
},
Table.EXPAND_COLUMN,
];
return (
<div>
<Divider orientation="left" plain>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '10px' }}>
<div>{caption}</div>
<TableExportBtn label={caption} columns={columns} dataSource={dataSource} />
</div>
</Divider>
<Table
id="table_to_xlsx_form"
dataSource={dataSource}
columns={columns}
loading={loading}
size="small"
// pagination={false}
rowKey={(record) => record.key}
expandable={{
expandedRowRender: (record) => (
<pre style={{ whiteSpace: 'pre-wrap', wordWrap: 'break-word', fontSize: '16px' }}>
{/* <Divider orientation="left" plain>
客户需求
</Divider>
{record.COLI_CustomerRequest} */}
<Divider orientation="left" plain>
订单内容
</Divider>
{record.COLI_OrderDetailText}
</pre>
),
}}
/>
</div>
);
};
const ToBOrderSub = observer(({ ...props }) => {
const { ordertype, ordertype_sub, ordertype_title } = useParams();
const { date_picker_store: searchFormStore } = useContext(stores_Context);
const [searchValues, setSearchValues] = useToBOrderStore(useShallow((state) => [state.searchValues, state.setSearchValues]));
const [searchValuesToSub] = useToBOrderStore(useShallow((state) => [state.searchValuesToSub]));
const [loading, typeLoading] = useToBOrderStore(useShallow((state) => [state.loading, state.typeLoading]));
const orderCountDataRawSub = useToBOrderStore((state) => state.orderCountDataRawSub);
const [orderCountDataLinesSub, avgLineValueSub] = useToBOrderStore(useShallow((state) => [state.orderCountDataLinesSub, state.avgLineValueSub]));
const [onChangeDateGroupSub, activeDateGroupRadioSub] = useToBOrderStore(useShallow((state) => [state.onChangeDateGroupSub, state.activeDateGroupRadioSub]));
const orderDetails = useToBOrderStore((state) => state.orderDetails);
const getToBOrderCount = useToBOrderStore((state) => state.getToBOrderCount);
const getToBOrderDetailByType = useToBOrderStore((state) => state.getToBOrderDetailByType);
useEffect(() => {
getToBOrderCount(searchValuesToSub, ordertype, ordertype_sub);
getToBOrderDetailByType(searchValuesToSub, ordertype, ordertype_sub);
}, []);
const avg_line_y = Math.round(avgLineValueSub);
const lineConfig = {
data: orderCountDataLinesSub,
padding: 'auto',
xField: 'xField',
yField: 'yField',
seriesField: 'seriesField',
// xAxis: {
// type: "timeCat",
// },
point: {
size: 4,
shape: 'cicle',
},
annotations: [
{
type: 'text',
position: ['start', avg_line_y],
content: avg_line_y,
offsetX: -15,
style: {
fill: '#F4664A',
textBaseline: 'bottom',
},
},
{
type: 'line',
start: [-10, avg_line_y],
end: ['max', avg_line_y],
style: {
stroke: '#F4664A',
lineDash: [2, 2],
},
},
],
label: {}, //
legend: {
itemValue: {
formatter: (text, item) => {
const items = orderCountDataLinesSub.filter((d) => d.seriesField === item.value); //
return items.length ? items.reduce((a, b) => a + b.yField, 0) : ''; //
},
},
},
tooltip: {
customItems: (originalItems) => {
// process originalItems,
return originalItems.map((ele) => ({ ...ele, name: ele.data?.seriesField || ele.data?.xField }));
},
title: (title, datum) => {
let ret = title;
switch (activeDateGroupRadioSub) {
case 'day':
ret = `${title} ${getWeek(datum.xField)}`; //
break;
default:
break;
}
return ret;
},
},
smooth: true,
};
const tab_items = [
{
key: 'detail',
label: (
<span>
<ContainerOutlined />
订单内容
</span>
),
title: '订单内容',
children: (
<>
<Space direction="vertical">
<OrderDetailTable caption={orderDetails[0]?.dateRangeStr} dataSource={orderDetails[0]?.data || []} loading={typeLoading} />
<OrderDetailTable caption={orderDetails[1]?.dateRangeStr} dataSource={orderDetails[1]?.data || []} loading={typeLoading} />
</Space>
</>
),
},
];
return (
<div>
<Row gutter={{ sm: 16, lg: 32 }} className={searchFormStore.siderBroken ? '' : 'sticky-top'}>
<Col md={24} lg={12} xxl={14}>
<NavLink to={`/tob_orders`}>返回</NavLink>
</Col>
<Col className="gutter-row" span={24}>
<SearchForm
defaultValue={{
initialValue: {
...searchFormStore.formValues,
...searchValues,
},
//
shows: ['DateType', 'DepartmentList', 'WebCode', 'IncludeTickets', 'dates'],
fieldProps: {
DepartmentList: { show_all: false, mode: 'multiple' },
WebCode: { show_all: false, mode: 'multiple' },
// dates: { hide_vs: true },
},
}}
onSubmit={(_err, obj, form, str) => {
setSearchValues(obj, form);
getToBOrderCount(obj, ordertype, ordertype_sub);
getToBOrderDetailByType(obj, ordertype, ordertype_sub);
}}
/>
</Col>
</Row>
<Row gutter={[16, { xs: 8, sm: 16, md: 24, lg: 32 }]}>
<Col span={24} style={{ textAlign: 'right' }}>
<DateGroupRadio
visible={orderCountDataLinesSub.length !== 0}
dataRaw={orderCountDataRawSub}
onChange={onChangeDateGroupSub}
value={activeDateGroupRadioSub}
dataMapper={orderCountDataMapper}
fieldMapper={orderCountDataFieldMapper}
/>
</Col>
<Col className="gutter-row" span={24}>
<Spin spinning={loading}>
<Line {...lineConfig} />
</Spin>
</Col>
<Col className="gutter-row" span={24}>
<Tabs
activeKey={'detail'}
// onChange={onTabsChange}
items={tab_items}
/>
</Col>
</Row>
</div>
);
});
export default ToBOrderSub;

@ -0,0 +1,172 @@
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { fetchJSON } from '@haina/utils-request';
import { HT_HOST } from '../config';
import { formatDate, isEmpty, sortBy } from '@haina/utils-commons';
import { groupsMappedByKey, sitesMappedByCode, pivotBy } from './../libs/ht';
const defaultParams = {};
export const fetchRegularCustomer = async (params) => {
const _params = {
Website: params.WebCode || '', // CHT,AH,JH,GH,ZWQD,GH_ZWQD_HW,GHKYZG,GHKYHW,HTravel
DEI_SNList: params.DepartmentList || '', // 1,2,28,7
ApplydateCheck: params.DateType === 'applyDate' ? 1 : 0, //
EntrancedateCheck: params.DateType === 'startDate' ? 1 : 0, //
ConfirmDateCheck: params.DateType === 'confirmDate' ? 1 : 0, //
ApplydateStart: params.Date1 || '',
ApplydateEnd: params.Date2 || '',
EntrancedateStart: params.Date1 || '',
EntrancedateEnd: params.Date2 || '',
ConfirmdateStart: params.Date1 || '',
ConfirmdateEnd: params.Date2 || '',
IsDetail: '', //
IncludeTickets: '', //
...params,
};
const { WebCode, DepartmentList, DateType, Date1, Date2, ...readyParams } = _params;
const [result1=[], result2=[]] = await Promise.all([
fetchJSON(HT_HOST + '/service-tourdesign/RegularCusOrder', { ...defaultParams, ...readyParams }),
...(params.DateDiff1 && params.IsDetail === 0
? [
fetchJSON(HT_HOST + '/service-tourdesign/RegularCusOrder', {
...defaultParams,
...readyParams,
ApplydateStart: params.DateDiff1 || '',
ApplydateEnd: params.DateDiff2 || '',
EntrancedateStart: params.DateDiff1 || '',
EntrancedateEnd: params.DateDiff2 || '',
ConfirmdateStart: params.DateDiff1 || '',
ConfirmdateEnd: params.DateDiff2 || '',
}),
]
: []),
]);
if (params.IsDetail === 1) {
return { result1, result2 };
}
const ret = {};
const result1Mapped = result1.reduce((r, v) => ({ ...r, [v.ItemName]: v }), {});
const allKeys = [...new Set([...result1.map((e) => e.ItemName), ...result2.map((e) => e.ItemName)])];
const result2Mapped = result2.reduce((r, v) => ({ ...r, [v.ItemName]: v }), {});
const x = {};
allKeys.forEach((key) => {
x[key] = { ...(result1Mapped?.[key] || { ItemName: key }), diff: result2Mapped[key] || {} };
});
ret.result1 = Object.values(x);
return { result1: ret.result1 }; // { result1, result2 };
};
// 老客户: 日期对应的数据字段
const dateTypeDataHelper = {
applyDate: 'SumOrder',
startDate: 'ConfirmOrder',
confirmDate: 'ConfirmOrder',
};
/**
* 构建 老客户系列数据
* * 用明细数据计算
* @param {[]} details
* @param {string} pivotByOrder
* @param {string} pivotByDate
* @returns
*/
const buildSeriesDataFromDetails = (details, pivotByOrder, pivotByDate) => {
const dataDetail = (details || []).map((ele) => ({
...ele,
key: ele.COLI_ID,
orderState: ele.OrderState,
applyDate: formatDate(new Date(ele.COLI_ApplyDate)),
startDate: ele.COLI_OrderStartDate,
confirmDate: formatDate(new Date(ele.COLI_ConfirmDate)),
}));
const { data: IsOldData } = pivotBy(
dataDetail.filter((ele) => ele.COLI_IsOld === '是'),
[['COLI_IsOld'], [], pivotByDate]
);
const { data: isCusCommendData } = pivotBy(
dataDetail.filter((ele) => ele.COLI_IsCusCommend === '是'),
[['COLI_IsCusCommend'], [], pivotByDate]
);
// console.log('IsOldData====', IsOldData, '\nisCusCommend', isCusCommendData);
// 合并成两个系列
const seriesData = []
.concat(
IsOldData.map((ele) => ({ ...ele, _ylabel: '老客户' })),
isCusCommendData.map((ele) => ({ ...ele, _ylabel: '老客户推荐' }))
)
.sort(sortBy(pivotByDate));
return seriesData;
};
/**
* --------------------------------------------------------------------------------------------------------
*/
const initialState = {
loading: false,
loading2: false,
searchValues: {
DepartmentList: ['1', '2', '28', '7', '33'].map((kk) => groupsMappedByKey[kk]),
WebCode: ['CHT', 'AH', 'JH', 'GH', 'ZWQD', 'GH_ZWQD_HW', 'GHKYZG', 'GHKYHW', 'HTravel'].map((kk) => sitesMappedByCode[kk]),
DateType: { key: 'applyDate', label: '提交日期' },
IncludeTickets: { key: '0', label: '不含门票' },
},
searchValuesToSub: {},
regular: { data: [], details: [], total_data_tips: '', pivotData: [], pivotY: 'SumOrder', pivotX: '' },
};
const useCustomerRelationsStore = create(
devtools(
immer((set, get) => ({
...initialState,
reset: () => set(initialState),
setLoading: (loading) => set({ loading }),
setLoading2: (loading2) => set({ loading2 }),
setSearchValues: (obj, values) => set((state) => ({ searchValues: values, searchValuesToSub: obj })),
setSearchValuesToSub: (values) => set((state) => ({ searchValuesToSub: values })),
// 获取数据 ---------------------------------------------------------------------------------------------------
// 老客户
getRegularCustomer: async (params) => {
const { setLoading, setLoading2 } = get();
const { IsDetail } = params;
setLoading(true);
setLoading2(IsDetail === 1);
const pivotByOrder = dateTypeDataHelper[params.DateType];
const pivotByDate = params.DateType;
try {
const {result1, result2} = await fetchRegularCustomer(params);
set((state) => {
if (IsDetail === 1) {
state.regular.details = result1;
const dump_l = (result1 || []).filter((ele) => ele.COLI_IsOld !== '' && ele.COLI_IsCusCommend !== '').length;
state.regular.total_data_tips = dump_l > 0 ? `包含 ${dump_l} 条同时勾选的数据` : '';
/** 使用明细数据画图 */
const seriesData = buildSeriesDataFromDetails(result1, pivotByOrder, pivotByDate);
state.regular.pivotData = seriesData;
state.regular.pivotX = pivotByDate;
state.regular.pivotY = pivotByOrder;
} else {
console.log('0000');
state.regular.data = result1;
}
});
} catch (error) {
console.error(error);
} finally {
setLoading(false);
IsDetail === 1 && setLoading2(false);
}
},
})),
{ name: 'CustomerRelations' }
)
);
export default useCustomerRelationsStore;

@ -0,0 +1,241 @@
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { groupsMappedByCode } from '../libs/ht';
import { fetchJSON } from '@haina/utils-request';
import { HT_HOST } from '../config';
import { resultDataCb } from '../components/DateGroupRadio/date';
import { isEmpty, price_to_number } from '@haina/utils-commons';
/**
* 分销(ToB)订单
*/
const defaultParams = {};
export const fetchToBOrderCount = async (params, type = '', typeVal = '') => {
const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCount_FX', {
...defaultParams,
...params,
COLI_ApplyDate1: params.Date1,
COLI_ApplyDate2: params.Date2,
COLI_ApplyDateOld1: params.DateDiff1 || '',
COLI_ApplyDateOld2: params.DateDiff2 || '',
OrderType: type,
OrderType_val: typeVal,
});
return errcode !== 0 ? {} : (result || {});
};
const _typeRes = {
'ordercount1': [],
'ordercount2': [],
'ordercountTotal1': {
'OrderType': '合计',
'OrderCount': 0,
'CJCount': 0,
'CJPersonNum': 0,
'YJLY': '',
'CJrate': '0%',
'Ordervalue': '',
'groups': '',
'key': 1,
},
'ordercountTotal2': {},
};
export const fetchToBOrderCountByType = async (type, params) => {
const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCountByType_FX', {
...defaultParams,
...params,
COLI_ApplyDate1: params.Date1,
COLI_ApplyDate2: params.Date2,
COLI_ApplyDateOld1: params.DateDiff1 || '',
COLI_ApplyDateOld2: params.DateDiff2 || '',
OrderType: type,
});
const res = errcode !== 0 ? _typeRes : (result || _typeRes);
const rows1Map = res.ordercount1.reduce((a, row1) => ({ ...a, [row1.OrderTypeSN]: {...row1, YJLYx: price_to_number(row1.YJLY)} }), {});
const rows2Map = res.ordercount2.reduce((a, row2) => ({ ...a, [row2.OrderTypeSN]: {...row2, YJLYx: price_to_number(row2.YJLY)} }), {});
const mixRow1 = res.ordercount1.map((row1) => ({ ...row1, YJLYx: price_to_number(row1.YJLY), diff: rows2Map[row1.OrderTypeSN] || {} }));
// Diff: elements in rows2 but not in rows1
const diff = [...new Set(Object.keys(rows2Map).filter((x) => !new Set(Object.keys(rows1Map)).has(x)))];
mixRow1.push(...diff.map((sn) => ({ diff: rows2Map[sn], OrderType: rows2Map[sn].OrderType, OrderTypeSN: rows2Map[sn].OrderTypeSN })));
return { ...res, ordercount1: mixRow1, ordercount2: res.ordercount2.map((row1) => ({ ...row1, YJLYx: price_to_number(row1.YJLY), })) };
};
const _detailRes = { ordercount1: [], ordercount2: [] };
export const fetchToBOrderDetailByType = async (params, type = '', typeVal = '', orderContent = 'detail') => {
const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCountByType_Sub_FX', {
...defaultParams,
SubOrderType: orderContent,
...params,
COLI_ApplyDate1: params.Date1,
COLI_ApplyDate2: params.Date2,
COLI_ApplyDateOld1: params.DateDiff1 || '',
COLI_ApplyDateOld2: params.DateDiff2 || '',
OrderType: type,
OrderType_val: typeVal,
});
const res = errcode !== 0 ? _detailRes : (result || _detailRes);
const dateStr = [params.Date1, params.Date2].map((d) => d.substring(0, 10)).join('~');
const dateDiffStr = isEmpty(params.DateDiff1) ? '' : [params.DateDiff1, params.DateDiff2].map((d) => d.substring(0, 10)).join('~');
const ret = [
{ dateRangeStr: dateStr, data: res.ordercount1 },
{ dateRangeStr: dateDiffStr, data: res.ordercount2 },
];
return ret;
};
const calculateLineData = (value, data, avg1) => {
const groupByDate = data.reduce((r, v) => {
(r[v.ApplyDate] || (r[v.ApplyDate] = [])).push(v);
return r;
}, {});
const _data = Object.keys(groupByDate)
.reduce((r, _d) => {
const xAxisGroup = groupByDate[_d].reduce((a, v) => {
(a[v.groups] || (a[v.groups] = [])).push(v);
return a;
}, {});
Object.keys(xAxisGroup).map((_group) => {
const summaryVal = xAxisGroup[_group].reduce((rows, row) => rows + row.orderCount, 0);
r.push({ ...xAxisGroup[_group][0], orderCount: summaryVal });
return _group;
});
return r;
}, [])
.map((row) => ({ xField: row.ApplyDate, yField: row.orderCount, seriesField: row.groups }));
return { lines: _data, dateRadioValue: value, avgLineValue: avg1 };
};
export const orderCountDataMapper = { 'data1': 'ordercount1', data2: 'ordercount2' };
export const orderCountDataFieldMapper = { 'dateKey': 'ApplyDate', 'valueKey': 'orderCount', 'seriesKey': 'id', _f: 'sum' };
/**
* --------------------------------------------------------------------------------------------------------
*/
const initialState = {
loading: false,
typeLoading: false,
searchValues: {
DateType: { key: 'applyDate', label: '提交日期' },
WebCode: { key: 'all', label: '所有来源' },
IncludeTickets: { key: '1', label: '含门票' },
DepartmentList: groupsMappedByCode.GH, // { key: 'All', label: '所有来源' }, //
},
searchValuesToSub: {
DateType: 'applyDate',
WebCode: 'all',
IncludeTickets: '1',
DepartmentList: -1, // -1: All
},
activeTab: 'customer_types',
activeDateGroupRadio: 'day',
orderCountDataRaw: {},
orderCountDataLines: [],
avgLineValue: 0,
orderCountDataByType: {},
// 二级页面
orderCountDataRawSub: {},
orderCountDataLinesSub: [],
avgLineValueSub: 0,
activeDateGroupRadioSub: 'day',
orderDetails: [],
};
const useToBOrderStore = create(
devtools(
immer((set, get) => ({
...initialState,
reset: () => set(initialState),
setLoading: (loading) => set({ loading }),
setTypeLoading: (typeLoading) => set({ typeLoading }),
setSearchValues: (obj, values) => set((state) => ({ searchValues: values, searchValuesToSub: obj })),
setSearchValuesToSub: (values) => set((state) => ({ searchValuesToSub: values })),
setActiveTab: (tab) => set({ activeTab: tab }),
setOrderCountDataLines: (data) => set({ orderCountDataLines: data }),
setOrderCountDataByType: (type, data) =>
set((state) => {
state.orderCountDataByType[type] = data;
}),
// data ----
onChangeDateGroup: (value, data, avg1) => {
const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1);
set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue });
},
onChangeDateGroupSub: (value, data, avg1) => {
const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1);
set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue });
},
// site effects
getToBOrderCount: async (params, type, typeVal) => {
const { setLoading } = get();
setLoading(true);
try {
const res = await fetchToBOrderCount(params, type, typeVal);
// 第一次得到数据
const { lines, dateRadioValue, avgLineValue } = resultDataCb(res, 'day', orderCountDataMapper, orderCountDataFieldMapper, calculateLineData);
if (isEmpty(type)) {
// index page
set({ orderCountDataRaw: res });
set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue });
} else {
// sub page
set({ orderCountDataRawSub: res });
set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue });
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
},
getToBOrderCount_type: async (type) => {
const { setTypeLoading, searchValuesToSub, setOrderCountDataByType } = get();
setTypeLoading(true);
try {
const res = await fetchToBOrderCountByType(type, searchValuesToSub);
setOrderCountDataByType(type, res);
} catch (error) {
console.error(error);
} finally {
setTypeLoading(false);
}
},
onTabChange: async (tab) => {
const { setActiveTab, getToBOrderCount_type } = get();
setActiveTab(tab);
await getToBOrderCount_type(tab);
},
// sub
getToBOrderDetailByType: async (params, type, typeVal) => {
const { setTypeLoading } = get();
try {
setTypeLoading(true);
const res = await fetchToBOrderDetailByType(params, type, typeVal, 'detail');
set({ orderDetails: res });
} catch (error) {
console.error(error);
} finally {
setTypeLoading(false);
}
},
})),
{ name: 'ToBOrder' }
)
);
export default useToBOrderStore;
Loading…
Cancel
Save