php项目统计落叶球射门成功率如何?

wen PHP项目 5

本文目录导读:

php项目统计落叶球射门成功率如何?

  1. 项目架构设计
  2. 数据库结构
  3. 核心统计类
  4. API接口实现
  5. 管理员统计页面
  6. 使用说明
  7. 核心功能特性
  8. 部署建议

我来帮你设计一个PHP项目来统计落叶球射门成功率,落叶球(Knuckleball)是一种特殊的射门技术,需要特定的统计维度。

项目架构设计

// 项目目录结构
/
├── config/
│   └── database.php          // 数据库配置
├── includes/
│   ├── Database.php          // 数据库连接类
│   ├── ShootingStats.php     // 射门统计核心类
│   └── Validator.php         // 数据验证类
├── api/
│   ├── record_shot.php       // 记录射门数据
│   ├── get_stats.php         // 获取统计数据
│   └── get_analysis.php      // 获取详细分析
├── admin/
│   ├── dashboard.php         // 管理后台
│   └── stats_view.php        // 统计展示页面
└── sql/
    └── schema.sql            // 数据库结构

数据库结构

-- sql/schema.sql
CREATE DATABASE IF NOT EXISTS football_stats;
USE football_stats;
-- 球员表
CREATE TABLE players (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    position VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 射门事件表
CREATE TABLE shot_events (
    id INT PRIMARY KEY AUTO_INCREMENT,
    player_id INT,
    match_id VARCHAR(50),
    shot_time DATETIME,
    shot_type ENUM('knuckleball', 'normal', 'curve', 'drive') DEFAULT 'normal',
    distance_meters DECIMAL(4,1),
    shot_angle DECIMAL(4,1),
    ball_velocity_kmh INT,
    shot_accuracy ENUM('target', 'off_target', 'blocked', 'saved'),
    is_goal BOOLEAN DEFAULT 0,
    weather_condition ENUM('sunny', 'rainy', 'windy', 'cloudy'),
    field_condition ENUM('dry', 'wet', 'artificial', 'natural'),
    opponent_strength ENUM('weak', 'medium', 'strong'),
    foot_used ENUM('right', 'left'),
    spin_rate_rpm INT DEFAULT 0,
    trajectory_swing VARCHAR(50),  // 落叶球摆动幅度
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (player_id) REFERENCES players(id)
);
-- 训练记录表
CREATE TABLE training_sessions (
    id INT PRIMARY KEY AUTO_INCREMENT,
    player_id INT,
    session_date DATE,
    total_shots INT,
    successful_shots INT,
    goal_conversions INT,
    average_speed INT,
    notes TEXT,
    FOREIGN KEY (player_id) REFERENCES players(id)
);
-- 统计汇总表
CREATE TABLE monthly_stats (
    id INT PRIMARY KEY AUTO_INCREMENT,
    player_id INT,
    stat_month DATE,
    total_shots INT,
    on_target INT,
    goals INT,
    knuckleball_success_rate DECIMAL(5,2),
    avg_velocity INT,
    FOREIGN KEY (player_id) REFERENCES players(id)
);

核心统计类

<?php
// includes/ShootingStats.php
class ShootingStats {
    private $db;
    private $playerId;
    public function __construct($db, $playerId = null) {
        $this->db = $db;
        $this->playerId = $playerId;
    }
    /**
     * 记录一次射门
     */
    public function recordShot($data) {
        $query = "INSERT INTO shot_events 
                  (player_id, match_id, shot_time, shot_type, distance_meters,
                   shot_angle, ball_velocity_kmh, shot_accuracy, is_goal,
                   weather_condition, field_condition, opponent_strength,
                   foot_used, spin_rate_rpm, trajectory_swing, notes)
                  VALUES 
                  (:player_id, :match_id, :shot_time, :shot_type, :distance_meters,
                   :shot_angle, :ball_velocity_kmh, :shot_accuracy, :is_goal,
                   :weather_condition, :field_condition, :opponent_strength,
                   :foot_used, :spin_rate_rpm, :trajectory_swing, :notes)";
        $stmt = $this->db->prepare($query);
        return $stmt->execute($data);
    }
    /**
     * 计算落叶球成功率
     */
    public function calculateKnuckleballSuccessRate($playerId = null, $dateRange = null) {
        $conditions = [];
        $params = [];
        if ($playerId) {
            $conditions[] = "player_id = :player_id";
            $params[':player_id'] = $playerId;
        }
        if ($dateRange) {
            $conditions[] = "shot_time BETWEEN :start_date AND :end_date";
            $params[':start_date'] = $dateRange['start'];
            $params[':end_date'] = $dateRange['end'];
        }
        $whereClause = $conditions ? "WHERE " . implode(" AND ", $conditions) : "";
        $query = "SELECT 
                    COUNT(*) as total_shots,
                    SUM(CASE WHEN is_goal = 1 THEN 1 ELSE 0 END) as goals,
                    SUM(CASE WHEN shot_accuracy = 'target' THEN 1 ELSE 0 END) as on_target,
                    AVG(CASE WHEN is_goal = 1 THEN 100.0 ELSE 0 END) as success_rate
                  FROM shot_events 
                  WHERE shot_type = 'knuckleball'
                  $whereClause";
        $stmt = $this->db->prepare($query);
        $stmt->execute($params);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
    /**
     * 计算综合射门分析
     */
    public function getKnuckleballAnalysis() {
        $query = "SELECT 
                    player_id,
                    COUNT(*) as total_attempts,
                    SUM(is_goal) as total_goals,
                    ROUND((SUM(is_goal) / COUNT(*)) * 100, 2) as success_rate,
                    ROUND(AVG(ball_velocity_kmh), 2) as avg_speed,
                    ROUND(AVG(spin_rate_rpm), 2) as avg_spin_rate,
                    ROUND(AVG(distance_meters), 2) as avg_distance,
                    MAX(distance_meters) as longest_goal_distance
                  FROM shot_events 
                  WHERE shot_type = 'knuckleball'
                  GROUP BY player_id
                  ORDER BY success_rate DESC";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    /**
     * 分析不同环境下的成功率
     */
    public function analyzeEnvironmentFactors() {
        $query = "SELECT 
                    weather_condition,
                    field_condition,
                    COUNT(*) as total_shots,
                    SUM(is_goal) as goals,
                    ROUND((SUM(is_goal) / COUNT(*)) * 100, 2) as success_rate
                  FROM shot_events 
                  WHERE shot_type = 'knuckleball'
                  GROUP BY weather_condition, field_condition";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    /**
     * 球员能力趋势分析
     */
    public function getPerformanceTrend($playerId, $months = 6) {
        $query = "SELECT 
                    DATE_FORMAT(shot_time, '%Y-%m') as month,
                    COUNT(*) as monthly_shots,
                    SUM(is_goal) as monthly_goals,
                    ROUND((SUM(is_goal) / COUNT(*)) * 100, 2) as monthly_success_rate
                  FROM shot_events 
                  WHERE player_id = :player_id
                    AND shot_type = 'knuckleball'
                    AND shot_time >= DATE_SUB(NOW(), INTERVAL $months MONTH)
                  GROUP BY DATE_FORMAT(shot_time, '%Y-%m')
                  ORDER BY month";
        $stmt = $this->db->prepare($query);
        $stmt->execute([':player_id' => $playerId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    /**
     * 优化建议分析
     */
    public function getOptimizationSuggestions($playerId) {
        $suggestions = [];
        // 分析最佳射门距离
        $distanceAnalysis = $this->analyzeDistancePerformance();
        // 分析最佳脚使用
        $footAnalysis = $this->analyzeFootPerformance($playerId);
        // 分析对手强度影响
        $opponentAnalysis = $this->analyzeOpponentStrength($playerId);
        return [
            'distance_recommendation' => $distanceAnalysis['recommended_distance'],
            'foot_recommendation' => $footAnalysis['preferred_foot'],
            'opponent_strategy' => $opponentAnalysis,
            'suggestions' => $suggestions
        ];
    }
    private function analyzeDistancePerformance() {
        $query = "SELECT 
                    CASE 
                        WHEN distance_meters < 20 THEN 'close'
                        WHEN distance_meters BETWEEN 20 AND 30 THEN 'medium'
                        WHEN distance_meters BETWEEN 30 AND 40 THEN 'long'
                        ELSE 'very_long'
                    END as distance_category,
                    COUNT(*) as shots,
                    SUM(is_goal) as goals,
                    ROUND((SUM(is_goal) / COUNT(*)) * 100, 2) as success_rate
                  FROM shot_events 
                  WHERE shot_type = 'knuckleball'
                  GROUP BY distance_category
                  ORDER BY success_rate DESC";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
        return [
            'recommended_distance' => $results[0]['distance_category'] ?? 'unknown',
            'details' => $results
        ];
    }
}

API接口实现

<?php
// api/record_shot.php
require_once '../includes/Database.php';
require_once '../includes/ShootingStats.php';
header('Content-Type: application/json');
// 验证请求方法
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['error' => 'Method Not Allowed']);
    exit;
}
// 获取请求数据
$input = json_decode(file_get_contents('php://input'), true);
// 验证数据
$requiredFields = ['player_id', 'shot_time', 'shot_accuracy'];
foreach ($requiredFields as $field) {
    if (!isset($input[$field])) {
        http_response_code(400);
        echo json_encode(['error' => "Missing required field: $field"]);
        exit;
    }
}
// 设置默认值
$input['shot_type'] = $input['shot_type'] ?? 'knuckleball';
$input['is_goal'] = ($input['shot_accuracy'] === 'goal') ? 1 : 0;
// 初始化类
$db = Database::getConnection();
$stats = new ShootingStats($db);
try {
    $result = $stats->recordShot($input);
    if ($result) {
        echo json_encode([
            'success' => true,
            'message' => 'Shot recorded successfully'
        ]);
    } else {
        http_response_code(500);
        echo json_encode(['error' => 'Failed to record shot']);
    }
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);
}

管理员统计页面

<?php
// admin/stats_view.php
require_once '../includes/Database.php';
require_once '../includes/ShootingStats.php';
$db = Database::getConnection();
$stats = new ShootingStats($db);
// 获取总体统计
$overallStats = $stats->calculateKnuckleballSuccessRate();
$playerStats = $stats->getKnuckleballAnalysis();
$environmentFactors = $stats->analyzeEnvironmentFactors();
// 计算综合评分
$overallRate = $overallStats['success_rate'] ?? 0;
$totalShots = $overallStats['total_shots'] ?? 0;
$goalRate = $overallStats['goals'] ?? 0;
// 评分标准示例
$score = 0;
$score += $overallRate * 0.4;  // 成功率权重
$score += min(($totalShots / 50) * 20, 20);  // 样本量评分
$score += ($goalRate / 20) * 20;  // 进球数评分
$score += min($overallStats['on_target'] / 100 * 20, 20);  // 命中率
// 显示页面
?>
<!DOCTYPE html>
<html>
<head>落叶球射门统计</title>
    <style>
        .stats-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            padding: 20px;
        }
        .stat-card {
            background: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .progress-bar {
            background: #e0e0e0;
            border-radius: 4px;
            height: 20px;
            overflow: hidden;
        }
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #4CAF50, #8BC34A);
            transition: width 0.3s ease;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #4CAF50;
            color: white;
        }
        tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        .score-meter {
            text-align: center;
            font-size: 2em;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="stats-container">
        <!-- 综合评分卡片 -->
        <div class="stat-card">
            <h3>球员综合能力评分</h3>
            <div class="score-meter">
                <?php echo number_format($score, 1); ?> / 100
            </div>
            <div class="progress-bar">
                <div class="progress-fill" style="width: <?php echo min($score, 100); ?>%"></div>
            </div>
            <p>
                <strong>整体成功率:</strong> <?php echo number_format($overallRate, 2); ?>%<br>
                <strong>总射门次数:</strong> <?php echo $totalShots; ?><br>
                <strong>总进球数:</strong> <?php echo $goalRate; ?>
            </p>
        </div>
        <!-- 球员排行榜 -->
        <div class="stat-card">
            <h3>球员落叶球成功率排行榜</h3>
            <table>
                <thead>
                    <tr>
                        <th>球员</th>
                        <th>尝试次数</th>
                        <th>成功率</th>
                        <th>平均速度(km/h)</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($playerStats as $player): ?>
                    <tr>
                        <td><?php echo htmlspecialchars($player['player_id']); ?></td>
                        <td><?php echo $player['total_attempts']; ?></td>
                        <td><?php echo number_format($player['success_rate'], 2); ?>%</td>
                        <td><?php echo $player['avg_speed']; ?></td>
                    </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        <!-- 环境因素分析 -->
        <div class="stat-card">
            <h3>环境因素对成功率的影响</h3>
            <table>
                <thead>
                    <tr>
                        <th>天气</th>
                        <th>场地</th>
                        <th>射门次数</th>
                        <th>成功率</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($environmentFactors as $factor): ?>
                    <tr>
                        <td><?php echo $factor['weather_condition']; ?></td>
                        <td><?php echo $factor['field_condition']; ?></td>
                        <td><?php echo $factor['total_shots']; ?></td>
                        <td><?php echo number_format($factor['success_rate'], 2); ?>%</td>
                    </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        <!-- 趋势图表(简化版) -->
        <div class="stat-card">
            <h3>近期表现趋势</h3>
            <?php
            // 获取示例球员数据(假设球员ID为1)
            $trends = $stats->getPerformanceTrend(1);
            ?>
            <canvas id="trendChart"></canvas>
            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
            <script>
                const ctx = document.getElementById('trendChart');
                const months = <?php echo json_encode(array_column($trends, 'month')); ?>;
                const successRates = <?php echo json_encode(array_column($trends, 'monthly_success_rate')); ?>;
                new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: months,
                        datasets: [{
                            label: '月度成功率 (%)',
                            data: successRates,
                            borderColor: 'rgb(75, 192, 192)',
                            tension: 0.1
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false
                    }
                });
            </script>
        </div>
        <!-- 优化建议 -->
        <div class="stat-card">
            <h3>技术优化建议</h3>
            <?php
            $suggestions = $stats->getOptimizationSuggestions(1);
            ?>
            <h4>最佳射门距离</h4>
            <p><?php echo htmlspecialchars($suggestions['distance_recommendation']); ?></p>
            <h4>脚部偏好</h4>
            <p><?php echo htmlspecialchars($suggestions['foot_recommendation']); ?></p>
            <h4>对手策略分析</h4>
            <pre><?php echo json_encode($suggestions['opponent_strategy'], JSON_PRETTY_PRINT); ?></pre>
        </div>
    </div>
    <script>
        // 添加实时数据刷新功能
        function refreshStats() {
            fetch('../api/get_stats.php')
                .then(response => response.json())
                .then(data => {
                    // 更新页面数据
                    console.log('Stats updated:', data);
                    // 这里可以添加更新DOM的代码
                });
        }
        // 每30秒自动刷新一次
        setInterval(refreshStats, 30000);
    </script>
</body>
</html>

使用说明

数据录入示例

// 记录一次成功的落叶球射门
$shotData = [
    'player_id' => 1,
    'match_id' => 'MATCH-2023-001',
    'shot_time' => '2023-09-15 89:30:00',
    'shot_type' => 'knuckleball',
    'distance_meters' => 25.5,
    'shot_angle' => 30.0,
    'ball_velocity_kmh' => 98,
    'shot_accuracy' => 'goal',
    'is_goal' => 1,
    'weather_condition' => 'sunny',
    'field_condition' => 'dry',
    'opponent_strength' => 'strong',
    'foot_used' => 'right',
    'spin_rate_rpm' => 0,  // 落叶球低旋转
    'trajectory_swing' => 'high_swing',
    'notes' => '完美落叶球,守门员脱手'
];

核心功能特性

  1. 多维度统计:距离、角度、速度、旋转率等
  2. 环境因素:天气、场地、对手强度
  3. 趋势分析:月度/赛季变化趋势
  4. 球员对比:多球员横向比较
  5. 智能建议:基于数据分析的优化建议
  6. 实时监控:通过API实时更新数据

部署建议

  1. 数据库优化:为高频查询字段建立索引
  2. 缓存机制:使用Redis缓存热点数据
  3. 数据可视化:可集成Highcharts或ECharts
  4. 移动端支持:开发移动端API
  5. 权限控制:管理员/教练/球员分级权限

这个系统可以根据实际需求进行调整和扩展,例如添加视频分析集成、实时球探报告等功能。

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