style: 统计分布; 首页

feature/2.0-sales-trade
Lei OT 2 years ago
parent c96c23a96e
commit aec35604ee

@ -198,7 +198,7 @@ export default observer((props) => {
// layout="inline" // layout="inline"
<Form form={form} name="advanced_search" className="orders-search-form" onFinish={onFinish} onValuesChange={onValuesChange}> <Form form={form} name="advanced_search" className="orders-search-form" onFinish={onFinish} onValuesChange={onValuesChange}>
<EditableContext.Provider value={form}> <EditableContext.Provider value={form}>
<Row gutter={10} style={{ background: '#f9fafa', margin: '0px 0px 10px 0px', padding: '16px 8px' }}> <Row gutter={10} style={{ background: '#f9fafa', margin: '0px 0px 10px 0px', padding: '16px 8px', boxShadow: '0px 0px 3px 0px rgba(0,0,0,0.15)' }}>
{getFields({ sort, initialValue, hides, shows, fieldProps, form })} {getFields({ sort, initialValue, hides, shows, fieldProps, form })}
{/* 'textAlign': 'right' */} {/* 'textAlign': 'right' */}
<Col flex="1 0 120px" style={{ padding: '0px 5px' }}> <Col flex="1 0 120px" style={{ padding: '0px 5px' }}>

@ -5,14 +5,14 @@ import moment from 'moment';
import { isEmpty, pick, sortBy, fixTo2Decimals, cloneDeep, unique } from '../utils/commons'; import { isEmpty, pick, sortBy, fixTo2Decimals, cloneDeep, unique } from '../utils/commons';
const modelMapper = { const modelMapper = {
'tourDays': { url: '/service-Analyse2/GetTradeApartByTourDays' }, 'tourDays': { url: '/service-Analyse2/GetTradeApartByTourDays', keySort: true },
'PML': { url: '/service-Analyse2/GetTradeApartByPML' }, 'PML': { url: '/service-Analyse2/GetTradeApartByPML', keySort: true },
'ConfirmDays': { url: '/service-Analyse2/GetTradeApartByConfirmDays' }, 'ConfirmDays': { url: '/service-Analyse2/GetTradeApartByConfirmDays', keySort: true },
'ApplyDays': { url: '/service-Analyse2/GetTradeApartByApplyDays' }, 'ApplyDays': { url: '/service-Analyse2/GetTradeApartByApplyDays', keySort: true },
'PersonNum': { url: '/service-Analyse2/GetTradeApartByPersonNum' }, 'PersonNum': { url: '/service-Analyse2/GetTradeApartByPersonNum', keySort: true },
'destination': { url: '/service-Analyse2/GetTradeApartByDestination' }, 'destination': { url: '/service-Analyse2/GetTradeApartByDestination', keySort: false },
'GlobalDestination': { url: '/service-Analyse2/GetTradeApartByGlobalDestination' }, 'GlobalDestination': { url: '/service-Analyse2/GetTradeApartByGlobalDestination', keySort: false },
'destinationCountry': { url: '/service-Analyse2/GetTradeApartByDestinationCountry' }, 'destinationCountry': { url: '/service-Analyse2/GetTradeApartByDestinationCountry', keySort: false },
}; };
class Distribution { class Distribution {
constructor(appStore) { constructor(appStore) {
@ -41,12 +41,13 @@ class Distribution {
param.DateToQ2 = DateToQ2.format(`${DATE_FORMAT} 23:59:59`); param.DateToQ2 = DateToQ2.format(`${DATE_FORMAT} 23:59:59`);
const json = await req.fetchJSON(modelMapper[mkey].url, param); const json = await req.fetchJSON(modelMapper[mkey].url, param);
if (json.errcode === 0) { if (json.errcode === 0) {
const dataLength = json.result.length;
const pickResult = dataLength > 20 ? json.result.slice(0, 30) : json.result;
const dataSource = calcDiff({ result: pickResult, resultToY: json.resultToY, resultToQ: json.resultToQ }, modelMapper[mkey].keySort);
runInAction(() => { runInAction(() => {
const dataLength = json.result.length;
this[mkey].loading = false; this[mkey].loading = false;
this[mkey].originData = json.result; this[mkey].originData = json.result;
const pickResult = dataLength > 20 ? json.result.slice(0, 30) : json.result; this[mkey].dataSource = dataSource;
this[mkey].dataSource = calcDiff({ result: pickResult, resultToY: json.resultToY, resultToQ: json.resultToQ });
this.pageLoading = false; this.pageLoading = false;
}); });
} }
@ -118,15 +119,14 @@ class Distribution {
/** /**
* 计算 同比, 环比 * 计算 同比, 环比
*/ */
const calcDiff = ({ result, resultToY, resultToQ }) => { const calcDiff = ({ result, resultToY, resultToQ }, keySort) => {
if (isEmpty(resultToY) || isEmpty(resultToQ)) { const initialDataWithAllKeys = unique([].concat(result, resultToY, resultToQ).map((ele) => `${ele.key}@${ele.label}`))
// return result; .reduce((r, v) => {
} const [key, label] = String(v).split('@');
const initialDataWithAllKeys = unique([].concat(result, resultToY, resultToQ).map((ele) => `${ele.key}@${ele.label}`)).reduce((r, v) => { r.push({ key: Number(key), label, SumML: 0, ConfirmOrder: 0, SumOrder: 0, SumMLPercent: 0, ConfirmOrderPercent: 0, SumOrderPercent: 0 });
const [key, label] = String(v).split('@'); return r;
r.push({key: Number(key), label, SumML: 0, ConfirmOrder: 0, SumOrder: 0, SumMLPercent: 0, ConfirmOrderPercent: 0, SumOrderPercent: 0}); }, [])
return r; .sort(keySort ? sortBy('key') : undefined);
}, []).sort(sortBy('key'));
const initialMapped = initialDataWithAllKeys.reduce((r, v) => ({ ...r, [v.key]: v }), {}); const initialMapped = initialDataWithAllKeys.reduce((r, v) => ({ ...r, [v.key]: v }), {});
const resultMapped = result.reduce((r, v) => ({ ...r, [v.key]: v }), cloneDeep(initialMapped)); const resultMapped = result.reduce((r, v) => ({ ...r, [v.key]: v }), cloneDeep(initialMapped));
const resultToYMapped = resultToY.reduce((r, v) => ({ ...r, [v.key]: v }), cloneDeep(initialMapped)); const resultToYMapped = resultToY.reduce((r, v) => ({ ...r, [v.key]: v }), cloneDeep(initialMapped));

@ -32,7 +32,7 @@ class Trade {
// hasKPI: !isEmpty(summary?.[dataFieldAlias.ConfirmOrder.nestkey.p]), // hasKPI: !isEmpty(summary?.[dataFieldAlias.ConfirmOrder.nestkey.p]),
hasKPI: false hasKPI: false
}, },
{ title: '毛利', value: summary?.SumML, KPIrate: summary?.[dataFieldAlias.SumML.nestkey.p], hasKPI: false }, { title: '毛利', value: dataFieldAlias.SumML.formatter(summary?.SumML || 0), KPIrate: summary?.[dataFieldAlias.SumML.nestkey.p], hasKPI: false },
{ title: '完成率', value: `${summary?.[dataFieldAlias.SumML.nestkey.p] || ''}%`, hasKPI: false }, { title: '完成率', value: `${summary?.[dataFieldAlias.SumML.nestkey.p] || ''}%`, hasKPI: false },
{ {
title: '人数', title: '人数',

@ -61,12 +61,14 @@ export default observer(() => {
autoFit: false, autoFit: false,
// color: ['#f6bd16', '#E8EDF3'], // color: ['#f6bd16', '#E8EDF3'],
color: ['#61ddaa', '#E8EDF3'], // #7cb305 color: ['#61ddaa', '#E8EDF3'], // #7cb305
innerRadius: 0.90,
}; };
const RingProgressConfigQ = { const RingProgressConfigQ = {
height: 50, height: 50,
width: 50, width: 50,
autoFit: false, autoFit: false,
color: ['#f6bd16', '#E8EDF3'], color: ['#f6bd16', '#E8EDF3'],
innerRadius: 0.90,
}; };
const columns = [ const columns = [
{ title: '', dataIndex: 'label' }, { title: '', dataIndex: 'label' },
@ -76,7 +78,7 @@ export default observer(() => {
render: (v, r) => ( render: (v, r) => (
<> <>
<Row align={'middle'}> <Row align={'middle'}>
<Col flex="1 1 100px"> <Col flex={"150px"}>
<Text strong>{v}</Text> <Text strong>{v}</Text>
</Col> </Col>
<Col flex={'auto'}> <Col flex={'auto'}>
@ -99,7 +101,7 @@ export default observer(() => {
render: (v, r) => ( render: (v, r) => (
<> <>
<Row align={'middle'}> <Row align={'middle'}>
<Col flex="1 1 100px"> <Col flex={"150px"}>
<Text strong>{dataFieldAlias.SumML.formatter(v)}</Text> <Text strong>{dataFieldAlias.SumML.formatter(v)}</Text>
</Col> </Col>
<Col flex={'auto'}> <Col flex={'auto'}>
@ -119,12 +121,12 @@ export default observer(() => {
{ {
title: '团数占比', title: '团数占比',
dataIndex: 'ConfirmOrderPercent', dataIndex: 'ConfirmOrderPercent',
render: (v, r) => <RingProgress {...RingProgressConfig} percent={v / 100} />, render: (v, r) => v ? <RingProgress {...RingProgressConfig} percent={v / 100} /> : '-',
}, },
{ {
title: '业绩占比', title: '业绩占比',
dataIndex: 'SumMLPercent', dataIndex: 'SumMLPercent',
render: (v, r) => <RingProgress {...RingProgressConfig} percent={v / 100} />, render: (v, r) => v ? <RingProgress {...RingProgressConfig} percent={v / 100} /> : '-',
}, },
{ {
title: () => <><div>去年同期</div><div>{dateStringY}</div></>, title: () => <><div>去年同期</div><div>{dateStringY}</div></>,
@ -134,13 +136,13 @@ export default observer(() => {
title: '团数占比', title: '团数占比',
width: 90, width: 90,
dataIndex: 'ConfirmOrderPercent', dataIndex: 'ConfirmOrderPercent',
render: (v, r) => <RingProgress {...RingProgressConfigY} percent={r.resultToY.ConfirmOrderPercent / 100} />, render: (v, r) => r.resultToY.ConfirmOrderPercent ? <RingProgress {...RingProgressConfigY} percent={r.resultToY.ConfirmOrderPercent / 100} /> : '-',
}, },
{ {
title: '业绩占比', title: '业绩占比',
width: 90, width: 90,
dataIndex: 'SumMLPercent', dataIndex: 'SumMLPercent',
render: (v, r) => <RingProgress {...RingProgressConfigY} percent={r.resultToY.SumMLPercent / 100} />, render: (v, r) => r.resultToY.SumMLPercent ? <RingProgress {...RingProgressConfigY} percent={r.resultToY.SumMLPercent / 100} /> : '-',
}, },
], ],
}, },
@ -152,13 +154,13 @@ export default observer(() => {
title: '团数占比', title: '团数占比',
width: 90, width: 90,
dataIndex: 'ConfirmOrderPercent', dataIndex: 'ConfirmOrderPercent',
render: (v, r) => <RingProgress {...RingProgressConfigQ} percent={r.resultToQ.ConfirmOrderPercent / 100} />, render: (v, r) => r.resultToQ.ConfirmOrderPercent ? <RingProgress {...RingProgressConfigQ} percent={r.resultToQ.ConfirmOrderPercent / 100} /> : '-',
}, },
{ {
title: '业绩占比', title: '业绩占比',
width: 90, width: 90,
dataIndex: 'SumMLPercent', dataIndex: 'SumMLPercent',
render: (v, r) => <RingProgress {...RingProgressConfigQ} percent={r.resultToQ.SumMLPercent / 100} />, render: (v, r) => r.resultToQ.SumMLPercent ? <RingProgress {...RingProgressConfigQ} percent={r.resultToQ.SumMLPercent / 100} /> : '-',
}, },
], ],
}, },

@ -17,11 +17,11 @@ import { Line } from '@ant-design/charts';
import './home.css'; import './home.css';
const topSeries = [ const topSeries = [
{ key: 'country', label: '国籍' }, { key: 'country', label: '国籍', graphVisible: true },
{ key: 'dept', label: '小组' }, { key: 'dept', label: '小组', graphVisible: true },
{ key: 'operator', label: '顾问' }, { key: 'operator', label: '顾问', graphVisible: true },
{ key: 'GuestGroupType', label: '客群类别' }, { key: 'GuestGroupType', label: '客群类别', graphVisible: false },
{ key: 'destination', label: '目的地' }, { key: 'destination', label: '目的地', graphVisible: true },
]; ];
// const iconSets = [CheckCircleTwoTone, <MoneyCollectTwoTone />, <FlagTwoTone />, <ClockCircleTwoTone />, <DashboardTwoTone />,<SmileTwoTone />,]; // const iconSets = [CheckCircleTwoTone, <MoneyCollectTwoTone />, <FlagTwoTone />, <ClockCircleTwoTone />, <DashboardTwoTone />,<SmileTwoTone />,];
@ -160,7 +160,7 @@ export default observer(() => {
}; };
return ( return (
<> <>
<Row gutter={16} style={{ margin: '-16px -8px' }}> <Row gutter={16} style={{ margin: '-16px -8px', position: 'sticky', top: 0, zIndex: 2, }}>
{/* style={{ margin: '-16px -8px', padding: 0 }} */} {/* style={{ margin: '-16px -8px', padding: 0 }} */}
<Col className="gutter-row" span={24}> <Col className="gutter-row" span={24}>
<SearchForm <SearchForm
@ -239,14 +239,14 @@ export default observer(() => {
</div> </div>
</Space> </Space>
<Row gutter={layoutProps.gutter}> <Row gutter={layoutProps.gutter}>
{topSeries.map((item) => ( {topSeries.map((item) => item.graphVisible ? (
<Col {...layoutProps} key={item.key}> <Col {...layoutProps} key={item.key}>
<Spin spinning={topData[item.key]?.loading || false}> <Spin spinning={topData[item.key]?.loading || false}>
<h3 style={{ textAlign: 'center' }}>{item.label}</h3> <h3 style={{ textAlign: 'center' }}>{item.label}</h3>
<Bullet {...BulletConfig} dataSource={topData[item.key]?.dataSource || []} itemLength={10} /> <Bullet {...BulletConfig} dataSource={topData[item.key]?.dataSource || []} itemLength={10} />
</Spin> </Spin>
</Col> </Col>
))} ) : null)}
</Row> </Row>
</section> </section>
</> </>

Loading…
Cancel
Save