Просмотр исходного кода

fix(kpi): 维度能力感知当前汇总版本 + 旧绑定 mismatch 提示与门禁 (server 1.0.293 / Web 2.4.273)

修复:capability 之前只回传维度绑定汇总版本,面板拿绑定字段自比恒'一致',无法识别'当前汇总已推进'的 VERSION_MISMATCH。
- 后端 capability DTO 明确区分 Bound/Current 汇总(Id+Version)+ IsSummaryBindingConsistent;GetCapabilityAsync 查当前汇总并同比 Id+Version,不一致→status=VERSION_MISMATCH/supported=false(SUMMARY_ONLY 语义不变)。
- 前端:面板当前汇总版本改读 currentSummaryConfigVersion、一致性以 isSummaryBindingConsistent 为权威,mismatch 显红+警告+禁激活;DynamicModuleDashboard isDimensionManaged 改按 CONFIGURED/VERSION_MISMATCH 状态(保留卡片显红,安全仍由后端 dashboard 门禁);通用抽屉优先判 VERSION_MISMATCH 态。
Dashboard 既有安全取数门禁未改(回归验证不回落);未改任何 KPI SQL/公式/数据。
YY968XX 1 неделя назад
Родитель
Сommit
2a6f64aa53

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
   "name": "admin.net",
   "type": "module",
-  "version": "2.4.272",
+  "version": "2.4.273",
   "packageManager": "pnpm@10.32.1",
   "lastBuildTime": "2026.03.15",
   "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 7 - 1
Web/src/views/aidop/api/kpiDimensionConfigApi.ts

