изменение текущего времени, тест 2
This commit is contained in:
168
static/script.js
168
static/script.js
@@ -98,6 +98,45 @@ function formatClock(totalSeconds) {
|
||||
return `${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
function formatVmixClock(totalSeconds) {
|
||||
const safeSeconds = Math.max(0, Math.floor(Number(totalSeconds) || 0));
|
||||
const hours = String(Math.floor(safeSeconds / 3600)).padStart(2, "0");
|
||||
const minutes = String(Math.floor((safeSeconds % 3600) / 60)).padStart(2, "0");
|
||||
const seconds = String(safeSeconds % 60).padStart(2, "0");
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
function parseClockInput(value) {
|
||||
const raw = String(value || "").trim().replaceAll(".", ":").replaceAll(",", ":");
|
||||
if (!raw) return null;
|
||||
|
||||
const parts = raw.split(":").map(part => part.trim());
|
||||
if (parts.length > 3 || parts.some(part => part === "" || !/^\d+$/.test(part))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let hours = 0;
|
||||
let minutes = 0;
|
||||
let seconds = 0;
|
||||
|
||||
if (parts.length === 1) {
|
||||
minutes = Number(parts[0]);
|
||||
} else if (parts.length === 2) {
|
||||
minutes = Number(parts[0]);
|
||||
seconds = Number(parts[1]);
|
||||
} else {
|
||||
hours = Number(parts[0]);
|
||||
minutes = Number(parts[1]);
|
||||
seconds = Number(parts[2]);
|
||||
}
|
||||
|
||||
if (![hours, minutes, seconds].every(Number.isFinite) || seconds > 59 || minutes > 999) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Math.max(0, hours * 3600 + minutes * 60 + seconds);
|
||||
}
|
||||
|
||||
function getFootballMinute(totalSeconds) {
|
||||
if (currentPeriod === "2H" || currentPeriod === "FT") {
|
||||
const secondHalfSeconds = Math.max(0, totalSeconds - 45 * 60);
|
||||
@@ -353,6 +392,90 @@ function startTimer() {
|
||||
saveMatchState();
|
||||
}
|
||||
|
||||
async function syncEditedClockToVmix(totalSeconds, shouldRun) {
|
||||
const commands = [
|
||||
vmixCmd("Function=SetCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text&Value=02:00:00"),
|
||||
vmixCmd(`Function=ChangeCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text&Value=${formatVmixClock(totalSeconds)}`),
|
||||
vmixCmd(shouldRun
|
||||
? "Function=StartCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text"
|
||||
: "Function=PauseCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text"
|
||||
),
|
||||
vmixCmd("Function=PreviewInput&Input=ВЕРХНИЙ СЧЕТ")
|
||||
];
|
||||
|
||||
await sendDirectVmixCommands(commands);
|
||||
}
|
||||
|
||||
function closeClockEditor() {
|
||||
const modal = document.getElementById("clockEditorModal");
|
||||
if (modal) modal.classList.remove("show");
|
||||
}
|
||||
|
||||
function openClockEditor() {
|
||||
if (!(currentPeriod === "1H" || currentPeriod === "2H")) {
|
||||
alert("Редактировать время можно после запуска 1-го или 2-го тайма");
|
||||
return;
|
||||
}
|
||||
|
||||
updateTimerUI();
|
||||
|
||||
const modal = document.getElementById("clockEditorModal");
|
||||
const input = document.getElementById("clockEditorInput");
|
||||
const hint = document.getElementById("clockEditorHint");
|
||||
|
||||
if (input) {
|
||||
input.value = formatClock(matchClockSeconds);
|
||||
}
|
||||
|
||||
if (hint) {
|
||||
hint.textContent = timerId
|
||||
? "Таймер сейчас идёт. После сохранения он продолжит идти с нового времени."
|
||||
: "Таймер сейчас на паузе. После сохранения он останется на паузе.";
|
||||
}
|
||||
|
||||
if (modal) modal.classList.add("show");
|
||||
|
||||
setTimeout(() => {
|
||||
if (input) {
|
||||
input.focus();
|
||||
input.select();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
async function applyClockEditor() {
|
||||
const input = document.getElementById("clockEditorInput");
|
||||
const newSeconds = parseClockInput(input ? input.value : "");
|
||||
|
||||
if (newSeconds === null) {
|
||||
alert("Введите время в формате MM:SS, например 12:30 или 57:20");
|
||||
return;
|
||||
}
|
||||
|
||||
const wasRunning = !!timerId;
|
||||
|
||||
if (timerId) {
|
||||
clearInterval(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
|
||||
pausedAccumulatedSeconds = newSeconds;
|
||||
matchClockSeconds = newSeconds;
|
||||
periodStartedAt = wasRunning ? Date.now() : null;
|
||||
|
||||
if (wasRunning) {
|
||||
timerId = setInterval(() => {
|
||||
updateTimerUI();
|
||||
saveMatchState();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
updateTimerUI();
|
||||
saveMatchState();
|
||||
closeClockEditor();
|
||||
await syncEditedClockToVmix(newSeconds, wasRunning);
|
||||
}
|
||||
|
||||
async function triggerVmixExtraTimeAction(minutes, half) {
|
||||
const title = "ДОБАВЛЕННОЕ ВРЕМЯ ДЛЯ ВЕРХНЕГО СЧЕТА"
|
||||
const value = `+${minutes}`;
|
||||
@@ -3761,49 +3884,4 @@ function buildChannelValue(matchId) {
|
||||
if (hasMatch) return "match";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function setClockSeconds(newSeconds) {
|
||||
const wasRunning = !!timerId;
|
||||
|
||||
if (timerId) {
|
||||
clearInterval(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
|
||||
pausedAccumulatedSeconds = Math.max(0, Number(newSeconds) || 0);
|
||||
matchClockSeconds = pausedAccumulatedSeconds;
|
||||
|
||||
if (wasRunning) {
|
||||
periodStartedAt = Date.now();
|
||||
timerId = setInterval(() => {
|
||||
updateTimerUI();
|
||||
saveMatchState();
|
||||
}, 1000);
|
||||
} else {
|
||||
periodStartedAt = null;
|
||||
}
|
||||
|
||||
updateTimerUI();
|
||||
saveMatchState();
|
||||
syncClockToVmix(matchClockSeconds, wasRunning);
|
||||
}
|
||||
|
||||
async function syncClockToVmix(seconds, shouldRun) {
|
||||
const h = String(Math.floor(seconds / 3600)).padStart(2, "0");
|
||||
const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, "0");
|
||||
const s = String(seconds % 60).padStart(2, "0");
|
||||
const value = `${h}:${m}:${s}`;
|
||||
|
||||
const commands = [
|
||||
vmixCmd("Function=SetCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text&Value=02:00:00"),
|
||||
vmixCmd(`Function=ChangeCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text&Value=${value}`),
|
||||
vmixCmd(
|
||||
shouldRun
|
||||
? "Function=StartCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text"
|
||||
: "Function=PauseCountdown&Input=ВЕРХНИЙ СЧЕТ&SelectedName=Таймер.Text"
|
||||
)
|
||||
];
|
||||
|
||||
await sendDirectVmixCommands(commands);
|
||||
}
|
||||
@@ -2351,4 +2351,35 @@ body:not(.edit-mode-on) .referee-search {
|
||||
.event-time-edit-btn:focus-visible {
|
||||
outline: 2px solid rgba(95,132,255,0.45);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.timer-box-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clock-editor-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,.45);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.clock-editor-content {
|
||||
background: #1f1f1f;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
width: 320px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.clock-editor-content input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@@ -289,7 +289,7 @@
|
||||
<span class="period-badge" id="periodBadge"
|
||||
>Матч не начат</span
|
||||
>
|
||||
<div class="timer-box" id="matchTimer" onclick="openClockEditor()">00:00</div>
|
||||
<div class="timer-box timer-box-clickable" id="matchTimer" onclick="openClockEditor()" title="Нажмите, чтобы изменить время">00:00</div>
|
||||
<div class="score-box" id="matchScore">0 : 0</div>
|
||||
|
||||
<div class="extra-time-wrap">
|
||||
@@ -1114,6 +1114,38 @@ data-role="{{ p.position or '' }}"
|
||||
awayCoachPool: []
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="formation-modal" id="clockEditorModal">
|
||||
<div class="formation-modal-backdrop" onclick="closeClockEditor()"></div>
|
||||
<div class="formation-modal-content clock-editor-modal-content">
|
||||
<div class="formation-modal-header">
|
||||
<div>
|
||||
<div class="formation-modal-title">Редактировать время</div>
|
||||
<div class="formation-modal-subtitle" id="clockEditorHint"></div>
|
||||
</div>
|
||||
<button type="button" class="modal-close-btn" onclick="closeClockEditor()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="formation-modal-body clock-editor-body">
|
||||
<label class="clock-editor-label" for="clockEditorInput">Текущее матчевое время</label>
|
||||
<input
|
||||
type="text"
|
||||
class="clock-editor-input"
|
||||
id="clockEditorInput"
|
||||
placeholder="12:30"
|
||||
inputmode="numeric"
|
||||
onkeydown="if (event.key === 'Enter') applyClockEditor(); if (event.key === 'Escape') closeClockEditor();"
|
||||
/>
|
||||
<div class="clock-editor-note">Можно ввести 12:30, 57:20 или 01:02:03.</div>
|
||||
</div>
|
||||
|
||||
<div class="formation-modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeClockEditor()">Отмена</button>
|
||||
<button type="button" class="btn btn-primary" onclick="applyClockEditor()">Применить в интерфейсе и vMix</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="formation-modal" id="formationAssignModal">
|
||||
<div
|
||||
class="formation-modal-backdrop"
|
||||
|
||||
Reference in New Issue
Block a user