From 05e7a8c23bf73364ff8bc7b1e60e86f4389a28e9 Mon Sep 17 00:00:00 2001 From: ShineKOT <1917095344@qq.com> Date: Fri, 20 Jun 2025 11:08:25 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=9B=BE=E8=A1=A8?= =?UTF-8?q?=E5=B9=B4=E5=91=A8=E5=88=86=E7=BB=84=E6=A8=A1=E5=BC=8F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=A1=AB=E5=85=85=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/CHANGELOG.md | 4 + .../chart/generator/base-series-generator.ts | 32 +++----- .../runtime/src/controller/utils/util/util.ts | 76 +++++++++++++++++-- 3 files changed, 87 insertions(+), 25 deletions(-) diff --git a/packages/runtime/CHANGELOG.md b/packages/runtime/CHANGELOG.md index a503ba2614..237c81fc1b 100644 --- a/packages/runtime/CHANGELOG.md +++ b/packages/runtime/CHANGELOG.md @@ -7,6 +7,10 @@ ## [Unreleased] +### Fixed + +- 修复图表年周分组模式数据填充异常 + ## [0.7.41-alpha.4] - 2025-06-19 ### Added diff --git a/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts b/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts index bb86671367..3c4779a0d8 100644 --- a/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts +++ b/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts @@ -17,6 +17,7 @@ import { } from './chart-options-generator'; import { CodeListItem, IChartData } from '../../../../interface'; import { ChartData } from '../../../../service'; +import { generateYearWeekRange } from '../../../utils'; dayjs.extend(minMax); dayjs.extend(isSameOrBefore); @@ -982,7 +983,7 @@ export class BaseSeriesGenerator { } } else if (groupMode === 'YEARWEEK') { // 找出最大和最小年周 - const yearWeeks: string[] = []; + let yearWeeks: string[] = []; Object.keys(data).forEach(key => { data[key].forEach((_val, yearWeek) => { yearWeeks.push(yearWeek); @@ -996,25 +997,16 @@ export class BaseSeriesGenerator { (max, current) => (current > max ? current : max), yearWeeks[0], ); - // 解析最小和最大年周 - const [minYear] = minYearWeek.split('-'); - const [maxYear] = maxYearWeek.split('-'); - // 填充中间年周的数据项 - for ( - let year = parseInt(minYear, 10); - year <= parseInt(maxYear, 10); - year++ - ) { - const numWeeks = dayjs(`${year}-12-31`).isoWeek(); - for (let week = 1; week <= numWeeks; week++) { - const yearWeek = `${year}-${week}`; - Object.keys(data).forEach(key => { - if (!data[key].get(yearWeek)) { - data[key].set(yearWeek, { value: 0 }); - } - }); - } - } + // 只解析开始周和结束周前后3周,防止数据过大 + yearWeeks = generateYearWeekRange(minYearWeek, maxYearWeek, 3); + // 填充年周数据项 + yearWeeks.forEach(yearWeek => { + Object.keys(data).forEach(key => { + if (!data[key].get(yearWeek)) { + data[key].set(yearWeek, { value: 0 }); + } + }); + }); } // 根据时间大小排序 this.sortTimeData(data); diff --git a/packages/runtime/src/controller/utils/util/util.ts b/packages/runtime/src/controller/utils/util/util.ts index 7622fedaa4..369b78273e 100644 --- a/packages/runtime/src/controller/utils/util/util.ts +++ b/packages/runtime/src/controller/utils/util/util.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-plusplus */ /* eslint-disable no-case-declarations */ /* eslint-disable no-restricted-globals */ import { isNil } from 'ramda'; @@ -204,20 +205,18 @@ export function formatDate( const date = new Date(val); if (!val || isNaN(date.getTime())) return value; const year = dayjs(date).year(); - const month = dayjs(date).month() + 1; switch (format) { case 'year': value = `${year}`; break; case 'quarter': - value = `${year} ${Math.ceil(month / 3)}${ibiz.i18n.t('runtime.controller.utils.util.quarter')}`; + value = `${year} ${dayjs(date).quarter()}${ibiz.i18n.t('runtime.controller.utils.util.quarter')}`; break; case 'month': - value = `${year} ${month}${ibiz.i18n.t('runtime.controller.utils.util.month')}`; + value = `${year} ${dayjs(date).month() + 1}${ibiz.i18n.t('runtime.controller.utils.util.month')}`; break; case 'week': - const week = dayjs(date).week(); - value = `${year} ${week}${ibiz.i18n.t('runtime.controller.utils.util.week')}`; + value = `${year} ${dayjs(date).week()}${ibiz.i18n.t('runtime.controller.utils.util.week')}`; break; case 'day': value = dayjs(date).format('YYYY-MM-DD'); @@ -227,3 +226,70 @@ export function formatDate( } return value; } + +/** + * @description 获取某年的总周数 + * @param {number} year 年份 + * @returns {*} {number} + */ +export function getWeeksInYear(year: number): number { + const lastDayOfYear = dayjs(`${year}-12-31`); + const week = lastDayOfYear.isoWeek(); + return week === 1 ? 52 : week; +} + +/** + * @description 生成年周数组 + * @export + * @param {string} minYearWeek 最小年周 + * @param {string} maxYearWeek 最大年周 + * @param {number} [paddingWeeks=0] 前后范围 + * @returns {*} {string[]} + */ +export function generateYearWeekRange( + minYearWeek: string, + maxYearWeek: string, + paddingWeeks = 0, +): string[] { + // 1. 解析最小和最大年周 + const [minYear, minWeek] = minYearWeek.split('-').map(Number); + const [maxYear, maxWeek] = maxYearWeek.split('-').map(Number); + + // 2. 计算起始年周(minYearWeek - paddingWeeks) + let startYear = minYear; + let startWeek = minWeek - paddingWeeks; + while (startWeek < 1) { + startYear--; + startWeek += getWeeksInYear(startYear); + } + + // 3. 计算结束年周(maxYearWeek + paddingWeeks) + let endYear = maxYear; + let endWeek = maxWeek + paddingWeeks; + const maxWeeksInEndYear = getWeeksInYear(endYear); + if (endWeek > maxWeeksInEndYear) { + endWeek -= maxWeeksInEndYear; + endYear++; + } + + // 4. 生成从 startYear-startWeek 到 endYear-endWeek 的所有年周 + const yearWeeks = []; + let currentYear = startYear; + let currentWeek = startWeek; + + while ( + currentYear < endYear || + (currentYear === endYear && currentWeek <= endWeek) + ) { + yearWeeks.push(`${currentYear}-${currentWeek}`); + + currentWeek++; + const weeksInCurrentYear = getWeeksInYear(currentYear); + if (currentWeek > weeksInCurrentYear) { + currentYear++; + currentWeek = 1; + } + } + + return yearWeeks; +} -- Gitee From 3b29991d76c08bf141fdae94c8c763b5d56ad1a3 Mon Sep 17 00:00:00 2001 From: ShineKOT <1917095344@qq.com> Date: Fri, 20 Jun 2025 15:35:08 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=E5=9B=BE=E8=A1=A8=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=BA=8F=E5=88=97=E8=87=AA=E5=AE=9A=E4=B9=89=E5=8F=82?= =?UTF-8?q?=E6=95=B0completionDate=EF=BC=88boolean=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=EF=BC=89=E6=8E=A7=E5=88=B6=E6=97=B6=E9=97=B4=E5=88=86=E7=BB=84?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E6=98=AF=E5=90=A6=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/CHANGELOG.md | 4 ++ .../chart/generator/base-series-generator.ts | 50 +++++++++++++++---- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/packages/runtime/CHANGELOG.md b/packages/runtime/CHANGELOG.md index 237c81fc1b..232017af64 100644 --- a/packages/runtime/CHANGELOG.md +++ b/packages/runtime/CHANGELOG.md @@ -11,6 +11,10 @@ - 修复图表年周分组模式数据填充异常 +### Added + +- 图表新增序列自定义参数completionDate(boolean类型)控制时间分组模式下是否补全时间数据(无横轴序列默认不补全(饼图,仪表盘,雷达图,漏斗图),有横轴序列默认补全) + ## [0.7.41-alpha.4] - 2025-06-19 ### Added diff --git a/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts b/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts index 3c4779a0d8..c0889c0bdb 100644 --- a/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts +++ b/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-expressions */ import { plus, RuntimeModelError, toNumberOrNil } from '@ibiz-template/core'; import { IChartSeriesCSCartesian2DEncode, @@ -766,9 +767,15 @@ export class BaseSeriesGenerator { * @return {*} {(SeriesOption[] | SeriesOption)} */ calcByData(data: IData[]): SeriesOption[] | SeriesOption { + const { userParam, echartsType } = this.model; const tempData = this.dataPreprocess(data); const groupData = this.calcGroupData(tempData); - this.addTimeData(groupData); + // 判断是否补全日期(无横轴序列默认不补全(饼图,仪表盘,雷达图,漏斗图),有横轴序列默认补全) + const completionDate = + userParam?.completionDate === 'false' || + (echartsType && + ['pie', 'gauge', 'radar', 'funnel'].includes(echartsType)); + completionDate ? this.calcTimeData(groupData) : this.addTimeData(groupData); return this.calcGroupSeries(groupData); } @@ -886,17 +893,15 @@ export class BaseSeriesGenerator { } /** - * 根据分组模式补全分组数据并排序 - * @param {IData} data - * @return {*} - * @author: zhujiamin - * @Date: 2023-08-16 13:57:53 + * @description 根据分组模式补全时间数据 + * - 将最小日期和最大日期之间的数据补全,确保横坐标时间的连续性 + * @param {GroupData} data + * @returns {*} {void} + * @memberof BaseSeriesGenerator */ addTimeData(data: GroupData): void { const { groupMode } = this.model; - if (!groupMode || groupMode === 'CODELIST') { - return; - } + if (!groupMode || groupMode === 'CODELIST') return; const dates: Dayjs[] = []; // 遍历数据,生成日期数组 Object.keys(data).forEach(key => { @@ -1011,4 +1016,31 @@ export class BaseSeriesGenerator { // 根据时间大小排序 this.sortTimeData(data); } + + /** + * @description 根据分组模式计算时间数据 + * - 只计算有值的日期,展示关键信息数据,多用于横轴日期显示跨度大的情况 + * @param {GroupData} data + * @memberof BaseSeriesGenerator + */ + calcTimeData(data: GroupData): void { + const { groupMode } = this.model; + if (!groupMode || groupMode === 'CODELIST') return; + // 所有有值的日期数组 + const dates: string[] = []; + // 遍历数据,生成日期数组 + Object.keys(data).forEach(key => { + data[key].forEach((_val, date) => { + dates.push(date); + }); + }); + // 补全每组缺失的日期值,防止横坐标绘制异常 + dates.forEach(date => { + Object.keys(data).forEach(key => { + if (!data[key].get(date)) data[key].set(date, { value: 0 }); + }); + }); + // 根据时间大小排序 + this.sortTimeData(data); + } } -- Gitee From 5dd0a39811bcad948025c1614278f83ef766a383 Mon Sep 17 00:00:00 2001 From: ShineKOT <1917095344@qq.com> Date: Fri, 20 Jun 2025 15:42:41 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../control/chart/generator/base-series-generator.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts b/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts index c0889c0bdb..ddec9329af 100644 --- a/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts +++ b/packages/runtime/src/controller/control/chart/generator/base-series-generator.ts @@ -771,11 +771,13 @@ export class BaseSeriesGenerator { const tempData = this.dataPreprocess(data); const groupData = this.calcGroupData(tempData); // 判断是否补全日期(无横轴序列默认不补全(饼图,仪表盘,雷达图,漏斗图),有横轴序列默认补全) - const completionDate = + const noCompletionDate = userParam?.completionDate === 'false' || (echartsType && ['pie', 'gauge', 'radar', 'funnel'].includes(echartsType)); - completionDate ? this.calcTimeData(groupData) : this.addTimeData(groupData); + noCompletionDate + ? this.calcTimeData(groupData) + : this.addTimeData(groupData); return this.calcGroupSeries(groupData); } -- Gitee