diff --git a/src/App.jsx b/src/App.jsx index 13c2d74..4a04b1c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -46,6 +46,7 @@ import ServicePersonNum from './views/ServicePersonNum'; import DataPivot from './views/DataPivot'; import Welcome from './views/Welcome'; import Meeting2024GH from './views/Meeting2024-GH'; +import SalesCustomerCareRegular from './views/SalesCustomerCareRegular'; import { stores_Context, APP_VERSION } from './config'; import { WaterMark } from '@ant-design/pro-components'; @@ -107,6 +108,7 @@ const App = () => { key: 32, label: 老客户, }, + { key: 'customer_care_regular_sales', label: 销售-老客户 }, { key: 33, label: 在华客户, @@ -220,6 +222,7 @@ const App = () => { }> } /> } /> + } /> } /> } /> } /> diff --git a/src/components/Data.jsx b/src/components/Data.jsx index 00d022d..e467f00 100644 --- a/src/components/Data.jsx +++ b/src/components/Data.jsx @@ -88,7 +88,7 @@ export const TableExportBtn = (props) => { disabled={false} onClick={onExport} > - 导出excel + {props.btnTxt || '导出excel'} ); }; diff --git a/src/libs/ht.js b/src/libs/ht.js index 1f472aa..c489598 100644 --- a/src/libs/ht.js +++ b/src/libs/ht.js @@ -208,6 +208,9 @@ export const pivotBy = (_data, [rows, columns, date]) => { ele.PPPriceRange = calcPPPriceRange(ele.PPPrice); ele.IsOld_txt = ele.IsOld === '1' ? '老客户' : '否'; ele.isCusCommend_txt = ele.isCusCommend === '1' ? '老客户推荐' : '否'; + const hasOld = (ele.IsOld === '1' || ele.isCusCommend === '1') ? 1 : 0; + ele.hasOld = hasOld; + ele.hasOld_txt = hasOld === 1 ? '老客户(推荐)' : ''; return ele; }); // 数组的字段值, 拆分处理 @@ -292,10 +295,11 @@ export const pivotBy = (_data, [rows, columns, date]) => { // Calculations calculatedData.tourdays = Math.ceil(calculatedData.tourdays / _len); + calculatedData.confirmTourdays = calculatedData.ConfirmOrder > 0 ? Math.ceil(calculatedData.confirmTourdays / calculatedData.ConfirmOrder) : '0'; calculatedData.applyDays = Math.ceil(calculatedData.applyDays / _len); calculatedData.confirmDays = Math.ceil(calculatedData.confirmDays / _len); const _rowCalc = { - ConfirmRates: calculatedData.ConfirmOrder ? fixTo4Decimals(calculatedData.ConfirmOrder / calculatedData.SumOrder) : 0, + ConfirmRates: calculatedData.ConfirmOrder ? fixTo4Decimals(calculatedData.ConfirmOrder / calculatedData.SumOrder*100) : 0, OrderValue: calculatedData.SumOrder ? fixToInt(calculatedData.SumML / calculatedData.SumOrder) : 0, SingleML: calculatedData.ConfirmOrder ? fixToInt(calculatedData.SumML / calculatedData.ConfirmOrder) : 0, @@ -355,6 +359,7 @@ export const pivotBy = (_data, [rows, columns, date]) => { }),everyR); summaryCalc.tourdays = Math.ceil(summaryCalc.tourdays / allColumns.length); + summaryCalc.confirmTourdays = summaryCalc.ConfirmOrder > 0 ? Math.ceil(summaryCalc.confirmTourdays / summaryCalc.ConfirmOrder) : '0'; summaryCalc.applyDays = Math.ceil(summaryCalc.applyDays / allColumns.length); summaryCalc.confirmDays = Math.ceil(summaryCalc.confirmDays / allColumns.length); summaryCalc.ConfirmRates = summaryCalc.ConfirmOrder ? fixTo2Decimals(summaryCalc.ConfirmOrder / summaryCalc.SumOrder*100) : 0; diff --git a/src/stores/CustomerStore.js b/src/stores/CustomerStore.js index 1333b54..3a79db9 100644 --- a/src/stores/CustomerStore.js +++ b/src/stores/CustomerStore.js @@ -1,7 +1,15 @@ import {makeAutoObservable, runInAction} from "mobx"; +import { fetchJSON } from '../utils/request'; import * as config from "../config"; -import { groupsMappedByKey, dataFieldAlias, sitesMappedByCode } from './../libs/ht'; +import { groupsMappedByKey, dataFieldAlias, sitesMappedByCode, pivotBy } from './../libs/ht'; +/** + * 用于透视的数据 + */ +const getDetailData = async (param) => { + const json = await fetchJSON('/service-Analyse2/GetTradeApartDetail', param); + return json.errcode === 0 ? json.result : []; +}; class CustomerStore { @@ -247,6 +255,39 @@ class CustomerStore { }; // 在华客人 end + sales_regular_data = { + loading: false, + data: [], + rawData: [], + searchValues: { + DepartmentList: ['1', '2', '28', '7'].map(kk => groupsMappedByKey[kk]), + WebCode: undefined, // ['ALL'].map(kk => sitesMappedByCode[kk]), + DateType: { key: 'applyDate', label: '提交日期'}, + }, + }; + + get_sales_regular_data = async (param) => { + this.sales_regular_data.loading = true; + const rawData = await getDetailData({...param, IncludeTickets: 1}); + const filterHasOld = rawData.filter(ele => (ele.IsOld === '1' || ele.isCusCommend === '1')); + const { data: hasOldData, columnValues, summaryRows, summaryColumns, pivotKeys, summaryMix } = pivotBy(filterHasOld, [['hasOld', 'operatorName'], [], []]); + const { data: IsOldData, } = pivotBy(filterHasOld.filter(ele => ele.IsOld === '1'), [['operatorName', 'IsOld_txt', ], [], []]); + const { data: isCusCommendData, } = pivotBy(filterHasOld.filter(ele => ele.isCusCommend === '1'), [['operatorName', 'isCusCommend_txt', ], [], []]); + // console.log('IsOldData====', IsOldData, '\nisCusCommend', isCusCommendData); + // console.log('data====', data, '\ncolumnValues', columnValues, '\nsummaryRows', summaryRows, '\nsummaryColumns', summaryColumns, '\nsummaryMix', summaryMix, '\nhasOld',filterHasOld); + const mergeDataBySales = hasOldData.map((ele) => ({ + ...ele, + children: [].concat( + IsOldData.filter((ele1) => ele1.operatorName === ele.operatorName).map(o => ({...o, operatorName: o.IsOld_txt, key: o.rowLabel})), + isCusCommendData.filter((ele2) => ele2.operatorName === ele.operatorName).map(o => ({...o, operatorName: o.isCusCommend_txt, key: o.rowLabel})) + ), + })); + // console.log('merge', mergeDataBySales); + this.sales_regular_data.loading = false; + this.sales_regular_data.data = mergeDataBySales; + this.sales_regular_data.rawData = filterHasOld; + }; + setSearchValues(obj, values, target) { this[target].groups = obj.DepartmentList; this[target].webcode = obj.WebCode; diff --git a/src/views/DataPivot.jsx b/src/views/DataPivot.jsx index 8fefb07..6ff59ae 100644 --- a/src/views/DataPivot.jsx +++ b/src/views/DataPivot.jsx @@ -25,6 +25,7 @@ const filterFields = [ { key: 'WebCode', label: '来源站点' }, { key: 'IsOld_txt', label: '是否老客户' }, { key: 'isCusCommend_txt', label: '是否老客户推荐' }, + { key: 'hasOld_txt', label: '老客户(推荐)' }, { key: 'destinationCountry_AsJOSN', label: '目的地国籍' }, { key: 'PPPriceRange', label: '人均天/单区间(外币)' }, // { key: 'unitPPPriceRange', label: '人均天(外币)' }, @@ -61,6 +62,12 @@ const pageSetting = { childrenColumns: [ { key: 'ConfirmOrder', title: '成交数', dataIndex: 'ConfirmOrder', width: '5em' }, { key: 'ConfirmRates', title: '成交率', dataIndex: 'ConfirmRates_txt', width: '5em' }, + { key: 'SumML', title: '毛利', dataIndex: 'SumML', width: '5em' }, // SumML_txt + { key: 'SingleML', title: '单团毛利', dataIndex: 'SingleML', width: '5em' }, + { key: 'tourdays', title: '团天数', dataIndex: 'tourdays', width: '5em' }, + { key: 'confirmTourdays', title: '✅团天数', dataIndex: 'confirmTourdays', width: '5em' }, + { key: 'SumPersonNum', title: '人数', dataIndex: 'SumPersonNum', width: '5em' }, + { key: 'ConfirmPersonNum', title: '✅人数', dataIndex: 'ConfirmPersonNum', width: '5em' }, ], searchInitial: { DateType: { key: 'applyDate', value: 'applyDate', label: '提交日期' } }, }, diff --git a/src/views/SalesCustomerCareRegular.jsx b/src/views/SalesCustomerCareRegular.jsx new file mode 100644 index 0000000..114104b --- /dev/null +++ b/src/views/SalesCustomerCareRegular.jsx @@ -0,0 +1,108 @@ +import { createContext, useContext, useEffect, useState } from 'react'; +import { observer } from 'mobx-react'; +import { stores_Context } from '../config'; +import { Table, Row, Col, Divider, Button } from 'antd'; +import SearchForm from '../components/search/SearchForm'; +import { TableExportBtn } from './../components/Data'; +import { uniqWith } from './../utils/commons'; + +// 注意TdCell要提到DataTable作用域外声明 +const TdCell = (tdprops) => { + // onMouseEnter, onMouseLeave在数据量多的时候,会严重阻塞表格单元格渲染,严重影响性能 + const { onMouseEnter, onMouseLeave, ...restProps } = tdprops; + return ; +}; + +const SalesCustomerCareRegular = (props) => { + const { orders_store, date_picker_store: searchFormStore, customer_store } = useContext(stores_Context); + const { formValues, formValuesToSub, siderBroken } = searchFormStore; + const { sales_regular_data: pageData } = customer_store; + const [expandRowKeys, setExpandRowKeys] = useState([]); + const [dataForExport, setDataForExport] = useState([]); + useEffect(() => { + setExpandRowKeys(pageData.data.map((ele) => ele.key)); + setDataForExport(pageData.data.reduce((r, c) => r.concat([{...c, children: undefined}], c.children.map(ele => ({...ele, operatorName: ele.rowLabel}))), [])); + return () => {}; + }, [pageData.data]); + + const allOPI1 = uniqWith( + pageData.data.map((rr) => ({ text: rr.operatorName, value: rr.operatorName })), + (a, b) => JSON.stringify(a) === JSON.stringify(b) + ).sort((a, b) => a.text.localeCompare(b.text)); + + const rowColumns = [ + { title: '顾问', dataIndex: 'operatorName', key: 'operatorName' }, + { title: '订单号', dataIndex: 'o_id', key: 'o_id' }, + { title: '预定日期', dataIndex: 'applyDate', key: 'applyDate' }, + { title: '订单状态', key: 'orderState', render: (_, r) => r.orderState === '1' ? '成行' : '', }, + { title: '毛利', dataIndex: 'ML', key: 'ML' }, + { title: '人数', dataIndex: 'personNum', key: 'personNum' }, + { title: '天数', dataIndex: 'tourdays', key: 'tourdays' }, + // { title: '人天数', dataIndex: 'CGI_PersonDays', key: 'CGI_PersonDays' }, + // { title: '走团日期', dataIndex: 'COLI_OrderStartDate', key: 'COLI_OrderStartDate' }, + { title: '小组', dataIndex: 'dept', key: 'dept' }, + { title: '老客户', key: 'IsOld', render: (_, r) => r.IsOld === '1' ? '是' : '' }, + { title: '老客户推荐', key: 'IsCusCommend', render: (_, r) => r.IsCusCommend === '1' ? '是' : '' }, + { title: '网站', dataIndex: 'WebCode', key: 'WebCode' }, + { title: '来源', dataIndex: 'SourceType', key: 'SourceType' }, + { title: '页面类型', dataIndex: 'COLI_LineClass', key: 'COLI_LineClass' }, + ]; + const columns = [ + { key: 'operatorName', title: '顾问', dataIndex: 'operatorName', width: '6em', filters: allOPI1, onFilter: (value, record) => record.operatorName === value, filterSearch: true }, + { key: 'SumOrder', title: '订单数', dataIndex: 'SumOrder', width: '5em' }, + { key: 'ConfirmOrder', title: '成交数', dataIndex: 'ConfirmOrder', width: '5em' }, + // { key: 'ConfirmPersonNum', title: '✔人数(SUM)', dataIndex: 'ConfirmPersonNum', width: '5em' }, + // { key: 'confirmTourdays', title: '✔团天数(AVG)', dataIndex: 'confirmTourdays', width: '5em' }, + { key: 'SumML', title: '预计毛利', dataIndex: 'SumML', width: '5em' }, // SumML_txt + { key: 'ConfirmRates', title: '成交率', dataIndex: 'ConfirmRates_txt', width: '5em' }, + { key: 'SingleML', title: '单团毛利', dataIndex: 'SingleML', width: '5em' }, + { key: 'action', title: '', width: '5em', render: (_, r) => { + const rowChildren = pageData.rawData.filter(ele => ele.operatorName === r.operatorName); + return r.hasOld ? : null; + } }, + ]; + return ( + <> + + + { + customer_store.setSearchValues(obj, form, 'sales_regular_data'); + customer_store.get_sales_regular_data(obj); + // MeetingDataStore.setSearchValues(form); + // dataRefresh(obj); + }} + /> + + +

销售-老客户, 含推荐

+ + + + + + ele.key) }} + /> + + ); +}; +export default observer(SalesCustomerCareRegular);