mirror of
https://github.com/oneclickvirt/ecs.git
synced 2025-10-17 12:50:46 +08:00
827 lines
32 KiB
HTML
Executable File
827 lines
32 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="google-site-verification" content="wdrGBim_2XmtMrqxivze70saMiPQAiOhpmN3KAWb0Sw" />
|
|
<title>CPU Performance Ladder For Sysbench</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: #fafafa;
|
|
color: #37352f;
|
|
line-height: 1.5;
|
|
}
|
|
.container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 40px 20px;
|
|
}
|
|
.header {
|
|
text-align: center;
|
|
margin-bottom: 48px;
|
|
padding-bottom: 24px;
|
|
border-bottom: 1px solid #e9e9e7;
|
|
position: relative;
|
|
}
|
|
.header h1 {
|
|
font-size: 32px;
|
|
font-weight: 700;
|
|
color: #2d2d2d;
|
|
margin-bottom: 8px;
|
|
}
|
|
.header p {
|
|
font-size: 16px;
|
|
color: #6b6b6b;
|
|
}
|
|
.language-toggle {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
background: white;
|
|
border: 1px solid #e9e9e7;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
}
|
|
.language-toggle button {
|
|
padding: 8px 16px;
|
|
border: none;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
transition: all 0.2s ease;
|
|
color: #6b6b6b;
|
|
}
|
|
.language-toggle button.active {
|
|
background: #0066cc;
|
|
color: white;
|
|
}
|
|
.language-toggle button:hover:not(.active) {
|
|
background: #f7f7f5;
|
|
}
|
|
.controls {
|
|
display: flex;
|
|
gap: 16px;
|
|
margin-bottom: 32px;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
}
|
|
.search-box {
|
|
flex: 1;
|
|
min-width: 200px;
|
|
position: relative;
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
.search-box input {
|
|
flex: 1;
|
|
padding: 12px 16px;
|
|
border: 1px solid #e9e9e7;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
background: white;
|
|
transition: all 0.2s ease;
|
|
}
|
|
.search-box input:focus {
|
|
outline: none;
|
|
border-color: #0066cc;
|
|
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
|
|
}
|
|
.search-buttons {
|
|
display: flex;
|
|
gap: 4px;
|
|
}
|
|
.search-btn {
|
|
padding: 12px 16px;
|
|
border: 1px solid #e9e9e7;
|
|
background: white;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
transition: all 0.2s ease;
|
|
color: #6b6b6b;
|
|
}
|
|
.search-btn:hover {
|
|
background: #f7f7f5;
|
|
}
|
|
.search-btn.search {
|
|
background: #0066cc;
|
|
color: white;
|
|
border-color: #0066cc;
|
|
}
|
|
.search-btn.clear {
|
|
background: #e91e63;
|
|
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));
|
|
gap: 20px;
|
|
margin-bottom: 32px;
|
|
}
|
|
.stat-card {
|
|
background: white;
|
|
padding: 24px;
|
|
border-radius: 12px;
|
|
border: 1px solid #e9e9e7;
|
|
text-align: center;
|
|
transition: transform 0.2s ease;
|
|
}
|
|
.stat-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px -8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
.stat-value {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
color: #0066cc;
|
|
margin-bottom: 4px;
|
|
}
|
|
.stat-label {
|
|
font-size: 14px;
|
|
color: #6b6b6b;
|
|
}
|
|
.pagination {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 16px;
|
|
margin-bottom: 32px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.pagination button {
|
|
padding: 8px 16px;
|
|
border: 1px solid #e9e9e7;
|
|
background: white;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
transition: all 0.2s ease;
|
|
}
|
|
.pagination button:hover:not(:disabled) {
|
|
background: #f7f7f5;
|
|
}
|
|
.pagination button:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
.pagination button.active {
|
|
background: #0066cc;
|
|
color: white;
|
|
border-color: #0066cc;
|
|
}
|
|
.pagination-info {
|
|
font-size: 14px;
|
|
color: #6b6b6b;
|
|
}
|
|
.page-jump {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
.page-jump input {
|
|
width: 60px;
|
|
padding: 6px 8px;
|
|
border: 1px solid #e9e9e7;
|
|
border-radius: 4px;
|
|
text-align: center;
|
|
font-size: 14px;
|
|
}
|
|
.page-jump button {
|
|
padding: 6px 12px;
|
|
font-size: 12px;
|
|
}
|
|
.cpu-groups {
|
|
display: grid;
|
|
gap: 24px;
|
|
}
|
|
.cpu-group {
|
|
background: white;
|
|
border-radius: 12px;
|
|
border: 1px solid #e9e9e7;
|
|
overflow: hidden;
|
|
transition: all 0.2s ease;
|
|
}
|
|
.cpu-group:hover {
|
|
box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.1);
|
|
}
|
|
.group-header {
|
|
padding: 20px 24px;
|
|
background: #f7f7f5;
|
|
border-bottom: 1px solid #e9e9e7;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.group-header:hover {
|
|
background: #f0f0ef;
|
|
}
|
|
.group-title-section {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
}
|
|
.rank-badge {
|
|
background: #0066cc;
|
|
color: white;
|
|
padding: 4px 12px;
|
|
border-radius: 20px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
min-width: 40px;
|
|
text-align: center;
|
|
}
|
|
.group-title {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: #2d2d2d;
|
|
}
|
|
.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;
|
|
}
|
|
.loading {
|
|
text-align: center;
|
|
padding: 60px 20px;
|
|
color: #6b6b6b;
|
|
}
|
|
.spinner {
|
|
display: inline-block;
|
|
width: 32px;
|
|
height: 32px;
|
|
border: 3px solid #f0f0ef;
|
|
border-top: 3px solid #0066cc;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin-bottom: 16px;
|
|
}
|
|
@keyframes spin {
|
|
0% {
|
|
transform: rotate(0deg);
|
|
}
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
.no-data {
|
|
text-align: center;
|
|
padding: 60px 20px;
|
|
color: #6b6b6b;
|
|
}
|
|
.footer {
|
|
margin-top: 60px;
|
|
padding: 32px 0;
|
|
border-top: 1px solid #e9e9e7;
|
|
text-align: center;
|
|
background: white;
|
|
border-radius: 12px;
|
|
}
|
|
.footer-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
align-items: center;
|
|
}
|
|
.footer-links {
|
|
display: flex;
|
|
gap: 32px;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
}
|
|
.footer-link {
|
|
color: #0066cc;
|
|
text-decoration: none;
|
|
font-size: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
transition: color 0.2s ease;
|
|
}
|
|
.footer-link:hover {
|
|
color: #004499;
|
|
}
|
|
.footer-text {
|
|
font-size: 13px;
|
|
color: #6b6b6b;
|
|
}
|
|
@media (max-width: 768px) {
|
|
.container {
|
|
padding: 20px 16px;
|
|
}
|
|
.header {
|
|
position: static;
|
|
}
|
|
.language-toggle {
|
|
position: static;
|
|
margin-bottom: 16px;
|
|
align-self: center;
|
|
}
|
|
.header h1 {
|
|
font-size: 24px;
|
|
}
|
|
.controls {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
.search-box {
|
|
min-width: auto;
|
|
flex-direction: column;
|
|
}
|
|
.search-buttons {
|
|
justify-content: center;
|
|
}
|
|
.stats-grid {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 16px;
|
|
}
|
|
.stat-card {
|
|
padding: 16px;
|
|
}
|
|
.stat-value {
|
|
font-size: 20px;
|
|
}
|
|
.group-stats {
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
.group-title-section {
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
align-items: flex-start;
|
|
}
|
|
.cpu-table {
|
|
font-size: 12px;
|
|
}
|
|
.cpu-table th,
|
|
.cpu-table td {
|
|
padding: 12px 16px;
|
|
}
|
|
.pagination {
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
.footer-links {
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<div class="language-toggle">
|
|
<button id="langZh" class="active">中文</button>
|
|
<button id="langEn">English</button>
|
|
</div>
|
|
<h1 data-zh="CPU Performance Ladder For Sysbench" data-en="CPU Performance Ladder For Sysbench">CPU Performance Ladder For Sysbench</h1>
|
|
<p data-zh="Sysbench天梯图" data-en="Sysbench CPU Benchmark Rankings">Sysbench天梯图</p>
|
|
</div>
|
|
<div class="controls">
|
|
<div class="search-box">
|
|
<input type="text" id="searchInput" placeholder="搜索CPU型号或关键词..." data-placeholder-zh="搜索CPU型号或关键词..." data-placeholder-en="Search CPU model or keywords...">
|
|
<div class="search-buttons">
|
|
<button id="searchBtn" class="search-btn search" data-zh="搜索" data-en="Search">搜索</button>
|
|
<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">
|
|
<div class="stat-value" id="topMulti">-</div>
|
|
<div class="stat-label" data-zh="最高多核分数" data-en="Highest Multi Score">最高多核分数</div>
|
|
</div>
|
|
</div>
|
|
<div id="loadingIndicator" class="loading">
|
|
<div class="spinner"></div>
|
|
<div data-zh="正在加载CPU数据..." data-en="Loading CPU data...">正在加载CPU数据...</div>
|
|
</div>
|
|
<div class="pagination" id="pagination" style="display: none;">
|
|
<button id="prevPage" data-zh="上一页" data-en="Previous">上一页</button>
|
|
<div class="pagination-info" id="pageInfo">-</div>
|
|
<div class="page-jump">
|
|
<span data-zh="跳转到" data-en="Go to">跳转到</span>
|
|
<input type="number" id="pageInput" min="1">
|
|
<span data-zh="页" data-en="page">页</span>
|
|
<button id="jumpBtn" data-zh="跳转" data-en="Go">跳转</button>
|
|
</div>
|
|
<button id="nextPage" data-zh="下一页" data-en="Next">下一页</button>
|
|
</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>
|
|
</div>
|
|
<div class="footer">
|
|
<div class="footer-content">
|
|
<div class="footer-links">
|
|
<a href="https://github.com/oneclickvirt/ecs" class="footer-link" target="_blank" rel="noopener">
|
|
<span>🚀</span>
|
|
<span data-zh="测试脚本" data-en="Test Script">测试脚本</span>
|
|
</a>
|
|
<a href="https://www.spiritlhl.net/" class="footer-link" target="_blank" rel="noopener">
|
|
<span>🌐</span>
|
|
<span data-zh="spiritlhl 官网" data-en="spiritlhl Official">spiritlhl 官网</span>
|
|
</a>
|
|
</div>
|
|
<div class="footer-text" data-zh="本项目隶属于 spiritlhl 旗下" data-en="This project is under spiritlhl">本项目隶属于 spiritlhl 旗下</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
class CPUDashboard {
|
|
constructor() {
|
|
this.data = [];
|
|
this.groupedData = {};
|
|
this.filteredGroups = {};
|
|
this.sortedPrefixes = [];
|
|
this.allSortedPrefixes = [];
|
|
this.prefixRanks = {};
|
|
this.isDetailView = false;
|
|
this.searchTerm = '';
|
|
this.currentPage = 1;
|
|
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();
|
|
});
|
|
searchBtn.addEventListener('click', performSearch);
|
|
clearBtn.addEventListener('click', () => {
|
|
searchInput.value = '';
|
|
this.searchTerm = '';
|
|
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.renderGroups();
|
|
}
|
|
});
|
|
document.getElementById('nextPage').addEventListener('click', () => {
|
|
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
|
|
if (this.currentPage < totalPages) {
|
|
this.currentPage++;
|
|
this.renderGroups();
|
|
}
|
|
});
|
|
document.getElementById('jumpBtn').addEventListener('click', () => {
|
|
const page = parseInt(document.getElementById('pageInput').value);
|
|
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
|
|
if (page >= 1 && page <= totalPages) {
|
|
this.currentPage = page;
|
|
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}`);
|
|
} else {
|
|
el.textContent = el.getAttribute(`data-${lang}`);
|
|
}
|
|
});
|
|
this.updatePagination();
|
|
this.renderGroups();
|
|
}
|
|
async loadData() {
|
|
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() {
|
|
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.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.filteredGroups = this.groupedData;
|
|
this.sortedPrefixes = [...this.allSortedPrefixes];
|
|
}
|
|
this.renderGroups();
|
|
}
|
|
renderGroups() {
|
|
const container = document.getElementById('cpuGroups');
|
|
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
|
|
const endIndex = startIndex + this.itemsPerPage;
|
|
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>
|
|
`;
|
|
}).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.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>
|