本文目录导读:

我来帮你设计一个PHP项目统计斜长传精准度的方案,这里提供完整的数据结构和实现代码:
数据库表设计
-- 球员表
CREATE TABLE players (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
team_id INT,
position VARCHAR(20)
);
-- 传球记录表
CREATE TABLE passes (
id INT PRIMARY KEY AUTO_INCREMENT,
player_id INT NOT NULL,
match_id INT NOT NULL,
pass_type ENUM('long_ball', 'through_ball', 'cross') DEFAULT 'long_ball',
start_x DECIMAL(5,2), -- 传球起始X坐标
start_y DECIMAL(5,2), -- 传球起始Y坐标
end_x DECIMAL(5,2), -- 传球落点X坐标
end_y DECIMAL(5,2), -- 传球落点Y坐标
target_x DECIMAL(5,2), -- 预期目标X坐标
target_y DECIMAL(5,2), -- 预期目标Y坐标
is_success TINYINT(1) DEFAULT 0, -- 是否成功
pass_distance DECIMAL(5,2), -- 传球距离
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_player_date (player_id, created_at)
);
-- 比赛信息表
CREATE TABLE matches (
id INT PRIMARY KEY AUTO_INCREMENT,
home_team VARCHAR(50),
away_team VARCHAR(50),
match_date DATE,
competition VARCHAR(50)
);
核心统计类
<?php
class LongPassAnalyzer {
private $pdo;
private $playerId;
public function __construct(PDO $pdo, $playerId) {
$this->pdo = $pdo;
$this->playerId = $playerId;
}
/**
* 计算单次传球精准度
*/
public function calculatePassAccuracy($pass) {
// 目标位置与实际落点距离
$targetDistance = $this->calculateDistance(
$pass['target_x'],
$pass['target_y'],
$pass['end_x'],
$pass['end_y']
);
// 根据距离计算精准度 (0-100)
$accuracy = max(0, 100 - $targetDistance * 2);
return $accuracy;
}
/**
* 获取球员所有传球统计
*/
public function getPlayerStatistics($dateFrom = null, $dateTo = null) {
$sql = "SELECT
p.id,
p.pass_type,
p.is_success,
p.pass_distance,
p.start_x, p.start_y,
p.end_x, p.end_y,
p.target_x, p.target_y,
m.match_date,
m.competition
FROM passes p
INNER JOIN matches m ON p.match_id = m.id
WHERE p.player_id = :playerId";
if ($dateFrom && $dateTo) {
$sql .= " AND m.match_date BETWEEN :dateFrom AND :dateTo";
$params = [
':playerId' => $this->playerId,
':dateFrom' => $dateFrom,
':dateTo' => $dateTo
];
} else {
$params = [':playerId' => $this->playerId];
}
$sql .= " ORDER BY m.match_date DESC";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$passes = $stmt->fetchAll(PDO::FETCH_ASSOC);
$statistics = [
'total_passes' => count($passes),
'success_passes' => 0,
'avg_accuracy' => 0,
'distance_breakdown' => [],
'type_breakdown' => [],
'recent_trend' => []
];
foreach ($passes as $pass) {
// 统计成功率
if ($pass['is_success']) {
$statistics['success_passes']++;
}
// 计算精准度
$accuracy = $this->calculatePassAccuracy($pass);
$statistics['avg_accuracy'] += $accuracy;
// 按距离分组统计
$distanceCategory = $this->categorizeDistance($pass['pass_distance']);
if (!isset($statistics['distance_breakdown'][$distanceCategory])) {
$statistics['distance_breakdown'][$distanceCategory] = [
'count' => 0,
'accuracy_sum' => 0
];
}
$statistics['distance_breakdown'][$distanceCategory]['count']++;
$statistics['distance_breakdown'][$distanceCategory]['accuracy_sum'] += $accuracy;
// 按传球类型统计
// ... 类似距离统计
}
// 计算平均精准度
if ($statistics['total_passes'] > 0) {
$statistics['avg_accuracy'] = round(
$statistics['avg_accuracy'] / $statistics['total_passes'], 2
);
}
// 计算成功率
$statistics['success_rate'] = $statistics['total_passes'] > 0
? round(($statistics['success_passes'] / $statistics['total_passes']) * 100, 1)
: 0;
// 近10场比赛趋势
$statistics['recent_trend'] = $this->getRecentTrend($passes);
return $statistics;
}
/**
* 计算两点距离
*/
private function calculateDistance($x1, $y1, $x2, $y2) {
return sqrt(pow($x2 - $x1, 2) + pow($y2 - $y1, 2));
}
/**
* 距离分类
*/
private function categorizeDistance($distance) {
if ($distance < 30) return 'short';
if ($distance < 45) return 'medium';
if ($distance < 60) return 'long';
return 'very_long';
}
/**
* 获取近期趋势
*/
private function getRecentTrend($passes) {
$trend = [];
$summary = array_slice($passes, 0, 10); // 最近10场
foreach ($summary as $pass) {
$date = $pass['match_date'];
if (!isset($trend[$date])) {
$trend[$date] = [
'total' => 0,
'accuracy' => 0
];
}
$trend[$date]['total']++;
$trend[$date]['accuracy'] += $this->calculatePassAccuracy($pass);
}
// 计算每日平均
foreach ($trend as &$day) {
$day['avg_accuracy'] = $day['total'] > 0
? round($day['accuracy'] / $day['total'], 1)
: 0;
unset($day['accuracy']);
}
return $trend;
}
/**
* 多维度分析报告
*/
public function generateReport() {
$statistics = $this->getPlayerStatistics();
return [
'summary' => [
'total_pass_attempts' => $statistics['total_passes'],
'success_rate' => $statistics['success_rate'],
'avg_accuracy' => $statistics['avg_accuracy']
],
'performance_by_distance' => $this->formatDistanceBreakdown($statistics['distance_breakdown']),
'strengths' => $this->identifyStrengths($statistics),
'areas_for_improvement' => $this->identifyWeaknesses($statistics),
'recommendations' => $this->generateRecommendations($statistics)
];
}
/**
* 格式化距离统计
*/
private function formatDistanceBreakdown($distanceStats) {
$formatted = [];
foreach ($distanceStats as $category => $data) {
$formatted[$category] = [
'attempts' => $data['count'],
'avg_accuracy' => $data['count'] > 0
? round($data['accuracy_sum'] / $data['count'], 1)
: 0
];
}
return $formatted;
}
/**
* 球员对标分析(与队内平均比较)
*/
public function compareToTeamAverage($teamId, $dateFrom = null, $dateTo = null) {
$playerStats = $this->getPlayerStatistics($dateFrom, $dateTo);
// 获取队伍平均数据
$sql = "SELECT AVG(is_success) * 100 as success_rate
FROM passes p
INNER JOIN players pl ON p.player_id = pl.id
WHERE pl.team_id = :teamId";
if ($dateFrom && $dateTo) {
$sql .= " AND p.created_at BETWEEN :dateFrom AND :dateTo";
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute(['teamId' => $teamId]);
$teamSuccessRate = $stmt->fetchColumn();
return [
'player' => $playerStats,
'team_avg' => [
'success_rate' => round($teamSuccessRate, 1)
],
'comparison' => [
'success_rate_diff' => round($playerStats['success_rate'] - $teamSuccessRate, 1)
]
];
}
}
使用示例
<?php
// 初始化
$pdo = new PDO('mysql:host=localhost;dbname=football', 'user', 'pass');
$analyzer = new LongPassAnalyzer($pdo, 12345);
// 获取球员统计
$stats = $analyzer->getPlayerStatistics('2024-01-01', '2024-06-30');
// 生成完整报告
$report = $analyzer->generateReport();
// 与队伍对比
$teamComparison = $analyzer->compareToTeamAverage(678);
// 输出结果
echo json_encode($stats, JSON_PRETTY_PRINT);
前端展示(可选)
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div class="pass-accuracy-chart">
<canvas id="accuracyChart"></canvas>
</div>
<script>
const ctx = document.getElementById('accuracyChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: Object.keys(trendData),
datasets: [{
label: '精准度趋势',
data: Object.values(trendData).map(d => d.avg_accuracy),
borderColor: 'rgba(75, 192, 192, 1)',
fill: false
}]
}
});
</script>
核心功能亮点:
- 多维度统计:按距离、类型、比赛日期分类
- 精准度算法:基于传球落点与目标位置的偏差计算
- 趋势分析:展示近10场表现变化
- 对比分析:与队内平均比较
- 个性化报告:自动识别优势和待改进方面
建议根据实际需求调整传球精准度计算的权重和阈值参数。