BUILD129 — три настраиваемых цвета команд
This commit is contained in:
@@ -161,9 +161,25 @@ class HockeyDatabase:
|
||||
migrated = self._migrate_operator_session_user_id()
|
||||
Base.metadata.create_all(self.engine)
|
||||
repaired = migrated + self._repair_game_table()
|
||||
|
||||
# BUILD129: preserve the behaviour of the legacy primary team
|
||||
# colour when the explicit enable flag is introduced. Existing
|
||||
# rows that already had color_hex become enabled exactly once,
|
||||
# only on the migration that creates color_enabled.
|
||||
team_repaired = self._repair_additive_table(Team)
|
||||
repaired.extend(team_repaired)
|
||||
if f"{Team.__tablename__}.color_enabled" in team_repaired:
|
||||
with self.engine.begin() as connection:
|
||||
connection.execute(
|
||||
text(
|
||||
"UPDATE \"hockey_teams\" SET \"color_enabled\" = TRUE "
|
||||
"WHERE COALESCE(TRIM(\"color_hex\"), '') <> ''"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
for model in (
|
||||
OperatorSession,
|
||||
Team,
|
||||
TeamLeague,
|
||||
Country,
|
||||
PenaltyType,
|
||||
|
||||
@@ -16,6 +16,7 @@ from .service import HockeyDataService
|
||||
from .models import (
|
||||
Game,
|
||||
GameControlState,
|
||||
Team,
|
||||
Tournament,
|
||||
MappingContextValue,
|
||||
MappingContextVariable,
|
||||
@@ -855,6 +856,12 @@ class MappingDataService:
|
||||
control = session.scalar(
|
||||
select(GameControlState).where(GameControlState.game_external_id == game_id)
|
||||
)
|
||||
home_team = session.scalar(
|
||||
select(Team).where(Team.external_id == str(game.home_team_external_id or ""))
|
||||
) if game.home_team_external_id else None
|
||||
away_team = session.scalar(
|
||||
select(Team).where(Team.external_id == str(game.away_team_external_id or ""))
|
||||
) if game.away_team_external_id else None
|
||||
current_period = str(getattr(control, "current_period", "1") or "1")
|
||||
stage = stage_key(
|
||||
str(getattr(tournament, "season_part", "") or ""),
|
||||
@@ -878,6 +885,47 @@ class MappingDataService:
|
||||
language=language,
|
||||
)
|
||||
result: list[dict[str, Any]] = []
|
||||
|
||||
# BUILD129: operator-managed team colours. Enabled is deliberately a
|
||||
# separate value from the HEX string so a colour may remain configured
|
||||
# while being disabled for the current graphics logic.
|
||||
for side, team, side_label in (("home", home_team, "Хозяева"), ("away", away_team, "Гости")):
|
||||
color_specs = (
|
||||
(1, "color_hex", "color_enabled"),
|
||||
(2, "color_2_hex", "color_2_enabled"),
|
||||
(3, "color_3_hex", "color_3_enabled"),
|
||||
)
|
||||
for index, color_field, enabled_field in color_specs:
|
||||
raw_color = str(getattr(team, color_field, "") or "") if team is not None else ""
|
||||
enabled = bool(getattr(team, enabled_field, False)) if team is not None else False
|
||||
result.append({
|
||||
"key": f"team.{side}.color{index}",
|
||||
"label": f"Цвет {index}",
|
||||
"category": f"Команды · Цвета · {side_label}",
|
||||
"value": raw_color if enabled else "",
|
||||
"kind": "color",
|
||||
"source_code": "live_control",
|
||||
"description": f"Цвет {index} команды. Пусто, если цвет выключен в справочнике команд.",
|
||||
})
|
||||
result.append({
|
||||
"key": f"team.{side}.color{index}_enabled",
|
||||
"label": f"Цвет {index} включён (1/0)",
|
||||
"category": f"Команды · Цвета · {side_label}",
|
||||
"value": "1" if enabled else "0",
|
||||
"kind": "text",
|
||||
"source_code": "live_control",
|
||||
"description": f"1 — цвет {index} включён; 0 — отключён оператором.",
|
||||
})
|
||||
result.append({
|
||||
"key": f"team.{side}.color{index}_raw",
|
||||
"label": f"Цвет {index} · сохранённый HEX",
|
||||
"category": f"Команды · Цвета · {side_label}",
|
||||
"value": raw_color,
|
||||
"kind": "color",
|
||||
"source_code": "live_control",
|
||||
"description": f"Сохранённый HEX цвета {index}, независимо от флага включения.",
|
||||
})
|
||||
|
||||
score_control = HockeyDataService._score_control_payload(game, control)
|
||||
score_fields = (
|
||||
("home", "Счёт HOME · LIVE", score_control["home"], "Оперативный счёт HOME. После первого ручного +/- становится главным до синхронизации."),
|
||||
|
||||
@@ -254,7 +254,14 @@ class Team(Base):
|
||||
short_name_en: Mapped[str] = mapped_column(String(255), nullable=False, default="")
|
||||
city_ru: Mapped[str] = mapped_column(String(255), nullable=False, default="")
|
||||
city_en: Mapped[str] = mapped_column(String(255), nullable=False, default="")
|
||||
# BUILD129: three operator-editable team colours. The legacy ``color_hex``
|
||||
# column remains colour #1 for backwards compatibility with existing SQL.
|
||||
color_hex: Mapped[str] = mapped_column(String(9), nullable=False, default="")
|
||||
color_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
color_2_hex: Mapped[str] = mapped_column(String(9), nullable=False, default="")
|
||||
color_2_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
color_3_hex: Mapped[str] = mapped_column(String(9), nullable=False, default="")
|
||||
color_3_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
logo_url: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
raw_payload: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
synced_at: Mapped[datetime] = mapped_column(
|
||||
|
||||
@@ -166,6 +166,11 @@ class TeamDirectoryPayload(BaseModel):
|
||||
city_ru: str = Field(default="", max_length=255)
|
||||
city_en: str = Field(default="", max_length=255)
|
||||
color_hex: str = Field(default="", max_length=9)
|
||||
color_enabled: bool = False
|
||||
color_2_hex: str = Field(default="", max_length=9)
|
||||
color_2_enabled: bool = False
|
||||
color_3_hex: str = Field(default="", max_length=9)
|
||||
color_3_enabled: bool = False
|
||||
logo_url: str = Field(default="", max_length=2000)
|
||||
active: bool = True
|
||||
|
||||
|
||||
@@ -609,6 +609,16 @@ class HockeyDataService:
|
||||
"city_ru": team.city_ru,
|
||||
"city_en": team.city_en,
|
||||
"color_hex": team.color_hex,
|
||||
"color_enabled": bool(team.color_enabled),
|
||||
"color_2_hex": team.color_2_hex,
|
||||
"color_2_enabled": bool(team.color_2_enabled),
|
||||
"color_3_hex": team.color_3_hex,
|
||||
"color_3_enabled": bool(team.color_3_enabled),
|
||||
"colors": [
|
||||
{"index": 1, "hex": team.color_hex, "enabled": bool(team.color_enabled)},
|
||||
{"index": 2, "hex": team.color_2_hex, "enabled": bool(team.color_2_enabled)},
|
||||
{"index": 3, "hex": team.color_3_hex, "enabled": bool(team.color_3_enabled)},
|
||||
],
|
||||
"logo_url": team.logo_url,
|
||||
"source": membership.source,
|
||||
"active": bool(membership.active),
|
||||
@@ -756,8 +766,17 @@ class HockeyDataService:
|
||||
if field in payload and payload[field] is not None:
|
||||
setattr(team, field, str(payload[field]).strip())
|
||||
|
||||
if "color_hex" in payload and payload["color_hex"] is not None:
|
||||
team.color_hex = normalise_team_color_hex(payload["color_hex"])
|
||||
color_fields = (
|
||||
("color_hex", "color_enabled"),
|
||||
("color_2_hex", "color_2_enabled"),
|
||||
("color_3_hex", "color_3_enabled"),
|
||||
)
|
||||
for color_field, enabled_field in color_fields:
|
||||
if color_field in payload and payload[color_field] is not None:
|
||||
setattr(team, color_field, normalise_team_color_hex(payload[color_field]))
|
||||
if enabled_field in payload:
|
||||
color_value = str(getattr(team, color_field, "") or "").strip()
|
||||
setattr(team, enabled_field, bool(payload.get(enabled_field)) and bool(color_value))
|
||||
|
||||
if not (team.name_ru or team.name_en):
|
||||
raise ValueError("Укажите название команды на русском или английском")
|
||||
|
||||
@@ -1745,3 +1745,25 @@
|
||||
.hockey-map-sql-table-ref span{font-size:8px;color:#7890a8;white-space:nowrap}
|
||||
.hockey-map-sql-table-ref code{grid-column:1/-1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:8px Consolas,monospace;color:#738da6}
|
||||
@media(max-width:1050px){.hockey-map-sql-table-list{grid-template-columns:1fr}}
|
||||
|
||||
/* BUILD129 — three optional team colours with explicit enable flags */
|
||||
.hockey-team-color-field-head{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin-bottom:3px}
|
||||
.hockey-team-color-field-head>span{color:#c8d7e6;font-size:10px;font-weight:900}
|
||||
.hockey-team-color-field-head>small{max-width:520px;text-align:right;line-height:1.35}
|
||||
.hockey-team-colors-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
|
||||
.hockey-team-color-item{min-width:0;padding:8px;border:1px solid #2b4057;border-radius:10px;background:#0b1725;opacity:.72;transition:border-color .15s ease,opacity .15s ease,background .15s ease}
|
||||
.hockey-team-color-item.is-enabled{border-color:#347662;background:#0d201f;opacity:1}
|
||||
.hockey-team-color-enabled{display:grid!important;grid-template-columns:auto minmax(0,1fr) auto!important;align-items:center!important;gap:6px!important;margin:0 0 6px!important}
|
||||
.hockey-team-color-enabled input{width:15px!important;height:15px!important;min-height:0!important;margin:0;accent-color:#48dfbd}
|
||||
.hockey-team-color-enabled>span{color:#d8e5f0;font-size:9px;font-weight:900}
|
||||
.hockey-team-color-enabled>small{overflow:hidden;color:#71869a;font-size:7px!important;text-overflow:ellipsis;white-space:nowrap}
|
||||
.hockey-team-color-item.is-enabled .hockey-team-color-enabled>small{color:#67d9bd}
|
||||
.hockey-team-colors-cell{display:grid;gap:3px;min-width:118px}
|
||||
.hockey-team-color-chip{display:grid;grid-template-columns:14px 15px minmax(0,1fr);align-items:center;gap:5px;min-height:20px;color:#7f94a8}
|
||||
.hockey-team-color-chip>b{display:grid;place-items:center;width:14px;height:14px;border-radius:50%;background:#142437;color:#7890a8;font-size:7px}
|
||||
.hockey-team-color-chip>i{width:14px;height:14px;border:1px solid rgba(255,255,255,.45);border-radius:4px;background:var(--team-color,#fff)}
|
||||
.hockey-team-color-chip>code{overflow:hidden;color:#8ea3b7;font-size:8px;text-overflow:ellipsis;white-space:nowrap}
|
||||
.hockey-team-color-chip.is-disabled{opacity:.38}
|
||||
.hockey-team-color-chip.is-enabled>b{background:#183a32;color:#71e2c7}
|
||||
.hockey-team-color-chip.is-enabled>code{color:#bed2e2}
|
||||
@media(max-width:1180px){.hockey-team-colors-grid{grid-template-columns:1fr}.hockey-team-color-field-head{align-items:flex-start;flex-direction:column}.hockey-team-color-field-head>small{text-align:left}}
|
||||
|
||||
@@ -80,6 +80,43 @@
|
||||
return color || "#FFFFFF";
|
||||
};
|
||||
|
||||
const teamColorFieldName = (index) => index === 1 ? "color_hex" : `color_${index}_hex`;
|
||||
const teamColorEnabledName = (index) => index === 1 ? "color_enabled" : `color_${index}_enabled`;
|
||||
|
||||
const teamColorEditorMarkup = (editing, index) => {
|
||||
const field = teamColorFieldName(index);
|
||||
const enabledField = teamColorEnabledName(index);
|
||||
const fieldNameAttr = index === 1 ? 'name="color_hex"' : `name="color_${index}_hex"`;
|
||||
const enabledNameAttr = index === 1 ? 'name="color_enabled"' : `name="color_${index}_enabled"`;
|
||||
const value = String(editing?.[field] || "");
|
||||
const enabled = editing ? Boolean(editing?.[enabledField]) : false;
|
||||
return `
|
||||
<div class="hockey-team-color-item ${enabled ? "is-enabled" : ""}" data-team-color-item="${index}">
|
||||
<label class="hockey-team-color-enabled">
|
||||
<input type="checkbox" ${enabledNameAttr} data-team-color-enabled="${index}" ${enabled ? "checked" : ""}>
|
||||
<span>Цвет ${index}</span>
|
||||
<small>${enabled ? "используется" : "выключен"}</small>
|
||||
</label>
|
||||
<div class="hockey-team-color-control">
|
||||
<button type="button" class="hockey-team-color-picker-wrap" data-team-color-open="${index}" title="Выбрать цвет ${index}">
|
||||
<i data-team-color-preview="${index}" style="--team-color:${escapeHtml(teamColorPreview(value))}"></i>
|
||||
<input type="color" data-team-color-picker="${index}" value="${escapeHtml(teamColorPreview(value))}" tabindex="-1" aria-label="Выбрать цвет ${index} команды">
|
||||
</button>
|
||||
<input ${fieldNameAttr} data-team-color-text="${index}" maxlength="7" placeholder="#282E66" value="${escapeHtml(value)}" autocomplete="off" spellcheck="false">
|
||||
<button type="button" class="hockey-team-color-clear" data-team-color-clear="${index}" title="Очистить цвет ${index}">×</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
const teamColorsCellMarkup = (item) => [1, 2, 3].map((index) => {
|
||||
const field = teamColorFieldName(index);
|
||||
const enabledField = teamColorEnabledName(index);
|
||||
const value = normalizeTeamColorHex(item?.[field]);
|
||||
const enabled = Boolean(item?.[enabledField]) && Boolean(value);
|
||||
return `<span class="hockey-team-color-chip ${enabled ? "is-enabled" : "is-disabled"}" title="Цвет ${index}: ${enabled ? "включён" : "выключен"}"><b>${index}</b><i style="--team-color:${escapeHtml(value || "#FFFFFF")}"></i><code>${escapeHtml(value || "—")}</code></span>`;
|
||||
}).join("");
|
||||
|
||||
const countryFlagMarkup = (item) => {
|
||||
const code = String(item?.iso2 || item?.country_code || "").trim().toLowerCase().replace(/[^a-z]/g, "").slice(0, 2);
|
||||
const url = String(item?.flag_url || (code.length === 2 ? `/hockey-assets/flags/${code}.svg` : ""));
|
||||
@@ -341,7 +378,7 @@
|
||||
<td><strong>${escapeHtml(item.name_ru || "—")}</strong><small>${escapeHtml(item.short_name_ru || "")}</small></td>
|
||||
<td><strong>${escapeHtml(item.name_en || "—")}</strong><small>${escapeHtml(item.short_name_en || "")}</small></td>
|
||||
<td>${escapeHtml(item.city_ru || item.city_en || "—")}</td>
|
||||
<td>${item.color_hex ? `<span class="hockey-team-color-cell"><i style="--team-color:${escapeHtml(item.color_hex)}"></i><code>${escapeHtml(item.color_hex)}</code></span>` : "—"}</td>
|
||||
<td><div class="hockey-team-colors-cell">${teamColorsCellMarkup(item)}</div></td>
|
||||
<td><span class="hockey-directory-source">${escapeHtml(item.source === "manual" ? "изменено" : "Stat2TV")}</span></td>
|
||||
<td><button type="button" class="hockey-directory-edit" data-edit-team="${item.id}">Изменить</button></td>
|
||||
</tr>
|
||||
@@ -361,7 +398,7 @@
|
||||
<div class="hockey-directory-grid">
|
||||
<div class="hockey-directory-table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>ID API</th><th>Русский</th><th>English</th><th>Город</th><th>Цвет</th><th>Источник</th><th></th></tr></thead>
|
||||
<thead><tr><th>ID API</th><th>Русский</th><th>English</th><th>Город</th><th>Цвета</th><th>Источник</th><th></th></tr></thead>
|
||||
<tbody>${rows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -381,18 +418,15 @@
|
||||
</div>
|
||||
<label><span>Логотип (URL)</span><input name="logo_url" maxlength="2000" value="${escapeHtml(editing?.logo_url || "")}"></label>
|
||||
<div class="hockey-team-color-field">
|
||||
<label>
|
||||
<span>Цвет команды</span>
|
||||
<div class="hockey-team-color-control">
|
||||
<button type="button" class="hockey-team-color-picker-wrap" data-team-color-open title="Выбрать цвет">
|
||||
<i data-team-color-preview style="--team-color:${escapeHtml(teamColorPreview(editing?.color_hex))}"></i>
|
||||
<input type="color" data-team-color-picker value="${escapeHtml(teamColorPreview(editing?.color_hex))}" tabindex="-1" aria-label="Выбрать цвет команды">
|
||||
</button>
|
||||
<input name="color_hex" data-team-color-text maxlength="7" placeholder="#282E66" value="${escapeHtml(editing?.color_hex || "")}" autocomplete="off" spellcheck="false">
|
||||
<button type="button" class="hockey-team-color-clear" data-team-color-clear title="Очистить цвет">×</button>
|
||||
</div>
|
||||
<small>HEX, например #282E66</small>
|
||||
</label>
|
||||
<div class="hockey-team-color-field-head">
|
||||
<span>Цвета команды</span>
|
||||
<small>HEX можно сохранить заранее, а галочкой отдельно включать/выключать цвет в данных Mapping.</small>
|
||||
</div>
|
||||
<div class="hockey-team-colors-grid">
|
||||
${teamColorEditorMarkup(editing, 1)}
|
||||
${teamColorEditorMarkup(editing, 2)}
|
||||
${teamColorEditorMarkup(editing, 3)}
|
||||
</div>
|
||||
</div>
|
||||
<label class="hockey-directory-check"><input type="checkbox" name="active" ${editing?.active === false ? "" : "checked"}><span>Активна</span></label>
|
||||
<div class="hockey-directory-form-actions">
|
||||
@@ -3088,57 +3122,82 @@
|
||||
setStatus("");
|
||||
renderTeams();
|
||||
});
|
||||
const colorText = modal.querySelector("[data-team-color-text]");
|
||||
const colorPicker = modal.querySelector("[data-team-color-picker]");
|
||||
const colorPreview = modal.querySelector("[data-team-color-preview]");
|
||||
const syncTeamColorUi = (rawValue, { commit = false } = {}) => {
|
||||
const normalized = normalizeTeamColorHex(rawValue);
|
||||
if (normalized) {
|
||||
if (colorText && (commit || colorText.value !== rawValue)) colorText.value = normalized;
|
||||
if (colorPicker) colorPicker.value = normalized;
|
||||
if (colorPreview) colorPreview.style.setProperty("--team-color", normalized);
|
||||
return normalized;
|
||||
}
|
||||
if (commit && colorText && String(rawValue || "").trim()) {
|
||||
setStatus("Цвет команды должен быть в формате #RRGGBB", true);
|
||||
}
|
||||
if (!String(rawValue || "").trim()) {
|
||||
if (colorText && commit) colorText.value = "";
|
||||
if (colorPicker) colorPicker.value = "#FFFFFF";
|
||||
if (colorPreview) colorPreview.style.setProperty("--team-color", "#FFFFFF");
|
||||
}
|
||||
return "";
|
||||
const bindTeamColor = (index) => {
|
||||
const item = modal.querySelector(`[data-team-color-item="${index}"]`);
|
||||
const colorText = modal.querySelector(`[data-team-color-text="${index}"]`);
|
||||
const colorPicker = modal.querySelector(`[data-team-color-picker="${index}"]`);
|
||||
const colorPreview = modal.querySelector(`[data-team-color-preview="${index}"]`);
|
||||
const colorEnabled = modal.querySelector(`[data-team-color-enabled="${index}"]`);
|
||||
const enabledCaption = item?.querySelector(".hockey-team-color-enabled small");
|
||||
const updateEnabledUi = () => {
|
||||
const enabled = Boolean(colorEnabled?.checked);
|
||||
item?.classList.toggle("is-enabled", enabled);
|
||||
if (enabledCaption) enabledCaption.textContent = enabled ? "используется" : "выключен";
|
||||
};
|
||||
const syncTeamColorUi = (rawValue, { commit = false } = {}) => {
|
||||
const normalized = normalizeTeamColorHex(rawValue);
|
||||
if (normalized) {
|
||||
if (colorText && (commit || colorText.value !== rawValue)) colorText.value = normalized;
|
||||
if (colorPicker) colorPicker.value = normalized;
|
||||
if (colorPreview) colorPreview.style.setProperty("--team-color", normalized);
|
||||
return normalized;
|
||||
}
|
||||
if (commit && colorText && String(rawValue || "").trim()) {
|
||||
setStatus(`Цвет ${index} команды должен быть в формате #RRGGBB`, true);
|
||||
}
|
||||
if (!String(rawValue || "").trim()) {
|
||||
if (colorText && commit) colorText.value = "";
|
||||
if (colorPicker) colorPicker.value = "#FFFFFF";
|
||||
if (colorPreview) colorPreview.style.setProperty("--team-color", "#FFFFFF");
|
||||
}
|
||||
return "";
|
||||
};
|
||||
modal.querySelector(`[data-team-color-open="${index}"]`)?.addEventListener("click", () => colorPicker?.click());
|
||||
colorPicker?.addEventListener("input", () => {
|
||||
if (colorText) colorText.value = String(colorPicker.value || "").toUpperCase();
|
||||
if (colorEnabled) colorEnabled.checked = true;
|
||||
updateEnabledUi();
|
||||
syncTeamColorUi(colorPicker.value);
|
||||
});
|
||||
colorText?.addEventListener("input", () => {
|
||||
const raw = String(colorText.value || "");
|
||||
const compact = raw.replace(/\s+/g, "").toUpperCase();
|
||||
if (raw !== compact) colorText.value = compact;
|
||||
const normalized = normalizeTeamColorHex(compact);
|
||||
if (normalized) syncTeamColorUi(normalized);
|
||||
});
|
||||
colorText?.addEventListener("blur", () => syncTeamColorUi(colorText.value, { commit: true }));
|
||||
colorEnabled?.addEventListener("change", updateEnabledUi);
|
||||
modal.querySelector(`[data-team-color-clear="${index}"]`)?.addEventListener("click", () => {
|
||||
if (colorText) colorText.value = "";
|
||||
if (colorEnabled) colorEnabled.checked = false;
|
||||
updateEnabledUi();
|
||||
syncTeamColorUi("", { commit: true });
|
||||
colorText?.focus();
|
||||
});
|
||||
updateEnabledUi();
|
||||
};
|
||||
modal.querySelector("[data-team-color-open]")?.addEventListener("click", () => colorPicker?.click());
|
||||
colorPicker?.addEventListener("input", () => {
|
||||
if (colorText) colorText.value = String(colorPicker.value || "").toUpperCase();
|
||||
syncTeamColorUi(colorPicker.value);
|
||||
});
|
||||
colorText?.addEventListener("input", () => {
|
||||
const raw = String(colorText.value || "");
|
||||
const compact = raw.replace(/\s+/g, "").toUpperCase();
|
||||
if (raw !== compact) colorText.value = compact;
|
||||
const normalized = normalizeTeamColorHex(compact);
|
||||
if (normalized) syncTeamColorUi(normalized);
|
||||
});
|
||||
colorText?.addEventListener("blur", () => syncTeamColorUi(colorText.value, { commit: true }));
|
||||
modal.querySelector("[data-team-color-clear]")?.addEventListener("click", () => {
|
||||
if (colorText) colorText.value = "";
|
||||
syncTeamColorUi("", { commit: true });
|
||||
colorText?.focus();
|
||||
});
|
||||
[1, 2, 3].forEach(bindTeamColor);
|
||||
|
||||
modal.querySelector("[data-team-form]")?.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
const form = event.currentTarget;
|
||||
const values = new FormData(form);
|
||||
const rawTeamColor = String(values.get("color_hex") || "").trim();
|
||||
const normalizedTeamColor = normalizeTeamColorHex(rawTeamColor);
|
||||
if (rawTeamColor && !normalizedTeamColor) {
|
||||
setStatus("Цвет команды должен быть в формате #RRGGBB", true);
|
||||
colorText?.focus();
|
||||
return;
|
||||
const normalizedColors = {};
|
||||
for (const index of [1, 2, 3]) {
|
||||
const field = teamColorFieldName(index);
|
||||
const enabledField = teamColorEnabledName(index);
|
||||
const raw = String(values.get(field) || "").trim();
|
||||
const normalized = normalizeTeamColorHex(raw);
|
||||
if (raw && !normalized) {
|
||||
setStatus(`Цвет ${index} команды должен быть в формате #RRGGBB`, true);
|
||||
modal.querySelector(`[data-team-color-text="${index}"]`)?.focus();
|
||||
return;
|
||||
}
|
||||
normalizedColors[field] = normalized;
|
||||
normalizedColors[enabledField] = values.has(enabledField) && Boolean(normalized);
|
||||
}
|
||||
const normalizedTeamColor = normalizedColors.color_hex;
|
||||
const payload = {
|
||||
external_id: values.get("external_id") || state.editingTeam?.external_id || "",
|
||||
league_key: values.get("league_key") || "",
|
||||
@@ -3150,6 +3209,11 @@
|
||||
city_ru: values.get("city_ru") || "",
|
||||
city_en: values.get("city_en") || "",
|
||||
color_hex: normalizedTeamColor,
|
||||
color_enabled: normalizedColors.color_enabled,
|
||||
color_2_hex: normalizedColors.color_2_hex,
|
||||
color_2_enabled: normalizedColors.color_2_enabled,
|
||||
color_3_hex: normalizedColors.color_3_hex,
|
||||
color_3_enabled: normalizedColors.color_3_enabled,
|
||||
logo_url: values.get("logo_url") || "",
|
||||
active: values.has("active"),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user