Ver Fonte

fix(s8): show empty state for module cards with zero total

YY968XX há 4 meses atrás
pai
commit
e4fedc82cb

+ 8 - 1
Web/src/views/aidop/s8/monitoring/S8MonitoringOverviewPage.vue

@@ -517,6 +517,12 @@ function buildStageCard(
 	//   不再用异常总数 total(不含正常底数会导致绿色永远 0);
 	// - 均时接入真实 API avgProcessHours,不再写死 0h。
 	const normal = DEFAULT_NORMAL_WORK_ORDER_COUNT;
+	// S8-MODULE-CARD-ZERO-TOTAL-EMPTY-STATE-1:total=0 模块无样本,闭环率/均时不可计算 → 显示「--」;
+	// total>0 但 avgProcessHours 无效(NaN/<=0)时均时也走空态,避免 0h 误读。
+	const hasSamples = total > 0;
+	const hasAvgHours = hasSamples && Number.isFinite(avgProcessHours) && avgProcessHours > 0;
+	const closeRateText = hasSamples ? formatPercent(closeRate, closeRate > 0 && closeRate < 10 ? 1 : 0) : '--';
+	const avgHoursText = hasAvgHours ? formatHours(avgProcessHours) : '--';
 
 	return {
 		code: meta.code,
@@ -528,6 +534,7 @@ function buildStageCard(
 		// 全部为自然数;warning + serious = 异常总数;绿色暂用 DEFAULT_NORMAL_WORK_ORDER_COUNT。
 		values: buildModuleTriColorStats({ total: anomalyCount, red, yellow }),
 		healthRate: closeRate,
+		healthRateText: hasSamples ? undefined : '--',
 		statusLabel: timeout > 0 ? `${timeout} 超时` : `${anomalyCount} 异常`,
 		progress: toProgress(normal, yellow, red),
 		tone,
@@ -535,7 +542,7 @@ function buildStageCard(
 		cardSpan: meta.wide ? 2 : 1,
 		minHeight: meta.wide ? 196 : 176,
 		wideRate: closeRate,
-		wideRateLabel: `闭环率 ${formatPercent(closeRate, closeRate > 0 && closeRate < 10 ? 1 : 0)} / 均时 ${formatHours(avgProcessHours)}`,
+		wideRateLabel: `闭环率 ${closeRateText} / 均时 ${avgHoursText}`,
 		avgProcessHours,
 	};
 }

+ 2 - 0
Web/src/views/aidop/s8/monitoring/components/S8MonitoringModulesGrid.vue

@@ -57,6 +57,8 @@ interface StageCardData {
   valueLabels?: { green: string; yellow: string; red: string }
   metricLabel: string
   healthRate: number
+  // S8-MODULE-CARD-ZERO-TOTAL-EMPTY-STATE-1:空态文本(如 "--"),优先于 `${healthRate}%` 渲染。
+  healthRateText?: string
   statusLabel: string
   progress: { green: number; yellow: number; red: number }
   tone: 'green' | 'yellow' | 'red'

+ 4 - 2
Web/src/views/aidop/s8/monitoring/components/S8MonitoringStageCard.vue

@@ -14,6 +14,8 @@ const props = defineProps<{
 	valueLabels?: { green: string; yellow: string; red: string };
 	metricLabel: string;
 	healthRate: number;
+	// S8-MODULE-CARD-ZERO-TOTAL-EMPTY-STATE-1:空态文本(如「--」),优先于 `${healthRate}%` 渲染。
+	healthRateText?: string;
 	statusLabel: string;
 	progress: {
 		green: number;
@@ -95,7 +97,7 @@ const isWide = computed(() => (props.cardSpan ?? 1) > 1);
 
 			<template #health-rate>
 				<div class="stage-card__stats stage-card__stats--health">
-					<span>闭环率 {{ healthRate }}%</span>
+					<span>闭环率 {{ healthRateText ?? `${healthRate}%` }}</span>
 				</div>
 			</template>
 
@@ -115,7 +117,7 @@ const isWide = computed(() => (props.cardSpan ?? 1) > 1);
 
 			<template #wide-meter>
 				<div v-if="isWide" class="stage-card__wide-meter">
-					<div class="stage-card__wide-label">{{ wideRateLabel || `闭环率 ${healthRate}%` }}</div>
+					<div class="stage-card__wide-label">{{ wideRateLabel || `闭环率 ${healthRateText ?? `${healthRate}%`}` }}</div>
 					<div class="stage-card__wide-track">
 						<div class="stage-card__wide-fill" :style="{ width: `${clampedWideRate}%` }" />
 					</div>

+ 4 - 0
Web/src/views/aidop/s8/monitoring/useS8StageConfig.ts

@@ -54,6 +54,8 @@ export interface StageCardPreviewData {
 	valueLabels?: Record<StageTone, string>;
 	metricLabel: string;
 	healthRate: number;
+	// S8-MODULE-CARD-ZERO-TOTAL-EMPTY-STATE-1:空态文本(如 "--"),优先于 `${healthRate}%` 渲染。
+	healthRateText?: string;
 	statusLabel: string;
 	progress: StageProgress;
 	tone: StageTone;
@@ -320,6 +322,8 @@ export function useS8StageConfig() {
 			// S8-MODULE-CARD-SEMANTICS-FIX-1A:实时 healthRate(=closeRate)来自 buildStageCard,
 			// 优先使用,避免 localStorage 残留的旧 health 值(计算公式已变更)覆盖。
 			healthRate: clampPercent(card.healthRate),
+			// S8-MODULE-CARD-ZERO-TOTAL-EMPTY-STATE-1:透传空态文本,让 total=0 卡显示「闭环率 --」。
+			healthRateText: card.healthRateText,
 			statusLabel: config.statusLabel,
 			progress,
 			tone,