445 lines
17 KiB
HTML
445 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>麻将直播控制面板</title>
|
||
<link rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body>
|
||
<div class="control-panel">
|
||
<h1>麻将直播控制面板</h1>
|
||
|
||
<!-- 视频源设置 -->
|
||
<div class="control-section">
|
||
<h3>视频源设置</h3>
|
||
<div class="form-group">
|
||
<label for="videoSource">视频URL:</label>
|
||
<input type="text" id="videoSource" placeholder="输入视频URL"
|
||
value="https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_1MB.mp4">
|
||
</div>
|
||
<button id="setVideoBtn" class="btn">设置视频源</button>
|
||
</div>
|
||
|
||
<!-- 玩家设置 -->
|
||
<div class="control-section">
|
||
<h3>玩家信息设置</h3>
|
||
<table class="player-settings">
|
||
<thead>
|
||
<tr>
|
||
<th>玩家</th>
|
||
<th>姓名</th>
|
||
<th>分数</th>
|
||
<th>颜色</th>
|
||
<th>听牌</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>北家</td>
|
||
<td><input type="text" id="playerName0" value="北家"></td>
|
||
<td><input type="number" id="playerScore0" value="25000"></td>
|
||
<td><input type="color" id="playerColor0" value="#FF6464"></td>
|
||
<td><input type="checkbox" id="playerTenpai0"></td>
|
||
</tr>
|
||
<tr>
|
||
<td>东家</td>
|
||
<td><input type="text" id="playerName1" value="东家"></td>
|
||
<td><input type="number" id="playerScore1" value="25000"></td>
|
||
<td><input type="color" id="playerColor1" value="#64FF64"></td>
|
||
<td><input type="checkbox" id="playerTenpai1"></td>
|
||
</tr>
|
||
<tr>
|
||
<td>南家</td>
|
||
<td><input type="text" id="playerName2" value="南家"></td>
|
||
<td><input type="number" id="playerScore2" value="25000"></td>
|
||
<td><input type="color" id="playerColor2" value="#6464FF"></td>
|
||
<td><input type="checkbox" id="playerTenpai2"></td>
|
||
</tr>
|
||
<tr>
|
||
<td>西家</td>
|
||
<td><input type="text" id="playerName3" value="西家"></td>
|
||
<td><input type="number" id="playerScore3" value="25000"></td>
|
||
<td><input type="color" id="playerColor3" value="#FFFF64"></td>
|
||
<td><input type="checkbox" id="playerTenpai3"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<button id="updateAllPlayersBtn" class="btn">更新所有玩家信息</button>
|
||
</div>
|
||
|
||
<!-- 胡牌控制 -->
|
||
<div class="control-section">
|
||
<h3>胡牌控制</h3>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="winnerSelect">胜者:</label>
|
||
<select id="winnerSelect">
|
||
<option value="0">北家</option>
|
||
<option value="1">东家</option>
|
||
<option value="2">南家</option>
|
||
<option value="3">西家</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="hanInput">番数:</label>
|
||
<input type="number" id="hanInput" value="2" min="1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="fuInput">符数:</label>
|
||
<input type="number" id="fuInput" value="30" min="0">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="pointsInput">总点数:</label>
|
||
<input type="number" id="pointsInput" value="4000" min="0">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="isTsumoInput">
|
||
<input type="checkbox" id="isTsumoInput"> 自摸
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="winTextInput">胡牌描述:</label>
|
||
<input type="text" id="winTextInput" placeholder="例如: 三暗刻 自摸">
|
||
</div>
|
||
<button id="winBtn" class="btn btn-warning">触发胡牌</button>
|
||
</div>
|
||
|
||
<!-- 分数调整 -->
|
||
<div class="control-section">
|
||
<h3>分数调整</h3>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="adjustPlayerSelect">玩家:</label>
|
||
<select id="adjustPlayerSelect">
|
||
<option value="0">北家</option>
|
||
<option value="1">东家</option>
|
||
<option value="2">南家</option>
|
||
<option value="3">西家</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="deltaInput">分数变动:</label>
|
||
<input type="number" id="deltaInput" value="1000">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<button id="adjustScoreBtn" class="btn">调整分数</button>
|
||
<button id="resetScoresBtn" class="btn btn-danger">重置所有分数</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 本场与立直棒 -->
|
||
<div class="control-section">
|
||
<h3>本场与立直棒</h3>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="honbaInput">本场:</label>
|
||
<input type="number" id="honbaInput" value="0" min="0">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="riichiInput">立直棒:</label>
|
||
<input type="number" id="riichiInput" value="0" min="0">
|
||
</div>
|
||
</div>
|
||
<button id="setHonbaRiichiBtn" class="btn">设置</button>
|
||
</div>
|
||
|
||
<!-- 样式设置 -->
|
||
<div class="control-section">
|
||
<h3>样式设置</h3>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="stylePlayerSelect">玩家:</label>
|
||
<select id="stylePlayerSelect">
|
||
<option value="0">北家</option>
|
||
<option value="1">东家</option>
|
||
<option value="2">南家</option>
|
||
<option value="3">西家</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="opacityInput">透明度:</label>
|
||
<input type="range" id="opacityInput" min="0.1" max="1" step="0.1" value="0.6">
|
||
<span id="opacityValue">0.6</span>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="fontSizeInput">字体大小:</label>
|
||
<input type="number" id="fontSizeInput" min="12" max="32" value="18">
|
||
</div>
|
||
</div>
|
||
<button id="setStyleBtn" class="btn">应用样式</button>
|
||
</div>
|
||
|
||
<!-- 测试按钮 -->
|
||
<div class="control-section">
|
||
<h3>测试功能</h3>
|
||
<button id="openOverlayBtn" class="btn">打开叠加层</button>
|
||
<button id="testWinBtn" class="btn btn-warning">测试胡牌动画</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 全局变量
|
||
let overlayWindow = null;
|
||
const defaultOpacity = 0.6;
|
||
|
||
// DOM元素
|
||
const elements = {
|
||
// 视频设置
|
||
videoSource: document.getElementById('videoSource'),
|
||
setVideoBtn: document.getElementById('setVideoBtn'),
|
||
|
||
// 玩家设置
|
||
updateAllPlayersBtn: document.getElementById('updateAllPlayersBtn'),
|
||
|
||
// 胡牌控制
|
||
winnerSelect: document.getElementById('winnerSelect'),
|
||
hanInput: document.getElementById('hanInput'),
|
||
fuInput: document.getElementById('fuInput'),
|
||
pointsInput: document.getElementById('pointsInput'),
|
||
isTsumoInput: document.getElementById('isTsumoInput'),
|
||
winTextInput: document.getElementById('winTextInput'),
|
||
winBtn: document.getElementById('winBtn'),
|
||
|
||
// 分数调整
|
||
adjustPlayerSelect: document.getElementById('adjustPlayerSelect'),
|
||
deltaInput: document.getElementById('deltaInput'),
|
||
adjustScoreBtn: document.getElementById('adjustScoreBtn'),
|
||
resetScoresBtn: document.getElementById('resetScoresBtn'),
|
||
|
||
// 本场与立直棒
|
||
honbaInput: document.getElementById('honbaInput'),
|
||
riichiInput: document.getElementById('riichiInput'),
|
||
setHonbaRiichiBtn: document.getElementById('setHonbaRiichiBtn'),
|
||
|
||
// 样式设置
|
||
stylePlayerSelect: document.getElementById('stylePlayerSelect'),
|
||
opacityInput: document.getElementById('opacityInput'),
|
||
opacityValue: document.getElementById('opacityValue'),
|
||
fontSizeInput: document.getElementById('fontSizeInput'),
|
||
setStyleBtn: document.getElementById('setStyleBtn'),
|
||
|
||
// 测试按钮
|
||
openOverlayBtn: document.getElementById('openOverlayBtn'),
|
||
testWinBtn: document.getElementById('testWinBtn')
|
||
};
|
||
|
||
// 初始化
|
||
function init() {
|
||
setupEventListeners();
|
||
}
|
||
|
||
// 设置事件监听
|
||
function setupEventListeners() {
|
||
// 视频设置
|
||
elements.setVideoBtn.addEventListener('click', setVideoSource);
|
||
|
||
// 玩家设置
|
||
elements.updateAllPlayersBtn.addEventListener('click', updateAllPlayers);
|
||
|
||
// 胡牌控制
|
||
elements.winBtn.addEventListener('click', triggerWin);
|
||
|
||
// 分数调整
|
||
elements.adjustScoreBtn.addEventListener('click', adjustScore);
|
||
elements.resetScoresBtn.addEventListener('click', resetScores);
|
||
|
||
// 本场与立直棒
|
||
elements.setHonbaRiichiBtn.addEventListener('click', setHonbaRiichi);
|
||
|
||
// 样式设置
|
||
elements.opacityInput.addEventListener('input', updateOpacityValue);
|
||
elements.setStyleBtn.addEventListener('click', setStyle);
|
||
|
||
// 测试按钮
|
||
elements.openOverlayBtn.addEventListener('click', openOverlay);
|
||
elements.testWinBtn.addEventListener('click', testWin);
|
||
|
||
// 听牌复选框事件
|
||
for (let i = 0; i < 4; i++) {
|
||
document.getElementById(`playerTenpai${i}`).addEventListener('change', (e) => {
|
||
sendEvent({
|
||
event: 'set_tenpai',
|
||
player_index: i,
|
||
is_tenpai: e.target.checked
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
// 打开叠加层窗口
|
||
function openOverlay() {
|
||
if (overlayWindow && !overlayWindow.closed) {
|
||
overlayWindow.focus();
|
||
} else {
|
||
overlayWindow = window.open('index.html', '麻将直播叠加层', 'width=1280,height=720');
|
||
}
|
||
}
|
||
|
||
// 发送事件到叠加层
|
||
function sendEvent(event) {
|
||
console.log('发送事件:', event);
|
||
|
||
// 发送到打开的窗口
|
||
if (overlayWindow && !overlayWindow.closed) {
|
||
overlayWindow.postMessage(event, '*');
|
||
}
|
||
|
||
// 同时发送到当前窗口(如果叠加层在同一个窗口)
|
||
window.postMessage(event, '*');
|
||
}
|
||
|
||
// 设置视频源
|
||
function setVideoSource() {
|
||
sendEvent({
|
||
event: 'set_video_source',
|
||
src: elements.videoSource.value
|
||
});
|
||
}
|
||
|
||
// 更新所有玩家信息
|
||
function updateAllPlayers() {
|
||
for (let i = 0; i < 4; i++) {
|
||
const name = document.getElementById(`playerName${i}`).value;
|
||
const score = parseInt(document.getElementById(`playerScore${i}`).value) || 0;
|
||
const color = document.getElementById(`playerColor${i}`).value;
|
||
const isTenpai = document.getElementById(`playerTenpai${i}`).checked;
|
||
|
||
// 将hex颜色转换为带透明度的rgba
|
||
const rgbaColor = hexToRgba(color, defaultOpacity);
|
||
|
||
sendEvent({
|
||
event: 'update_player',
|
||
player_index: i,
|
||
name: name,
|
||
score: score,
|
||
color: rgbaColor,
|
||
is_tenpai: isTenpai
|
||
});
|
||
}
|
||
}
|
||
|
||
// 触发胡牌
|
||
function triggerWin() {
|
||
const winner = parseInt(elements.winnerSelect.value);
|
||
const han = parseInt(elements.hanInput.value);
|
||
const fu = parseInt(elements.fuInput.value);
|
||
const points = parseInt(elements.pointsInput.value);
|
||
const isTsumo = elements.isTsumoInput.checked;
|
||
const text = elements.winTextInput.value;
|
||
|
||
// 确定输家
|
||
let losers = [];
|
||
if (isTsumo) {
|
||
// 自摸时,其他三人为输家
|
||
losers = [0, 1, 2, 3].filter(i => i !== winner);
|
||
} else {
|
||
// 默认为下家放铳,可根据实际情况修改
|
||
losers = [(winner + 1) % 4];
|
||
}
|
||
|
||
sendEvent({
|
||
event: 'win',
|
||
winner: winner,
|
||
losers: losers,
|
||
han: han,
|
||
fu: fu,
|
||
points: points,
|
||
is_tsumo: isTsumo,
|
||
text: text
|
||
});
|
||
}
|
||
|
||
// 调整分数
|
||
function adjustScore() {
|
||
const playerIndex = parseInt(elements.adjustPlayerSelect.value);
|
||
const delta = parseInt(elements.deltaInput.value);
|
||
|
||
sendEvent({
|
||
event: 'adjust_score',
|
||
player_index: playerIndex,
|
||
delta: delta
|
||
});
|
||
}
|
||
|
||
// 重置所有分数
|
||
function resetScores() {
|
||
if (confirm('确定要重置所有玩家分数为25000吗?')) {
|
||
for (let i = 0; i < 4; i++) {
|
||
document.getElementById(`playerScore${i}`).value = 25000;
|
||
sendEvent({
|
||
event: 'update_player',
|
||
player_index: i,
|
||
score: 25000
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置本场与立直棒
|
||
function setHonbaRiichi() {
|
||
const honba = parseInt(elements.honbaInput.value);
|
||
const riichiSticks = parseInt(elements.riichiInput.value);
|
||
|
||
sendEvent({
|
||
event: 'set_honba_riichi',
|
||
honba: honba,
|
||
riichi_sticks: riichiSticks
|
||
});
|
||
}
|
||
|
||
// 更新透明度显示值
|
||
function updateOpacityValue() {
|
||
elements.opacityValue.textContent = elements.opacityInput.value;
|
||
}
|
||
|
||
// 设置样式
|
||
function setStyle() {
|
||
const playerIndex = parseInt(elements.stylePlayerSelect.value);
|
||
const opacity = parseFloat(elements.opacityInput.value);
|
||
const fontSize = parseInt(elements.fontSizeInput.value);
|
||
|
||
sendEvent({
|
||
event: 'set_style',
|
||
player_index: playerIndex,
|
||
opacity: opacity,
|
||
font_size: fontSize
|
||
});
|
||
}
|
||
|
||
// 测试胡牌动画
|
||
function testWin() {
|
||
sendEvent({
|
||
event: 'win',
|
||
winner: 1,
|
||
losers: [0, 2, 3],
|
||
han: 3,
|
||
fu: 40,
|
||
points: 8000,
|
||
is_tsumo: true,
|
||
text: '三暗刻 自摸'
|
||
});
|
||
}
|
||
|
||
// 辅助函数:将hex颜色转换为rgba
|
||
function hexToRgba(hex, alpha) {
|
||
// 移除#号
|
||
hex = hex.replace('#', '');
|
||
|
||
// 解析RGB值
|
||
const r = parseInt(hex.substring(0, 2), 16);
|
||
const g = parseInt(hex.substring(2, 4), 16);
|
||
const b = parseInt(hex.substring(4, 6), 16);
|
||
|
||
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
||
}
|
||
|
||
// 初始化控制面板
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
</script>
|
||
</body>
|
||
</html> |