chore: обновить паузу занятия от main
# Conflicts: # backend/app/scoring/dispatcher.py # backend/app/session/store.py
This commit is contained in:
commit
0d58878cbe
51 changed files with 4545 additions and 87 deletions
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import type { Level, SessionMode, SessionReport, StationSnapshot } from "@/shared/types/generated";
|
||||
import type {
|
||||
Level, SessionMode, SessionReport, StationSnapshot, TimerState,
|
||||
} from "@/shared/types/generated";
|
||||
|
||||
import { reportErrorMessage, reportRetryDelay, shouldRetryReport } from "./report.mjs";
|
||||
|
||||
|
|
@ -94,6 +96,12 @@ export interface SessionInfo {
|
|||
end_reason: string | null;
|
||||
}
|
||||
|
||||
export interface Signal {
|
||||
kind: "backlog" | "refusals" | "offline";
|
||||
severity: TimerState;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ActiveSessionInfo {
|
||||
session_id: string;
|
||||
trainee_name: string | null;
|
||||
|
|
@ -109,6 +117,8 @@ export interface ActiveSessionInfo {
|
|||
dds_work_overdue_cards: number;
|
||||
dds_statuses: Record<string, string>;
|
||||
dds_snapshot: StationSnapshot | null;
|
||||
signals: Signal[];
|
||||
presence_known: boolean;
|
||||
}
|
||||
|
||||
export const useActiveSessions = () =>
|
||||
|
|
@ -230,6 +240,17 @@ export const useIncidentGroups = () => useQuery({
|
|||
queryFn: () => request<IncidentGroupsPage>("/api/ekp/groups"),
|
||||
});
|
||||
|
||||
export interface ServiceCatalogPage {
|
||||
source: string;
|
||||
services: { id: string; name: string; organization: string | null; service_level: string | null; source_reference: string }[];
|
||||
}
|
||||
|
||||
/** Каталог окна «Добавьте службы»: 209 служб, включая районные ДДС. */
|
||||
export const useServiceCatalog = () => useQuery({
|
||||
queryKey: ["ekp-services"], staleTime: Infinity,
|
||||
queryFn: () => request<ServiceCatalogPage>("/api/ekp/services"),
|
||||
});
|
||||
|
||||
export function useSigns(prefix: string[], group: number | null = null) {
|
||||
const params = new URLSearchParams();
|
||||
if (group !== null) params.set("group", String(group));
|
||||
|
|
|
|||
|
|
@ -164,8 +164,17 @@ export const callChannel = (
|
|||
...options,
|
||||
queueKey: (event) => event.type === "kio.patch" ? "kio.patch" : null,
|
||||
isAcknowledged: (incoming, pending) => {
|
||||
if (pending.type !== "kio.patch" || incoming.type !== "kio.patch"
|
||||
|| incoming.source !== "operator") return false;
|
||||
if (pending.type !== "kio.patch" || incoming.type !== "kio.patch") return false;
|
||||
// `auto` по всем полям команды с другим значением — сервер её переписал
|
||||
// (так он отвечает и на отклонённый пакет), а merge.ts уже снял правку из
|
||||
// pending. Повтор затёр бы серверную истину, а слияние с новыми правками
|
||||
// отклоняло бы и их. Совпадающий `auto` ничего не доказывает: команда
|
||||
// могла не дойти, повтор безвреден.
|
||||
if (incoming.source === "auto") {
|
||||
const keys = Object.keys(pending.fields);
|
||||
return keys.every((key) => key in incoming.fields)
|
||||
&& keys.some((key) => !sameJsonValue(pending.fields[key], incoming.fields[key]));
|
||||
}
|
||||
return Object.entries(pending.fields).every(([key, value]) =>
|
||||
sameJsonValue(value, incoming.fields[key]),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ export interface DdsCardReport {
|
|||
card_id: string;
|
||||
scenario_id: string;
|
||||
score_auto: number;
|
||||
score_reviewed?: number | null;
|
||||
reply_text: string;
|
||||
metrics: Array<Metric>;
|
||||
findings: Array<Finding>;
|
||||
|
|
@ -267,6 +268,23 @@ export interface Finding {
|
|||
competency?: Competency | null;
|
||||
transcript_ref?: string | null;
|
||||
at?: string | null;
|
||||
metric_key?: string | null;
|
||||
card?: number | null;
|
||||
service?: string | null;
|
||||
author?: string | null;
|
||||
client_id?: string | null;
|
||||
reviews?: Array<FindingReview>;
|
||||
}
|
||||
|
||||
/** Решение преподавателя по отметке на разборе. */
|
||||
export type FindingDecision = "confirmed" | "dismissed";
|
||||
|
||||
/** Кто, когда и почему подтвердил или снял отметку. Сама отметка остаётся. */
|
||||
export interface FindingReview {
|
||||
decision: FindingDecision;
|
||||
reason: string;
|
||||
author: string;
|
||||
at: string;
|
||||
}
|
||||
|
||||
/** Источник объяснимой отметки; `judge` оставлен для старых отчётов. */
|
||||
|
|
@ -346,6 +364,8 @@ export interface KIO {
|
|||
evacuation_needed?: boolean;
|
||||
/** Список оповещения */
|
||||
notify?: Array<string>;
|
||||
/** Дополнительно оповестить */
|
||||
notify_extra?: Array<string>;
|
||||
/** Устаревшее: одна служба. Заменено списком оповещения */
|
||||
dds?: DDSCode | null;
|
||||
dispatch_order_at?: string | null;
|
||||
|
|
@ -380,6 +400,7 @@ export interface LessonCriteria {
|
|||
decision_time_limit_seconds?: number;
|
||||
card_fill_time_limit_seconds?: number;
|
||||
dds_card_work_time_limit_seconds?: number;
|
||||
dds_report_reaction_limit_seconds?: number;
|
||||
allowed_errors?: number;
|
||||
require_correct_grammar?: boolean;
|
||||
score_weights?: Record<string, number>;
|
||||
|
|
@ -407,6 +428,10 @@ export interface Metric {
|
|||
passed: boolean;
|
||||
weight?: number;
|
||||
credit?: number | null;
|
||||
card?: number | null;
|
||||
service?: string | null;
|
||||
passed_auto?: boolean | null;
|
||||
credit_auto?: number | null;
|
||||
}
|
||||
|
||||
export interface ModeSet {
|
||||
|
|
@ -619,6 +644,7 @@ export interface SessionReport {
|
|||
self_assessment_diff?: SelfAssessmentDiff | null;
|
||||
notes?: Array<InstructorNoteShown>;
|
||||
score_auto: number;
|
||||
score_reviewed?: number | null;
|
||||
score_final: number;
|
||||
overridden_by?: string | null;
|
||||
override_comment?: string | null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue