Compare commits

...

4 Commits

Author SHA1 Message Date
spiritlhl
65296157d9 Merge pull request #14 from oneclickvirt/copilot/fix-4e1e0c95-b391-49d3-b126-a1c59ac93663
Fix index.html JSON loading with CDN fallback mechanism
2025-09-20 00:34:26 +08:00
copilot-swe-agent[bot]
61d1607366 Fix index.html JSON loading with CDN fallback and data transformation
Co-authored-by: spiritLHLS <103393591+spiritLHLS@users.noreply.github.com>
2025-09-19 16:30:52 +00:00
copilot-swe-agent[bot]
8533cfd108 Initial plan 2025-09-19 16:23:22 +00:00
CPU Ranking Bot
8512f5e34b 更新CPU性能排行榜数据 - 2025-09-19 16:19:22 2025-09-19 16:19:22 +00:00
4 changed files with 19297 additions and 1611463 deletions

View File

@@ -32,7 +32,7 @@
## 更新时间
最后更新时间: 2025-09-19 01:38:02 UTC
最后更新时间: 2025-09-19 16:19:22 UTC
## 数据来源

File diff suppressed because it is too large Load Diff

18978
cpu_statistics.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -120,6 +120,28 @@
color: white;
border-color: #e91e63;
}
.view-toggle {
display: flex;
background: white;
border: 1px solid #e9e9e7;
border-radius: 8px;
overflow: hidden;
}
.view-toggle button {
padding: 12px 20px;
border: none;
background: transparent;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
}
.view-toggle button.active {
background: #0066cc;
color: white;
}
.view-toggle button:hover:not(.active) {
background: #f7f7f5;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
@@ -198,28 +220,33 @@
padding: 6px 12px;
font-size: 12px;
}
.cpu-list {
.cpu-groups {
display: grid;
gap: 16px;
gap: 24px;
}
.cpu-card {
.cpu-group {
background: white;
border-radius: 12px;
border: 1px solid #e9e9e7;
padding: 24px;
overflow: hidden;
transition: all 0.2s ease;
}
.cpu-card:hover {
.cpu-group:hover {
box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.cpu-header {
.group-header {
padding: 20px 24px;
background: #f7f7f5;
border-bottom: 1px solid #e9e9e7;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.cpu-title-section {
.group-header:hover {
background: #f0f0ef;
}
.group-title-section {
display: flex;
align-items: center;
gap: 16px;
@@ -234,35 +261,65 @@
min-width: 40px;
text-align: center;
}
.cpu-model {
.group-title {
font-size: 18px;
font-weight: 600;
color: #2d2d2d;
}
.cpu-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 16px;
margin-top: 16px;
}
.stat-item {
text-align: center;
}
.stat-item-value {
font-size: 20px;
font-weight: 600;
margin-bottom: 4px;
}
.stat-item-label {
font-size: 12px;
.group-stats {
display: flex;
gap: 24px;
font-size: 14px;
color: #6b6b6b;
}
.expand-icon {
transition: transform 0.2s ease;
font-size: 12px;
}
.cpu-group.expanded .expand-icon {
transform: rotate(180deg);
}
.group-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.cpu-group.expanded .group-content {
max-height: 2000px;
}
.cpu-table {
width: 100%;
border-collapse: collapse;
}
.cpu-table th,
.cpu-table td {
padding: 16px 24px;
text-align: left;
border-bottom: 1px solid #f0f0ef;
}
.cpu-table th {
font-weight: 600;
color: #6b6b6b;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
background: #fafafa;
}
.cpu-table td {
font-size: 14px;
}
.cpu-table tbody tr:hover {
background: #fafafa;
}
.score-cell {
font-weight: 600;
}
.score-single {
color: #0066cc;
}
.score-multi {
color: #e91e63;
}
.score-single { color: #0066cc; }
.score-multi { color: #e91e63; }
.score-avg { color: #4caf50; }
.score-samples { color: #ff9800; }
.loading {
text-align: center;
padding: 60px 20px;
@@ -279,8 +336,12 @@
margin-bottom: 16px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.no-data {
text-align: center;
@@ -360,14 +421,21 @@
.stat-value {
font-size: 20px;
}
.cpu-title-section {
.group-stats {
flex-direction: column;
gap: 8px;
}
.group-title-section {
flex-direction: column;
gap: 8px;
align-items: flex-start;
}
.cpu-stats {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
.cpu-table {
font-size: 12px;
}
.cpu-table th,
.cpu-table td {
padding: 12px 16px;
}
.pagination {
flex-wrap: wrap;
@@ -398,10 +466,22 @@
<button id="clearBtn" class="search-btn clear" data-zh="清除" data-en="Clear">清除</button>
</div>
</div>
<div class="view-toggle">
<button id="compactView" class="active" data-zh="紧凑视图" data-en="Compact View">紧凑视图</button>
<button id="detailView" data-zh="详细视图" data-en="Detail View">详细视图</button>
</div>
</div>
<div class="stats-grid" id="statsGrid">
<div class="stat-card">
<div class="stat-value" id="totalCpus">-</div>
<div class="stat-label" data-zh="CPU型号总数" data-en="Total CPU Models">CPU型号总数</div>
</div>
<div class="stat-card">
<div class="stat-value" id="totalTests">-</div>
<div class="stat-label" data-zh="测试样本数" data-en="Test Samples">测试样本数</div>
</div>
<div class="stat-card">
<div class="stat-value" id="topSingle">-</div>
<div class="stat-label" data-zh="最高单核分数" data-en="Highest Single Score">最高单核分数</div>
</div>
<div class="stat-card">
@@ -424,7 +504,7 @@
</div>
<button id="nextPage" data-zh="下一页" data-en="Next">下一页</button>
</div>
<div id="cpuList" class="cpu-list" style="display: none;"></div>
<div id="cpuGroups" class="cpu-groups" style="display: none;"></div>
<div id="noData" class="no-data" style="display: none;">
<div data-zh="📄 未找到CPU数据文件" data-en="📄 CPU data file not found">📄 未找到CPU数据文件</div>
<p data-zh="请确保 cpu_statistics.json 文件存在于当前目录" data-en="Please ensure cpu_statistics.json file exists in current directory">请确保 cpu_statistics.json 文件存在于当前目录</p>
@@ -448,28 +528,29 @@
<script>
class CPUDashboard {
constructor() {
this.data = {};
this.filteredCpus = [];
this.allCpus = [];
this.data = [];
this.groupedData = {};
this.filteredGroups = {};
this.sortedPrefixes = [];
this.allSortedPrefixes = [];
this.prefixRanks = {};
this.isDetailView = false;
this.searchTerm = '';
this.currentPage = 1;
this.itemsPerPage = 20;
this.itemsPerPage = 10;
this.currentLang = 'zh';
this.initializeEventListeners();
this.loadData();
}
initializeEventListeners() {
const searchInput = document.getElementById('searchInput');
const searchBtn = document.getElementById('searchBtn');
const clearBtn = document.getElementById('clearBtn');
const performSearch = () => {
this.searchTerm = searchInput.value.toLowerCase();
this.currentPage = 1;
this.filterAndRender();
};
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') performSearch();
});
@@ -480,45 +561,44 @@
this.currentPage = 1;
this.filterAndRender();
});
document.getElementById('compactView').addEventListener('click', () => {
this.setViewMode(false);
});
document.getElementById('detailView').addEventListener('click', () => {
this.setViewMode(true);
});
document.getElementById('prevPage').addEventListener('click', () => {
if (this.currentPage > 1) {
this.currentPage--;
this.renderCpus();
this.renderGroups();
}
});
document.getElementById('nextPage').addEventListener('click', () => {
const totalPages = Math.ceil(this.filteredCpus.length / this.itemsPerPage);
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
if (this.currentPage < totalPages) {
this.currentPage++;
this.renderCpus();
this.renderGroups();
}
});
document.getElementById('jumpBtn').addEventListener('click', () => {
const page = parseInt(document.getElementById('pageInput').value);
const totalPages = Math.ceil(this.filteredCpus.length / this.itemsPerPage);
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
if (page >= 1 && page <= totalPages) {
this.currentPage = page;
this.renderCpus();
this.renderGroups();
}
});
document.getElementById('langZh').addEventListener('click', () => {
this.setLanguage('zh');
});
document.getElementById('langEn').addEventListener('click', () => {
this.setLanguage('en');
});
}
setLanguage(lang) {
this.currentLang = lang;
document.getElementById('langZh').classList.toggle('active', lang === 'zh');
document.getElementById('langEn').classList.toggle('active', lang === 'en');
document.querySelectorAll('[data-zh]').forEach(el => {
if (el.tagName === 'INPUT') {
el.placeholder = el.getAttribute(`data-placeholder-${lang}`);
@@ -526,131 +606,221 @@
el.textContent = el.getAttribute(`data-${lang}`);
}
});
this.updatePagination();
this.renderCpus();
this.renderGroups();
}
async loadData() {
try {
const response = await fetch('cpu_statistics.json');
if (!response.ok) throw new Error('数据文件不存在');
this.data = await response.json();
this.allCpus = this.data.cpu_statistics;
this.updateStats();
this.filterAndRender();
document.getElementById('loadingIndicator').style.display = 'none';
document.getElementById('pagination').style.display = 'flex';
document.getElementById('cpuList').style.display = 'block';
} catch (error) {
console.error('加载数据失败:', error);
document.getElementById('loadingIndicator').style.display = 'none';
document.getElementById('noData').style.display = 'block';
const cdnUrls = [
"http://cdn1.spiritlhl.net/",
"http://cdn2.spiritlhl.net/",
"http://cdn3.spiritlhl.net/",
"http://cdn4.spiritlhl.net/"
];
const urls = [
'cpu_statistics.json',
...cdnUrls.map(cdn => `${cdn}https://raw.githubusercontent.com/oneclickvirt/ecs/refs/heads/ranks/cpu_statistics.json`)
];
for (let url of urls) {
try {
console.log(`尝试加载: ${url}`);
const response = await fetch(url);
if (!response.ok) throw new Error('请求失败');
const data = await response.json();
// 转换数据格式以匹配HTML期望的结构
if (data.cpu_statistics) {
// 转换统计数据为单个CPU记录
this.data = data.cpu_statistics.map(stat => ({
cpu_prefix: stat.cpu_prefix,
cpu_model: stat.cpu_model,
cpu_cores: stat.typical_cores,
single_score: stat.max_single_score,
multi_score: stat.max_multi_score,
multi_threads: stat.typical_threads
}));
} else {
// 如果是其他格式,假设是数组
this.data = Array.isArray(data) ? data : [];
}
console.log(`成功加载数据,共 ${this.data.length} 条记录`);
this.processData();
this.updateStats();
this.filterAndRender();
document.getElementById('loadingIndicator').style.display = 'none';
document.getElementById('pagination').style.display = 'flex';
document.getElementById('cpuGroups').style.display = 'block';
return;
} catch (error) {
console.error(`加载失败 ${url}:`, error);
continue;
}
}
// 所有URL都失败了
console.error('所有数据源都无法加载');
document.getElementById('loadingIndicator').style.display = 'none';
document.getElementById('noData').style.display = 'block';
}
processData() {
this.groupedData = {};
this.data.forEach(cpu => {
const prefix = cpu.cpu_prefix;
if (!this.groupedData[prefix]) {
this.groupedData[prefix] = [];
}
this.groupedData[prefix].push(cpu);
});
Object.keys(this.groupedData).forEach(prefix => {
this.groupedData[prefix].sort((a, b) => b.single_score - a.single_score);
});
this.allSortedPrefixes = Object.keys(this.groupedData).sort((a, b) => {
const maxSingleA = Math.max(...this.groupedData[a].map(cpu => cpu.single_score));
const maxSingleB = Math.max(...this.groupedData[b].map(cpu => cpu.single_score));
return maxSingleB - maxSingleA;
});
this.allSortedPrefixes.forEach((prefix, index) => {
this.prefixRanks[prefix] = index + 1;
});
this.sortedPrefixes = [...this.allSortedPrefixes];
}
updateStats() {
document.getElementById('totalCpus').textContent = this.data.total_cpu_models.toLocaleString();
document.getElementById('totalTests').textContent = this.data.total_samples.toLocaleString();
document.getElementById('topSingle').textContent = this.data.global_max_single.toLocaleString();
document.getElementById('topMulti').textContent = this.data.global_max_multi.toLocaleString();
const totalCpus = Object.keys(this.groupedData).length;
const totalTests = this.data.length;
const topSingle = Math.max(...this.data.map(cpu => cpu.single_score));
const topMulti = Math.max(...this.data.map(cpu => cpu.multi_score));
document.getElementById('totalCpus').textContent = totalCpus.toLocaleString();
document.getElementById('totalTests').textContent = totalTests.toLocaleString();
document.getElementById('topSingle').textContent = topSingle.toLocaleString();
document.getElementById('topMulti').textContent = topMulti.toLocaleString();
}
filterAndRender() {
if (this.searchTerm) {
this.filteredCpus = this.allCpus.filter(cpu =>
cpu.cpu_model.toLowerCase().includes(this.searchTerm) ||
cpu.cpu_prefix.toLowerCase().includes(this.searchTerm)
);
this.filteredGroups = {};
const filteredPrefixes = [];
this.allSortedPrefixes.forEach(prefix => {
const filteredCpus = this.groupedData[prefix].filter(cpu =>
cpu.cpu_model.toLowerCase().includes(this.searchTerm) ||
cpu.cpu_prefix.toLowerCase().includes(this.searchTerm)
);
if (filteredCpus.length > 0) {
this.filteredGroups[prefix] = filteredCpus;
filteredPrefixes.push(prefix);
}
});
this.sortedPrefixes = filteredPrefixes;
} else {
this.filteredCpus = [...this.allCpus];
this.filteredGroups = this.groupedData;
this.sortedPrefixes = [...this.allSortedPrefixes];
}
this.renderCpus();
this.renderGroups();
}
renderCpus() {
const container = document.getElementById('cpuList');
renderGroups() {
const container = document.getElementById('cpuGroups');
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
const endIndex = startIndex + this.itemsPerPage;
const currentPageCpus = this.filteredCpus.slice(startIndex, endIndex);
const labels = this.currentLang === 'zh' ? {
samples: '样本数',
maxSingle: '最高单核',
maxMulti: '最高多核',
avgSingle: '平均单核',
avgMulti: '平均多核',
cores: '核心数'
} : {
samples: 'Samples',
maxSingle: 'Max Single',
maxMulti: 'Max Multi',
avgSingle: 'Avg Single',
avgMulti: 'Avg Multi',
cores: 'Cores'
};
container.innerHTML = currentPageCpus.map(cpu => `
<div class="cpu-card">
<div class="cpu-header">
<div class="cpu-title-section">
<div class="rank-badge">#${cpu.rank}</div>
<div class="cpu-model">${cpu.cpu_model}</div>
const currentPagePrefixes = this.sortedPrefixes.slice(startIndex, endIndex);
container.innerHTML = currentPagePrefixes.map(prefix => {
const cpus = this.filteredGroups[prefix];
const topCpu = cpus[0];
const maxSingle = Math.max(...cpus.map(cpu => cpu.single_score));
const maxMulti = Math.max(...cpus.map(cpu => cpu.multi_score));
const rank = this.prefixRanks[prefix];
const sampleText = this.currentLang === 'zh' ? '样本' : 'Samples';
const singleText = this.currentLang === 'zh' ? '单核最高' : 'Max Single';
const multiText = this.currentLang === 'zh' ? '多核最高' : 'Max Multi';
return `
<div class="cpu-group" data-prefix="${prefix}">
<div class="group-header">
<div class="group-title-section">
<div class="rank-badge">#${rank}</div>
<div class="group-title">${topCpu.cpu_model}</div>
</div>
<div class="group-stats">
<span>${sampleText}: ${cpus.length}</span>
<span>${singleText}: ${maxSingle.toLocaleString()}</span>
<span>${multiText}: ${maxMulti.toLocaleString()}</span>
</div>
<div class="expand-icon">▼</div>
</div>
<div class="group-content">
${this.renderTable(cpus)}
</div>
</div>
<div class="cpu-stats">
<div class="stat-item">
<div class="stat-item-value score-samples">${cpu.sample_count}</div>
<div class="stat-item-label">${labels.samples}</div>
</div>
<div class="stat-item">
<div class="stat-item-value score-single">${cpu.max_single_score.toLocaleString()}</div>
<div class="stat-item-label">${labels.maxSingle}</div>
</div>
<div class="stat-item">
<div class="stat-item-value score-multi">${cpu.max_multi_score.toLocaleString()}</div>
<div class="stat-item-label">${labels.maxMulti}</div>
</div>
<div class="stat-item">
<div class="stat-item-value score-avg">${cpu.avg_single_score.toLocaleString()}</div>
<div class="stat-item-label">${labels.avgSingle}</div>
</div>
<div class="stat-item">
<div class="stat-item-value score-avg">${cpu.avg_multi_score.toLocaleString()}</div>
<div class="stat-item-label">${labels.avgMulti}</div>
</div>
<div class="stat-item">
<div class="stat-item-value">${cpu.typical_cores}</div>
<div class="stat-item-label">${labels.cores}</div>
</div>
</div>
</div>
`).join('');
`;
}).join('');
container.querySelectorAll('.group-header').forEach(header => {
header.addEventListener('click', () => {
const group = header.parentElement;
group.classList.toggle('expanded');
});
});
this.updatePagination();
}
updatePagination() {
const totalPages = Math.ceil(this.filteredCpus.length / this.itemsPerPage);
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
const pageInfo = document.getElementById('pageInfo');
const pageText = this.currentLang === 'zh'
? `${this.currentPage} 页,共 ${totalPages}`
: `Page ${this.currentPage} of ${totalPages}`;
pageInfo.textContent = pageText;
const pageInput = document.getElementById('pageInput');
pageInput.max = totalPages;
pageInput.value = this.currentPage;
const prevBtn = document.getElementById('prevPage');
const nextBtn = document.getElementById('nextPage');
prevBtn.disabled = this.currentPage === 1;
nextBtn.disabled = this.currentPage === totalPages;
}
renderTable(cpus) {
const headers = this.isDetailView
? (this.currentLang === 'zh'
? ['CPU型号', '核心数', '单核分数', '多核分数', '多核线程']
: ['CPU Model', 'Cores', 'Single Score', 'Multi Score', 'Multi Threads'])
: (this.currentLang === 'zh'
? ['CPU型号', '核心数', '单核分数', '多核分数']
: ['CPU Model', 'Cores', 'Single Score', 'Multi Score']);
const rows = cpus.slice(0, this.isDetailView ? cpus.length : 10).map(cpu => {
const cells = this.isDetailView
? [cpu.cpu_model, cpu.cpu_cores, cpu.single_score.toLocaleString(),
cpu.multi_score.toLocaleString(), cpu.multi_threads]
: [cpu.cpu_model, cpu.cpu_cores, cpu.single_score.toLocaleString(),
cpu.multi_score.toLocaleString()];
return `
<tr>
${cells.map((cell, index) => {
let className = '';
if (index === 2) className = 'score-cell score-single';
else if (index === 3) className = 'score-cell score-multi';
return `<td class="${className}">${cell}</td>`;
}).join('')}
</tr>
`;
}).join('');
return `
<table class="cpu-table">
<thead>
<tr>
${headers.map(header => `<th>${header}</th>`).join('')}
</tr>
</thead>
<tbody>
${rows}
</tbody>
</table>
`;
}
setViewMode(isDetail) {
this.isDetailView = isDetail;
document.getElementById('compactView').classList.toggle('active', !isDetail);
document.getElementById('detailView').classList.toggle('active', isDetail);
this.renderGroups();
}
}
new CPUDashboard();
</script>
</body>
</html>