综合php项目,边路传中成功率对比?

wen PHP项目 2

综合PHP项目:边路传中成功率对比系统

下面给你一个完整的PHP项目方案,用于统计和对比足球比赛中"边路传中成功率"(可按球员/球队/左右路/比赛维度对比)。

综合php项目,边路传中成功率对比?


需求分析

核心指标:

  • 传中总次数(Crosses Attempted)
  • 成功传中次数(Successful Crosses,即找到队友)
  • 传中成功率 = 成功次数 / 总次数 × 100%
  • 分维度:球队 / 球员 / 左路 vs 右路 / 主客场 / 时间段

对比对象示例: | 球员 | 总传中 | 成功 | 成功率 | |------|--------|------|--------| | 德布劳内 | 120 | 42 | 35.0% | | 阿诺德 | 150 | 45 | 30.0% |


数据库设计(MySQL)

CREATE DATABASE football_stats DEFAULT CHARSET utf8mb4;
USE football_stats;
-- 球队表
CREATE TABLE teams (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL
);
-- 球员表
CREATE TABLE players (
    id INT PRIMARY KEY AUTO_INCREMENT,
    team_id INT,
    name VARCHAR(50) NOT NULL,
    position VARCHAR(20),
    FOREIGN KEY (team_id) REFERENCES teams(id)
);
-- 比赛表
CREATE TABLE matches (
    id INT PRIMARY KEY AUTO_INCREMENT,
    home_team_id INT,
    away_team_id INT,
    match_date DATE
);
-- 传中记录表(核心)
CREATE TABLE crosses (
    id INT PRIMARY KEY AUTO_INCREMENT,
    match_id INT,
    player_id INT,
    minute INT,
    side ENUM('left','right') NOT NULL,   -- 左路/右路
    is_success TINYINT(1) DEFAULT 0,      -- 1成功 0失败
    FOREIGN KEY (match_id) REFERENCES matches(id),
    FOREIGN KEY (player_id) REFERENCES players(id),
    INDEX idx_player (player_id),
    INDEX idx_side (side)
);

示例数据:

INSERT INTO teams (name) VALUES ('曼城'),('利物浦');
INSERT INTO players (team_id,name,position) VALUES
(1,'德布劳内','MF'),(1,'福登','MF'),
(2,'阿诺德','DF'),(2,'萨拉赫','FW');
INSERT INTO matches (home_team_id,away_team_id,match_date) VALUES
(1,2,'2024-03-10'),(2,1,'2024-04-05');
INSERT INTO crosses (match_id,player_id,minute,side,is_success) VALUES
(1,1,12,'right',1),(1,1,30,'right',0),(1,1,55,'left',1),
(1,2,20,'left',0),(1,2,66,'left',1),
(2,3,10,'right',1),(2,3,40,'right',1),(2,3,70,'left',0),
(2,4,15,'right',0),(2,4,50,'right',1),(2,4,88,'right',1);

PHP 项目结构

cross-analysis/
├── config/
│   └── db.php
├── includes/
│   └── functions.php
├── api/
│   ├── by_player.php
│   ├── by_team.php
│   └── by_side.php
├── index.php          # 可视化对比页
└── assets/
    └── style.css

核心代码

config/db.php

<?php
$host = '127.0.0.1';
$db   = 'football_stats';
$user = 'root';
$pass = 'root';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
    die('DB连接失败: '.$e->getMessage());
}

includes/functions.php — 通用统计函数

<?php
require_once __DIR__.'/../config/db.php';
/**
 * 按球员统计传中成功率
 */
function getCrossStatsByPlayer(PDO $pdo, ?int $teamId = null): array {
    $sql = "SELECT p.id, p.name AS player_name, t.name AS team_name,
                   COUNT(c.id) AS total,
                   SUM(c.is_success) AS success,
                   ROUND(SUM(c.is_success)/COUNT(c.id)*100, 2) AS rate
            FROM players p
            JOIN teams t ON p.team_id = t.id
            JOIN crosses c ON c.player_id = p.id";
    if ($teamId) {
        $sql .= " WHERE p.team_id = :tid";
    }
    $sql .= " GROUP BY p.id ORDER BY rate DESC";
    $stmt = $pdo->prepare($sql);
    if ($teamId) $stmt->bindValue(':tid', $teamId, PDO::PARAM_INT);
    $stmt->execute();
    return $stmt->fetchAll();
}
/**
 * 按球队统计
 */
function getCrossStatsByTeam(PDO $pdo): array {
    $sql = "SELECT t.id, t.name AS team_name,
                   COUNT(c.id) AS total,
                   SUM(c.is_success) AS success,
                   ROUND(SUM(c.is_success)/COUNT(c.id)*100, 2) AS rate
            FROM teams t
            JOIN players p ON p.team_id = t.id
            JOIN crosses c ON c.player_id = p.id
            GROUP BY t.id
            ORDER BY rate DESC";
    return $pdo->query($sql)->fetchAll();
}
/**
 * 按左右路统计(可指定球员)
 */
function getCrossStatsBySide(PDO $pdo, ?int $playerId = null): array {
    $sql = "SELECT side,
                   COUNT(*) AS total,
                   SUM(is_success) AS success,
                   ROUND(SUM(is_success)/COUNT(*)*100, 2) AS rate
            FROM crosses";
    if ($playerId) $sql .= " WHERE player_id = :pid";
    $sql .= " GROUP BY side";
    $stmt = $pdo->prepare($sql);
    if ($playerId) $stmt->bindValue(':pid', $playerId, PDO::PARAM_INT);
    $stmt->execute();
    return $stmt->fetchAll();
}
/**
 * 两两对比(任意两名球员)
 */
