идентификатор удаления выделенного

This commit is contained in:
2026-09-29 10:21:06 +03:00
parent 203ce44b6d
commit 5d416b729b
3 changed files with 16739 additions and 5 deletions

View File

@@ -104,7 +104,7 @@ DEFAULT_CONTEXT_VARIABLES: tuple[dict[str, Any], ...] = (
{"key": "active_away_penalty_team_penalty", "label": "Активное удаление правой команды — командное (1/0)", "category": "Активные удаления — правая команда", "entity_type": "penalty", "scope": "match_shared", "source_type": "selection", "value_type": "text"},
{"key": "active_away_penalty_time_type", "label": "Активное удаление правой команды — тип времени (2 / 2+2 / 4 / 5 / 5+20 / 10)", "category": "Активные удаления — правая команда", "entity_type": "penalty", "scope": "match_shared", "source_type": "selection", "value_type": "text", "description": "Пресет штрафного времени текущего удаления; доступен сразу после назначения времени, до запуска countdown."},
{"key": "selected_penalty_infraction_id", "label": "Нарушение выбранного удаления", "category": "Выделенные", "entity_type": "penalty", "scope": "match", "source_type": "selection"},
{"key": "selected_penalty_preset_id", "label": "Длительность выбранного удаления", "category": "Выделенные", "entity_type": "penalty", "scope": "match", "source_type": "selection"},
{"key": "selected_penalty_preset_id", "label": "ID типа выбранного удаления (hockey_penalty_types.id)", "category": "Выделенные", "entity_type": "penalty", "scope": "match", "source_type": "selection", "value_type": "text", "description": "Реальный ID типа нарушения из hockey_penalty_types для выделенной карточки удаления во вкладке Игра. Обновляется при выборе другого удаления."},
{"key": "selected_penalty_time_type", "label": "Тип времени выбранного удаления (2 / 2+2 / 4 / 5 / 5+20 / 10)", "category": "Выделенные", "entity_type": "penalty", "scope": "match", "source_type": "selection", "value_type": "text", "description": "Точное название выбранного пресета штрафного времени. Например: 2, 2+2, 4, 5, 5+20, 10."},
{"key": "selected_penalty_side", "label": "Сторона выбранного удаления", "category": "Выделенные", "entity_type": "penalty", "scope": "match", "source_type": "selection"},
{"key": "selected_penalty_event_time", "label": "Время события выбранного удаления", "category": "Выделенные", "entity_type": "penalty", "scope": "match", "source_type": "selection"},

File diff suppressed because it is too large Load Diff

View File

@@ -5337,6 +5337,7 @@ function startCustomTooltips() {
const boardComponent = hockeyPenaltyBoardComponent();
const selectedEvent = boardComponent ? selectedHockeyEvent(boardComponent) : null;
const selectedTimeType = String(selectedEvent?.preset || "");
const selectedPenaltyTypeId = hockeyPenaltyInfractionDbId(selectedEvent);
const values = {
active_home_penalty_id: home?.penalty_id || "",
active_home_penalty_player_id: home?.player_id || "",
@@ -5348,9 +5349,9 @@ function startCustomTooltips() {
active_away_penalty_player_db_id: away?.player_db_id || "",
active_away_penalty_team_penalty: away ? (away.team_penalty ? "1" : "0") : "",
active_away_penalty_time_type: away?.time_type || "",
// Keep the currently highlighted Game-tab penalty type ready before
// penalty_ready/penalty_assigned invokes any vMix trigger.
selected_penalty_preset_id: selectedTimeType,
// Real hockey_penalty_types.id of the highlighted Game-tab penalty.
// Keep the textual duration (2 / 2+2 / 5+20 / ...) in a separate key.
selected_penalty_preset_id: selectedPenaltyTypeId,
selected_penalty_time_type: selectedTimeType,
};
const signature = JSON.stringify([gameId, values]);
@@ -7034,7 +7035,11 @@ function openTimerQuickEditor(focusActionId = "") {
return directory
.filter((item) => item && item.active !== false)
.map((item, index) => ({
// `id` remains the stable penalty code for compatibility with old
// saved boards/triggers. `dbId` is the real hockey_penalty_types.id.
id: String(item.code || item.id || `INF_${index + 1}`),
code: String(item.code || ""),
dbId: String(item.id ?? ""),
label: String(item.name || item.name_ru || item.name_en || item.code || `Нарушение ${index + 1}`),
labelRu: String(item.name_ru || ""),
labelEn: String(item.name_en || ""),
@@ -8758,6 +8763,38 @@ function hockeyPenaltyPlayerIdentifiers(component, event) {
return { externalId, dbId };
}
function hockeyPenaltyInfractionDbId(event) {
const infraction = event?.infraction;
if (!infraction || typeof infraction !== "object") return "";
const direct = String(
infraction.dbId
|| infraction.db_id
|| infraction.database_id
|| infraction.raw?.id
|| ""
).trim();
if (direct) return direct;
// Old saved penalty boards only contain the penalty code in infraction.id.
// Recover the real DB PK from the current penalty directory so selecting an
// old penalty still updates :selected_penalty_preset_id correctly.
const lookupValues = new Set([
String(infraction.code || "").trim(),
String(infraction.id || "").trim(),
].filter(Boolean));
if (!lookupValues.size) return "";
const directory = getByPath(state.data, "hockey.penalty_directory");
if (!Array.isArray(directory)) return "";
const row = directory.find((item) => {
const code = String(item?.code || "").trim();
const id = String(item?.id ?? "").trim();
return lookupValues.has(code) || lookupValues.has(id);
});
return row ? String(row.id ?? "").trim() : "";
}
async function hockeyClearSelectedPenaltyMappingContext(side, { clearCommon = false } = {}) {
if (!hockeyCanControl()) return false;
const gameId = hockeyTimerSelectedGameId();
@@ -8846,6 +8883,9 @@ async function hockeySelectPenaltyForPreview(component, event) {
team_id: teamId,
team_penalty: Boolean(event.teamPenalty),
infraction_id: String(event.infraction?.id || ""),
penalty_type_id: hockeyPenaltyInfractionDbId(event),
// `preset_id` remains the legacy duration value in interaction payloads;
// Mapping uses penalty_type_id for selected_penalty_preset_id below.
preset_id: String(event.preset || ""),
time_type: String(event.preset || ""),
side,
@@ -8878,7 +8918,7 @@ async function hockeySelectPenaltyForPreview(component, event) {
selected_penalty_team_penalty: detail.team_penalty ? "1" : "0",
selected_penalty_team_id: detail.team_id,
selected_penalty_infraction_id: detail.infraction_id,
selected_penalty_preset_id: detail.preset_id,
selected_penalty_preset_id: detail.penalty_type_id,
selected_penalty_time_type: detail.time_type,
selected_penalty_side: detail.side,
selected_penalty_event_time: detail.event_time,
@@ -13400,6 +13440,8 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
if (!infraction || typeof infraction !== "object") return null;
return {
id: String(infraction.id || ""),
code: String(infraction.code || ""),
dbId: String(infraction.dbId || infraction.db_id || infraction.database_id || ""),
label: String(infraction.label || ""),
labelRu: String(infraction.labelRu || infraction.name_ru || ""),
labelEn: String(infraction.labelEn || infraction.name_en || ""),