php项目统计门球短传配合成功率?

wen PHP项目 8

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

php项目统计门球短传配合成功率?

数据库设计

数据表结构

-- 比赛信息表
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%
  • 平均配合传球数:总传球次数 / 配合序列数

功能模块

  1. 实时数据录入:记录每次传球的数据(球员、类型、区域、距离、是否成功)
  2. 连续配合追踪:记录多次连续传球是否形成有效配合
  3. 球员统计:分析每位球员的传球成功率
  4. 区域分析:统计不同区域的传球成功率
  5. 比赛报告:生成完整的比赛统计

抱歉,评论功能暂时关闭!