fix: preserve SCADA comparison device coverage
This commit is contained in:
@@ -9,6 +9,7 @@ export function createChartSampleTimeSchema(zod: typeof z = z) {
|
||||
|
||||
type PublicationChart = {
|
||||
chart_type: string;
|
||||
scada?: { role: "current" | "comparison"; window_start: string };
|
||||
x_data: string[];
|
||||
series: Array<{ type?: string; data: Array<number | null>; sample_times?: Array<string | null> }>;
|
||||
};
|
||||
@@ -56,8 +57,12 @@ export function chartPublicationError(chart: PublicationChart): string | null {
|
||||
if ((series.type ?? "line") === "line") for (const base of bases) current.add(base);
|
||||
else historical.push(...bases);
|
||||
}
|
||||
if (current.size !== 1) return "当前 line 必须包含真实采样时间,且所有当前曲线使用同一窗口";
|
||||
const start = [...current][0];
|
||||
const emptyScada = current.size === 0 && chart.scada?.role === "comparison";
|
||||
if (current.size !== 1 && !emptyScada) return "当前 line 必须包含真实采样时间,且所有当前曲线使用同一窗口";
|
||||
const windowStart = emptyScada ? Date.parse(chart.scada!.window_start) + 8 * 3600_000 : 0;
|
||||
const midnight = Math.floor(windowStart / 86400_000) * 86400_000;
|
||||
const firstSlot = midnight + seconds[0] * 1000;
|
||||
const start = emptyScada ? firstSlot + (firstSlot < windowStart ? 86400_000 : 0) : [...current][0];
|
||||
return historical.some((base) => start <= base || (start - base) % 86400_000 !== 0)
|
||||
? "历史 scatter 必须来自当前窗口之前的对应日期" : null;
|
||||
}
|
||||
@@ -67,9 +72,25 @@ export function createViewSchemas(zod: typeof z = z, publication = false, valida
|
||||
const z = zod;
|
||||
|
||||
const presentationIdentifierSchema = z.string().trim().min(1).max(128);
|
||||
const scadaChartSchema = z.object({
|
||||
role: z.enum(["current", "comparison"]),
|
||||
metric: z.enum(["pressure", "flow"]),
|
||||
unit: presentationIdentifierSchema,
|
||||
window_start: createChartSampleTimeSchema(z),
|
||||
window_end: createChartSampleTimeSchema(z),
|
||||
value_field: z.enum(["monitored_value", "cleaned_value"]).optional(),
|
||||
// Populated by Server after checking observations, never a display exemption.
|
||||
gaps: z.array(z.object({
|
||||
device_id: presentationIdentifierSchema,
|
||||
day_offset: z.number().int().min(0).max(7),
|
||||
missing_count: z.number().int().min(1).max(100),
|
||||
reason: z.enum(["no_readings", "outside_frozen_scope", "outside_frozen_window", "no_scheduled_samples"])
|
||||
}).strict()).max(8).optional()
|
||||
}).strict();
|
||||
const chartSchema = z
|
||||
.object({
|
||||
title: z.string().max(200),
|
||||
scada: scadaChartSchema.optional(),
|
||||
chart_type: z.enum(["line", "bar", "time_comparison"]),
|
||||
x_axis_name: z.string().max(128).optional(),
|
||||
y_axis_name: z.string().max(128).optional(),
|
||||
@@ -79,6 +100,8 @@ export function createViewSchemas(zod: typeof z = z, publication = false, valida
|
||||
z
|
||||
.object({
|
||||
name: z.string().max(128),
|
||||
device_id: presentationIdentifierSchema.optional(),
|
||||
day_offset: z.number().int().min(0).max(7).optional(),
|
||||
type: z.enum(["line", "bar", "scatter"]).optional(),
|
||||
data: z.array(z.number().finite().nullable()).min(1).max(100),
|
||||
sample_times: z.array(createChartSampleTimeSchema(z).nullable()).min(1).max(100).optional()
|
||||
|
||||
Reference in New Issue
Block a user