function compareTwoPlayers(PDO $pdo, int $p1, int $p2): array {
    $sql = "SELECT p.id, p.name,
                   COUNT(c.id) AS total,
                   SUM(c.is_success) AS success,
                   ROUND(SUM(c.is_success)/COUNT(c.id)*100,2) AS rate
            FROM players p
            JOIN crosses c ON c.player_id = p.id
            WHERE p.id IN (:a, :b)
            GROUP BY p.id";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([':a'=>$p1, ':b'=>$p2]);
    return $stmt->fetchAll();
}

api/by_player.php — JSON接口

<?php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__.'/../includes/functions.php';
$teamId = isset($_GET['team_id']) ? (int)$_GET['team_id'] : null;
try {
    $data = getCrossStatsByPlayer($pdo, $teamId);
    echo json_encode(['code'=>0,'data'=>$data], JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
    echo json_encode(['code'=>1,'msg'=>$e->getMessage()]);
}

index.php — 对比可视化页

<?php
require_once __DIR__.'/includes/functions.php';
$teamStats   = getCrossStatsByTeam($pdo);
$playerStats = getCrossStatsByPlayer($pdo);
$sideStats   = getCrossStatsBySide($pdo);
// 简化:取前两名球员做对比
$top2 = array_slice($playerStats, 0, 2);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">边路传中成功率对比</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body{font-family:system-ui,sans-serif;max-width:1000px;margin:20px auto;padding:0 15px;}
table{width:100%;border-collapse:collapse;margin:15px 0;}
th,td{border:1px solid #ddd;padding:8px;text-align:center;}
th{background:#2c3e50;color:#fff;}
.rate{font-weight:bold;color:#27ae60;}
</style>
</head>
<body>
<h1>⚽ 边路传中成功率对比</h1>
<h2>📊 球队对比</h2>
<table>
<tr><th>球队</th><th>传中总数</th><th>成功</th><th>成功率</th></tr>
<?php foreach($teamStats as $r): ?>
<tr>
  <td><?=htmlspecialchars($r['team_name'])?></td>
  <td><?=$r['total']?></td>
  <td><?=$r['success']?></td>
  <td class="rate"><?=$r['rate']?>%</td>
</tr>
<?php endforeach; ?>
</table>
<h2>👤 球员对比</h2>
<table>
<tr><th>球员</th><th>球队</th><th>传中</th><th>成功</th><th>成功率</th></tr>
<?php foreach($playerStats as $r): ?>
<tr>
  <td><?=htmlspecialchars($r['player_name'])?></td>
  <td><?=htmlspecialchars($r['team_name'])?></td>
  <td><?=$r['total']?></td>
  <td><?=$r['success']?></td>
  <td class="rate"><?=$r['rate']?>%</td>
</tr>
<?php endforeach; ?>
</table>
<h2>↔️ 左右路对比</h2>
<table>
<tr><th>边路</th><th>传中</th><th>成功</th><th>成功率</th></tr>
<?php foreach($sideStats as $r): ?>
<tr>
  <td><?=$r['side']==='left'?'左路':'右路'?></td>
  <td><?=$r['total']?></td>
  <td><?=$r['success']?></td>
  <td class="rate"><?=$r['rate']?>%</td>
</tr>
<?php endforeach; ?>
</table>
<h2>📈 球员成功率可视化</h2>
<canvas id="chart" height="100"></canvas>
<script>
new Chart(document.getElementById('chart'), {
  type: 'bar',
  data: {
    labels: <?=json_encode(array_column($playerStats,'player_name'), JSON_UNESCAPED_UNICODE)?>,
    datasets: [{
      label: '传中成功率 (%)',
      data: <?=json_encode(array_column($playerStats,'rate'))?>,
      backgroundColor: ['#3498db','#e74c3c','#2ecc71','#f39c12','#9b59b6']
    }]
  },
  options: { scales: { y: { beginAtZero:true, max:100 } } }
});
</script>
</body>
</html>

扩展功能建议

功能 说明
分时间段 0-15、15-30…分钟传中效率,看体能影响
主客场对比 加一列 is_home 判断
对阵强度 关联对手排名,做加权分析
雷达对比图 Chart.js radar,直观呈现两球员多维能力
数据导入 支持从 Opta/StatsBomb CSV 批量导入
缓存 用 Redis 缓存统计结果,减少聚合查询压力

关键设计要点

  1. 一次传中一条记录,用 is_success 布尔字段存储,聚合灵活。
  2. side 用 ENUM,方便按边路筛选。
  3. 接口与视图分离:functions.php 做统计,api/* 输出 JSON,index.php 渲染。
  4. 百分比用 SQL 直接算(SUM/COUNT*100),避免 PHP 端二次计算。
  5. 索引优化:player_id、side、match_id 建索引,聚合查询更快。

如果你需要我进一步扩展为:

  • 完整前后端(含 Vue/React 前端)
  • 采集真实比赛数据(API)自动写入
  • 多名球员横向雷达图对比

告诉我具体方向,我可以继续帮你完善代码。

上一篇这个php项目是否分析了顺风局稳定性?

下一篇当前分类已是最新一篇

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