本文目录导读:

我来帮你设计一个PHP项目统计界外球进攻威胁次数的方案。
数据库设计
-- 界外球事件表
CREATE TABLE throw_in_events (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT NOT NULL,
team_id INT NOT NULL,
player_id INT,
period INT COMMENT '上半场/下半场',
minute INT COMMENT '发生时间',
field_area VARCHAR(50) COMMENT '球场区域',
threat_level TINYINT COMMENT '威胁等级1-5',
is_threat BOOLEAN DEFAULT FALSE,
threat_type VARCHAR(50) COMMENT '威胁类型',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_match (match_id),
INDEX idx_team (team_id)
);
-- 球队表(示例)
CREATE TABLE teams (
id INT PRIMARY KEY AUTO_INCREMENT,
team_name VARCHAR(100) NOT NULL,
country VARCHAR(50)
);
-- 球员表(示例)
CREATE TABLE players (
id INT PRIMARY KEY AUTO_INCREMENT,
team_id INT,
player_name VARCHAR(100),
position VARCHAR(50)
);
核心PHP类设计
<?php
class ThrowInThreatAnalyzer {
private $db;
public function __construct($pdo) {
$this->db = $pdo;
}
/**
* 记录界外球事件
*/
public function recordThrowIn($matchId, $teamId, $playerId, $data) {
$sql = "INSERT INTO throw_in_events
(match_id, team_id, player_id, period, minute, field_area,
threat_level, is_threat, threat_type)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([
$matchId,
$teamId,
$playerId,
$data['period'],
$data['minute'],
$data['field_area'],
$data['threat_level'],
$data['threat_level'] >= 3, // 3级以上算威胁
$this->determineThreatType($data['field_area'], $data['threat_level'])
]);
}
/**
* 判断威胁类型
*/
private function determineThreatType($fieldArea, $threatLevel) {
$threatAreas = ['禁区左侧', '禁区右侧', '禁区前沿'];
if (in_array($fieldArea, $threatAreas) && $threatLevel >= 4) {
return 'high_danger';
} elseif (in_array($fieldArea, $threatAreas)) {
return 'dangerous';
} elseif ($threatLevel >= 3) {
return 'potential';
}
return 'none';
}
/**
* 统计某场比赛的威胁次数
*/
public function getMatchThreatStats($matchId, $teamId = null) {
$sql = "SELECT
COUNT(*) as total_throws,
SUM(CASE WHEN is_threat = 1 THEN 1 ELSE 0 END) as threat_count,
SUM(CASE WHEN threat_type = 'high_danger' THEN 1 ELSE 0 END) as high_threats,
SUM(CASE WHEN threat_type = 'dangerous' THEN 1 ELSE 0 END) as medium_threats,
AVG(threat_level) as avg_threat_level,
GROUP_CONCAT(threat_type) as threat_types
FROM throw_in_events
WHERE match_id = ?";
$params = [$matchId];
if ($teamId) {
$sql .= " AND team_id = ?";
$params[] = $teamId;
}
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
/**
* 按区域统计威胁分布
*/
public function getThreatByArea($matchId) {
$sql = "SELECT
field_area,
COUNT(*) as total,
SUM(CASE WHEN is_threat = 1 THEN 1 ELSE 0 END) as threats,
SUM(CASE WHEN threat_level >= 4 THEN 1 ELSE 0 END) as critical
FROM throw_in_events
WHERE match_id = ?
GROUP BY field_area
ORDER BY threats DESC";
$stmt = $this->db->prepare($sql);
$stmt->execute([$matchId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 获取给定时间段的威胁趋势
*/
public function getThreatTrend($matchId, $intervalMinutes = 15) {
$sql = "SELECT
CASE
WHEN minute BETWEEN 0 AND ? THEN '0-15'
WHEN minute BETWEEN ? AND ? THEN '15-30'
WHEN minute BETWEEN ? AND ? THEN '30-45'
WHEN minute BETWEEN ? AND ? THEN '45-60'
WHEN minute BETWEEN ? AND ? THEN '60-75'
ELSE '75-90'
END as time_range,
COUNT(*) as throws,
SUM(CASE WHEN is_threat = 1 THEN 1 ELSE 0 END) as threats
FROM throw_in_events
WHERE match_id = ?
GROUP BY time_range
ORDER BY MIN(minute)";
$stmt = $this->db->prepare($sql);
$stmt->execute([15, 15, 30, 30, 45, 45, 60, 60, 75, $matchId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 计算威胁转化率
*/
public function getThreatConversionRate($matchId, $teamId = null) {
$stats = $this->getMatchThreatStats($matchId, $teamId);
if ($stats['total_throws'] == 0) {
return 0;
}
return round(($stats['threat_count'] / $stats['total_throws']) * 100, 2);
}
/**
* 球员威胁贡献度分析
*/
public function getPlayerThreatAnalysis($matchId) {
$sql = "SELECT
p.player_name,
COUNT(t.id) as total_throws,
SUM(CASE WHEN t.is_threat = 1 THEN 1 ELSE 0 END) as threats,
AVG(t.threat_level) as avg_threat,
MAX(t.threat_level) as max_threat
FROM throw_in_events t
JOIN players p ON t.player_id = p.id
WHERE t.match_id = ? AND t.is_threat = 1
GROUP BY t.player_id, p.player_name
ORDER BY threats DESC
LIMIT 10";
$stmt = $this->db->prepare($sql);
$stmt->execute([$matchId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 实时威胁检测(简化版)
*/
public function calculateRealTimeThreat($data) {
$score = 0;
// 距离球门越近,威胁越大
$distanceScores = [
'本方半场' => 1,
'中场' => 2,
'前场' => 3,
'禁区前沿' => 4,
'禁区内' => 5,
'禁区两侧' => 4
];
$score += $distanceScores[$data['field_area']] ?? 2;
// 配合位置加分
if (isset($data['in_attack_phase'])) {
$score += 1;
}
// 人数优势加分
if (isset($data['numbers_advantage']) && $data['numbers_advantage']) {
$score += 1;
}
// 时间因素(比赛末段威胁更大)
if (isset($data['minute']) && $data['minute'] > 80) {
$score += 0.5;
}
return min(5, round($score));
}
}
使用示例
<?php
// 初始化
$pdo = new PDO('mysql:host=localhost;dbname=football', 'user', 'password');
$analyzer = new ThrowInThreatAnalyzer($pdo);
// 1. 记录一次界外球
$analyzer->recordThrowIn(1, 1, 10, [
'period' => 1,
'minute' => 25,
'field_area' => '禁区右侧',
'threat_level' => 4
]);
// 2. 统计全场威胁
$stats = $analyzer->getMatchThreatStats(1);
print_r($stats);
// 3. 查看特定球队
$teamStats = $analyzer->getMatchThreatStats(1, 1);
echo "威胁次数: " . $teamStats['threat_count'];
// 4. 威胁转化率
$rate = $analyzer->getThreatConversionRate(1, 1);
echo "转化率: " . $rate . "%";
// 5. 区域分布
$areas = $analyzer->getThreatByArea(1);
foreach ($areas as $area) {
echo "{$area['field_area']}: {$area['threats']}次威胁\n";
}
// 6. 时间趋势
$trends = $analyzer->getThreatTrend(1);
foreach ($trends as $trend) {
echo "{$trend['time_range']}: {$trend['threats']}次威胁\n";
}
前端展示建议
<!-- 威胁统计卡片 -->
<div class="threat-card">
<h3>界外球威胁统计</h3>
<div class="stats-grid">
<div class="stat">
<span class="label">总界外球</span>
<span class="value"><?php echo $stats['total_throws']; ?></span>
</div>
<div class="stat">
<span class="label">威胁次数</span>
<span class="value"><?php echo $stats['threat_count']; ?></span>
</div>
<div class="stat">
<span class="label">高威胁</span>
<span class="value"><?php echo $stats['high_threats']; ?></span>
</div>
<div class="stat">
<span class="label">平均威胁度</span>
<span class="value"><?php echo number_format($stats['avg_threat_level'], 1); ?></span>
</div>
</div>
</div>
这个系统可以灵活扩展,你可以根据实际需求调整威胁判定逻辑和统计维度,是否需要我补充更具体的功能或样式?