diff --git a/src/components/StatisticCard2.jsx b/src/components/StatisticCard2.jsx new file mode 100644 index 0000000..ac6a624 --- /dev/null +++ b/src/components/StatisticCard2.jsx @@ -0,0 +1,128 @@ +import { useContext, useState } from 'react'; +import { observer } from 'mobx-react'; +import { StatisticCard } from '@ant-design/pro-components'; +import { RingProgress, Progress, Bullet, } from '@ant-design/plots'; +import RcResizeObserver from 'rc-resize-observer'; +import { stores_Context } from '../config'; +import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons'; +import { Table } from 'antd'; + +const { Statistic, Divider } = StatisticCard; + +export default observer((props) => { + const { icon, traditional, biz, kpiVal, originVal, ...extProps } = props; + const ValueIcon = props.icon; + const valueStyle = { color: (props?.VSrate || -1) < 0 ? '#3f8600' : '#cf1322' }; + const VSIcon = () => ((props?.VSrate || -1) < 0 ? : ); + console.log(props, ';;;;'); + const [responsive, setResponsive] = useState(false); + const bulletData = [ + { + title: '', + // ranges: [0, kpiVal || (traditional.value + biz.value + 100 )], + ranges: [0, Math.ceil(originVal*1.1)], + measures: [traditional.value, biz.value], + target: kpiVal || 0, + }, + ]; + console.log(bulletData, 'bbbbbbbbb'); + + const RingProgressConfigBlue = { + height: 60, + width: 60, + autoFit: false, + color: ['#5B8FF9', '#E8EDF3'], + label: false, + }; + const RingProgressConfigGreen = { + height: 50, + width: 50, + autoFit: false, + // color: ['#f6bd16', '#E8EDF3'], + color: ['#61ddaa', '#E8EDF3'], // #7cb305 + // innerRadius: 0.90, + }; + + const bulletConfig = { + // data, + measureField: 'measures', + rangeField: 'ranges', + targetField: 'target', + xField: 'title', + // autoFit: false, + // width: 20, + height: 60, + // renderer: 'svg', + color: { + range: [ '#E8EDF3', '#FFF3E1'], + // range: ['#FFbcb8', '#FFe0b0', '#bfeec8'], + measure: ['#5B8FF9', '#61DDAA'], + target: '#39a3f4', + }, + label: { + measure: { + position: 'middle', + style: { + fill: '#fff', + }, + }, + }, + xAxis: { + line: null, + label: false, + }, + yAxis: false, + tooltip: false, + // 自定义 legend + legend: false, + }; + return ( + { + setResponsive(offset.width < 596); + }} + > + + , + }} + chart={} + /> + {false && <> + {/* {props.childrenVisible && <> */} + + , + }} + chart={} + chartPlacement="left" + /> + , + }} + chart={百分比} + chartPlacement="left" + /> + } + + + ); +}); diff --git a/src/stores/Trade.js b/src/stores/Trade.js index 5524272..5dab423 100644 --- a/src/stores/Trade.js +++ b/src/stores/Trade.js @@ -12,43 +12,72 @@ class Trade { /** * 年度总额 */ - fetchSummaryData(queryData) { + async fetchSummaryData(queryData) { this.summaryData.loading = true; queryData.groupType = queryData?.groupType || 'overview'; queryData.groupDateType = 'year'; - this.fetchTradeData(queryData).then((json) => { - if (json.errcode === 0) { + const multiData = await this.fetchTradeDataAll(queryData); + console.log(multiData, 'mmmmmmmm', queryData); + // this.fetchTradeData(queryData).then((json) => { + const { summary, traditional, biz } = multiData.result1; + const summaryData = { + loading: false, + dataSource: [ + { + title: '成团', + value: summary?.[0]?.ConfirmOrder, + originVal: (summary?.[0]?.ConfirmOrder || 0), + valueSuffix: summary?.[0]?.ConfirmRates ? ` / ${summary?.[0]?.ConfirmRates} %` : undefined, + // VSrate: summary?.[0]?.ConfirmOrderrate, + KPIrate: summary?.[0]?.[dataFieldAlias.ConfirmOrder.nestkey.p], + // hasKPI: !isEmpty(summary?.[0]?.[dataFieldAlias.ConfirmOrder.nestkey.p]), + hasKPI: false, + childrenVisible: true, + kpiVal: summary?.[0]?.[dataFieldAlias.ConfirmOrder.nestkey.v], + traditional: { title: '传统', value: traditional?.[0]?.ConfirmOrder }, + biz: { title: '商务', value: biz?.[0]?.ConfirmOrder }, + }, + { + title: '毛利', + originVal: (summary?.[0]?.SumML || 0), + value: dataFieldAlias.SumML.formatter(summary?.[0]?.SumML || 0) + '=' + dataFieldAlias.SumML.formatter((traditional?.[0]?.SumML || 0)) + '+' + dataFieldAlias.SumML.formatter((biz?.[0]?.SumML || 0)), + KPIrate: summary?.[0]?.[dataFieldAlias.SumML.nestkey.p], + hasKPI: false, + childrenVisible: true, + kpiVal: summary?.[0]?.[dataFieldAlias.SumML.nestkey.v], + traditional: { title: '传统', value: (traditional?.[0]?.SumML || 0) }, + biz: { title: '商务', value: (biz?.[0]?.SumML || 0) }, + }, + { + title: '完成率', + originVal: (summary?.[0]?.[dataFieldAlias.SumML.nestkey.p] || 0), + value: `${summary?.[0]?.[dataFieldAlias.SumML.nestkey.p] || ''}%`, + hasKPI: false, + childrenVisible: false, + kpiVal: 0 , // summary?.[0]?.[dataFieldAlias.SumML.nestkey.p], + traditional: { title: '传统', value: traditional?.[0]?.[dataFieldAlias.SumML.nestkey.p] || 0, }, + biz: { title: '商务', value: biz?.[0]?.[dataFieldAlias.SumML.nestkey.p] || 0, }, + }, + { + title: '人数', + originVal: (summary?.[0]?.SumPersonNum || 0), + value: summary?.[0]?.SumPersonNum, + // VSrate: summary?.[0]?.SumPersonNumrate, + // KPIrate: summary?.[0]?.[dataFieldAlias.SumPersonNum.nestkey.p], + hasKPI: false, // // !isEmpty(summary?.[0]?.[dataFieldAlias.SumPersonNum.nestkey.p]),, + childrenVisible: true, + // kpiVal: summary?.[0]?.[dataFieldAlias.SumPersonNum.nestkey.v], + traditional: { title: '传统', value: traditional?.[0]?.SumPersonNum, }, + biz: { title: '商务', value: biz?.[0]?.SumPersonNum, }, + }, + ], + }; runInAction(() => { - const summary = json.result1?.[0] || {}; - const summaryData = { - loading: false, - dataSource: [ - { - title: '成团', - value: summary?.ConfirmOrder, - valueSuffix: summary?.ConfirmRates ? ` / ${summary.ConfirmRates} %` : undefined, - // VSrate: summary?.ConfirmOrderrate, - KPIrate: summary?.[dataFieldAlias.ConfirmOrder.nestkey.p], - // hasKPI: !isEmpty(summary?.[dataFieldAlias.ConfirmOrder.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?.SumPersonNum, - // VSrate: summary?.SumPersonNumrate, - // KPIrate: summary?.[dataFieldAlias.SumPersonNum.nestkey.p], - hasKPI: false, // // !isEmpty(summary?.[dataFieldAlias.SumPersonNum.nestkey.p]), - }, - ], - }; this.summaryData = summaryData; - const kpi = { label: '', value: summary.MLKPIvalue }; + const kpi = { label: '', value: summary?.[0]?.MLKPIvalue }; this.summaryData.kpi = kpi; }); - } - }); + // }); } /** @@ -157,14 +186,56 @@ class Trade { } /** - * 获取业绩数据 + * 获取业绩数据: 传统订单 */ async fetchTradeData(queryData) { const json = await req.fetchJSON('/service-Analyse2/GetTradeProcess', queryData); - if (json.errcode === 0) { - return json; - } - return null; + // if (json.errcode === 0) { + // return json; + // } + return json; + } + + /** + * 获取业绩数据: 商务订单 + */ + async fetchTradeDataBiz(queryData) { + const json = await req.fetchJSON('/service-Analyse2/GetTradeProcess_biz', queryData); + // if (json.errcode === 0) { + // return json; + // } + return json; + } + + /** + * 合并传统和商务 + */ + async fetchTradeDataAll(queryData) { + const traditional = await this.fetchTradeData(queryData); + const biz = await this.fetchTradeDataBiz(queryData); + const rr = ['result1', 'result2'].reduce((res, resKey) => { + const mergeItem = { traditional: traditional[resKey], biz: biz[resKey] }; + const mergeRes = [].concat(traditional[resKey], biz[resKey]); + // const kpiKeys = []; + const groupsData = mergeRes.reduce((r, v) => { + if (v.groupsLabel ) { + (r[v.groupsLabel] || (r[v.groupsLabel] = [])).push(v); + } + return r; + }, {}); + const summary = Object.keys(groupsData).map(groupsKey => { + return ['ConfirmOrder', 'SumOrder', 'SumML', 'transactions', 'SumPersonNum'].reduce( + (r, skey) => ({ ...r, [skey]: groupsData[groupsKey].reduce((a, c) => a + c[skey], 0) }), + groupsData[groupsKey]?.[0] || {} + ); + }).map(row => ({...row, + ConfirmRates: fixTo2Decimals((row.ConfirmOrder/row.SumOrder)*100), + MLKPIrates: fixTo2Decimals((row.SumML/row.MLKPIvalue)*100), + // todo: + })); + return Object.assign(res, { [resKey]: Object.assign({}, mergeItem, { summary }) }); + }, {}); + return rr; } /** diff --git a/src/views/Home.jsx b/src/views/Home.jsx index d798a40..c60c94a 100644 --- a/src/views/Home.jsx +++ b/src/views/Home.jsx @@ -5,6 +5,7 @@ import { CheckCircleTwoTone, MoneyCollectTwoTone, FlagTwoTone, SmileTwoTone } fr import { stores_Context } from '../config'; import { useNavigate } from 'react-router-dom'; import StatisticCard from '../components/StatisticCard'; +import StatisticCard2 from '../components/StatisticCard2'; import Bullet from '../components/BulletWithSort'; import Waterfall from '../components/Waterfall'; import LineWithKPI from '../components/LineWithKPI'; @@ -54,7 +55,7 @@ export default observer(() => { TradeStore.fetchTradeDataByDate(queryData); TradeStore.fetchTradeDataByBU(queryData); TradeStore.fetchTradeDataByMonth(queryData); - const topSeriesF = _overviewFlag ? topSeries : topSeries.filter(ele => ele.key !== 'dept'); + const topSeriesF = _overviewFlag ? topSeries : topSeries.filter((ele) => ele.key !== 'dept'); setTopSeriesSet(topSeriesF); setOverviewFlag(_overviewFlag); for (const iterator of topSeriesF) { @@ -154,7 +155,7 @@ export default observer(() => { tooltip: { customItems: (originalItems) => { // process originalItems, - const items = originalItems.map((ele) => ({ ...ele, name: ele.data?.extraLine ? ele.name : (dataFieldAlias[key]?.alias || key) })); + const items = originalItems.map((ele) => ({ ...ele, name: ele.data?.extraLine ? ele.name : dataFieldAlias[key]?.alias || key })); return items; }, }, @@ -165,7 +166,7 @@ export default observer(() => { setDateField(value); TradeStore.setTimeLineKey(value); if (!isEmpty(TradeStore.searchPayloadHome)) { - TradeStore.fetchTradeDataByDate({groupType: groupTypeVal}); + TradeStore.fetchTradeDataByDate({ groupType: groupTypeVal }); } }; return ( @@ -194,14 +195,19 @@ export default observer(() => {
-

年度业绩

+

年度业绩=传统+商务

- {summaryData.dataSource.map((item, i) => ( + {/* {summaryData.dataSource.map((item, i) => ( + ))} */} + {summaryData.dataSource.map((item, i) => ( + + + ))}