|
|
|
|
@ -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,
|
|
|
|
|
|