diff --git a/src/views/biz/reports/TrainsUpsell.jsx b/src/views/biz/reports/TrainsUpsell.jsx index 47d61a3..eb32443 100644 --- a/src/views/biz/reports/TrainsUpsell.jsx +++ b/src/views/biz/reports/TrainsUpsell.jsx @@ -51,12 +51,14 @@ const TrainsUpsell = observer(({ ...props }) => { const { date_picker_store: searchFormStore } = useContext(stores_Context); const [searchValues, setSearchValues] = useTrainsStore(useShallow((state) => [state.searchValues, state.setSearchValues])); - const [loading] = useTrainsStore(useShallow((state) => [state.loading])); + const [loading, typeLoading] = useTrainsStore(useShallow((state) => [state.loading, state.typeLoading])); const [trainsOrdersSummary, compareData] = useTrainsStore((state) => state.trainsOrdersSummary); + const trainsUpsellOrdersDetail = useTrainsStore((state) => state.trainsUpsellOrdersDetail); // const showDiff = !comm.isEmpty(searchValuesToSub.DateDiff2); const showDiff = !comm.isEmpty(compareData); const getTrainsWithUpsell = useTrainsStore((state) => state.getTrainsWithUpsell); + const getTrainsOrderDetail = useTrainsStore((state) => state.getTrainsOrderDetail); const data0 = buildFunnelData(trainsOrdersSummary, compareData); const chartConfig = { @@ -126,12 +128,13 @@ const TrainsUpsell = observer(({ ...props }) => { const tableProps = { title: () => `${trainsOrdersSummary?.dateRangeStr || ''}` + (showDiff ? ` vs ${compareData?.dateRangeStr}` : ''), dataSource: trainsOrdersSummary?.data || [], - columns: [ - { - title: '#', - fixed: 'left', - dataIndex: 'OrderType', - }, + // columns: [], + size: 'small', + pagination: false, + scroll: { x: 100 * 7 }, + loading, + }; + const tableCols = [ { title: '数量', dataIndex: 'OrderCount', @@ -163,12 +166,7 @@ const TrainsUpsell = observer(({ ...props }) => { dataIndex: 'Ordervalue', render: (text, r) => (!showDiff ? text : comm.show_vs_tag(r.Ordervalue_vs, r.Ordervalue_diff, r.Ordervalue, r.diff?.Ordervalue)), }, - ], - size: 'small', - pagination: false, - scroll: { x: 100 * 7 }, - loading, - }; + ]; return ( <>
@@ -190,12 +188,13 @@ const TrainsUpsell = observer(({ ...props }) => { onSubmit={(_err, obj, form, str) => { setSearchValues(obj, form); getTrainsWithUpsell(obj); + getTrainsOrderDetail(obj); }} /> - +
@@ -230,6 +229,16 @@ const TrainsUpsell = observer(({ ...props }) => { + +
`火车票Upsell: 各站`} + /> diff --git a/src/zustand/Trains.js b/src/zustand/Trains.js index 9c05fa1..6cbea43 100644 --- a/src/zustand/Trains.js +++ b/src/zustand/Trains.js @@ -5,7 +5,7 @@ import { groupsCTplus, groupsMappedByCode } from '../libs/ht'; import { fetchJSON } from '../utils/request'; import { HT_HOST } from '../config'; import { resultDataCb } from '../components/DateGroupRadio/date'; -import { groupBy, isEmpty } from '../utils/commons'; +import { fixTo2Decimals, fixTo4Decimals, groupBy, isEmpty } from '../utils/commons'; const SERVICETYPE_TRAINSBOOKING = '2'; // 火车票服务 const FORM_TRAINSBOOKING = 32024; // 火车票预定 @@ -63,6 +63,114 @@ export const fetchTrainsUpsellTSummaryByType = async (params, type = 'Form', typ return ret; }; +const calcSummary = (arr, keepKeys = []) => { + const s = arr.reduce( + (acc, cur) => { + acc.CJCount += cur.COLI_Success === 1 ? 1 : 0; + acc.CJPersonNum += cur.COLI_Success === 1 ? cur.COLI_PersonNum + cur.COLI_ChildNum + cur.COLI_BabyNum : 0; + acc.OrderCount += 1; + acc.YJLY += cur.CGI_YJLY; + keepKeys.forEach((key) => { + acc[key] = cur[key]; + }); + return acc; + }, + { CJCount: 0, CJPersonNum: 0, CJrate: 0, OrderCount: 0, YJLY: 0 } + ); + s.CJrate = s.OrderCount ? (fixTo2Decimals(s.CJCount / s.OrderCount * 100)) : 0; + s.YJLY = fixTo2Decimals(s.YJLY); + return s; +}; + +const _detailRes = { ordercount1: [], ordercount2: [] }; +export const fetchUpsellOrderDetailByType = async (params, type = 'Form', typeVal = FORM_TRAINSUPSELL, orderContent = 'detail') => { + const { errcode, errmsg, ...result } = await fetchJSON(HT_HOST + '/service-web/QueryData/GetOrderCountByType_Sub', { + ...defaultParams, + SubOrderType: orderContent, + ...params, + COLI_ApplyDate1: params.Date1, + COLI_ApplyDate2: params.Date2, + COLI_ApplyDateOld1: params.DateDiff1 || '', + COLI_ApplyDateOld2: params.DateDiff2 || '', + OrderType: type, + OrderType_val: typeVal, + }); + const res = errcode !== 0 ? _detailRes : (result || _detailRes); + const dateStr = [params.Date1, params.Date2].map((d) => d.substring(0, 10)).join('~'); + const ret = [ + { dateRangeStr: dateStr, data: res.ordercount1 }, + // { dateRangeStr: dateDiffStr, data: res.ordercount2 }, + ]; + 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 }); + } + const retS = ret.map(({ dateRangeStr, data }) => { + const byWebCode = (Object.values(groupBy(data, 'COLI_WebCode'))).map((group) => calcSummary(group, ['COLI_WebCode'])); + const summary = calcSummary(data); + return { dateRangeStr, data , summary, byWebCode }; + }); + // diff + if (!isEmpty(dateDiffStr)) { + const [{ byWebCode: byWebCode1 }, { byWebCode: byWebCode2 }] = retS; + const withDiff1 = byWebCode1.map((row, i) => { + const row2 = byWebCode2.find((r2) => r2.COLI_WebCode === row.COLI_WebCode); + row.diff = row2 || {}; + row.CJCount_vs = row2.CJCount ? fixTo2Decimals(((row.CJCount - row2.CJCount) / row2.CJCount) * 100) : 0; + row.CJPersonNum_vs = row2.CJPersonNum ? fixTo2Decimals(((row.CJPersonNum - row2.CJPersonNum) / row2.CJPersonNum) * 100) : 0; + row.CJrate_vs = row2.CJrate ? fixTo2Decimals(row.CJrate - row2.CJrate) : 0; + row.YJLY_vs = row2.YJLY ? fixTo2Decimals(((row.YJLY - row2.YJLY) / row2.YJLY) * 100) : 0; + row.OrderCount_vs = row2.OrderCount ? fixTo2Decimals(((row.OrderCount - row2.OrderCount) / row2.OrderCount) * 100) : 0; + row.CJCount_diff = row2.CJCount ? row.CJCount - row2.CJCount : 0; + row.CJPersonNum_diff = row2.CJPersonNum ? row.CJPersonNum - row2.CJPersonNum : 0; + row.CJrate_diff = row2.CJrate ? fixTo2Decimals(row.CJrate - row2.CJrate) : 0; + row.YJLY_diff = row2.YJLY ? fixTo2Decimals(row.YJLY - row2.YJLY) : 0; + row.OrderCount_diff = row2.OrderCount ? row.OrderCount - row2.OrderCount : 0; + return row; + }); + // + const rows1Map = byWebCode1.reduce((a, row1) => ({ ...a, [row1.COLI_WebCode]: row1 }), {}); + const rows2Map = byWebCode2.reduce((a, row2) => ({ ...a, [row2.COLI_WebCode]: row2 }), {}); + // Diff: elements in rows2 but not in rows1 + const diffKey = [...new Set(Object.keys(rows2Map).filter((x) => !new Set(Object.keys(rows1Map)).has(x)))]; + withDiff1.push( + ...diffKey.map((key) => ({ + diff: rows2Map[key], + CJrate: 0, + COLI_WebCode: rows2Map[key].COLI_WebCode, + CJCount_vs: -100, + CJPersonNum_vs: -100, + CJrate_vs: -100, + YJLY_vs: -100, + OrderCount_vs: -100, + CJCount_diff: -rows2Map[key].CJCount, + CJPersonNum_diff: -rows2Map[key].CJPersonNum, + CJrate_diff: -rows2Map[key].CJrate, + YJLY_diff: -rows2Map[key].YJLY, + OrderCount_diff: -rows2Map[key].OrderCount, + })) + ); + retS[0].byWebCode = withDiff1; + } + // % + retS.forEach(({ summary, byWebCode }, i) => { + summary.CJrate = `${summary.CJrate}%`; + if (i !== 0) { + } else { + byWebCode.forEach((row) => { + row.CJrate = `${row.CJrate}%`; + row.CJrate_vs = `${row.CJrate_vs}%`; + row.CJrate_diff = `${row.CJrate_diff}%`; + row.CJCount_vs = `${row.CJCount_vs}%`; + row.CJPersonNum_vs = `${row.CJPersonNum_vs}%`; + row.OrderCount_vs = `${row.OrderCount_vs}%`; + row.YJLY_vs = `${row.YJLY_vs}%`; + }); + } + }); + return retS; +}; + export const fetchTrainsWithUpsellSummary = async (params) => { const [trains, upsell] = await Promise.all([ // fetchBizTrainsOrderSummaryByType(params, 'Form', FORM_TRAINSBOOKING), // todo: 换成servicetype=2 @@ -117,6 +225,7 @@ const initialState = { }, trainsOrdersSummary: [], + trainsUpsellOrdersDetail: [], activeTab: 'Form', activeDateGroupRadio: 'day', @@ -170,6 +279,19 @@ const useTrainsStore = create( } }, + getTrainsOrderDetail: async (params) => { + const { setTypeLoading } = get(); + setTypeLoading(true); + set({ trainsUpsellOrdersDetail: [] }); + try { + const res = await fetchUpsellOrderDetailByType(params); + set({ trainsUpsellOrdersDetail: res }); + } catch (error) { + } finally { + setTypeLoading(false); + } + } + // sub })), { name: 'trains' }