diff --git a/src/components/DateGroupRadio/date.js b/src/components/DateGroupRadio/date.js index be91eab..813d575 100644 --- a/src/components/DateGroupRadio/date.js +++ b/src/components/DateGroupRadio/date.js @@ -1,5 +1,5 @@ import moment from 'moment'; -import { fixTo2Decimals, groupBy } from '../../utils/commons'; +import { fixTo2Decimals, groupBy, isEmpty, sortBy } from '../../utils/commons'; export const datePartOptions = [ { label: '日', value: 'day' }, @@ -8,6 +8,48 @@ export const datePartOptions = [ { label: '季', value: 'season' }, { label: '年', value: 'year' }, ]; +function generateDateRange(minDate, maxDate, dateType = "day") { + // console.log('🔁', minDate, maxDate, dateType); + const dates = []; + const rangeForUnit = {}; + const current = moment(minDate).startOf(dateType); + const end = moment(maxDate); + + while (current.isSameOrBefore(end)) { + let formatted; + const currentRange = current.format("YYYY-MM-DD"); + switch (dateType) { + case "day": + formatted = current.format("YYYY-MM-DD"); + current.add(1, "days"); + break; + case "week": + // formatted = `Week ${current.week()} ${current.year()}`; + formatted = `${current.weekYear()}-W${String(current.week()).padStart(2, '0')}`; + current.add(1, "weeks"); + break; + case "month": + formatted = current.format("YYYY-MM"); + current.add(1, "months"); + break; + case "quarter": + case "season": + // formatted = `Q${current.quarter()} ${current.year()}`; + formatted = `${current.year()}-${String(current.quarter()).padStart(2, 'Q')}`; + current.add(1, "quarters"); + break; + case "year": + formatted = current.format("YYYY"); + current.add(1, "years"); + break; + } + dates.push(formatted); + rangeForUnit[formatted] = currentRange; + // rangeForUnit.push({formatted: currentRange}); + } + + return [dates, rangeForUnit]; +} export const datePartMethod = { 'day': (date) => { return { 'dateKey': date, 'groupKey': date, date }; @@ -17,7 +59,7 @@ export const datePartMethod = { const year = dateO.weekYear(); const week = dateO.week(); // const weekOfMonth = dateO.week() - moment(date).startOf('month').week() + 1; - const key = `W${String(week).padStart(2, '0')}`; + // const key = `W${String(week).padStart(2, '0')}`; const dateKey = `${year}-W${String(week).padStart(2, '0')}`; return { dateKey, 'groupKey': dateKey, date }; }, @@ -51,10 +93,27 @@ export const datePartMethod = { * * data: 转换后的数组 * * avg: 平均值 */ -export const parseDateType = (data, dateType = 'day', { dateKey, valueKey, seriesKey, _f }) => { +export const parseDateType = (data, dateType = 'day', { dateKey, valueKey, seriesKey, _f }, range = []) => { + if (isEmpty(data)) { + return { data: [], avgVal: 0 }; + } const _calcF = { 'avg': (sum, len) => sum / len, }; + // if (data.length ===0 ) console.groupCollapsed('📙'); + // else console.group('📅'); + // console.log('💠', dateKey, valueKey, seriesKey, range); + const rawDates = [...new Set(data.map((c) => c[dateKey]))].sort(); + const _minDate = rawDates[0]; + const _maxDate = rawDates[rawDates.length - 1]; + const [minDate, maxDate] = range; + const [solidDateArr, solidDateStartsObj] = generateDateRange(minDate || _minDate, maxDate || _maxDate, dateType); + // // Diff: elements in solidDateArr but not in rawDates + // const diffKey = [...new Set(solidDateArr.filter((x) => !new Set(rawDates).has(x)))]; + + // console.log('⏩', rawDates); + // console.log('💫 solidDateArr', solidDateArr, solidDateStartsObj); + // console.log('⛔', diffKey); const seriesDataMapped = data.reduce((r, v) => { const _k = v[seriesKey]; (r[_k] || (r[_k] = [])).push(v); @@ -69,6 +128,7 @@ export const parseDateType = (data, dateType = 'day', { dateKey, valueKey, serie }, {}); return { ...rs, ...e }; }, {}); + // console.log('🌗 raw', everySeries); const resultKeys = Object.keys(everySeries); resultKeys.sort(); const dateArr = []; @@ -88,6 +148,28 @@ export const parseDateType = (data, dateType = 'day', { dateKey, valueKey, serie }, []); const avgDiv = [...new Set(dateArr)].length; const avgVal = groupSum.length !== 0 ? groupSum.reduce((s, c) => s + c.value, 0) / avgDiv : 0; + // 补全连续的时间轴 + const fakeSeries = isEmpty(groupSum) ? '' : groupSum[0][seriesKey]; + // Diff: elements in solidDateArr but not in dateArr + const emptyDateUnits = [...new Set(solidDateArr.filter((x) => !new Set(dateArr).has(x)))]; + // console.log('🌕 real ret', structuredClone(groupSum)); + // console.log('🌕 date units',dateArr); + // console.log('🌕 [?]', emptyDateUnits); + emptyDateUnits.forEach(dateUnit => { + const unitStartDate = solidDateStartsObj[dateUnit]; + groupSum.push({ + groupKey: dateUnit + '@' + fakeSeries, + value: null, // 0 undefined + dateKey: unitStartDate, + dateRange: [unitStartDate,unitStartDate], + containDate: [unitStartDate], + [seriesKey]: fakeSeries, + [dateKey]: dateUnit, + }); + }); + groupSum.sort(sortBy(dateKey)); + // console.log('☀ ret ', groupSum); + // console.groupEnd(); return { data: groupSum, avgVal }; }; @@ -103,10 +185,10 @@ export const parseDateType = (data, dateType = 'day', { dateKey, valueKey, serie * * _f: 计算方法. 'sum' | 'avg * @author LYT */ -export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper, cb) => { +export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, { range1, range2, ...fieldMapper }, cb) => { const _data1 = data1 ? dataRaw[data1] : dataRaw; const _data2 = data2 ? dataRaw[data2] : []; - const parse1 = parseDateType(_data1, dateGroup, fieldMapper); + const parse1 = parseDateType(_data1, dateGroup, fieldMapper, range1); const parseData1 = parse1.data.map((ele) => ({ [fieldMapper.dateKey]: ele[fieldMapper.dateKey] === 'Invalid date' ? '空日期' : ele[fieldMapper.dateKey], [fieldMapper.valueKey]: ele.value, @@ -116,7 +198,7 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper, dateRange: ele.dateRange, dateGroup: ele[fieldMapper.dateKey], })); - const parse2 = parseDateType(_data2, dateGroup, fieldMapper); + const parse2 = parseDateType(_data2, dateGroup, fieldMapper, range2); const parseData2 = parse2.data.map((ele) => ({ [fieldMapper.dateKey]: ele[fieldMapper.dateKey] === 'Invalid date' ? '空日期' : ele[fieldMapper.dateKey], // [fieldMapper.dateKey]: ele.groupKey, diff --git a/src/components/DateGroupRadio/index.jsx b/src/components/DateGroupRadio/index.jsx index 16a325f..8cc97fa 100644 --- a/src/components/DateGroupRadio/index.jsx +++ b/src/components/DateGroupRadio/index.jsx @@ -1,16 +1,23 @@ +import { useContext } from 'react'; import { Radio } from 'antd'; import { observer } from 'mobx-react'; +import { toJS } from 'mobx'; import { datePartOptions, resultDataCb } from './date'; +import { stores_Context } from '../../config'; /** * 仅前端转换数据 * 把按天的数据转换成 按周,季,月,年 */ export default observer((props) => { + const { date_picker_store } = useContext(stores_Context); + const { Date1, Date2, DateDiff1, DateDiff2 } = toJS(date_picker_store.formValuesToSub); + const { visible, dataRaw, dataMapper, fieldMapper, onChange, ...extProps } = props; const _dataMapper = dataMapper || { 'data1': null, data2: null }; const handleChange = ({ target: { value } }) => { - resultDataCb(dataRaw, value, _dataMapper, fieldMapper, onChange); + resultDataCb(dataRaw, value, _dataMapper, { ...fieldMapper, range1: [Date1, Date2], range2: [DateDiff1, DateDiff2] }, onChange); }; - return <>{visible !== false ? : null}; + // return <>{visible !== false ? : null}; + return ; });