diff --git a/src/components/Bullet.jsx b/src/components/Bullet.jsx index e2cc0dd..c2e22d7 100644 --- a/src/components/Bullet.jsx +++ b/src/components/Bullet.jsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { observer } from 'mobx-react'; import { Bullet } from '@ant-design/plots'; -import { sortBy } from '../utils/commons'; +import { sortBy, merge } from '../utils/commons'; import { dataFieldAlias } from './../libs/ht'; export default observer((props) => { @@ -24,7 +24,7 @@ export default observer((props) => { return () => {}; }, [extProps.measureField, dataSource]); - const config = { + const config = merge({ color: { range: ['#FFbcb8', '#FFe0b0', '#bfeec8'], measure: '#5B8FF9', @@ -72,17 +72,17 @@ export default observer((props) => { }, ], }, - // 全局的alias不起作用 + // ? 全局的alias不起作用 tooltip: { customItems: (originalItems) => { // process originalItems, return originalItems.map((ele) => ({ ...ele, name: dataFieldAlias[ele.name]?.alias || ele.name })); }, }, - }; + }, extProps); return ( <> - + ); }); diff --git a/src/components/Column.jsx b/src/components/Column.jsx new file mode 100644 index 0000000..301de04 --- /dev/null +++ b/src/components/Column.jsx @@ -0,0 +1,66 @@ +import { useEffect, useState } from 'react'; +import { observer } from 'mobx-react'; +import { sortBy, merge } from '../utils/commons'; +import { dataFieldAlias } from '../libs/ht'; +import { Column } from '@ant-design/plots'; + +export default observer((props) => { + const { dataSource, line, ...extProps } = props; + const yMax = Math.max(line?.value || 0, ...dataSource.map((ele) => ele[extProps.yField])); + const annotationsLine = line + ? [ + { + type: 'text', + position: ['start', line.value], + content: `${line.label} ${line.value / 1000} K`, + // offsetX: -15, + style: { + fill: '#F4664A', + textBaseline: 'bottom', + }, + }, + { + type: 'line', + start: [-10, line.value], + end: ['max', line.value], + style: { + stroke: '#F4664A', + lineDash: [2, 2], + }, + }, + ] + : []; + const config = merge({ + isStack: true, + // xField: 'value', + // yField: 'year', + // seriesField: 'type', + label: { + // 可手动配置 label 数据标签位置 + position: 'middle', + // 'left', 'middle', 'right' + // 可配置附加的布局方法 + layout: [ + // 柱形图数据标签位置自动调整 + { + type: 'interval-adjust-position', + }, // 数据标签防遮挡 + { + type: 'interval-hide-overlap', + }, // 数据标签文颜色自动调整 + { + type: 'adjust-color', + }, + ], + }, + meta: { + [extProps.yField]: { + alias: dataFieldAlias[extProps.yField]?.alias || extProps.yField, + formatter: (v) => dataFieldAlias[extProps.yField]?.formatter(v) || v, + max: Math.ceil(yMax / 0.95), + }, + }, + annotations: [...annotationsLine], + }, extProps); + return ; +}); diff --git a/src/components/Waterfall.jsx b/src/components/Waterfall.jsx index b23c2d1..9fc15f0 100644 --- a/src/components/Waterfall.jsx +++ b/src/components/Waterfall.jsx @@ -1,6 +1,7 @@ import { observer } from 'mobx-react'; import { Waterfall } from '@ant-design/plots'; import { dataFieldAlias } from './../libs/ht'; +import { merge } from '../utils/commons'; export default observer((props) => { const { dataSource, line, title, ...extProps } = props; @@ -29,7 +30,7 @@ export default observer((props) => { ] : []; - const config = { + const config = merge({ padding: 'auto', appendPadding: [20, 0, 0, 0], @@ -50,18 +51,16 @@ export default observer((props) => { }, annotations: [...annotationsLine], meta: { - ...extProps.mergeMeta, [extProps.yField]: { - ...extProps.mergeMeta[extProps.yField], max: Math.ceil(yMax / 0.95), alias: dataFieldAlias[extProps.yField]?.alias || extProps.yField, formatter: (v) => dataFieldAlias[extProps.yField]?.formatter(v) || v, }, }, - }; + }, extProps); return ( <> - + ); }); diff --git a/src/mock/2.0/trade.json b/src/mock/2.0/trade.json index d78ed3d..12d533c 100644 --- a/src/mock/2.0/trade.json +++ b/src/mock/2.0/trade.json @@ -13,7 +13,7 @@ "SumOrderKPIrate|20-100": 25, "SumPersonNum": "@integer(999,9999)", "SumPersonNumrate|-50-1": 33, - "SumPersonNumKPIrate|20-100": 33, + "SumPersonNumKPIrate": 0, "groups": "2023-05-01~2023-05-31", "key": "@increment" }, @@ -87,11 +87,11 @@ "result1|24": [ { "groups|1": "@pick([\"inside\",\"outside\"])", + "groupDateVal": "@date('2023-MM')", "SumML": "@increment(1000)", "SumMLVSrate": "@float(0,70,2,2)", "SumMLKPI": "@integer(1000,10000)", "SumMLKPIrate": "@float(0,70,2,2)", - "month": "@date('2023-MM')", "SumOrder": "@integer(9,999)", "SumOrderVSrate": "@float(-20,20,0,2)", "SumOrderKPIrate": "@float(20,100,0,2)", @@ -103,5 +103,26 @@ "result2": [ {} ] + }, + "get|/service-web/QueryData/Getkpi": { + "errcode": 0, + "errmsg": "", + "loading": false, + "data": null, + "result1|10": [ + { + "object|1": "@pick([\"dept\",\"sales\", \"group\"])", + "subject|1": "@pick([\"OrderCount\",\"SumML\", \"AvgML\", \"SuccessRate\"])", + "object_id": "@integer(10,100)", + "object_name": "@cname", + "date_type": "@pick([\"ConfirmDate\",\"startDate\", \"applyDate\"])", + "start_date": "@date(\"yyyy-MM-dd\")", + "end_date": "@datetime(\"yyyy-MM-dd HH:mm:ss\")", + "value": "@integer(99,9999)", + "key": "@increment" + }], + "result2": [ + {} + ] } } diff --git a/src/stores/Trade.js b/src/stores/Trade.js index db40f98..113d473 100644 --- a/src/stores/Trade.js +++ b/src/stores/Trade.js @@ -23,6 +23,9 @@ class Trade { const summaryData = { loading: false, dataSource: [ + { title: '成团', value: json.result1?.SumOrder, VSrate: json.result1?.SumOrderrate, KPIrate: json.result1?.SumOrderKPIrate, hasKPI: !isEmpty(json.result1?.SumOrderKPIrate) }, + { title: '毛利', value: json.result1?.SumML, VSrate: json.result1?.SumMLrate, KPIrate: json.result1?.SumMLKPIrate, hasKPI: !isEmpty(json.result1?.SumMLKPIrate) }, + { title: '完成率', value: `${json.result1?.SumMLKPIrate}%`, hasKPI: false }, { title: '人数', value: json.result1?.SumPersonNum, @@ -30,9 +33,6 @@ class Trade { KPIrate: json.result1?.SumPersonNumKPIrate, hasKPI: !isEmpty(json.result1?.SumPersonNumKPIrate), }, - { title: '成团', value: json.result1?.SumOrder, VSrate: json.result1?.SumOrderrate, KPIrate: json.result1?.SumOrderKPIrate, hasKPI: !isEmpty(json.result1?.SumOrderKPIrate) }, - { title: '毛利', value: json.result1?.SumML, VSrate: json.result1?.SumMLrate, KPIrate: json.result1?.SumMLKPIrate, hasKPI: !isEmpty(json.result1?.SumMLKPIrate) }, - { title: '完成率', value: `${json.result1?.SumMLKPIrate}%`, hasKPI: false }, ], }; this.summaryData = summaryData; @@ -47,7 +47,7 @@ class Trade { // req.fetchJSON('/service-web/QueryData/GetTradeByMonth').then((json) => { if (json.errcode === 0) { runInAction(() => { - const sortResult = json.result1.sort(sortBy('month')); + const sortResult = json.result1.sort(sortBy('groupDateVal')); const groupsData = sortResult.reduce((r, v) => { (r[v.groups] || (r[v.groups] = [])).push(v); return r; @@ -56,6 +56,7 @@ class Trade { const kpi = { label: '', value: 1200000 }; // 标注KPI this.sideData.loading = false; this.sideData.dataSource = groupsData; + this.sideData.monthData = sortResult; this.sideData.kpi = kpi; }); } @@ -76,7 +77,7 @@ class Trade { } summaryData = { loading: false, dataSource: [] }; - sideData = { loading: false, dataSource: {}, kpi: {}, }; + sideData = { loading: false, dataSource: {}, kpi: {}, monthData: [] }; topData = {}; defaultDataSubject = 'CJCount'; } diff --git a/src/utils/commons.js b/src/utils/commons.js index 5cde768..e1c856d 100644 --- a/src/utils/commons.js +++ b/src/utils/commons.js @@ -282,3 +282,36 @@ export function set_array_index(result) { export const sortBy = (key) => { return (a, b) => (a[key] > b[key]) ? 1 : ((b[key] > a[key]) ? -1 : 0); }; + +/** + * 合并Object, 递归地 + */ +export function merge(...objects) { + const isDeep = objects.some(obj => obj !== null && typeof obj === 'object'); + + const result = objects[0] ?? {}; + + for (let i = 1; i < objects.length; i++) { + const obj = objects[i]; + + if (!obj) continue; + + Object.keys(obj).forEach(key => { + const val = obj[key]; + + if (isDeep) { + if (Array.isArray(val)) { + result[key] = [...result[key] || [], ...val]; + } else if (typeof val === 'object') { + result[key] = merge(result[key], val); + } else { + result[key] = val; + } + } else { + result[key] = typeof val === 'boolean' ? val : result[key]; + } + }); + } + + return result; +} diff --git a/src/views/Home.jsx b/src/views/Home.jsx index 09de37a..75b7d6b 100644 --- a/src/views/Home.jsx +++ b/src/views/Home.jsx @@ -3,10 +3,11 @@ import { observer } from 'mobx-react'; import { Row, Col, Spin, Space } from 'antd'; import { stores_Context } from '../config'; import { useNavigate } from 'react-router-dom'; -import { SlackOutlined, SketchOutlined, AntCloudOutlined, RedditOutlined, GithubOutlined, ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons'; +// import { SlackOutlined, SketchOutlined, AntCloudOutlined, RedditOutlined, GithubOutlined, ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons'; import StatisticCard from '../components/StatisticCard'; import Bullet from '../components/Bullet'; import Waterfall from '../components/Waterfall'; +import Column from '../components/Column'; import DataFieldRadio from './../components/DateFieldRadio'; import DatePickerCharts from './../components/search/DatePickerCharts'; @@ -68,10 +69,10 @@ export default observer(() => { }; const WaterfallConfig = { - xField: 'month', + xField: 'groupDateVal', yField: 'SumML', - mergeMeta: { - month: { + meta: { + groupDateVal: { alias: '月份', }, }, @@ -80,6 +81,29 @@ export default observer(() => { }, }; + const ColumnConfig = { + xField: 'groupDateVal', + yField: 'SumML', + seriesField: 'groups', + label: { + formatter: (v) => ((v.SumML / sideData.kpi.value) * 100).toFixed(2) + '%', + }, + legend: false, + // annotations: sideData.monthData.map((d, ...args) => { + // console.log('aaa', d, args); + // return { + // type: 'dataMarker', + // position: d, + // point: { + // style: { + // stroke: '#FF6B3B', + // lineWidth: 1.5, + // }, + // }, + // }; + // }), + }; + return ( <>
@@ -101,6 +125,9 @@ export default observer(() => {

市场进度

+ + + {Object.keys(sideData.dataSource).map((key) => (