From d29dab5824131f7d7296267e25f4214e481e341c Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 3 Apr 2025 10:08:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E9=80=8F=E8=A7=86:?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0=20=E4=BA=BA=E5=A4=A9=E6=B6=88=E8=B4=B9;?= =?UTF-8?q?=20=E9=85=92=E5=BA=97=E6=98=9F=E7=BA=A7;=20=0Bperf:=20=E6=AF=9B?= =?UTF-8?q?=E5=88=A9=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/ht.js | 90 ++++++++++++++++++++++++++++++++++++----- src/views/DataPivot.jsx | 19 +++++---- 2 files changed, 92 insertions(+), 17 deletions(-) diff --git a/src/libs/ht.js b/src/libs/ht.js index db592f5..439480d 100644 --- a/src/libs/ht.js +++ b/src/libs/ht.js @@ -192,17 +192,70 @@ const calcPPPriceRange = (value) => { if (value < 0) { return '--'; } - const step = 30; // step = 30 USD const start = Math.floor(value / step) * step; const end = start + step; - if (value >= 301) { - return `301-Infinity`; + return `≥301`; } - return `${start === 0 ? start : (start+1)}-${end}`; }; + +function calculateRangeScale(data, numScales = 36) { + if (!data || data.length === 0 || numScales <= 0) { + return []; + } + const sortedData = [...data].sort((a, b) => a - b); + const min = sortedData[0]; + const max = sortedData[sortedData.length - 1]; + if (min === max) { + return [roundToNice(min), roundToNice(min)]; + } + const scales = [roundToNice(min)]; + const scaleSize = sortedData.length / numScales; + for (let i = 1; i < numScales; i++) { + const index = Math.floor(i * scaleSize); + scales.push(roundToNice(sortedData[Math.min(index, sortedData.length - 1)])); + } + scales.push(roundToNice(max)); + return [...new Set(scales)]; +} + +function roundToNice(value) { + if (value === 0) { + return 0; + } + const magnitude = Math.pow(10, Math.floor(Math.log10(Math.abs(value)))); + const normalized = value / magnitude; + let rounded; + if (normalized < 1.5) { + rounded = Math.floor(normalized); + } else if (normalized < 3) { + rounded = Math.floor(normalized * 2) / 2; // round to 0.5 + } else if (normalized < 5) { + rounded = Math.floor(normalized/2) * 2; // round to 2 + } else if (normalized < 7.5) { + rounded = Math.floor(normalized / 5) * 5; + } else { + // rounded = Math.floor(normalized / 5) * 5; + rounded = Math.floor(normalized / 10) * 10; + } + return rounded * magnitude; +}; +const findRange = (value, scale) => { + if (value < scale[0]) { + return `0-${scale[0]}`; // `Value ${value} is below the scale range.`; + } + for (let i = 1; i < scale.length; i++) { + if (value >= scale[i - 1] && value < scale[i]) { + return `${scale[i - 1]}-${scale[i]}`; // `Value ${value} is in the range [${scale[i - 1]}, ${scale[i]})`; + } + } + if (value >= scale[scale.length - 1]) { + return `≥${scale[scale.length - 1]}`; // `Value ${value} is in the range [${scale[scale.length - 1]}, Infinity)`; + } +}; +const SumML_range = [1, 1.5, 2, 3, 4].map(v => v * 10000); /** * 数据透视计算 * @param {object[]} data @@ -216,19 +269,24 @@ export const pivotBy = (_data, [rows, columns, date]) => { // if (groupbyKeys.includes('PPPriceRange')) { // } // 补充计算的字段 + const RTXF_WB_values = cloneDeep(_data).map(ele => ele.RTXF_WB); + // const max_RTXF_WB = Math.max(...RTXF_WB_values); + const RTXF_WB_range = calculateRangeScale(RTXF_WB_values); let data = cloneDeep(_data).map(ele => { - ele.PPPrice = (Number(ele.orderState) === 1 && ele.tourdays && ele.personNum) ? fixToInt(ele.quotePrice / ele.tourdays / ele.personNum) : -1; + ele.PPPrice = (Number(ele.orderState) === 1 && ele.tourdays && ele.personNum) ? fixToInt(ele.quotePrice / ele.tourdays / ele.personNum) : -1; // 报价: 人均天 ele.PPPriceRange = calcPPPriceRange(ele.PPPrice); + ele.RTXF_WB_range = findRange(ele.RTXF_WB, RTXF_WB_range); 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 ? '老客户(推荐)' : ''; - ele.SumML_ctxt1 = ele.ML > 10000 ? '1W+' : '1W-'; - ele.SumML_ctxt1_5 = ele.ML > 15000 ? '1.5W+' : '1.5W-'; - ele.SumML_ctxt2 = ele.ML > 20000 ? '2W+' : '2W-'; - ele.SumML_ctxt3 = ele.ML > 30000 ? '3W+' : '3W-'; - ele.SumML_ctxt4 = ele.ML > 40000 ? '4W+' : '4W-'; + // ele.SumML_ctxt1 = ele.ML > 10000 ? '1W+' : '1W-'; + // ele.SumML_ctxt1_5 = ele.ML > 15000 ? '1.5W+' : '1.5W-'; + // ele.SumML_ctxt2 = ele.ML > 20000 ? '2W+' : '2W-'; + // ele.SumML_ctxt3 = ele.ML > 30000 ? '3W+' : '3W-'; + // ele.SumML_ctxt4 = ele.ML > 40000 ? '4W+' : '4W-'; + ele.SumML_ctxt = findRange(ele.ML, SumML_range); return ele; }); // 数组的字段值, 拆分处理 @@ -244,6 +302,18 @@ export const pivotBy = (_data, [rows, columns, date]) => { return r; }, []); } + if (groupbyKeys.includes('destinations_AsJOSN')) { + data = _data.reduce((r, v, i) => { + const vjson = isEmpty(v.destinations_AsJOSN) ? [] : v.destinations_AsJOSN; + const xv = (vjson).reduce((rv, cv, vi) => { + rv.push({...v, destinations_AsJOSN: cv, key: vi === 0 ? v.key : `${v.key}@${cv}`}); + return rv; + }, []); + + r = r.concat(xv); + return r; + }, []); + } const getKeys = (keys) => keys.map((keyField) => [...new Set(data.map((f) => f[keyField]))]); const [rowsKeys, columnsKeys, dateKeys] = [getKeys(rows), getKeys(columns), [getKeys([date])[0].filter(s => s)]]; diff --git a/src/views/DataPivot.jsx b/src/views/DataPivot.jsx index 1fb9cd9..1fac8f3 100644 --- a/src/views/DataPivot.jsx +++ b/src/views/DataPivot.jsx @@ -26,15 +26,18 @@ const filterFields = [ { key: 'IsOld_txt', label: '是否老客户' }, { key: 'isCusCommend_txt', label: '是否老客户推荐' }, { key: 'hasOld_txt', label: '老客户(推荐)' }, + { key: 'HotelStar', label: '酒店星级' }, { key: 'destinationCountry_AsJOSN', label: '目的地国籍' }, - { key: 'PPPriceRange', label: '人均天/单区间(外币)' }, + { key: 'destinations_AsJOSN', label: '目的地城市' }, + { key: 'RTXF_WB_range', label: '人天消费(外币)' }, + { key: 'PPPriceRange', label: '人均天/单(外币)' }, // { key: 'unitPPPriceRange', label: '人均天(外币)' }, - // todo: 目的地, 目的地国家, - { key: 'SumML_ctxt1', label: '毛利范围[1W]' }, - { key: 'SumML_ctxt1_5', label: '毛利范围[1.5W]' }, - { key: 'SumML_ctxt2', label: '毛利范围[2W]' }, - { key: 'SumML_ctxt3', label: '毛利范围[3W]' }, - { key: 'SumML_ctxt4', label: '毛利范围[4W]' }, + // { key: 'SumML_ctxt1', label: '毛利范围[1W]' }, + // { key: 'SumML_ctxt1_5', label: '毛利范围[1.5W]' }, + // { key: 'SumML_ctxt2', label: '毛利范围[2W]' }, + // { key: 'SumML_ctxt3', label: '毛利范围[3W]' }, + // { key: 'SumML_ctxt4', label: '毛利范围[4W]' }, + { key: 'SumML_ctxt', label: '毛利' }, ]; const filterFieldsMapped = filterFields.reduce((r, v) => ({ ...r, [v.key]: v }), {}); @@ -706,6 +709,7 @@ export default observer((props) => { /> + { !pivotDateColumns[0].includes('destinationCountry_AsJOSN') && !pivotDateColumns[0].includes('destinations_AsJOSN') &&

@@ -721,6 +725,7 @@ export default observer((props) => { + } ); });