diff --git a/public/host.html b/public/host.html index cc11385..f34c8ca 100644 --- a/public/host.html +++ b/public/host.html @@ -5,7 +5,7 @@ 出題者ページ @@ -31,7 +38,6 @@ - @@ -42,6 +48,20 @@ + +
+

手動得点調整

+ + + +
+

参加チーム一覧

@@ -75,10 +95,13 @@ const nextBtn = document.getElementById("nextBtn"); const correctBtn = document.getElementById("correctBtn"); const incorrectBtn = document.getElementById("incorrectBtn"); - const teamsTableBody = document.querySelector("#teamsTable tbody"); - // ▼▼▼【追加】ボタン要素の取得 ▼▼▼ const scoreResetBtn = document.getElementById("scoreResetBtn"); - + const teamsTableBody = document.querySelector("#teamsTable tbody"); + // ▼▼▼【追加】得点調整UIの要素を取得 ▼▼▼ + const adjustGroupSelect = document.getElementById("adjustGroupSelect"); + const adjustScoreInput = document.getElementById("adjustScoreInput"); + const adjustScoreBtn = document.getElementById("adjustScoreBtn"); + let musicFiles = []; let currentIndex = -1; @@ -88,43 +111,55 @@ // (fetch, WebSocket接続は変更なし) fetch(`http://192.168.0.145:8890/music_list.json`) .then(res => res.json()) - .then(data => { - musicFiles = data.files.sort((a, b) => (parseInt(a.match(/^\d+/), 10) || 0) - (parseInt(b.match(/^\d+/), 10) || 0)); - }); + .then(data => { musicFiles = data.files.sort((a, b) => (parseInt(a.match(/^\d+/), 10) || 0) - (parseInt(b.match(/^\d+/), 10) || 0)); }); const conn = new WebSocket(`ws://${location.hostname}:8888`); - // (通常のボタンイベントリスナーは変更なし) playBtn.addEventListener("click", () => { if (currentIndex === -1) return; conn.send(JSON.stringify({ type: "play" })); }); pauseBtn.addEventListener("click", () => conn.send(JSON.stringify({ type: "pause" }))); stopBtn.addEventListener("click", () => conn.send(JSON.stringify({ type: "stop" }))); resetBtn.addEventListener("click", () => conn.send(JSON.stringify({ type: "reset" }))); - prevBtn.addEventListener("click", () => { if (musicFiles.length === 0) return; currentIndex = (currentIndex - 1 + musicFiles.length) % musicFiles.length; const file = musicFiles[currentIndex]; songLabel.textContent = `現在の曲: ${file}`; conn.send(JSON.stringify({ type: "select", file: file })); }); - nextBtn.addEventListener("click", () => { if (musicFiles.length === 0) return; currentIndex = (currentIndex + 1) % musicFiles.length; const file = musicFiles[currentIndex]; songLabel.textContent = `現在の曲: ${file}`; conn.send(JSON.stringify({ type: "select", file: file })); }); correctBtn.addEventListener("click", () => { if (currentIndex === -1) return; conn.send(JSON.stringify({ type: "correct", answer: musicFiles[currentIndex] })); }); incorrectBtn.addEventListener("click", () => conn.send(JSON.stringify({ type: "incorrect" }))); - - // ▼▼▼【追加】得点リセットボタンの処理 ▼▼▼ + prevBtn.addEventListener("click", () => { if (musicFiles.length === 0) return; currentIndex = (currentIndex - 1 + musicFiles.length) % musicFiles.length; const file = musicFiles[currentIndex]; songLabel.textContent = `現在の曲: ${file}`; conn.send(JSON.stringify({ type: "select", file: file })); }); + nextBtn.addEventListener("click", () => { if (musicFiles.length === 0) return; currentIndex = (currentIndex + 1) % musicFiles.length; const file = musicFiles[currentIndex]; songLabel.textContent = `現在の曲: ${file}`; conn.send(JSON.stringify({ type: "select", file: file })); }); scoreResetBtn.addEventListener("click", () => { - const confirmCode = "1111"; // 確認コード(自由に変更してください) - const input = prompt(`【得点リセット確認】\n\n誤操作防止のため、確認コード「${confirmCode}」を入力してください。`); - + const confirmCode = "1111"; + const input = prompt(`【得点リセット確認】\n\n確認コード「${confirmCode}」を入力してください。`); if (input === confirmCode) { - if (confirm("本当によろしいですか?\nすべてのチームの得点が0点にリセットされます。この操作は元に戻せません。")) { + if (confirm("本当によろしいですか?\nすべてのチームの得点が0点にリセットされます。")) { conn.send(JSON.stringify({ type: "reset_scores" })); alert("全チームの得点をリセットしました。"); } - } else if (input !== null) { // キャンセルではなく、何か入力された場合 - alert("確認コードが違います。得点のリセットはキャンセルされました。"); + } else if (input !== null) { + alert("確認コードが違います。"); } }); + // ▼▼▼【追加】手動得点調整ボタンの処理 ▼▼▼ + adjustScoreBtn.addEventListener("click", () => { + const group = adjustGroupSelect.value; + const scoreText = adjustScoreInput.value; + const score = parseInt(scoreText, 10); + + if (!group) { + alert("班を選択してください。"); + return; + } + if (isNaN(score) || scoreText.trim() === "") { + alert("有効な数値を入力してください。"); + return; + } + + conn.send(JSON.stringify({ type: "adjust_score", group: group, score: score })); + console.log(`${group}の得点を${score}点調整します。`); + adjustScoreInput.value = ""; // 送信後に入力欄をクリア + }); // (onmessageの処理は変更なし) conn.onmessage = ev => { let msg; try { msg = JSON.parse(ev.data); } catch { return; } - switch (msg.type) { case "select": announce.textContent = "曲選択完了、待機中..."; @@ -145,18 +180,13 @@ const participants = msg.teams || []; const points = msg.points || {}; const teamMembers = { '1班': [], '2班': [], '3班': [], '4班': [], '5班': [] }; - participants.forEach(p => { - if (teamMembers[p.group]) { teamMembers[p.group].push(p.name); } - }); + participants.forEach(p => { if (teamMembers[p.group]) { teamMembers[p.group].push(p.name); } }); for (let i = 1; i <= 5; i++) { const groupName = `${i}班`; const memberCell = document.getElementById(`members-${i}`); const members = teamMembers[groupName]; - if (members.length > 0) { - memberCell.innerHTML = members.join('
'); - } else { - memberCell.textContent = '(まだ誰もいません)'; - } + if (members.length > 0) { memberCell.innerHTML = members.join('
'); } + else { memberCell.textContent = '(まだ誰もいません)'; } const pointsCell = document.getElementById(`points-${i}`); pointsCell.textContent = points[groupName] || 0; }