From bf9400d4198094194439214b5e90036b2f040052 Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期四, 24 九月 2026 16:03:10 +0800
Subject: [PATCH] bug修复,用真实数据
---
src/modules/report/data/screen-merge.ts | 371 +++++++++++++++-------------------------------------
1 files changed, 106 insertions(+), 265 deletions(-)
diff --git a/src/modules/report/data/screen-merge.ts b/src/modules/report/data/screen-merge.ts
index 3f76e64..b820412 100644
--- a/src/modules/report/data/screen-merge.ts
+++ b/src/modules/report/data/screen-merge.ts
@@ -1,12 +1,5 @@
import type { ScreenData, TimeRange } from './screen';
-import { demoScreen } from './screen-demo';
-import {
- FieldTracker,
- KPI_GROUPS,
- groupHasLive,
- resolveDataMode,
- type ScreenDataMode
-} from './screen-field-meta';
+import { FieldTracker, resolveDataMode, type ScreenDataMode } from './screen-field-meta';
import { structureScreen } from './screen-structure';
export type { ScreenDataMode };
@@ -18,271 +11,120 @@
liveFields: string[];
}
-function sum(nums: number[]) {
- return nums.reduce((a, b) => a + (Number(b) || 0), 0);
+function num(v: unknown, fallback = 0) {
+ const n = Number(v);
+ return Number.isFinite(n) ? n : fallback;
}
-function hasPositive(nums: number[]) {
- return nums.some(v => Number(v) > 0);
+function alignSeries(source: number[] | undefined, len: number) {
+ const values = (source || []).map(v => num(v));
+ if (!values.length) return Array.from({ length: len }, () => 0);
+ if (values.length === len) return values;
+ if (values.length > len) return values.slice(values.length - len);
+ return [...Array.from({ length: len - values.length }, () => 0), ...values];
}
-function hasRankData(list: any[]) {
- return list.length > 0 && list.some(e => Number(e?.people) > 0 || Number(e?.weight) > 0);
-}
-
-function pickKpis(
- live: Record<string, number> | undefined,
- demo: Record<string, number>,
- ctx: FieldTracker
-) {
- const out = { ...demo };
- if (!live) {
- Object.values(KPI_GROUPS)
- .flat()
- .forEach(key => ctx.markDemo(`kpis.${key}`));
- return out;
- }
-
- for (const [group, keys] of Object.entries(KPI_GROUPS)) {
- if (groupHasLive(keys, live)) {
- keys.forEach(key => {
- const v = Number(live[key]);
- out[key] = Number.isFinite(v) ? v : demo[key];
- ctx.markLive(`kpis.${key}`);
- });
- } else {
- keys.forEach(key => ctx.markDemo(`kpis.${key}`));
- }
- }
- return out;
-}
-
-function pickArray<T>(
- field: string,
- live: T[] | undefined,
- demo: T[],
- ctx: FieldTracker,
- valid: (v: T[]) => boolean
-) {
- if (live && valid(live)) {
- ctx.markLive(field);
- return live;
- }
- ctx.markDemo(field);
- return demo;
-}
-
-function pickTrend(
- field: string,
- live: { weight: number[]; value: number[]; carbon: number[] } | undefined,
- demo: ScreenData['trend'],
- axis: string[],
- ctx: FieldTracker
-) {
- const valid =
- live &&
- live.weight?.length &&
- (sum(live.weight) > 0 || sum(live.value) > 0 || sum(live.carbon) > 0);
- if (valid) {
- ctx.markLive(field);
- return {
- weight: alignSeries(live!.weight, axis.length, live!.weight[live!.weight.length - 1] || 0),
- value: alignSeries(live!.value, axis.length, live!.value[live!.value.length - 1] || 0),
- carbon: alignSeries(live!.carbon, axis.length, live!.carbon[live!.carbon.length - 1] || 0)
- };
- }
- ctx.markDemo(field);
- return alignTrend(demo, axis.length);
-}
-
-function alignSeries(source: number[], len: number, fill = 0) {
- if (!source?.length) return Array.from({ length: len }, () => fill);
- if (source.length === len) return [...source];
- if (source.length > len) return source.slice(source.length - len);
- return [...Array.from({ length: len - source.length }, () => fill), ...source];
-}
-
-function alignTrend(trend: ScreenData['trend'], len: number) {
- return {
- weight: alignSeries(trend.weight, len),
- value: alignSeries(trend.value, len),
- carbon: alignSeries(trend.carbon, len)
- };
-}
-
-function pickWasteMix(
- live: ScreenData['wasteMix'] | undefined,
- demo: ScreenData['wasteMix'],
- ctx: FieldTracker
-) {
- if (
- live?.length &&
- live.some(e => Number(e.weight) > 0 || Number(e.count) > 0 || Number(e.value) > 0)
- ) {
- ctx.markLive('wasteMix');
- return live.map((item, i) => ({
- ...demo[i],
- ...item,
- color: item.color || demo[i]?.color
- }));
- }
- ctx.markDemo('wasteMix');
- return demo;
-}
-
-function pickRecycleItems(
- live: ScreenData['recycleItems'] | undefined,
- demo: ScreenData['recycleItems'],
- ctx: FieldTracker
-) {
- if (live?.length && live.some(e => Number(e.weight) > 0 || Number(e.value) > 0 || Number(e.carbon) > 0)) {
- ctx.markLive('recycleItems');
- return live.map((item, i) => ({
- ...demo[i],
- ...item,
- color: item.color || demo[i]?.color
- }));
- }
- ctx.markDemo('recycleItems');
- return demo;
-}
-
-function pickPointFlow(
- live: ScreenData['pointFlow'] | undefined,
- demo: ScreenData['pointFlow'],
- ctx: FieldTracker
-) {
- const out = { ...demo };
- if (!live) {
- ctx.markDemo('pointFlow');
- (['issued', 'transfer', 'donate', 'mall', 'balance'] as const).forEach(key =>
- ctx.markDemo(`pointFlow.${key}`)
- );
- return out;
- }
-
- let hasLive = false;
- (['issued', 'transfer', 'donate', 'mall', 'balance'] as const).forEach(key => {
- if (Number(live[key]) > 0) {
- out[key] = live[key];
- ctx.markLive(`pointFlow.${key}`);
- hasLive = true;
- } else {
- ctx.markDemo(`pointFlow.${key}`);
- }
- });
- if (hasLive) ctx.markLive('pointFlow');
- else ctx.markDemo('pointFlow');
- return out;
-}
-
-function pickOrdersByType(
- live: ScreenData['ordersByType'] | undefined,
- demo: ScreenData['ordersByType'],
- ctx: FieldTracker
-) {
- const keys = ['鐜板満鍥炴敹', '棰勭害涓婇棬', '澶у睆鎶曢��', '娲诲姩鍥炴敹'] as const;
- const liveValid = live?.axis?.length && keys.some(k => hasPositive(live[k] || []));
- if (liveValid) {
- ctx.markLive('ordersByType');
- return live!;
- }
- ctx.markDemo('ordersByType');
- return demo;
-}
-
-function pickAppointmentFlow(
- live: ScreenData['appointmentFlow'] | undefined,
- demo: ScreenData['appointmentFlow'],
- ctx: FieldTracker
-) {
- if (live?.length && live.some(e => Number(e.value) > 0)) {
- ctx.markLive('appointmentFlow');
- return live;
- }
- ctx.markDemo('appointmentFlow');
- return demo;
-}
-
-function pickSorterStatus(
- live: ScreenData['sorterStatus'] | undefined,
- demo: ScreenData['sorterStatus'],
- ctx: FieldTracker
-) {
- if (live?.length && sum(live.map(e => Number(e.value))) > 0) {
- ctx.markLive('sorterStatus');
- return live;
- }
- ctx.markDemo('sorterStatus');
- return demo;
-}
-
-function pickAxis(
- live: ScreenData | null | undefined,
- demo: ScreenData,
- structure: ScreenData,
- ctx: FieldTracker
-) {
- const useLiveAxis =
- live?.axis?.length &&
- (sum(live.trend?.weight || []) > 0 ||
- sum(live.participateTrend || []) > 0 ||
- sum(live.deliverTrend || []) > 0 ||
- live.axis.length > 1);
- if (useLiveAxis) {
- ctx.markLive('axis');
- return live!.axis;
- }
- ctx.markDemo('axis');
- return demo.axis.length ? demo.axis : structure.axis;
-}
-
-/** 缁撴瀯 + 婕旂ず + 鐪熷疄鏁版嵁鎸夊瓧娈�/鍒嗙粍鍚堝苟 */
+/** 鐢ㄦ帴鍙g粨鏋滆鐩栭浂鍊肩粨鏋勩�傜己瀛楁淇濇寔 0 鎴栫┖鍒楄〃锛屼笉鍐嶅洖钀藉埌婕旂ず鏁版嵁銆� */
export function resolveScreenData(live: ScreenData | null | undefined, range: TimeRange): ResolvedScreenData {
- const structure = structureScreen(range);
- const demo = demoScreen(range);
+ const base = structureScreen(range);
const ctx = new FieldTracker();
- const axis = pickAxis(live, demo, structure, ctx);
- const kpis = pickKpis(live?.kpis, demo.kpis, ctx);
- const wasteMix = pickWasteMix(live?.wasteMix, demo.wasteMix, ctx);
- const recycleItems = pickRecycleItems(live?.recycleItems, demo.recycleItems, ctx);
- const trend = pickTrend('trend', live?.trend, demo.trend, axis, ctx);
-
- let yearCarbon = demo.yearCarbon;
- if (live?.yearCarbon?.length && sum(live.yearCarbon) > 0) {
- yearCarbon = live.yearCarbon;
- ctx.markLive('yearCarbon');
- } else {
- ctx.markDemo('yearCarbon');
+ if (!live) {
+ return {
+ data: base,
+ mode: 'live',
+ demoFields: [],
+ liveFields: []
+ };
}
- const deptRank = pickArray('deptRank', live?.deptRank, demo.deptRank, ctx, hasRankData);
- const classRank = pickArray('classRank', live?.classRank, demo.classRank, ctx, hasRankData);
- const majorRank = pickArray('majorRank', live?.majorRank, demo.majorRank, ctx, hasRankData);
- const pointFlow = pickPointFlow(live?.pointFlow, demo.pointFlow, ctx);
+ const axis = live.axis?.length ? live.axis : base.axis;
+ ctx.markLive('axis');
- let participateTrend = alignSeries(demo.participateTrend, axis.length);
- if (live?.participateTrend?.length && sum(live.participateTrend) > 0) {
- participateTrend = alignSeries(live.participateTrend, axis.length);
- ctx.markLive('participateTrend');
- } else {
- ctx.markDemo('participateTrend');
- }
+ const kpis = { ...base.kpis };
+ Object.keys(kpis).forEach(key => {
+ if (live.kpis && live.kpis[key] != null) {
+ kpis[key] = num(live.kpis[key]);
+ }
+ ctx.markLive(`kpis.${key}`);
+ });
- let deliverTrend = alignSeries(demo.deliverTrend, axis.length);
- if (live?.deliverTrend?.length && sum(live.deliverTrend) > 0) {
- deliverTrend = alignSeries(live.deliverTrend, axis.length);
- ctx.markLive('deliverTrend');
- } else {
- ctx.markDemo('deliverTrend');
- }
+ const wasteMix = live.wasteMix?.length
+ ? live.wasteMix.map((item, i) => ({
+ ...base.wasteMix[i],
+ ...item,
+ weight: num(item.weight),
+ value: num(item.value),
+ count: num(item.count),
+ color: item.color || base.wasteMix[i]?.color
+ }))
+ : base.wasteMix;
+ ctx.markLive('wasteMix');
- const ordersByType = pickOrdersByType(live?.ordersByType, demo.ordersByType, ctx);
- const appointmentFlow = pickAppointmentFlow(live?.appointmentFlow, demo.appointmentFlow, ctx);
- const sorterStatus = pickSorterStatus(live?.sorterStatus, demo.sorterStatus, ctx);
- const vehicles = pickArray('vehicles', live?.vehicles, demo.vehicles, ctx, v => v.length > 0);
- const sites = pickArray('sites', live?.sites, demo.sites, ctx, v => v.length > 0);
+ const recycleItems = live.recycleItems?.length
+ ? live.recycleItems.map((item, i) => ({
+ ...base.recycleItems[i],
+ ...item,
+ weight: num(item.weight),
+ value: num(item.value),
+ carbon: num(item.carbon),
+ color: item.color || base.recycleItems[i]?.color
+ }))
+ : base.recycleItems;
+ ctx.markLive('recycleItems');
+
+ const trend = {
+ weight: alignSeries(live.trend?.weight, axis.length),
+ value: alignSeries(live.trend?.value, axis.length),
+ carbon: alignSeries(live.trend?.carbon, axis.length)
+ };
+ ctx.markLive('trend');
+
+ const yearCarbon = live.yearCarbon?.length
+ ? alignSeries(live.yearCarbon, 12)
+ : base.yearCarbon;
+ ctx.markLive('yearCarbon');
+
+ const deptRank = Array.isArray(live.deptRank) ? live.deptRank : [];
+ const classRank = Array.isArray(live.classRank) ? live.classRank : [];
+ const majorRank = Array.isArray(live.majorRank) ? live.majorRank : [];
+ ctx.markLive('deptRank');
+ ctx.markLive('classRank');
+ ctx.markLive('majorRank');
+
+ const pointFlow = {
+ issued: num(live.pointFlow?.issued),
+ transfer: num(live.pointFlow?.transfer),
+ donate: num(live.pointFlow?.donate),
+ mall: num(live.pointFlow?.mall),
+ balance: num(live.pointFlow?.balance)
+ };
+ ctx.markLive('pointFlow');
+
+ const participateTrend = alignSeries(live.participateTrend, axis.length);
+ const deliverTrend = alignSeries(live.deliverTrend, axis.length);
+ ctx.markLive('participateTrend');
+ ctx.markLive('deliverTrend');
+
+ const ordersByType = live.ordersByType?.axis?.length
+ ? {
+ axis: live.ordersByType.axis,
+ 鐜板満鍥炴敹: alignSeries(live.ordersByType.鐜板満鍥炴敹, live.ordersByType.axis.length),
+ 棰勭害涓婇棬: alignSeries(live.ordersByType.棰勭害涓婇棬, live.ordersByType.axis.length),
+ 澶у睆鎶曢��: alignSeries(live.ordersByType.澶у睆鎶曢��, live.ordersByType.axis.length),
+ 娲诲姩鍥炴敹: alignSeries(live.ordersByType.娲诲姩鍥炴敹, live.ordersByType.axis.length)
+ }
+ : base.ordersByType;
+ ctx.markLive('ordersByType');
+
+ const appointmentFlow = live.appointmentFlow?.length ? live.appointmentFlow : base.appointmentFlow;
+ const sorterStatus = live.sorterStatus?.length ? live.sorterStatus : base.sorterStatus;
+ const vehicles = Array.isArray(live.vehicles) ? live.vehicles : [];
+ const sites = Array.isArray(live.sites) ? live.sites : [];
+ ctx.markLive('appointmentFlow');
+ ctx.markLive('sorterStatus');
+ ctx.markLive('vehicles');
+ ctx.markLive('sites');
const data: ScreenData = {
range,
@@ -303,21 +145,20 @@
sorterStatus,
vehicles,
sites,
- unavailable: live?.unavailable || []
+ unavailable: live.unavailable || []
};
return {
data,
mode: resolveDataMode(live, ctx),
- demoFields: ctx.listDemo(),
+ demoFields: [],
liveFields: ctx.listLive()
};
}
-/** 鎺ュ彛澶辫触鎴栨棤 live 鏁版嵁鏃剁殑鍒濆灞曠ず */
+/** 鎺ュ彛灏氭湭杩斿洖鏃跺厛灞曠ず闆跺�硷紝閬垮厤鍏堥棯鍑烘紨绀烘暟瀛� */
export function initialScreenData(range: TimeRange = 'month') {
return resolveScreenData(null, range);
}
export { structureScreen, buildScreenAxis } from './screen-structure';
-export { demoScreen } from './screen-demo';
--
Gitblit v1.9.1