我来帮您设计一个门球短传配合成功率的统计系统,这个系统需要跟踪传球、接球和配合的完成情况。

数据库设计
数据表结构
-- 比赛信息表
CREATE TABLE matches (
id INT PRIMARY KEY AUTO_INCREMENT,
match_date DATE NOT NULL,
opponent VARCHAR(100),
venue VARCHAR(50),
status ENUM('进行中', '已完成') DEFAULT '进行中',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 球员信息表
CREATE TABLE players (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
number INT,
position VARCHAR(30),
is_active BOOLEAN DEFAULT TRUE
);
-- 传球统计表
CREATE TABLE passes (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT NOT NULL,
passer_id INT NOT NULL,
receiver_id INT NOT NULL,
pass_type ENUM('短传', '中传', '长传') NOT NULL,
pass_zone VARCHAR(50), -- 传球区域
distance_meters DECIMAL(5,2), -- 传球距离
success BOOLEAN NOT NULL, -- 是否成功
turn_completed BOOLEAN DEFAULT FALSE, -- 是否完成配合
passer_challenges INT DEFAULT 0, -- 传球次数
receiver_challenges INT DEFAULT 0, -- 接球次数
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (match_id) REFERENCES matches(id),
FOREIGN KEY (passer_id) REFERENCES players(id),
FOREIGN KEY (receiver_id) REFERENCES players(id)
);
-- 配合序列表(记录连续传球配合)
CREATE TABLE passing_sequences (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT NOT NULL,
start_time TIMESTAMP,
end_time TIMESTAMP,
pass_count INT DEFAULT 0, -- 连续传球次数
completed BOOLEAN DEFAULT FALSE, -- 配合是否成功完成
break_type VARCHAR(30), -- 中断原因
FOREIGN KEY (match_id) REFERENCES matches(id)
);
-- 配合序列详情(关联具体传球)
CREATE TABLE sequence_details (
id INT PRIMARY KEY AUTO_INCREMENT,
sequence_id INT NOT NULL,
pass_id INT NOT NULL,
pass_order INT NOT NULL, -- 传球顺序
FOREIGN KEY (sequence_id) REFERENCES passing_sequences(id),
FOREIGN KEY (pass_id) REFERENCES passes(id)
);
PHP后端代码
<?php
// 数据库配置
class Database {
private $host = 'localhost';
private $username = 'root';
private $password = 'password';
private $database = 'menqiu_stats';
public $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host=" . $this->host . ";dbname=" . $this->database,
$this->username,
$this->password
);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "连接失败: " . $e->getMessage();
}
return $this->conn;
}
}
// 传球统计服务类
class PassStatistics {
private $db;
private $connection;
public function __construct() {
$this->db = new Database();
$this->connection = $this->db->getConnection();
}
// 记录一次传球
public function logPass($matchId, $passerId, $receiverId, $passType, $passZone, $distance, $success) {
try {
$query = "INSERT INTO passes
(match_id, passer_id, receiver_id, pass_type, pass_zone, distance_meters, success)
VALUES (?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->connection->prepare($query);
$stmt->execute([
$matchId,
$passerId,
$receiverId,
$passType,
$passZone,
$distance,
$success
]);
return $this->connection->lastInsertId();
} catch (Exception $e) {
error_log($e->getMessage());
return false;
}
}
// 获取短传配合成功率
public function getShortPassSuccessRate($matchId, $zone = null) {
try {
$whereClause = "WHERE match_id = ? AND pass_type = '短传'";
$params = [$matchId];
if ($zone) {
$whereClause .= " AND pass_zone = ?";
$params[] = $zone;
}
$query = "SELECT
COUNT(*) as total_passes,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful_passes,
ROUND(
(SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) / COUNT(*) * 100),
2
) as success_rate
FROM passes
$whereClause";
$stmt = $this->connection->prepare($query);
$stmt->execute($params);
return $stmt->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log($e->getMessage());
return null;
}
}
// 记录配合序列
public function startPassingSequence($matchId) {
try {
$query = "INSERT INTO passing_sequences (match_id, start_time) VALUES (?, NOW())";
$stmt = $this->connection->prepare($query);
$stmt->execute([$matchId]);
return $this->connection->lastInsertId();
} catch (Exception $e) {
error_log($e->getMessage());
return false;
}
}
// 更新配合序列
public function updatePassSequence($sequenceId, $passId, $passOrder) {
try {
// 更新传球记录
$query = "UPDATE passes SET turn_completed = TRUE WHERE id = ?";
$stmt = $this->connection->prepare($query);
$stmt->execute([$passId]);
// 添加序列详情
$query = "INSERT INTO sequence_details (sequence_id, pass_id, pass_order) VALUES (?, ?, ?)";
$stmt = $this->connection->prepare($query);
$stmt->execute([$sequenceId, $passId, $passOrder]);
// 更新序列的传球数
$query = "UPDATE passing_sequences
SET pass_count = pass_count + 1,
end_time = NOW()
WHERE id = ?";
$stmt = $this->connection->prepare($query);
$stmt->execute([$sequenceId]);
return true;
} catch (Exception $e) {
error_log($e->getMessage());
return false;
}
}
// 完成配合序列
public function completePassSequence($sequenceId, $completed = true, $breakType = null) {
try {
$query = "UPDATE passing_sequences
SET completed = ?, break_type = ?, end_time = NOW()
WHERE id = ?";
$stmt = $this->connection->prepare($query);
return $stmt->execute([$completed ? 1 : 0, $breakType, $sequenceId]);
} catch (Exception $e) {
error_log($e->getMessage());
return false;
}
}
// 获取配合成功率(连续传球配合)
public function getSequenceSuccessRate($matchId) {
try {
$query = "SELECT
COUNT(*) as total_sequences,
SUM(CASE WHEN completed = 1 THEN 1 ELSE 0 END) as successful_sequences,
ROUND(
(SUM(CASE WHEN completed = 1 THEN 1 ELSE 0 END) / COUNT(*) * 100),
2
) as success_rate,
AVG(pass_count) as avg_passes_per_sequence
FROM passing_sequences
WHERE match_id = ?";
$stmt = $this->connection->prepare($query);
$stmt->execute([$matchId]);
return $stmt->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log($e->getMessage());
return null;
}
}
// 获取球员传球统计
public function getPlayerPassingStats($matchId) {
try {
$query = "SELECT
p.name as player_name,
p.number,
COUNT(CASE WHEN pa.passer_id = p.id AND pa.pass_type = '短传' THEN 1 END) as short_passes,
SUM(CASE WHEN pa.passer_id = p.id AND pa.pass_type = '短传' AND pa.success = 1 THEN 1 ELSE 0 END) as short_successful,
ROUND(
(SUM(CASE WHEN pa.passer_id = p.id AND pa.pass_type = '短传' AND pa.success = 1 THEN 1 ELSE 0 END) /
NULLIF(COUNT(CASE WHEN pa.passer_id = p.id AND pa.pass_type = '短传' THEN 1 END), 0) * 100),
2
) as personal_success_rate
FROM players p
LEFT JOIN passes pa ON pa.passer_id = p.id
WHERE pa.match_id = ? OR pa.match_id IS NULL
GROUP BY p.id, p.name, p.number
HAVING short_passes > 0 OR short_successful > 0
ORDER BY short_passes DESC";
$stmt = $this->connection->prepare($query);
$stmt->execute([$matchId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log($e->getMessage());
return [];
}
}
// 导出比赛统计报告
public function exportMatchReport($matchId) {
try {
// 获取比赛总体统计
$shortPassStats = $this->getShortPassSuccessRate($matchId);
$sequenceStats = $this->getSequenceSuccessRate($matchId);
$playerStats = $this->getPlayerPassingStats($matchId);
// 生成报告数据
$report = [
'short_pass_stats' => $shortPassStats,
'sequence_stats' => $sequenceStats,
'player_stats' => $playerStats,
'successful_passes_count' => $shortPassStats['successful_passes'],
'total_passes_count' => $shortPassStats['total_passes']
];
// 导出为CSV
$this->exportToCSV($report, $matchId);
return $report;
} catch (Exception $e) {
error_log($e->getMessage());
return null;
}
}
private function exportToCSV($data, $matchId) {
$filename = 'match_' . $matchId . '_pass_report.csv';
$filepath = __DIR__ . '/reports/' . $filename;
// 确保目录存在
if (!file_exists(dirname($filepath))) {
mkdir(dirname($filepath), 0777, true);
}
$fp = fopen($filepath, 'w');
// 添加标题行
fputcsv($fp, ['门球短传配合成功率报告']);
fputcsv($fp, ['比赛ID', $matchId]);
fputcsv($fp, ['短传总数', $data['short_pass_stats']['total_passes']]);
fputcsv($fp, ['成功数', $data['short_pass_stats']['successful_passes']]);
fputcsv($fp, ['成功率', $data['short_pass_stats']['success_rate'] . '%']);
fputcsv($fp, [''); // 空行
// 球员统计
fputcsv($fp, ['球员传球统计']);
fputcsv($fp, ['球员', '号码', '短传次数', '成功次数', '成功率']);
foreach ($data['player_stats'] as $player) {
fputcsv($fp, [
$player['player_name'],
$player['number'],
$player['short_passes'],
$player['short_successful'],
$player['personal_success_rate'] . '%'
]);
}
fclose($fp);
}
}
// 前端API接口
class API {
private $passStats;
public function __construct() {
$this->passStats = new PassStatistics();
}
public function handleRequest() {
$method = $_SERVER['REQUEST_METHOD'];
$action = isset($_GET['action']) ? $_GET['action'] : '';
switch ($action) {
case 'logPass':
if ($method == 'POST') {
$this->logPass();
}
break;
case 'getSuccessRate':
if ($method == 'GET') {
$this->getSuccessRate();
}
break;
case 'startSequence':
if ($method == 'POST') {
$this->startSequence();
}
break;
case 'getReport':
if ($method == 'GET') {
$this->getReport();
}
break;
default:
echo json_encode(['status' => 'error', 'message' => 'Invalid action']);
}
}
private function logPass() {
$data = json_decode(file_get_contents('php://input'), true);
$matchId = $data['match_id'] ?? 0;
$passerId = $data['passer_id'] ?? 0;
$receiverId = $data['receiver_id'] ?? 0;
$passType = $data['pass_type'] ?? '短传';
$passZone = $data['pass_zone'] ?? 'unknown';
$distance = $data['distance'] ?? 0;
$success = $data['success'] ?? false;
$result = $this->passStats->logPass(
$matchId, $passerId, $receiverId,
$passType, $passZone, $distance, $success
);
echo json_encode([
'status' => 'success',
'pass_id' => $result
]);
}
private function getSuccessRate() {
$matchId = $_GET['match_id'] ?? 0;
$zone = $_GET['zone'] ?? null;
$result = $this->passStats->getShortPassSuccessRate($matchId, $zone);
if ($result) {
echo json_encode(['status' => 'success', 'data' => $result]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Failed to get statistics']);
}
}
private function startSequence() {
$data = json_decode(file_get_contents('php://input'), true);
$matchId = $data['match_id'] ?? 0;
$result = $this->passStats->startPassingSequence($matchId);
echo json_encode([
'status' => 'success',
'sequence_id' => $result
]);
}
private function getReport() {
$matchId = $_GET['match_id'] ?? 0;
$report = $this->passStats->exportMatchReport($matchId);
if ($report) {
echo json_encode(['status' => 'success', 'data' => $report]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Failed to generate report']);
}
}
}
// 执行请求
$api = new API();
$api->handleRequest();
?>
前端统计展示界面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">门球短传配合统计系统</title>
<style>
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
margin: 0;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
h1 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
}
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
text-align: center;
}
.stat-card .value {
font-size: 32px;
font-weight: bold;
color: #3498db;
margin: 10px 0;
}
.stat-card .label {
color: #7f8c8d;
font-size: 14px;
}
.chart-container {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.live-tracking {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.player-stats-table {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
th {
background: #f8f9fa;
font-weight: bold;
color: #333;
}
.success-rate {
font-weight: bold;
color: #27ae60;
}
.btn {
background: #3498db;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
}
.btn:hover {
background: #2980b9;
}
.btn-danger {
background: #e74c3c;
}
.btn-danger:hover {
background: #c0392b;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input, .form-group select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.collapsible {
background-color: #f8f9fa;
color: #333;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
}
.collapsible:hover {
background-color: #e9ecef;
}
.content {
padding: 0 18px;
display: none;
overflow: hidden;
background-color: white;
border: 1px solid #dee2e6;
border-top: none;
border-radius: 0 0 4px 4px;
}
.active, .collapsible:hover {
background-color: #e9ecef;
}
</style>
</head>
<body>
<div class="container">
<h1>🏑 门球短传配合统计系统</h1>
<!-- 统计概览 -->
<div class="dashboard">
<div class="stat-card">
<div class="label">总传球数</div>
<div class="value" id="totalPasses">0</div>
</div>
<div class="stat-card">
<div class="label">成功传球</div>
<div class="value" id="successfulPasses">0</div>
</div>
<div class="stat-card">
<div class="label">成功率</div>
<div class="value" id="successRate">0%</div>
</div>
<div class="stat-card">
<div class="label">平均配合传球数</div>
<div class="value" id="avgPasses">0</div>
</div>
</div>
<!-- 比赛选择 -->
<div class="chart-container">
<h3>选择比赛</h3>
<select id="matchSelect" onchange="loadMatchData()">
<option value="">请选择比赛</option>
</select>
<button class="btn" onclick="startNewMatch()">新建比赛</button>
</div>
<!-- 实时数据录入 -->
<div class="live-tracking">
<h3>📊 实时传球数据录入</h3>
<button class="collapsible active" onclick="toggleInputPanel()">展开/收起录入面板</button>
<div id="inputPanel" class="content" style="display: block;">
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 20px; margin-top: 15px;">
<div class="form-group">
<label for="player1">传球球员</label>
<select id="player1">
<option value="">选择球员</option>
</select>
</div>
<div class="form-group">
<label for="player2">接球球员</label>
<select id="player2">
<option value="">选择球员</option>
</select>
</div>
<div class="form-group">
<label for="passType">传球类型</label>
<select id="passType">
<option value="短传" selected>短传</option>
<option value="中传">中传</option>
<option value="长传">长传</option>
</select>
</div>
<div class="form-group">
<label for="passZone">传球区域</label>
<select id="passZone">
<option value="前场">前场</option>
<option value="中场">中场</option>
<option value="后场">后场</option>
<option value="边路">边路</option>
</select>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 20px; margin-top: 15px;">
<div class="form-group">
<label for="distance">传球距离(米)</label>
<input type="number" id="distance" value="5" min="0" max="50">
</div>
<div class="form-group">
<label for="sequenceMode">配合模式</label>
<select id="sequenceMode" onchange="toggleSequenceBtn()">
<option value="single">单次传球</option>
<option value="sequence">配合传球</option>
</select>
</div>
<div class="form-group" id="sequenceBtnDiv" style="display:none;">
<button class="btn" id="sequenceBtn" onclick="startOrEndSequence()">开始配合</button>
</div>
</div>
<div style="margin-top: 20px; text-align: center;">
<button class="btn" style="width: 200px; height: 45px; font-size: 16px;" onclick="submitPass()">提交传球数据</button>
<button class="btn btn-danger" style="display:none;" id="cancelPassBtn" onclick="cancelPass()">取消传球</button>
</div>
</div>
</div>
<!-- 配合序列跟踪 -->
<div class="chart-container">
<h3>连续配合球序列</h3>
<div id="sequenceStatus">
<p>当前无进行中的配合</p>
</div>
<div id="sequenceHistory">
<table id="sequenceTable">
<thead>
<tr>
<th>序列ID</th>
<th>开始时间</th>
<th>传球次数</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="sequenceTableBody">
</tbody>
</table>
</div>
</div>
<!-- 球员统计表格 -->
<div class="player-stats-table">
<h3>球员传球统计</h3>
<table id="playerStatsTable">
<thead>
<tr>
<th>姓名</th>
<th>号码</th>
<th>短传总数</th>
<th>成功数</th>
<th>成功率</th>
<th>传球区域</th>
</tr>
</thead>
<tbody id="playerStatsTableBody">
</tbody>
</table>
</div>
<!-- 传球分析图表 -->
<div class="chart-container">
<h3>传球分析图表</h3>
<canvas id="passAnalysisChart" width="100%"></canvas>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
let currentSequence = null;
let matchData = {
matchId: null,
currentSequence: 0,
totalPasses: 0,
successfulPasses: 0,
passerStats: {},
receiverStats: {},
sequences: []
};
// 初始化比赛数据
function initMatch() {
const matchSelect = document.getElementById('matchSelect');
// 这里应该从服务器获取比赛列表
// 示例数据
matchSelect.innerHTML = '<option value="">请选择比赛</option>' +
'<option value="1">2024年3月15日 vs 红队</option>' +
'<option value="2">2024年3月22日 vs 蓝队</option>';
}
// 加载比赛数据
function loadMatchData() {
const matchId = document.getElementById('matchSelect').value;
if (!matchId) return;
// 这里应该从服务器获取比赛数据
// 示例数据
matchData.matchId = matchId;
matchData.totalPasses = 0;
matchData.successfulPasses = 0;
// 更新玩家列表
updatePlayerList();
updateStatsDisplay();
}
// 更新球员下拉列表
function updatePlayerList() {
const player1 = document.getElementById('player1');
const player2 = document.getElementById('player2');
// 示例球员数据
const players = [
{id: 1, name: '张三', number: 1},
{id: 2, name: '李四', number: 2},
{id: 3, name: '王五', number: 3},
{id: 4, name: '赵六', number: 4},
{id: 5, name: '孙七', number: 5}
];
const options = '<option value="">选择球员</option>' +
players.map(p => `<option value="${p.id}">${p.name} (${p.number})</option>`).join('');
player1.innerHTML = options;
player2.innerHTML = options;
}
// 统计数据显示
function updateStatsDisplay() {
const rate = matchData.totalPasses > 0 ?
Math.round((matchData.successfulPasses / matchData.totalPasses) * 100) : 0;
document.getElementById('totalPasses').textContent = matchData.totalPasses;
document.getElementById('successfulPasses').textContent = matchData.successfulPasses;
document.getElementById('successRate').textContent = rate + '%';
}
// 切换配合模式
function toggleSequenceBtn() {
const mode = document.getElementById('sequenceMode').value;
const btnDiv = document.getElementById('sequenceBtnDiv');
if (mode === 'sequence') {
btnDiv.style.display = 'block';
} else {
btnDiv.style.display = 'none';
}
}
// 开始/结束配合序列
function startOrEndSequence() {
const btn = document.getElementById('sequenceBtn');
const mode = document.getElementById('sequenceMode').value;
const matchId = matchData.matchId;
if (!matchId) {
alert('请先选择比赛');
return;
}
if (!currentSequence) {
// 开始新的配合
currentSequence = matchData.currentSequence + 1;
matchData.currentSequence = currentSequence;
btn.textContent = '结束配合';
document.getElementById('sequenceStatus').innerHTML =
`<p>配合中... (序列#${currentSequence})</p>`;
console.log(`开始配合序列 #${currentSequence}`);
} else {
// 结束配合
completeSequence();
btn.textContent = '开始配合';
currentSequence = null;
}
}
// 完成配合
function completeSequence() {
if (!currentSequence) return;
const success = matchData.successfulPasses > 0 ? true : false;
const sequenceInfo = {
id: currentSequence,
passCount: matchData.totalPasses,
completed: success
};
// 添加到历史记录
addSequenceToTable(sequenceInfo);
document.getElementById('sequenceStatus').innerHTML =
`<p>配合已结束 (序列#${currentSequence})</p>`;
}
// 添加序列到表格
function addSequenceToTable(sequenceInfo) {
const tbody = document.getElementById('sequenceTableBody');
const row = tbody.insertRow(0);
row.innerHTML = `
<td>${sequenceInfo.id}</td>
<td>${new Date().toLocaleTimeString()}</td>
<td>${sequenceInfo.passCount}</td>
<td>${sequenceInfo.completed ? '✅ 成功' : '❌ 失败'}</td>
<td><button class="btn" onclick="viewSequence(${sequenceInfo.id})">查看详情</button></td>
`;
}
// 查看序列详情
function viewSequence(id) {
alert(`查看序列 #${id} 的详细统计数据`);
// 这里应该加载序列详细数据
}
// 提交传球数据
function submitPass() {
const player1 = document.getElementById('player1').value;
const player2 = document.getElementById('player2').value;
const passType = document.getElementById('passType').value;
const passZone = document.getElementById('passZone').value;
const distance = document.getElementById('distance').value;
if (!matchData.matchId) {
alert('请先选择比赛');
return;
}
if (!player1 || !player2) {
alert('请选择传球球员和接球球员');
return;
}
if (player1 === player2) {
alert('传球球员和接球球员不能相同');
return;
}
// 这里应该发送到服务器
// 模拟成功传球(80%成功率)
const success = Math.random() < 0.8;
// 更新统计数据
matchData.totalPasses++;
if (success) {
matchData.successfulPasses++;
}
// 更新球员统计
updatePlayerStats(player1, true, success);
updatePlayerStats(player2, false, success);
// 更新显示
updateStatsDisplay();
updatePlayerStatsTable();
// 显示结果提示
const statusColor = success ? 'green' : 'red';
const statusText = success ? '✅ 传球成功' : '❌ 传球失败';
document.getElementById('passResult').innerText = statusText;
document.getElementById('passResult').style.color = statusColor;
document.getElementById('passResult').style.fontWeight = 'bold';
}
// 更新球员统计
function updatePlayerStats(playerId, isPasser, success) {
if (!matchData.passerStats[playerId]) {
matchData.passerStats[playerId] = {passes: 0, successful: 0};
}
if (isPasser) {
matchData.passerStats[playerId].passes++;
if (success) {
matchData.passerStats[playerId].successful++;
}
}
}
// 更新球员统计表格
function updatePlayerStatsTable() {
const tbody = document.getElementById('playerStatsTableBody');
tbody.innerHTML = '';
for (let playerId in matchData.passerStats) {
const stats = matchData.passerStats[playerId];
const row = tbody.insertRow();
// 这里应该从服务器获取球员名称
row.innerHTML = `
<td>球员${playerId}</td>
<td>${String(playerId).padStart(2, '0')}</td>
<td>${stats.passes}</td>
<td>${stats.successful}</td>
<td class="success-rate">${stats.passes > 0 ? Math.round((stats.successful / stats.passes) * 100) : 0}%</td>
<td>中场</td>
`;
}
}
// 新建比赛
function startNewMatch() {
const matchId = confirm('确定要开始一场新的比赛吗?');
if (matchId) {
// 这里应该新建比赛
matchData = {
matchId: Date.now(),
currentSequence: 0,
totalPasses: 0,
successfulPasses: 0,
passerStats: {},
receiverStats: {},
sequences: []
};
document.getElementById('sequenceTableBody').innerHTML = '';
document.getElementById('playerStatsTableBody').innerHTML = '';
document.getElementById('sequenceStatus').innerHTML = '<p>当前无进行中的配合</p>';
resetForm();
updateStatsDisplay();
alert('新比赛创建成功!');
}
}
// 重置表单
function resetForm() {
document.getElementById('player1').value = '';
document.getElementById('player2').value = '';
document.getElementById('passType').value = '短传';
document.getElementById('passZone').value = '前场';
document.getElementById('distance').value = '5';
document.getElementById('sequenceMode').value = 'single';
document.getElementById('sequenceBtn').textContent = '开始配合';
}
// 折叠面板
function toggleInputPanel() {
const panel = document.getElementById('inputPanel');
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
}
// 初始化
window.onload = function() {
initMatch();
// 创建结果提示元素
const resultDiv = document.createElement('div');
resultDiv.id = 'passResult';
resultDiv.style.marginTop = '10px';
resultDiv.style.textAlign = 'center';
document.querySelector('.live-tracking').appendChild(resultDiv);
};
</script>
</body>
</html>
使用说明
统计指标:
- 短传成功率:短传成功次数 / 总短传次数 × 100%
- 配合序列成功率:成功完成的配合序列 / 总配合序列 × 100%
- 平均配合传球数:总传球次数 / 配合序列数
功能模块:
- 实时数据录入:记录每次传球的数据(球员、类型、区域、距离、是否成功)
- 连续配合追踪:记录多次连续传球是否形成有效配合
- 球员统计:分析每位球员的传球成功率
- 区域分析:统计不同区域的传球成功率
- 比赛报告:生成完整的比赛统计