diff --git a/src/components/Donut.jsx b/src/components/Donut.jsx
new file mode 100644
index 0000000..a18447a
--- /dev/null
+++ b/src/components/Donut.jsx
@@ -0,0 +1,84 @@
+import { observer } from 'mobx-react';
+import { Pie, measureTextWidth } from '@ant-design/plots';
+import { fixTo2Decimals, merge } from '../utils/commons';
+import { dataFieldAlias } from './../libs/ht';
+
+export default observer((props) => {
+ const { dataSource, title, ...extProps } = props;
+
+ const renderStatistic = (containerWidth, text, style) => {
+ const { width: textWidth, height: textHeight } = measureTextWidth(text, style);
+ const R = containerWidth / 2; // r^2 = (w / 2)^2 + (h - offsetY)^2
+ let scale = 1;
+ if (containerWidth < textWidth) {
+ scale = Math.min(Math.sqrt(Math.abs(Math.pow(R, 2) / (Math.pow(textWidth / 2, 2) + Math.pow(textHeight, 2)))), 1);
+ }
+ const textStyleStr = `width:${containerWidth}px;`;
+ return `
${text}
`;
+ };
+
+ const config = merge(
+ {
+ appendPadding: 10,
+ // angleField: 'value',
+ // colorField: 'type',
+ radius: 0.7,
+ innerRadius: 0.65,
+ label: {
+ type: 'inner',
+ offset: '-50%',
+ autoRotate: false,
+ // content: '{value}',
+ content: ({ percent }) => `${fixTo2Decimals(percent * 100)}%`,
+ style: {
+ textAlign: 'center',
+ fontSize: 14,
+ },
+ },
+ interactions: [{ type: 'element-selected' }, { type: 'element-active' }, { type: 'pie-statistic-active' }],
+ statistic: {
+ title: {
+ offsetY: -4,
+ customHtml: (container, view, datum) => {
+ const { width, height } = container.getBoundingClientRect();
+ const d = Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height / 2, 2));
+ const text = datum ? datum[extProps.colorField] : (title || '');
+ return renderStatistic(d, text, {
+ fontSize: '28px',
+ });
+ },
+ },
+ content: {
+ // style: {
+ // whiteSpace: 'pre-wrap',
+ // overflow: 'hidden',
+ // textOverflow: 'ellipsis',
+ // },
+ // content: title || '',
+ offsetY: 4,
+ style: {
+ fontSize: '28px',
+ },
+ customHtml: (container, view, datum, data) => {
+ const { width } = container.getBoundingClientRect();
+ const _sum = data.reduce((r, d) => r + d[extProps.angleField], 0);
+ const showVal = datum ? datum[extProps.angleField] : _sum;
+ const text = dataFieldAlias[extProps.angleField].formatter(showVal);
+ return renderStatistic(width, text, {
+ fontSize: '28px',
+ });
+ },
+
+ },
+ },
+ meta: {
+ [extProps.angleField]: {
+ alias: dataFieldAlias[extProps.angleField]?.alias || extProps.angleField,
+ formatter: (v) => dataFieldAlias[extProps.angleField]?.formatter(v) || v,
+ },
+ },
+ },
+ extProps
+ );
+ return ;
+});
diff --git a/src/components/LineWithKPI.jsx b/src/components/LineWithKPI.jsx
index ee8a813..50d196a 100644
--- a/src/components/LineWithKPI.jsx
+++ b/src/components/LineWithKPI.jsx
@@ -24,7 +24,7 @@ const uniqueByKey = (array, key, pickLast) => {
};
export default observer((props) => {
- const { config, dataSource, ...extProps } = props;
+ const { dataSource, ...config } = props;
const kpiKey = dataFieldAlias[config.yField]?.nestkey?.v;
const _data = dataSource.reduce((r, v) => {
r.push(v);
diff --git a/src/components/Waterfall.jsx b/src/components/Waterfall.jsx
index 87bf2ec..9e55075 100644
--- a/src/components/Waterfall.jsx
+++ b/src/components/Waterfall.jsx
@@ -1,7 +1,7 @@
import { observer } from 'mobx-react';
import { Waterfall } from '@ant-design/plots';
import { dataFieldAlias } from './../libs/ht';
-import { merge } from '../utils/commons';
+import { fixTo4Decimals, merge } from '../utils/commons';
export default observer((props) => {
const { dataSource, line, title, ...extProps } = props;
@@ -11,7 +11,7 @@ export default observer((props) => {
{
type: 'text',
position: ['start', line.value],
- content: `${line.label} ${line.value / 10000} 万`,
+ content: `${line.label} ${fixTo4Decimals(line.value / 10000)} 万`,
// offsetX: -15,
style: {
fill: '#F4664A',
diff --git a/src/libs/ht.js b/src/libs/ht.js
index b3e840a..c7274c1 100644
--- a/src/libs/ht.js
+++ b/src/libs/ht.js
@@ -1,3 +1,5 @@
+import { fixTo4Decimals } from "../utils/commons";
+
/**
* 事业部
*/
@@ -95,8 +97,8 @@ export const dateTypes = [
* 结果字段
*/
export const dataFieldOptions = [
- { label: '营收', value: 'transactions', formatter: (v) => `${v / 10000} 万`, nestkey: { p: 'transactionsKPIrates', v: 'transactionsKPIvalue' } },
- { label: '毛利', value: 'SumML', formatter: (v) => `${v / 10000} 万`, nestkey: { p: 'MLKPIrates', v: 'MLKPIvalue' } },
+ { label: '营收', value: 'transactions', formatter: (v) => `${fixTo4Decimals(v / 10000)} 万`, nestkey: { p: 'transactionsKPIrates', v: 'transactionsKPIvalue' } },
+ { label: '毛利', value: 'SumML', formatter: (v) => `${fixTo4Decimals(v / 10000)} 万`, nestkey: { p: 'MLKPIrates', v: 'MLKPIvalue' } },
{ label: '订单数', value: 'SumOrder', formatter: (v) => v, nestkey: { p: 'OrderKPIrates', v: 'OrderKPIvalue' } },
{ label: '成交数', value: 'ConfirmOrder', formatter: (v) => v, nestkey: { p: 'ConfirmOrderKPIrates', v: 'ConfirmOrderKPIvalue' } },
{ label: '成交率', value: 'ConfirmRates', formatter: (v) => `${v} %`, nestkey: { p: 'ConfirmRatesKPIrates', v: 'ConfirmRatesKPIvalue' } },
diff --git a/src/stores/Trade.js b/src/stores/Trade.js
index 5f9cf55..0d41bc3 100644
--- a/src/stores/Trade.js
+++ b/src/stores/Trade.js
@@ -54,9 +54,9 @@ class Trade {
/**
* 时间轴
*/
- fetchTradeDataByDate(queryData) {
+ fetchTradeDataByDate(queryData = {}) {
this.timeData.loading = true;
- queryData = queryData || this.searchPayloadHome;
+ queryData = Object.assign({}, this.searchPayloadHome, queryData); // queryData || this.searchPayloadHome;
queryData.groupType = queryData?.groupType || 'overview';
Object.assign(queryData, { groupDateType: this.timeLineKey });
this.fetchTradeData(queryData).then((json) => {
@@ -123,10 +123,17 @@ class Trade {
}
return r;
}, {});
+ const summaryData = 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] || {}
+ );
+ });
runInAction(() => {
this.sideData.loading = false;
this.sideData.dataSource = groupsData;
this.sideData.monthData = sortResult;
+ this.sideData.yearData = summaryData;
});
}
});
@@ -197,7 +204,7 @@ class Trade {
this.summaryData = { loading: false, dataSource: [], kpi: {}, };
this.timeData = { loading: false, dataSource: [] };
this.BuData = { loading: false, dataSource: [] };
- this.sideData = { loading: false, dataSource: {}, monthData: [] };
+ this.sideData = { loading: false, dataSource: {}, monthData: [], yearData: [] };
this.topData = {};
this.targetData = { targetTotal: {}, targetCountry: {}, targetGuest: {} };
this.targetTableProps.dataSource = [];
@@ -207,7 +214,7 @@ class Trade {
summaryData = { loading: false, dataSource: [], kpi: {}, };
timeData = { loading: false, dataSource: [] };
BuData = { loading: false, dataSource: [] };
- sideData = { loading: false, dataSource: {}, monthData: [] };
+ sideData = { loading: false, dataSource: {}, monthData: [], yearData: [] };
topData = {};
targetData = { targetTotal: {}, targetCountry: {}, targetGuest: {} };
targetTableProps = { loading: false, columns: [
diff --git a/src/views/Home.jsx b/src/views/Home.jsx
index 6033c83..200ab4f 100644
--- a/src/views/Home.jsx
+++ b/src/views/Home.jsx
@@ -8,6 +8,7 @@ import StatisticCard from '../components/StatisticCard';
import Bullet from '../components/BulletWithSort';
import Waterfall from '../components/Waterfall';
import LineWithKPI from '../components/LineWithKPI';
+import Donut from './../components/Donut';
import DataFieldRadio from '../components/DataFieldRadio';
import { datePartOptions } from './../components/DateGroupRadio/date';
import SearchForm from './../components/search/SearchForm';
@@ -17,9 +18,9 @@ import { Line } from '@ant-design/charts';
import './home.css';
const topSeries = [
- { key: 'country', label: '国籍', graphVisible: true },
{ key: 'dept', label: '小组', graphVisible: true },
{ key: 'operator', label: '顾问', graphVisible: true },
+ { key: 'country', label: '国籍', graphVisible: true },
{ key: 'GuestGroupType', label: '客群类别', graphVisible: false },
{ key: 'destination', label: '目的地', graphVisible: true },
];
@@ -40,15 +41,23 @@ export default observer(() => {
return () => {};
}, []);
+ const [topSeriesSet, setTopSeriesSet] = useState(topSeries);
+ const [overviewFlag, setOverviewFlag] = useState(true);
+ const [groupTypeVal, setGroupTypeVal] = useState('overview');
const pageRefresh = (queryData) => {
- const overviewFlag = queryData.DepartmentList.toLowerCase() === 'all' || queryData.DepartmentList.toLowerCase().includes(',');
- queryData.groupType = overviewFlag ? 'overview' : 'dept';
+ const _overviewFlag = queryData.DepartmentList.toLowerCase() === 'all' || queryData.DepartmentList.toLowerCase().includes(',');
+ const groupType = _overviewFlag ? 'overview' : 'dept';
+ queryData.groupType = groupType;
+ setGroupTypeVal(groupType);
TradeStore.resetData();
- TradeStore.fetchSummaryData(queryData);
+ TradeStore.fetchSummaryData(Object.assign({}, queryData, { groupType }));
TradeStore.fetchTradeDataByDate(queryData);
TradeStore.fetchTradeDataByBU(queryData);
TradeStore.fetchTradeDataByMonth(queryData);
- for (const iterator of topSeries) {
+ const topSeriesF = _overviewFlag ? topSeries : topSeries.filter(ele => ele.key !== 'dept');
+ setTopSeriesSet(topSeriesF);
+ setOverviewFlag(_overviewFlag);
+ for (const iterator of topSeriesF) {
TradeStore.fetchTradeDataByType(iterator.key, queryData);
}
};
@@ -156,12 +165,12 @@ export default observer(() => {
setDateField(value);
TradeStore.setTimeLineKey(value);
if (!isEmpty(TradeStore.searchPayloadHome)) {
- TradeStore.fetchTradeDataByDate();
+ TradeStore.fetchTradeDataByDate({groupType: groupTypeVal});
}
};
return (
<>
-
+
{/* style={{ margin: '-16px -8px', padding: 0 }} */}
{
{/* */}
-
+
- 市场进度
+ 市场
-
- {`各事业部总业绩`}
+ {overviewFlag ? (
+ <>
+
+ {`各事业部总业绩`}
+ >
+ ) : (
+ <>>
+ )}
{Object.keys(sideData.dataSource).map((key) => (
@@ -226,7 +241,8 @@ export default observer(() => {
- 英语区目标客户
+
+ 英语区目标客户
@@ -240,14 +256,16 @@ export default observer(() => {
- {topSeries.map((item) => item.graphVisible ? (
-
-
- {item.label}
-
-
-
- ) : null)}
+ {topSeriesSet.map((item) =>
+ item.graphVisible ? (
+
+
+ {item.label}
+
+
+
+ ) : null
+ )}
>
diff --git a/src/views/home.css b/src/views/home.css
index 2713a7b..0175da4 100644
--- a/src/views/home.css
+++ b/src/views/home.css
@@ -1,3 +1,6 @@
+.__hn-sta-wrapper .ant-statistic-title{
+ color: rgb(0, 0, 0, .45);
+}
.__hn-sta-wrapper .ant-statistic-content-suffix{
float: right;
font-size: 18px;