diff --git a/src/components/LineWithKPI.jsx b/src/components/LineWithKPI.jsx
new file mode 100644
index 0000000..afdb70d
--- /dev/null
+++ b/src/components/LineWithKPI.jsx
@@ -0,0 +1,71 @@
+import { observer } from 'mobx-react';
+import { DualAxes } from '@ant-design/plots';
+import { merge, pick, cloneDeep } from '../utils/commons';
+import { dataFieldAlias } from '../libs/ht';
+
+const uniqueByKey = (array, key, pickLast) => {
+ const seen = new Map();
+ const isPickLast = pickLast === true;
+
+ return array.filter(item => {
+ const k = item[key];
+ const storedItem = seen.get(k);
+
+ if(storedItem) {
+ if(isPickLast) {
+ seen.set(k, item); // update with last item
+ }
+ return false;
+ }
+
+ seen.set(k, item);
+ return true;
+ });
+};
+
+export default observer((props) => {
+ const { config, dataSource, ...extProps } = props;
+ const kpiKey = dataFieldAlias[config.yField]?.nestkey?.v;
+ const _data = uniqueByKey(dataSource, config.xField, true); // debug:
+ const mergeConfig = merge(
+ // color: ['#1979C9', '#F4664A', '#FAAD14'],
+
+ // padding: 'auto',
+ // xField: 'groupDateVal',
+ // yField: 'SumML',
+ // seriesField: 'groupsLabel',
+ {
+ ...pick(config, ['padding', 'xField', 'seriesField']),
+ yField: [config.yField, kpiKey],
+ legend: false,
+ xAxis: {
+ type: 'cat',
+ },
+ meta: { ...cloneDeep(dataFieldAlias) },
+ geometryOptions: [
+ {
+ geometry: 'line',
+ smooth: true,
+ point: {
+ size: 4,
+ shape: 'cicle',
+ },
+ },
+ {
+ geometry: 'line',
+ smooth: true,
+ point: {
+ size: 4,
+ shape: 'cicle',
+ },
+ lineStyle: {
+ lineWidth: 1,
+ lineDash: [5, 5],
+ },
+ color: '#F4664A',
+ },
+ ],
+ }
+ );
+ return ;
+});
diff --git a/src/libs/ht.js b/src/libs/ht.js
index b8b1cbf..2687c07 100644
--- a/src/libs/ht.js
+++ b/src/libs/ht.js
@@ -107,7 +107,7 @@ export const dataFieldAlias = dataFieldOptions.reduce(
(a, c) => ({
...a,
[c.value]: { ...c, alias: c.label, formatter: (v) => c.formatter(v) },
- [c.nestkey.v]: { ...c, value: c.nestkey.v, alias: `${c.label}目标`, formatter: (v) => c.formatter(v) },
+ [c.nestkey.v]: { ...c, value: c.nestkey.v, alias: `${c.label}目标`, label: `${c.label}目标`, formatter: (v) => c.formatter(v) },
}),
{}
);
diff --git a/src/utils/commons.js b/src/utils/commons.js
index 6a9adff..a90a0f2 100644
--- a/src/utils/commons.js
+++ b/src/utils/commons.js
@@ -289,7 +289,7 @@ export const sortBy = (key) => {
export function merge(...objects) {
const isDeep = objects.some(obj => obj !== null && typeof obj === 'object');
- const result = objects[0] ?? {};
+ const result = objects[0] || (isDeep ? {} : objects[0]);
for (let i = 1; i < objects.length; i++) {
const obj = objects[i];
@@ -301,7 +301,7 @@ export function merge(...objects) {
if (isDeep) {
if (Array.isArray(val)) {
- result[key] = [...result[key] || [], ...val];
+ result[key] = [].concat(Array.isArray(result[key]) ? result[key] : [result[key]], val);
} else if (typeof val === 'object') {
result[key] = merge(result[key], val);
} else {
diff --git a/src/views/Detail.jsx b/src/views/Detail.jsx
index dc97d35..8ba1c80 100644
--- a/src/views/Detail.jsx
+++ b/src/views/Detail.jsx
@@ -1,11 +1,12 @@
import { useContext, useEffect, useMemo } from 'react';
-import { observer } from "mobx-react";
+import { observer } from 'mobx-react';
import { stores_Context } from '../config';
import { Row, Col, Spin, Space, Radio, Tabs, Table } from 'antd';
import { empty } from '../utils/commons';
import { dataFieldAlias } from '../libs/ht';
import Scatter from './../components/Scatter';
import SearchForm from './../components/search/SearchForm';
+import { Histogram } from '@ant-design/plots';
export default observer((props) => {
const { date_picker_store: searchFormStore, DistributionStore } = useContext(stores_Context);
@@ -46,35 +47,44 @@ export default observer((props) => {
position: 'right-top',
},
};
- return (
- <>
-
- {/* style={{ margin: '-16px -8px', padding: 0 }} */}
-
- {
- detailRefresh(obj);
- }}
- />
-
-
+ const HistogramConfig = {
+ binField: 'personNum',
+ binWidth: 1,
+ };
+ return (
+ <>
+
+ {/* style={{ margin: '-16px -8px', padding: 0 }} */}
+
+ {
+ detailRefresh(obj);
+ }}
+ />
+
+
-
- >
- );
+
+ {/* */}
+ >
+ );
});
diff --git a/src/views/Home.jsx b/src/views/Home.jsx
index 409955b..92fe06c 100644
--- a/src/views/Home.jsx
+++ b/src/views/Home.jsx
@@ -1,12 +1,13 @@
import { useContext, useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { Row, Col, Spin, Space, Radio } from 'antd';
-import { CheckCircleTwoTone, MoneyCollectTwoTone, FlagTwoTone, SmileTwoTone, } from '@ant-design/icons';
+import { CheckCircleTwoTone, MoneyCollectTwoTone, FlagTwoTone, SmileTwoTone } from '@ant-design/icons';
import { stores_Context } from '../config';
import { useNavigate } from 'react-router-dom';
import StatisticCard from '../components/StatisticCard';
import Bullet from '../components/BulletWithSort';
import Waterfall from '../components/Waterfall';
+import LineMix from '../components/LineWithKPI';
import DataFieldRadio from '../components/DataFieldRadio';
import { datePartOptions } from './../components/DateGroupRadio/date';
import SearchForm from './../components/search/SearchForm';
@@ -30,7 +31,7 @@ export default observer(() => {
// const navigate = useNavigate();
const { TradeStore, date_picker_store: searchFormStore } = useContext(stores_Context);
const { sideData, summaryData, BuData, topData, timeData, timeLineKey } = TradeStore;
- const { formValues, } = searchFormStore;
+ const { formValues } = searchFormStore;
useEffect(() => {
if (empty(summaryData.dataSource)) {
@@ -92,7 +93,7 @@ export default observer(() => {
},
},
label: {
- formatter: (v) => summaryData.kpi.value === 0 ? (dataFieldAlias.SumML?.formatter(v.SumML) || v.SumML) : ((v.SumML / summaryData.kpi.value) * 100).toFixed(2) + '%',
+ formatter: (v) => (summaryData.kpi.value === 0 ? dataFieldAlias.SumML?.formatter(v.SumML) || v.SumML : ((v.SumML / summaryData.kpi.value) * 100).toFixed(2) + '%'),
},
};
@@ -108,7 +109,8 @@ export default observer(() => {
autoHide: true,
autoRotate: false,
},
- }
+ },
+ legend: false,
};
const lineConfigSet = {
@@ -123,10 +125,11 @@ export default observer(() => {
smooth: true,
point: {
size: 4,
- shape: "cicle",
+ shape: 'cicle',
},
legend: false,
- meta: { ...cloneDeep(dataFieldAlias)
+ meta: {
+ ...cloneDeep(dataFieldAlias),
// [extProps.yField]: {
// alias: dataFieldAlias[extProps.yField]?.alias || extProps.yField,
// formatter: (v) => dataFieldAlias[extProps.yField]?.formatter(v) || v,
@@ -139,7 +142,7 @@ export default observer(() => {
const handleChangetimeDataField = (key) => {
setTimeDataField(key);
setLineConfig({
- ...lineConfig,
+ ...cloneDeep(lineConfig),
yField: key,
tooltip: {
customItems: (originalItems) => {
@@ -151,7 +154,7 @@ export default observer(() => {
});
};
const [dateField, setDateField] = useState(timeLineKey);
- const handleChangeDateType = ({target: {value}}) => {
+ const handleChangeDateType = ({ target: { value } }) => {
setDateField(value);
TradeStore.setTimeLineKey(value);
if (!isEmpty(TradeStore.searchPayloadHome)) {
@@ -204,6 +207,7 @@ export default observer(() => {
+ {/* */}
@@ -212,7 +216,7 @@ export default observer(() => {
- {`各事业部总业绩`}
+ {`各事业部总业绩`}
{Object.keys(sideData.dataSource).map((key) => (