@@ -32,8 +32,14 @@ export interface KpiDimensionCapability {
 	metricCode: string;
 	moduleCode: string;
 	supported: boolean;
-	capabilityStatus: string; // PENDING_DIMENSION_SQL / CONFIGURED / SUMMARY_ONLY
+	capabilityStatus: string; // PENDING_DIMENSION_SQL / CONFIGURED / SUMMARY_ONLY / VERSION_MISMATCH
+	/** 【兼容旧字段】= 维度绑定汇总版本;判定一致性请用 bound/current 字段 */
 	summaryConfigVersion?: number | null;
+	boundSummaryConfigId?: number | null;
+	boundSummaryConfigVersion?: number | null;
+	currentSummaryConfigId?: number | null;
+	currentSummaryConfigVersion?: number | null;
+	isSummaryBindingConsistent?: boolean;
 	dimensionConfigVersion?: number | null;
 	supportedDimensions: string[];
 	aggregationType?: string | null;

+ 4 - 1
Web/src/views/aidop/kanban/components/DynamicModuleDashboard.vue

@@ -361,7 +361,10 @@ function dimensionCapOf(metricCode?: string | null): KpiDimensionCapability | nu
 	return (metricCode && capMap.value[metricCode]) || null;
 }
 function isDimensionManaged(metric: any): boolean {
-	return dimensionCapOf(metric?.metricCode)?.supported === true;
+	// 有可用维度配置(CONFIGURED)或版本不匹配(VERSION_MISMATCH)都算受管:
+	// 后者需继续在卡片显红并保留“查看明细”,其安全语义由后端 dashboard filterMode 决定,不依赖前端。
+	const st = dimensionCapOf(metric?.metricCode)?.capabilityStatus;
+	return st === 'CONFIGURED' || st === 'VERSION_MISMATCH';
 }
 // 收集页面上 L1+L2 指标码,一次性并发拉 capability,缓存至下次刷新/激活/运行
 async function loadCapabilities() {

+ 7 - 2
Web/src/views/aidop/kanban/components/KpiDimensionConfigPanel.vue

@@ -218,13 +218,18 @@ const draft = ref<DraftForm>(emptyDraft());
 const sqlEditorRef = ref<any>(null);
 
 const current = computed<KpiDimensionConfig | null>(() => versions.value.find((v) => v.isCurrent) || null);
-// 生效汇总版本:能力接口回传的绑定汇总版本即当前生效汇总版本
-const activeSummaryVersion = computed<number | null>(() => capability.value?.summaryConfigVersion ?? null);
+// 当前生效汇总版本:取 capability 明确的 currentSummaryConfigVersion(勿再用绑定字段自比)
+const activeSummaryVersion = computed<number | null>(
+	() => capability.value?.currentSummaryConfigVersion ?? capability.value?.summaryConfigVersion ?? null
+);
+// 一致性以后端 isSummaryBindingConsistent 为权威(同时比对 Id+Version);后端未回传时退回版本比对
 const isCurrentBindingConsistent = computed(() => {
 	if (!current.value) return true;
+	if (capability.value?.isSummaryBindingConsistent != null) return capability.value.isSummaryBindingConsistent;
 	if (activeSummaryVersion.value == null) return true;
 	return current.value.summaryConfigVersion === activeSummaryVersion.value;
 });
+// 某版本行是否与“当前生效汇总版本”不一致(禁激活用)
 function isMismatch(row: KpiDimensionConfig): boolean {
 	return activeSummaryVersion.value != null && row.summaryConfigVersion !== activeSummaryVersion.value;
 }

+ 5 - 5
Web/src/views/aidop/kanban/components/KpiDimensionDrawer.vue

@@ -163,14 +163,14 @@ async function loadDetail() {
 		// 能力优先:未配置直接空态,不请求明细
 		const cap = unwrapDim<KpiDimensionCapability>(await getDimensionCapability(props.metricCode, moduleCode.value));
 		capability.value = cap || null;
-		if (!cap || cap.supported !== true) {
-			capState.value = 'pending';
+		// 版本不匹配优先判定(capability 明确状态 或 卡片传入 filterMode);不回落、不误显未配置
+		if (cap?.capabilityStatus === 'VERSION_MISMATCH' || props.initialFilterMode === FILTER_MODE.VERSION_MISMATCH) {
+			capState.value = 'version_mismatch';
 			detail.value = null;
 			return;
 		}
-		// 版本不匹配以卡片传入 filterMode 为准(详情端点只读当前版本,不作版本裁决,不回落)
-		if (props.initialFilterMode === FILTER_MODE.VERSION_MISMATCH) {
-			capState.value = 'version_mismatch';
+		if (!cap || cap.supported !== true) {
+			capState.value = 'pending';
 			detail.value = null;
 			return;
 		}

+ 3 - 3
server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -11,9 +11,9 @@
     <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
     <Copyright>Admin.NET</Copyright>
     <Description>Admin.NET ͨ��Ȩ�޿���ƽ̨</Description>
-    <AssemblyVersion>1.0.292</AssemblyVersion>
-    <FileVersion>1.0.292</FileVersion>
-    <Version>1.0.292</Version>
+    <AssemblyVersion>1.0.293</AssemblyVersion>
+    <FileVersion>1.0.293</FileVersion>
+    <Version>1.0.293</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 12 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Dto/SmartOps/KpiDimensionConfigDtos.cs

@@ -83,9 +83,20 @@ public sealed class KpiDimensionCapabilityDto
     public string ModuleCode { get; set; } = string.Empty;
     /// <summary>是否已配置并激活维度(PENDING_DIMENSION_SQL 时 false)。</summary>
     public bool Supported { get; set; }
-    /// <summary>能力状态 PENDING_DIMENSION_SQL / CONFIGURED / SUMMARY_ONLY。</summary>
+    /// <summary>能力状态 PENDING_DIMENSION_SQL / CONFIGURED / SUMMARY_ONLY / VERSION_MISMATCH。</summary>
     public string CapabilityStatus { get; set; } = "PENDING_DIMENSION_SQL";
+    /// <summary>【兼容旧字段】= 维度配置绑定的汇总版本(历史调用方勿依赖其为“当前汇总版本”)。新调用方改用 BoundSummaryConfigVersion / CurrentSummaryConfigVersion。</summary>
     public int? SummaryConfigVersion { get; set; }
+    /// <summary>维度配置绑定的汇总配置 Id。</summary>
+    public long? BoundSummaryConfigId { get; set; }
+    /// <summary>维度配置绑定的汇总版本。</summary>
+    public int? BoundSummaryConfigVersion { get; set; }
+    /// <summary>当前生效的汇总配置 Id(可能已推进超过维度绑定)。</summary>
+    public long? CurrentSummaryConfigId { get; set; }
+    /// <summary>当前生效的汇总版本。</summary>
+    public int? CurrentSummaryConfigVersion { get; set; }
+    /// <summary>维度绑定汇总(Id+Version)是否与当前生效汇总一致;false 表示汇总已推进、维度需重绑。</summary>
+    public bool IsSummaryBindingConsistent { get; set; }
     public int? DimensionConfigVersion { get; set; }
     public List<string> SupportedDimensions { get; set; } = new();
     public string? AggregationType { get; set; }

+ 28 - 2
server/Plugins/Admin.NET.Plugin.AiDOP/SmartOps/AdoSmartOpsKpiDimensionConfigService.cs

@@ -276,12 +276,38 @@ public sealed class AdoSmartOpsKpiDimensionConfigService : ITransient
             cap.CapabilityStatus = "PENDING_DIMENSION_SQL";
             return cap;
         }
+        // 维度绑定的汇总版本(兼容旧字段 + 明确的 Bound* 字段)
         cap.SummaryConfigVersion = active.SummaryConfigVersion;
+        cap.BoundSummaryConfigId = active.SummaryConfigId;
+        cap.BoundSummaryConfigVersion = active.SummaryConfigVersion;
         cap.DimensionConfigVersion = active.DimensionConfigVersion;
         cap.AggregationType = active.AggregationType;
         cap.SupportedDimensions = ParseDimensions(active.SupportedDimensionsJson);
-        cap.Supported = active.AggregationType != "SUMMARY_ONLY";
-        cap.CapabilityStatus = active.AggregationType == "SUMMARY_ONLY" ? "SUMMARY_ONLY" : "CONFIGURED";
+
+        // 当前生效的汇总版本(可能已推进超过维度绑定);一致性同时比对 Id 与 Version
+        var currentSummary = await _summaryConfig.GetActiveAsync(tenantId, metricCode);
+        cap.CurrentSummaryConfigId = currentSummary?.Id;
+        cap.CurrentSummaryConfigVersion = currentSummary?.VersionNo;
+        cap.IsSummaryBindingConsistent = currentSummary != null
+            && currentSummary.Id == active.SummaryConfigId
+            && currentSummary.VersionNo == active.SummaryConfigVersion;
+
+        if (active.AggregationType == "SUMMARY_ONLY")
+        {
+            cap.Supported = false;
+            cap.CapabilityStatus = "SUMMARY_ONLY";
+        }
+        else if (!cap.IsSummaryBindingConsistent)
+        {
+            // 汇总已推进 / 当前汇总缺失:旧绑定维度不可直接投用,避免误判可用
+            cap.Supported = false;
+            cap.CapabilityStatus = "VERSION_MISMATCH";
+        }
+        else
+        {
+            cap.Supported = true;
+            cap.CapabilityStatus = "CONFIGURED";
+        }
 
         var lastRun = await _db.Queryable<AdoSmartOpsKpiDimensionRunLog>().ClearFilter<ITenantIdFilter>()
             .Where(x => x.MetricCode == metricCode && x.TenantId == tenantId)