1.0.0 : Web Implemented.
This commit is contained in:
161
web/templates/tactics/compare.html
Normal file
161
web/templates/tactics/compare.html
Normal file
@@ -0,0 +1,161 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="space-y-6">
|
||||
<div class="bg-white dark:bg-slate-800 shadow rounded-lg p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">数据对比中心 (Data Center)</h2>
|
||||
|
||||
<!-- Search & Add -->
|
||||
<div class="mb-6 relative">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">添加对比玩家</label>
|
||||
<input type="text" id="playerSearch" placeholder="输入 ID 或昵称搜索..." class="w-full border border-gray-300 rounded-md py-2 px-4 dark:bg-slate-700 dark:text-white">
|
||||
<div id="searchResults" class="absolute z-10 w-full bg-white dark:bg-slate-700 shadow-lg rounded-b-md hidden"></div>
|
||||
</div>
|
||||
|
||||
<!-- Selected Players Tags -->
|
||||
<div id="selectedPlayers" class="flex flex-wrap gap-2 mb-6">
|
||||
<!-- Tags will be injected here -->
|
||||
</div>
|
||||
|
||||
<!-- Chart -->
|
||||
<div class="relative h-96">
|
||||
<canvas id="compareChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchInput = document.getElementById('playerSearch');
|
||||
const resultsDiv = document.getElementById('searchResults');
|
||||
const selectedDiv = document.getElementById('selectedPlayers');
|
||||
|
||||
let selectedIds = [];
|
||||
let chartInstance = null;
|
||||
|
||||
// Init Chart
|
||||
const ctx = document.getElementById('compareChart').getContext('2d');
|
||||
chartInstance = new Chart(ctx, {
|
||||
type: 'radar',
|
||||
data: {
|
||||
labels: ['STA', 'BAT', 'HPS', 'PTL', 'SIDE', 'UTIL'],
|
||||
datasets: []
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
r: {
|
||||
beginAtZero: true,
|
||||
suggestedMax: 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Search
|
||||
let debounceTimer;
|
||||
searchInput.addEventListener('input', function() {
|
||||
clearTimeout(debounceTimer);
|
||||
const query = this.value;
|
||||
if (query.length < 2) {
|
||||
resultsDiv.classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
fetch(`/players/api/search?q=${query}`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
resultsDiv.innerHTML = '';
|
||||
if (data.length > 0) {
|
||||
resultsDiv.classList.remove('hidden');
|
||||
data.forEach(p => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'p-2 hover:bg-gray-100 dark:hover:bg-slate-600 cursor-pointer text-gray-900 dark:text-white';
|
||||
div.innerText = `${p.username} (${p.steam_id})`;
|
||||
div.onclick = () => addPlayer(p);
|
||||
resultsDiv.appendChild(div);
|
||||
});
|
||||
} else {
|
||||
resultsDiv.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
// Hide results on click outside
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!searchInput.contains(e.target) && !resultsDiv.contains(e.target)) {
|
||||
resultsDiv.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
function addPlayer(player) {
|
||||
if (selectedIds.includes(player.steam_id)) return;
|
||||
selectedIds.push(player.steam_id);
|
||||
|
||||
// Add Tag
|
||||
const tag = document.createElement('span');
|
||||
tag.className = 'inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-yrtv-100 text-yrtv-800';
|
||||
tag.innerHTML = `
|
||||
${player.username}
|
||||
<button type="button" class="flex-shrink-0 ml-1.5 h-4 w-4 rounded-full inline-flex items-center justify-center text-yrtv-400 hover:bg-yrtv-200 hover:text-yrtv-500 focus:outline-none" onclick="removePlayer('${player.steam_id}', this)">
|
||||
<span class="sr-only">Remove</span>
|
||||
×
|
||||
</button>
|
||||
`;
|
||||
selectedDiv.appendChild(tag);
|
||||
|
||||
// Fetch Stats and Update Chart
|
||||
updateChart();
|
||||
|
||||
searchInput.value = '';
|
||||
resultsDiv.classList.add('hidden');
|
||||
}
|
||||
|
||||
window.removePlayer = function(id, btn) {
|
||||
selectedIds = selectedIds.filter(sid => sid !== id);
|
||||
btn.parentElement.remove();
|
||||
updateChart();
|
||||
}
|
||||
|
||||
function updateChart() {
|
||||
if (selectedIds.length === 0) {
|
||||
chartInstance.data.datasets = [];
|
||||
chartInstance.update();
|
||||
return;
|
||||
}
|
||||
|
||||
const ids = selectedIds.join(',');
|
||||
fetch(`/players/api/batch_stats?ids=${ids}`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
const datasets = data.map((p, index) => {
|
||||
const colors = [
|
||||
'rgba(124, 58, 237, 1)', 'rgba(16, 185, 129, 1)', 'rgba(239, 68, 68, 1)',
|
||||
'rgba(59, 130, 246, 1)', 'rgba(245, 158, 11, 1)'
|
||||
];
|
||||
const color = colors[index % colors.length];
|
||||
|
||||
return {
|
||||
label: p.username,
|
||||
data: [
|
||||
p.radar.STA, p.radar.BAT, p.radar.HPS,
|
||||
p.radar.PTL, p.radar.SIDE, p.radar.UTIL
|
||||
],
|
||||
backgroundColor: color.replace('1)', '0.2)'),
|
||||
borderColor: color,
|
||||
pointBackgroundColor: color
|
||||
};
|
||||
});
|
||||
|
||||
chartInstance.data.datasets = datasets;
|
||||
chartInstance.update();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user