diff --git a/src/components/search/SearchForm.jsx b/src/components/search/SearchForm.jsx index 232a3ad..3f94fcc 100644 --- a/src/components/search/SearchForm.jsx +++ b/src/components/search/SearchForm.jsx @@ -92,6 +92,11 @@ export default observer((props) => { transform: (value) => value?.key || '', default: '', }, + 'IncludeInternal': { + key: 'IncludeInternal', + transform: (value) => value?.key || '', + default: '', + }, 'operator': { key: 'operator', // transform: (value) => value?.key || '', diff --git a/src/views/biz/BizOrder.jsx b/src/views/biz/BizOrder.jsx index 8c194a1..f3b7078 100644 --- a/src/views/biz/BizOrder.jsx +++ b/src/views/biz/BizOrder.jsx @@ -425,6 +425,7 @@ const BizOrder = observer(() => { 包含空值 */} + @@ -433,6 +434,7 @@ const BizOrder = observer(() => { + ); diff --git a/src/views/biz/reports/TrainsUpsell.jsx b/src/views/biz/reports/TrainsUpsell.jsx index a22402a..47d61a3 100644 --- a/src/views/biz/reports/TrainsUpsell.jsx +++ b/src/views/biz/reports/TrainsUpsell.jsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; -import { Row, Col, Table, Spin, Space } from 'antd'; -import { Funnel } from '@ant-design/charts'; +import { Row, Col, Table, Spin, Space, Divider } from 'antd'; +import { Funnel, Pie } from '@ant-design/charts'; import * as comm from '../../../utils/commons'; import SearchForm from '../../../components/search/SearchForm'; @@ -14,14 +14,14 @@ import useTrainsStore from '../../../zustand/Trains'; const buildFunnelData = (data1, data2) => { // const key = 'OrderCount'; const data01 = [ - { stage: '火车票预定', number: data1?.data?.[0]?.OrderCount, dateRange: data1?.dateRangeStr }, + { stage: '火车票服务', number: data1?.data?.[0]?.OrderCount, dateRange: data1?.dateRangeStr }, { stage: '成行出票', number: data1?.data?.[0]?.CJCount, dateRange: data1?.dateRangeStr }, { stage: '火车票Upsell', number: (data1?.data?.[1]?.OrderCount || 0) + 0, dateRange: data1?.dateRangeStr }, { stage: 'Upsell成行', number: data1?.data?.[1]?.CJCount, dateRange: data1?.dateRangeStr }, ]; const data02 = !comm.isEmpty(data2) ? [ - { stage: '火车票预定', number: data2?.data?.[0]?.OrderCount, dateRange: data2?.dateRangeStr }, + { stage: '火车票服务', number: data2?.data?.[0]?.OrderCount, dateRange: data2?.dateRangeStr }, { stage: '成行出票', number: data2?.data?.[0]?.CJCount, dateRange: data2?.dateRangeStr }, { stage: '火车票Upsell', number: data2?.data?.[1]?.OrderCount, dateRange: data2?.dateRangeStr }, { stage: 'Upsell成行', number: data2?.data?.[1]?.CJCount, dateRange: data2?.dateRangeStr }, @@ -31,6 +31,21 @@ const buildFunnelData = (data1, data2) => { // return data02.concat(data01); }; +const buildPieData = (data1, data2) => { + const data01 = !comm.isEmpty(data1) + ? [ + { stage: '火车票出票', number: Number((data1?.data?.[0]?.YJLY || '0').replaceAll(',', '')), dateRange: data1?.dateRangeStr }, + { stage: 'Upsell成行', number: Number((data1?.data?.[1]?.YJLY || '0').replaceAll(',', '')), dateRange: data1?.dateRangeStr }, + ] + : []; + const data02 = !comm.isEmpty(data2) + ? [ + { stage: '火车票出票', number: Number((data2?.data?.[0]?.YJLY || '0').replaceAll(',', '')), dateRange: data2?.dateRangeStr }, + { stage: 'Upsell成行', number: Number((data2?.data?.[1]?.YJLY || '0').replaceAll(',', '')), dateRange: data2?.dateRangeStr }, + ] + : []; + return data01.concat(data02); +}; const TrainsUpsell = observer(({ ...props }) => { const { date_picker_store: searchFormStore } = useContext(stores_Context); @@ -41,7 +56,7 @@ const TrainsUpsell = observer(({ ...props }) => { // const showDiff = !comm.isEmpty(searchValuesToSub.DateDiff2); const showDiff = !comm.isEmpty(compareData); - const getBizOrderCount = useTrainsStore((state) => state.getBizOrderCount); + const getTrainsWithUpsell = useTrainsStore((state) => state.getTrainsWithUpsell); const data0 = buildFunnelData(trainsOrdersSummary, compareData); const chartConfig = { @@ -67,17 +82,47 @@ const TrainsUpsell = observer(({ ...props }) => { theme: { colors10: [ // '#b5d8f3', - '#95bbda', + '#c4e1ff', // '#739ec1', - '#5a89ad', + '#7ebdff', // '#3d759b', - '#2f668a', + '#5b90f9', // '#1f5373', - '#0F405D', + '#526bd1', '#002c45', ], }, }; + + const pieData = buildPieData(trainsOrdersSummary); + const pieData2 = buildPieData(compareData); + // console.log('🟠', pieData, pieData2); + const pieConfig = { + appendPadding: 0, + // data: pieData, + angleField: 'number', + colorField: 'stage', + radius: 0.8, + innerRadius: 0.6, + // startAngle: Math.PI , + // endAngle: Math.PI * 1.5, + label: { + type: 'spider', + // content: '{name} {value} \n {percentage}', + content: '{name}\n{percentage}', + }, + statistic: false, + legend: false, // 不显示图例 + interactions: [ + { + type: 'element-selected', + }, + { + type: 'element-active', + }, + ], + }; + const tableProps = { title: () => `${trainsOrdersSummary?.dateRangeStr || ''}` + (showDiff ? ` vs ${compareData?.dateRangeStr}` : ''), dataSource: trainsOrdersSummary?.data || [], @@ -144,7 +189,7 @@ const TrainsUpsell = observer(({ ...props }) => { }} onSubmit={(_err, obj, form, str) => { setSearchValues(obj, form); - getBizOrderCount(obj); + getTrainsWithUpsell(obj); }} /> @@ -152,14 +197,39 @@ const TrainsUpsell = observer(({ ...props }) => { - - - + + +

订单数量

- - - + + +

预计利润

+
+ + {showDiff && ( + + )} +
+ + + diff --git a/src/zustand/BizOrder.js b/src/zustand/BizOrder.js index 5a837f8..433a593 100644 --- a/src/zustand/BizOrder.js +++ b/src/zustand/BizOrder.js @@ -7,9 +7,9 @@ import { HT_HOST } from '../config'; import { resultDataCb } from '../components/DateGroupRadio/date'; import { isEmpty } from '../utils/commons'; -const defaultParams = { WebCode: 'all', IncludeTickets: 1, IncludeInternal: 1, }; +const defaultParams = { WebCode: 'all', IncludeTickets: 1, IncludeInternal: 1 }; -export const fetchBizOrderCount = async (params, type='', typeVal='') => { +export const fetchBizOrderCount = async (params, type = '', typeVal = '') => { const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCount_biz', { ...defaultParams, ...params, @@ -62,7 +62,7 @@ export const fetchBizOrderCountByType = async (type, params) => { }; const _detailRes = { ordercount1: [], ordercount2: [] }; -export const fetchBizOrderDetailByType = async (params, type='', typeVal='', orderContent='detail') => { +export const fetchBizOrderDetailByType = async (params, type = '', typeVal = '', orderContent = 'detail') => { const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCountByType_Sub_biz', { ...defaultParams, SubOrderType: orderContent, @@ -75,9 +75,12 @@ export const fetchBizOrderDetailByType = async (params, type='', typeVal='', ord OrderType_val: typeVal, }); const res = errcode !== 0 ? _detailRes : (result || _detailRes); - const dateStr = [params.Date1, params.Date2].map(d => d.substring(0, 10)).join('~'); - const dateDiffStr = isEmpty(params.DateDiff1) ? '' : [params.DateDiff1, params.DateDiff2].map(d => d.substring(0, 10)).join('~'); - const ret = [{ dateRangeStr: dateStr, data: res.ordercount1 }, { dateRangeStr: dateDiffStr, data: res.ordercount2 }]; + const dateStr = [params.Date1, params.Date2].map((d) => d.substring(0, 10)).join('~'); + const dateDiffStr = isEmpty(params.DateDiff1) ? '' : [params.DateDiff1, params.DateDiff2].map((d) => d.substring(0, 10)).join('~'); + const ret = [ + { dateRangeStr: dateStr, data: res.ordercount1 }, + { dateRangeStr: dateDiffStr, data: res.ordercount2 }, + ]; return ret; }; @@ -125,7 +128,7 @@ const initialState = { DepartmentList: -1, // -1: All }, - activeTab: 'Form', + activeTab: 'servicetype', activeDateGroupRadio: 'day', orderCountDataRaw: {}, @@ -142,94 +145,90 @@ const initialState = { orderDetails: [], }; - const useBizOrderStore = create( devtools( - immer( - (set, get) => ({ - ...initialState, - reset: () => set(initialState), - - setLoading: (loading) => set({ loading }), - setTypeLoading: (typeLoading) => set({ typeLoading }), - - setSearchValues: (obj, values) => set((state) => ({ searchValues: values, searchValuesToSub: obj })), - setSearchValuesToSub: (values) => set((state) => ({ searchValuesToSub: values })), - setActiveTab: (tab) => set({ activeTab: tab }), - - setOrderCountDataLines: (data) => set({ orderCountDataLines: data }), - setOrderCountDataByType: (type, data) => - set((state) => { - state.orderCountDataByType[type] = data; - }), - - // data ---- - onChangeDateGroup: (value, data, avg1) => { - const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1); - set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue }); - }, - onChangeDateGroupSub: (value, data, avg1) => { - const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1); - set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue }); - }, - - - // site effects - getBizOrderCount: async (params, type, typeVal) => { - const { setLoading, } = get(); - setLoading(true); - try { - const res = await fetchBizOrderCount(params, type, typeVal); - // 第一次得到数据 - const { lines, dateRadioValue, avgLineValue } = resultDataCb(res, 'day', orderCountDataMapper, orderCountDataFieldMapper, calculateLineData); - if (isEmpty(type)) { - // index page - set({ orderCountDataRaw: res }); - set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue }); - } else { - // sub page - set({ orderCountDataRawSub: res }); - set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue }); - } - } catch (error) { - } finally { - setLoading(false); + immer((set, get) => ({ + ...initialState, + reset: () => set(initialState), + + setLoading: (loading) => set({ loading }), + setTypeLoading: (typeLoading) => set({ typeLoading }), + + setSearchValues: (obj, values) => set((state) => ({ searchValues: values, searchValuesToSub: obj })), + setSearchValuesToSub: (values) => set((state) => ({ searchValuesToSub: values })), + setActiveTab: (tab) => set({ activeTab: tab }), + + setOrderCountDataLines: (data) => set({ orderCountDataLines: data }), + setOrderCountDataByType: (type, data) => + set((state) => { + state.orderCountDataByType[type] = data; + }), + + // data ---- + onChangeDateGroup: (value, data, avg1) => { + const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1); + set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue }); + }, + onChangeDateGroupSub: (value, data, avg1) => { + const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1); + set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue }); + }, + + // site effects + getBizOrderCount: async (params, type, typeVal) => { + const { setLoading } = get(); + setLoading(true); + try { + const res = await fetchBizOrderCount(params, type, typeVal); + // 第一次得到数据 + const { lines, dateRadioValue, avgLineValue } = resultDataCb(res, 'day', orderCountDataMapper, orderCountDataFieldMapper, calculateLineData); + if (isEmpty(type)) { + // index page + set({ orderCountDataRaw: res }); + set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue }); + } else { + // sub page + set({ orderCountDataRawSub: res }); + set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue }); } - }, - - getBizOrderCount_type: async (type) => { - const { setTypeLoading, searchValuesToSub, setOrderCountDataByType } = get(); + } catch (error) { + } finally { + setLoading(false); + } + }, + + getBizOrderCount_type: async (type) => { + const { setTypeLoading, searchValuesToSub, setOrderCountDataByType } = get(); + setTypeLoading(true); + try { + const res = await fetchBizOrderCountByType(type, searchValuesToSub); + setOrderCountDataByType(type, res); + } catch (error) { + } finally { + setTypeLoading(false); + } + }, + + onTabChange: async (tab) => { + const { setActiveTab, getBizOrderCount_type } = get(); + setActiveTab(tab); + await getBizOrderCount_type(tab); + }, + + // sub + getBizOrderDetailByType: async (params, type, typeVal) => { + const { setTypeLoading } = get(); + try { setTypeLoading(true); - try { - const res = await fetchBizOrderCountByType(type, searchValuesToSub); - setOrderCountDataByType(type, res); - } catch (error) { - } finally { - setTypeLoading(false); - } - }, - - onTabChange: async (tab) => { - const { setActiveTab, getBizOrderCount_type } = get(); - setActiveTab(tab); - await getBizOrderCount_type(tab); - }, - - // sub - getBizOrderDetailByType: async (params, type, typeVal) => { - const { setTypeLoading, } = get(); - try { - setTypeLoading(true); - const res = await fetchBizOrderDetailByType(params, type, typeVal, 'detail'); - set({ orderDetails: res }); - } catch (error) { - } finally { - setTypeLoading(false); - } - }, - }), - { name: 'bizOrder' } - ) + const res = await fetchBizOrderDetailByType(params, type, typeVal, 'detail'); + set({ orderDetails: res }); + } catch (error) { + } finally { + setTypeLoading(false); + } + }, + })), + { name: 'bizOrder' } ) ); export default useBizOrderStore; diff --git a/src/zustand/Trains.js b/src/zustand/Trains.js index 356b4f8..9c05fa1 100644 --- a/src/zustand/Trains.js +++ b/src/zustand/Trains.js @@ -7,14 +7,14 @@ import { HT_HOST } from '../config'; import { resultDataCb } from '../components/DateGroupRadio/date'; import { groupBy, isEmpty } from '../utils/commons'; -const SERVICETYPE_TRAINSBOOKING = 2; // 火车票服务 +const SERVICETYPE_TRAINSBOOKING = '2'; // 火车票服务 const FORM_TRAINSBOOKING = 32024; // 火车票预定 const FORM_TRAINSUPSELL = 32214; // 火车票Upsell const defaultParams = { WebCode: 'all', IncludeTickets: 1, IncludeInternal: 1 }; const _res = { ordercount1: [], ordercount2: [] }; -export const fetchBizTrainsOrderSummaryByType = async (params) => { +export const fetchBizTrainsOrderSummaryByType = async (params, type = 'Form', typeVal = '') => { const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCountByType_biz', { ...defaultParams, ...params, @@ -22,17 +22,17 @@ export const fetchBizTrainsOrderSummaryByType = async (params) => { COLI_ApplyDate2: params.Date2, COLI_ApplyDateOld1: params.DateDiff1 || '', COLI_ApplyDateOld2: params.DateDiff2 || '', - OrderType: 'Form', + OrderType: type, }); const res = errcode !== 0 ? _res : result || _res; const dateStr = [params.Date1, params.Date2].map((d) => d.substring(0, 10)).join('~'); const ret = [ - { dateRangeStr: dateStr, data: res.ordercount1.find((row) => row.OrderTypeSN === FORM_TRAINSBOOKING) }, - // { dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === FORM_TRAINSBOOKING) }, + { dateRangeStr: dateStr, data: res.ordercount1.find((row) => row.OrderTypeSN === typeVal) }, + // { dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === typeVal) }, ]; const dateDiffStr = isEmpty(params.DateDiff1) ? '' : [params.DateDiff1, params.DateDiff2].map((d) => d.substring(0, 10)).join('~'); if (!isEmpty(dateDiffStr)) { - ret.push({ dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === FORM_TRAINSBOOKING) }); + ret.push({ dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === typeVal) }); } return ret; }; @@ -40,7 +40,7 @@ export const fetchBizTrainsOrderSummaryByType = async (params) => { /** * 从传统订单中获取upsell数据 */ -export const fetchTrainsUpsellTSummaryByType = async (params) => { +export const fetchTrainsUpsellTSummaryByType = async (params, type = 'Form', typeVal = '') => { const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCountByType', { ...defaultParams, ...params, @@ -48,25 +48,26 @@ export const fetchTrainsUpsellTSummaryByType = async (params) => { COLI_ApplyDate2: params.Date2, COLI_ApplyDateOld1: params.DateDiff1 || '', COLI_ApplyDateOld2: params.DateDiff2 || '', - OrderType: 'Form', + OrderType: type, }); const res = errcode !== 0 ? _res : result || _res; const dateStr = [params.Date1, params.Date2].map((d) => d.substring(0, 10)).join('~'); const ret = [ - { dateRangeStr: dateStr, data: res.ordercount1.find((row) => row.OrderTypeSN === FORM_TRAINSUPSELL) }, - // { dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === FORM_TRAINSUPSELL) }, + { dateRangeStr: dateStr, data: res.ordercount1.find((row) => row.OrderTypeSN === typeVal) }, + // { dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === typeVal) }, ]; const dateDiffStr = isEmpty(params.DateDiff1) ? '' : [params.DateDiff1, params.DateDiff2].map((d) => d.substring(0, 10)).join('~'); if (!isEmpty(dateDiffStr)) { - ret.push({ dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === FORM_TRAINSUPSELL) }); + ret.push({ dateRangeStr: dateDiffStr, data: res.ordercount2.find((row) => row.OrderTypeSN === typeVal) }); } return ret; }; export const fetchTrainsWithUpsellSummary = async (params) => { const [trains, upsell] = await Promise.all([ - fetchBizTrainsOrderSummaryByType(params), // todo: 换成servicetype=2 - fetchTrainsUpsellTSummaryByType(params) + // fetchBizTrainsOrderSummaryByType(params, 'Form', FORM_TRAINSBOOKING), // todo: 换成servicetype=2 + fetchBizTrainsOrderSummaryByType(params, 'servicetype', SERVICETYPE_TRAINSBOOKING), + fetchTrainsUpsellTSummaryByType(params, 'Form', FORM_TRAINSUPSELL), ]); if (!isEmpty(trains[1])) { trains[0].data.diff = trains[1].data; @@ -136,92 +137,42 @@ const initialState = { const useTrainsStore = create( devtools( - immer( - (set, get) => ({ - ...initialState, - reset: () => set(initialState), - - setLoading: (loading) => set({ loading }), - setTypeLoading: (typeLoading) => set({ typeLoading }), - - setSearchValues: (obj, values) => set((state) => ({ searchValues: values, searchValuesToSub: obj })), - setSearchValuesToSub: (values) => set((state) => ({ searchValuesToSub: values })), - setActiveTab: (tab) => set({ activeTab: tab }), - - setOrderCountDataLines: (data) => set({ orderCountDataLines: data }), - setOrderCountDataByType: (type, data) => - set((state) => { - state.orderCountDataByType[type] = data; - }), - - // data ---- - onChangeDateGroup: (value, data, avg1) => { - // const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1); - // set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue }); - }, - onChangeDateGroupSub: (value, data, avg1) => { - // const { lines, dateRadioValue, avgLineValue } = calculateLineData(value, data, avg1); - // set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue }); - }, - - // site effects - getBizOrderCount: async (params, type, typeVal) => { - const { setLoading } = get(); - setLoading(true); - set({ trainsOrdersSummary: [] }); - try { - const res = await fetchTrainsWithUpsellSummary(params); - // 第一次得到数据 - // const { lines, dateRadioValue, avgLineValue } = resultDataCb(res, 'day', orderCountDataMapper, orderCountDataFieldMapper, calculateLineData); - // if (isEmpty(type)) { - // // index page - set({ trainsOrdersSummary: res }); - // set({ orderCountDataLines: lines, avgLineValue, activeDateGroupRadio: dateRadioValue }); - // } else { - // // sub page - // set({ orderCountDataRawSub: res }); - // set({ orderCountDataLinesSub: lines, avgLineValueSub: avgLineValue, activeDateGroupRadioSub: dateRadioValue }); - // } - } catch (error) { - } finally { - setLoading(false); - } - }, - - getBizOrderCount_type: async (type) => { - const { setTypeLoading, searchValuesToSub, setOrderCountDataByType } = get(); - setTypeLoading(true); - try { - // const res = await fetchBizOrderCountByType(type, searchValuesToSub); - // setOrderCountDataByType(type, res); - } catch (error) { - } finally { - setTypeLoading(false); - } - }, - - onTabChange: async (tab) => { - const { setActiveTab, getBizOrderCount_type } = get(); - setActiveTab(tab); - await getBizOrderCount_type(tab); - }, - - // sub - getBizOrderDetailByType: async (params, type, typeVal) => { - const { setTypeLoading } = get(); - try { - setTypeLoading(true); - // const res = await fetchBizOrderDetailByType(params, type, typeVal, 'detail'); - // console.log('💥111', res); - // set({ orderDetails: res }); - } catch (error) { - } finally { - setTypeLoading(false); - } - }, - }), - { name: 'bizOrder' } - ) + immer((set, get) => ({ + ...initialState, + reset: () => set(initialState), + + setLoading: (loading) => set({ loading }), + setTypeLoading: (typeLoading) => set({ typeLoading }), + + setSearchValues: (obj, values) => set((state) => ({ searchValues: values, searchValuesToSub: obj })), + setSearchValuesToSub: (values) => set((state) => ({ searchValuesToSub: values })), + setActiveTab: (tab) => set({ activeTab: tab }), + + setOrderCountDataLines: (data) => set({ orderCountDataLines: data }), + setOrderCountDataByType: (type, data) => + set((state) => { + state.orderCountDataByType[type] = data; + }), + + // data ---- + + // site effects + getTrainsWithUpsell: async (params, type, typeVal) => { + const { setLoading } = get(); + setLoading(true); + set({ trainsOrdersSummary: [] }); + try { + const res = await fetchTrainsWithUpsellSummary(params); + set({ trainsOrdersSummary: res }); + } catch (error) { + } finally { + setLoading(false); + } + }, + + // sub + })), + { name: 'trains' } ) ); export default useTrainsStore;