feat: классификатор ЕКП — признаки вместо выбора службы (lct-32)
Оператор системы-112 службу не выбирает: он проставляет формализованные признаки происшествия, комбинация признаков даёт код ЕКП, а коду соответствует список оповещения, который система собирает сама (docs/spec/DATASET.md). Прежняя модель с полем dds из пяти значений оценивала действие, которого в боевой работе нет. - scripts/import_ekp.py (make ekp): книга заказчика → app/domain/ekp.json, 1283 кода, 61 служба, 23 группы. Разовый импорт, результат под гитом: читать xlsx в рантайме — лишняя зависимость и полсекунды на старте. - domain/ekp.py: справочник с ленивой загрузкой, каскад значений признаков, список оповещения с модификаторами (нет доступа, угроза людям, пострадавшие, газификация и ещё десяток). - КИО: поля signs, incident_code, notify. Последние два только на чтение и пересчитываются при каждой правке признаков; добавленная вручную служба не теряется, удалить службу нельзя — как в боевом АРМ. - GET /api/ekp/signs отдаёт один уровень признаков, а не дерево на полмегабайта. - Карточка на фронте: три каскадных селектора вместо выбора службы. - Оценка: метрика incident_signs (E2, маршрутизация). Для размеченных сценариев dds_choice больше не считается — список оповещения производен от признаков, и штрафовать за него отдельно значит наказать дважды за одну ошибку. Разбор книги оказался основной работой: имя службы лежит то в первой строке заголовка, то во второй, то склеено с модификатором; «Классификатор МЧС» — заголовок группы колонок, а не служба. Правила разбора в докстринге импорта. 113 тестов зелёных (14 новых в tests/test_ekp.py), make typecheck чистый.
This commit is contained in:
parent
ed0b13f060
commit
7212251112
16 changed files with 522 additions and 19 deletions
|
|
@ -105,6 +105,23 @@ export interface Profile {
|
|||
hints_total: number;
|
||||
}
|
||||
|
||||
/** Значения следующего признака происшествия при уже выбранных (ЕКП). */
|
||||
export interface SignsPage {
|
||||
level: number;
|
||||
values: string[];
|
||||
incident: { code: string; type: string; notify: string[] } | null;
|
||||
}
|
||||
|
||||
export function useSigns(prefix: string[]) {
|
||||
const query = prefix.map((sign) => `prefix=${encodeURIComponent(sign)}`).join("&");
|
||||
return useQuery({
|
||||
queryKey: ["ekp-signs", prefix],
|
||||
// Справочник не меняется между занятиями — перезапрашивать незачем.
|
||||
staleTime: Infinity,
|
||||
queryFn: () => request<SignsPage>(`/api/ekp/signs${query ? `?${query}` : ""}`),
|
||||
});
|
||||
}
|
||||
|
||||
export const useTrainees = () =>
|
||||
useQuery({ queryKey: ["trainees"], queryFn: () => request<TraineeInfo[]>("/api/trainees") });
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue