From 2942a61c8e3231ace6591a0480ab31ed3e05fdc7 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 25 Oct 2023 11:28:47 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=BE=E9=97=AE:=20=E9=94=80=E5=94=AE?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6:=20=E6=98=BE=E7=A4=BA=E5=85=A8=E5=B9=B4?= =?UTF-8?q?=E7=9A=84KPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LineWithKPI.jsx | 2 +- src/libs/ht.js | 4 +-- src/stores/SaleStore.js | 47 +++++++++++++++++++++++++++++++--- src/views/Sale_KPI.jsx | 15 +++++------ 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/components/LineWithKPI.jsx b/src/components/LineWithKPI.jsx index d06bee3..0271fae 100644 --- a/src/components/LineWithKPI.jsx +++ b/src/components/LineWithKPI.jsx @@ -22,7 +22,7 @@ export default observer((props) => { const colorSets = Object.keys(seriesData).sort().reduce((obj, k, i) => ({...obj, [k]: dataColors[i]}), {}); const mergeLineConfig = merge({ color: (item) => { - const thisSeries = item[config.seriesField].split(' ')?.[0]; + const thisSeries = item[config.seriesField]?.split(' ')?.[0]; return colorSets[thisSeries]; // return thisSeries.includes('目标') ? '#F4664A' : colorSets[thisSeries]; }, diff --git a/src/libs/ht.js b/src/libs/ht.js index 1a81b4b..89eb3ca 100644 --- a/src/libs/ht.js +++ b/src/libs/ht.js @@ -97,8 +97,8 @@ export const dateTypes = [ * 结果字段 */ export const dataFieldOptions = [ - { label: '营收', value: 'transactions', formatter: (v) => `${fixTo1Decimals(v / 10000)} 万`, nestkey: { p: 'transactionsKPIrates', v: 'transactionsKPIvalue' } }, - { label: '毛利', value: 'SumML', formatter: (v) => `${fixTo1Decimals(v / 10000)} 万`, nestkey: { p: 'MLKPIrates', v: 'MLKPIvalue' } }, + { label: '营收', value: 'transactions', formatter: (v) => `${fixTo1Decimals((v || 0) / 10000)} 万`, nestkey: { p: 'transactionsKPIrates', v: 'transactionsKPIvalue' } }, + { label: '毛利', value: 'SumML', formatter: (v) => `${fixTo1Decimals((v || 0) / 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/SaleStore.js b/src/stores/SaleStore.js index cfdf8bd..4b28a99 100644 --- a/src/stores/SaleStore.js +++ b/src/stores/SaleStore.js @@ -5,6 +5,7 @@ import * as comm from '../utils/commons'; import { NavLink } from 'react-router-dom'; import { groupsMappedByCode, dataFieldAlias } from './../libs/ht'; import * as req from '../utils/request'; +import { parseKPI } from './KPI'; // 销售数据 class SaleStore { @@ -31,7 +32,8 @@ class SaleStore { date_title = 'date_title'; // 日期段,只用于显示,防止日期选择控件的变化导致页面刷新 salesTrade = { - groupType: 'dept', loading: false, operator: [], dept: [], overview: [], + groupType: 'dept', loading: false, + operator: [], dept: [], overview: [], operatorMapped: {}, pickSales: [], pickSalesData: [], }; @@ -523,13 +525,52 @@ class SaleStore { data: undefined, yearML: Object.values(yData[ykey].data)[0]?.SumML || 0, // 整理排序用 })).sort(comm.sortBy('yearML')).reverse(); + + const kpiObjects = mergeYearMonth.map(v => ({ key: v.groupsKey, value: v.groupsKey, label: v.groupsLabel })); + const kpiData = await this.getKPISettings(groupType, queryData, kpiObjects); + const salesTradeDataMapped = mergeYearMonth.reduce((ro, vo) => ({...ro, [vo.groupsKey]: vo}), {}); + kpiData.map(ele => { + ele.kpiData.map((km) => { + const padM = String(km.monthIndex).padStart(2, '0'); + const _monthMLKPI = { [dataFieldAlias.SumML.nestkey.v]: km.value, 'groupsKey': ele.object_id, 'groupsLabel': ele.object_name, 'groupDateVal': `${km.yearIndex}-${padM}-01`, }; + if (comm.isEmpty(salesTradeDataMapped[ele.object_id])) { + return true; + } + if (comm.isEmpty(salesTradeDataMapped[ele.object_id].mData[`month_${padM}`])) { + salesTradeDataMapped[ele.object_id].mData[`month_${padM}`] = {}; + } + Object.assign(salesTradeDataMapped[ele.object_id].mData[`month_${padM}`], _monthMLKPI); + return km; + }); + return ele; + }); + runInAction(() => { this.salesTrade.loading = false; - this.salesTrade[groupType] = mergeYearMonth; - this.salesTrade[`${groupType}Mapped`] = mergeYearMonth.reduce((r, v) => ({...r, [v.groupsKey]: Object.values(v.mData)}), {}); + this.salesTrade[groupType] = Object.values(salesTradeDataMapped); + this.salesTrade[`${groupType}Mapped`] = Object.values(salesTradeDataMapped).reduce((r, v) => ({...r, [v.groupsKey]: Object.values(v.mData)}), {}); }); } + async getKPISettings(curObject, queryData, objects) { + const getkpiParam = comm.objectMapper(queryData, { + DateType: { key: 'date_type' }, + Date1: { key: 'start_date' }, + Date2: { key: 'end_date' }, + HTBusinessUnits: { key: 'object_id' }, + DepartmentList: { key: 'object_id' }, + }); + Object.assign(getkpiParam, { object: curObject, subject: 'sum_profit' }); + getkpiParam.object_id = curObject === 'overview' ? '' : objects.map((ele) => ele.key).join(','); + const json = await req.fetchJSON('/service-Analyse2/getkpi', getkpiParam); + if (json.errcode === 0) { + const yearData = parseKPI(json.result, ['subject', 'object_id']); + const year = moment(queryData.Date1).year(); + return yearData?.[year]?.sum_profit || []; + } + return []; + }; + /** * 获取业绩数据 */ diff --git a/src/views/Sale_KPI.jsx b/src/views/Sale_KPI.jsx index e565c93..54b2379 100644 --- a/src/views/Sale_KPI.jsx +++ b/src/views/Sale_KPI.jsx @@ -1,29 +1,24 @@ -import React, { useContext, useEffect, useState } from 'react'; -import { Row, Col, Button, Tabs, Table, Divider, Radio, Select, Space, Typography, Progress, Spin } from 'antd'; -import { ContainerOutlined, SearchOutlined, UserSwitchOutlined } from '@ant-design/icons'; +import React, { useContext } from 'react'; +import { Row, Col, Table, Select, Space, Typography, Progress, Spin } from 'antd'; import { stores_Context } from '../config'; import { observer } from 'mobx-react'; -import { NavLink, useParams } from 'react-router-dom'; import * as comm from '../utils/commons'; -import * as config from '../config'; -import { utils, writeFileXLSX } from 'xlsx'; import SearchForm from './../components/search/SearchForm'; import { dataFieldAlias } from '../libs/ht'; import Donut from './../components/Donut'; import LineWithKPI from '../components/LineWithKPI'; -import { Line, DualAxes } from '@ant-design/plots'; const { Text } = Typography; const Sale_KPI = () => { const { sale_store, date_picker_store: searchFormStore } = useContext(stores_Context); const { formValues } = searchFormStore; - const { groupType, loading, operator } = sale_store.salesTrade; + const { groupType, loading, operator, } = sale_store.salesTrade; const dataSource = [].concat(sale_store.salesTrade[groupType], operator); const yearData = Object.values(sale_store.salesTrade[groupType]?.[0]?.mData || {}); const operatorObjects = operator.map((v) => ({ key: v.groupsKey, value: v.groupsKey, label: v.groupsLabel })); - const pageRefresh = (queryData) => { + const pageRefresh = async (queryData) => { const overviewFlag = queryData.DepartmentList.toLowerCase() === 'all' || queryData.DepartmentList.toLowerCase().includes(','); const _groupType = overviewFlag ? 'overview' : 'dept'; sale_store.setGroupType(_groupType); @@ -39,11 +34,13 @@ const Sale_KPI = () => { width: '7.5em', render: (_, row) => ( + {/* 目标 */}
{dataFieldAlias.SumML.formatter(row.mData[`month_${String(index + 1).padStart(2, '0')}`]?.MLKPIvalue || 0)}
+ {/* 完成 */}
{dataFieldAlias.SumML.formatter(row.mData[`month_${String(index + 1).padStart(2, '0')}`]?.SumML || 0)}
{row.mData[`month_${String(index + 1).padStart(2, '0')}`]?.MLKPIrates || 0 ? (