feat: 添加后台管理功能
功能: - 概览统计 - 模型/GPU/CPU管理(增删改查) - 侧边栏导航 - 表单验证
This commit is contained in:
657
templates/admin.html
Normal file
657
templates/admin.html
Normal file
@@ -0,0 +1,657 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>后台管理 - ParamHub</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-gray-100 min-h-screen">
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="fixed left-0 top-0 w-64 h-full bg-gray-800 text-white">
|
||||
<div class="p-4 border-b border-gray-700">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="ri-dashboard-3-line text-2xl"></i>
|
||||
<span class="text-xl font-bold">ParamHub</span>
|
||||
</div>
|
||||
<div class="text-sm text-gray-400 mt-1">后台管理</div>
|
||||
</div>
|
||||
<nav class="p-4">
|
||||
<div class="space-y-2">
|
||||
<a href="#overview" onclick="showSection('overview')" class="flex items-center gap-2 px-3 py-2 rounded-lg bg-indigo-600 text-white">
|
||||
<i class="ri-home-4-line"></i>
|
||||
<span>概览</span>
|
||||
</a>
|
||||
<a href="#models" onclick="showSection('models')" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-700 text-gray-300">
|
||||
<i class="ri-robot-line"></i>
|
||||
<span>模型管理</span>
|
||||
</a>
|
||||
<a href="#gpus" onclick="showSection('gpus')" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-700 text-gray-300">
|
||||
<i class="ri-cpu-line"></i>
|
||||
<span>GPU管理</span>
|
||||
</a>
|
||||
<a href="#cpus" onclick="showSection('cpus')" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-700 text-gray-300">
|
||||
<i class="ri-memory-line"></i>
|
||||
<span>CPU管理</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-8 pt-4 border-t border-gray-700">
|
||||
<a href="/" target="_blank" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-700 text-gray-400">
|
||||
<i class="ri-external-link-line"></i>
|
||||
<span>访问前台</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="ml-64 p-8">
|
||||
<!-- 概览 -->
|
||||
<section id="section-overview">
|
||||
<h1 class="text-2xl font-bold text-gray-800 mb-6">管理概览</h1>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<div class="grid grid-cols-4 gap-6 mb-8">
|
||||
<div class="bg-white rounded-xl p-6 shadow-sm">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-lg bg-blue-100 flex items-center justify-center">
|
||||
<i class="ri-robot-line text-2xl text-blue-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-2xl font-bold text-gray-800" id="stat-models">-</div>
|
||||
<div class="text-sm text-gray-500">模型数量</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl p-6 shadow-sm">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-lg bg-green-100 flex items-center justify-center">
|
||||
<i class="ri-cpu-line text-2xl text-green-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-2xl font-bold text-gray-800" id="stat-gpus">-</div>
|
||||
<div class="text-sm text-gray-500">GPU数量</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl p-6 shadow-sm">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-lg bg-purple-100 flex items-center justify-center">
|
||||
<i class="ri-memory-line text-2xl text-purple-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-2xl font-bold text-gray-800" id="stat-cpus">-</div>
|
||||
<div class="text-sm text-gray-500">CPU数量</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl p-6 shadow-sm">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-lg bg-orange-100 flex items-center justify-center">
|
||||
<i class="ri-time-line text-2xl text-orange-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-lg font-bold text-gray-800" id="stat-time">-</div>
|
||||
<div class="text-sm text-gray-500">更新时间</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 快捷操作 -->
|
||||
<div class="bg-white rounded-xl p-6 shadow-sm mb-8">
|
||||
<h2 class="text-lg font-semibold text-gray-800 mb-4">快捷操作</h2>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<button onclick="showSection('models'); openAddModal('model')" class="px-4 py-3 bg-blue-50 text-blue-600 rounded-lg hover:bg-blue-100 transition">
|
||||
<i class="ri-add-line mr-2"></i>添加模型
|
||||
</button>
|
||||
<button onclick="showSection('gpus'); openAddModal('gpu')" class="px-4 py-3 bg-green-50 text-green-600 rounded-lg hover:bg-green-100 transition">
|
||||
<i class="ri-add-line mr-2"></i>添加GPU
|
||||
</button>
|
||||
<button onclick="showSection('cpus'); openAddModal('cpu')" class="px-4 py-3 bg-purple-50 text-purple-600 rounded-lg hover:bg-purple-100 transition">
|
||||
<i class="ri-add-line mr-2"></i>添加CPU
|
||||
</button>
|
||||
<a href="/" target="_blank" class="px-4 py-3 bg-gray-50 text-gray-600 rounded-lg hover:bg-gray-100 transition text-center">
|
||||
<i class="ri-external-link-line mr-2"></i>查看前台
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最近添加 -->
|
||||
<div class="bg-white rounded-xl p-6 shadow-sm">
|
||||
<h2 class="text-lg font-semibold text-gray-800 mb-4">最近添加的模型</h2>
|
||||
<div id="recent-models" class="space-y-2">加载中...</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 模型管理 -->
|
||||
<section id="section-models" class="hidden">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-800">模型管理</h1>
|
||||
<button onclick="openAddModal('model')" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition">
|
||||
<i class="ri-add-line mr-2"></i>添加模型
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<table class="w-full">
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">厂商</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">参数量</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">上下文</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">类型</th>
|
||||
<th class="px-4 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-models-table">
|
||||
<tr><td colspan="6" class="text-center text-gray-400 py-8">加载中...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- GPU管理 -->
|
||||
<section id="section-gpus" class="hidden">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-800">GPU管理</h1>
|
||||
<button onclick="openAddModal('gpu')" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition">
|
||||
<i class="ri-add-line mr-2"></i>添加GPU
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<table class="w-full">
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">厂商</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">显存</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">架构</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">价格</th>
|
||||
<th class="px-4 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-gpus-table">
|
||||
<tr><td colspan="6" class="text-center text-gray-400 py-8">加载中...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CPU管理 -->
|
||||
<section id="section-cpus" class="hidden">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-800">CPU管理</h1>
|
||||
<button onclick="openAddModal('cpu')" class="px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition">
|
||||
<i class="ri-add-line mr-2"></i>添加CPU
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<table class="w-full">
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">厂商</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">核心/线程</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">主频</th>
|
||||
<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">价格</th>
|
||||
<th class="px-4 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-cpus-table">
|
||||
<tr><td colspan="6" class="text-center text-gray-400 py-8">加载中...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<div id="editModal" class="fixed inset-0 bg-black/50 z-50 hidden flex items-center justify-center">
|
||||
<div class="bg-white rounded-xl max-w-2xl w-full mx-4 max-h-[90vh] overflow-auto">
|
||||
<div class="p-6 border-b flex justify-between items-center sticky top-0 bg-white">
|
||||
<h2 class="text-xl font-bold text-gray-800" id="modalTitle">添加/编辑</h2>
|
||||
<button onclick="closeModal()" class="text-gray-400 hover:text-gray-600">
|
||||
<i class="ri-close-line text-2xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="modalContent" class="p-6"></div>
|
||||
<div class="p-6 border-t flex justify-end gap-4 sticky bottom-0 bg-white">
|
||||
<button onclick="closeModal()" class="px-4 py-2 bg-gray-200 text-gray-600 rounded-lg hover:bg-gray-300">取消</button>
|
||||
<button onclick="saveItem()" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentType = '';
|
||||
let currentId = '';
|
||||
let currentData = {};
|
||||
|
||||
// 切换显示区域
|
||||
function showSection(section) {
|
||||
document.querySelectorAll('section').forEach(s => s.classList.add('hidden'));
|
||||
document.getElementById('section-' + section).classList.remove('hidden');
|
||||
|
||||
// 更新导航样式
|
||||
document.querySelectorAll('nav a').forEach(a => {
|
||||
a.className = a.getAttribute('onclick')?.includes(section)
|
||||
? 'flex items-center gap-2 px-3 py-2 rounded-lg bg-indigo-600 text-white'
|
||||
: 'flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-700 text-gray-300';
|
||||
});
|
||||
|
||||
// 加载对应数据
|
||||
if (section === 'models') loadAdminModels();
|
||||
if (section === 'gpus') loadAdminGpus();
|
||||
if (section === 'cpus') loadAdminCpus();
|
||||
}
|
||||
|
||||
// 加载概览统计
|
||||
async function loadOverview() {
|
||||
const res = await fetch('/api/stats');
|
||||
const data = await res.json();
|
||||
|
||||
document.getElementById('stat-models').textContent = data.models_count;
|
||||
document.getElementById('stat-gpus').textContent = data.gpus_count;
|
||||
document.getElementById('stat-cpus').textContent = data.cpus_count;
|
||||
document.getElementById('stat-time').textContent = new Date().toLocaleString('zh-CN');
|
||||
|
||||
// 最近添加的模型
|
||||
const models = data.latest_models || [];
|
||||
document.getElementById('recent-models').innerHTML = models.length > 0
|
||||
? models.map(m => `
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<span class="font-medium text-gray-800">${m.name}</span>
|
||||
<span class="text-sm text-gray-500 ml-2">${m.organization}</span>
|
||||
</div>
|
||||
<div class="text-sm text-gray-400">${m.is_open_source ? '开源' : '商业'}</div>
|
||||
</div>
|
||||
`).join('')
|
||||
: '<div class="text-gray-400">暂无数据</div>';
|
||||
}
|
||||
|
||||
// 加载模型列表
|
||||
async function loadAdminModels() {
|
||||
const res = await fetch('/api/models');
|
||||
const models = await res.json();
|
||||
|
||||
if (models.length === 0) {
|
||||
document.getElementById('admin-models-table').innerHTML = '<tr><td colspan="6" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('admin-models-table').innerHTML = models.map(m => `
|
||||
<tr class="border-b hover:bg-gray-50">
|
||||
<td class="px-4 py-3 font-medium text-gray-800">${m.name}</td>
|
||||
<td class="px-4 py-3 text-gray-600">${m.organization}</td>
|
||||
<td class="px-4 py-3">${m.parameters}B</td>
|
||||
<td class="px-4 py-3 text-gray-600">${m.context_length || '-'}</td>
|
||||
<td class="px-4 py-3">${m.is_open_source ? '<span class="text-green-600">开源</span>' : '<span class="text-gray-600">商业</span>'}</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
<button onclick="editItem('model', '${m.id}')" class="text-blue-600 hover:text-blue-800 mr-2">
|
||||
<i class="ri-edit-line"></i>
|
||||
</button>
|
||||
<button onclick="deleteItem('model', '${m.id}')" class="text-red-600 hover:text-red-800">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 加载GPU列表
|
||||
async function loadAdminGpus() {
|
||||
const res = await fetch('/api/gpus');
|
||||
const gpus = await res.json();
|
||||
|
||||
if (gpus.length === 0) {
|
||||
document.getElementById('admin-gpus-table').innerHTML = '<tr><td colspan="6" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('admin-gpus-table').innerHTML = gpus.map(g => `
|
||||
<tr class="border-b hover:bg-gray-50">
|
||||
<td class="px-4 py-3 font-medium text-gray-800">${g.name}</td>
|
||||
<td class="px-4 py-3 text-gray-600">${g.manufacturer}</td>
|
||||
<td class="px-4 py-3">${g.memory_gb}GB</td>
|
||||
<td class="px-4 py-3 text-gray-600">${g.architecture}</td>
|
||||
<td class="px-4 py-3 text-gray-600">$${g.price_usd || '-'}</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
<button onclick="editItem('gpu', '${g.id}')" class="text-blue-600 hover:text-blue-800 mr-2">
|
||||
<i class="ri-edit-line"></i>
|
||||
</button>
|
||||
<button onclick="deleteItem('gpu', '${g.id}')" class="text-red-600 hover:text-red-800">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 加载CPU列表
|
||||
async function loadAdminCpus() {
|
||||
const res = await fetch('/api/cpus');
|
||||
const cpus = await res.json();
|
||||
|
||||
if (cpus.length === 0) {
|
||||
document.getElementById('admin-cpus-table').innerHTML = '<tr><td colspan="6" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('admin-cpus-table').innerHTML = cpus.map(c => `
|
||||
<tr class="border-b hover:bg-gray-50">
|
||||
<td class="px-4 py-3 font-medium text-gray-800">${c.name}</td>
|
||||
<td class="px-4 py-3 text-gray-600">${c.manufacturer}</td>
|
||||
<td class="px-4 py-3">${c.cores}/${c.threads}</td>
|
||||
<td class="px-4 py-3 text-gray-600">${c.base_clock_ghz}-${c.boost_clock_ghz}GHz</td>
|
||||
<td class="px-4 py-3 text-gray-600">$${c.price_usd || '-'}</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
<button onclick="editItem('cpu', '${c.id}')" class="text-blue-600 hover:text-blue-800 mr-2">
|
||||
<i class="ri-edit-line"></i>
|
||||
</button>
|
||||
<button onclick="deleteItem('cpu', '${c.id}')" class="text-red-600 hover:text-red-800">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 打开添加弹窗
|
||||
function openAddModal(type) {
|
||||
currentType = type;
|
||||
currentId = '';
|
||||
currentData = {};
|
||||
|
||||
document.getElementById('modalTitle').textContent = '添加' + (type === 'model' ? '模型' : type === 'gpu' ? 'GPU' : 'CPU');
|
||||
|
||||
if (type === 'model') {
|
||||
document.getElementById('modalContent').innerHTML = getModelForm();
|
||||
} else if (type === 'gpu') {
|
||||
document.getElementById('modalContent').innerHTML = getGpuForm();
|
||||
} else {
|
||||
document.getElementById('modalContent').innerHTML = getCpuForm();
|
||||
}
|
||||
|
||||
document.getElementById('editModal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
// 编辑项
|
||||
async function editItem(type, id) {
|
||||
currentType = type;
|
||||
currentId = id;
|
||||
|
||||
const res = await fetch(`/api/${type}s/${id}`);
|
||||
currentData = await res.json();
|
||||
|
||||
document.getElementById('modalTitle').textContent = '编辑' + (type === 'model' ? '模型' : type === 'gpu' ? 'GPU' : 'CPU');
|
||||
|
||||
if (type === 'model') {
|
||||
document.getElementById('modalContent').innerHTML = getModelForm(currentData);
|
||||
} else if (type === 'gpu') {
|
||||
document.getElementById('modalContent').innerHTML = getGpuForm(currentData);
|
||||
} else {
|
||||
document.getElementById('modalContent').innerHTML = getCpuForm(currentData);
|
||||
}
|
||||
|
||||
document.getElementById('editModal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
// 删除项
|
||||
async function deleteItem(type, id) {
|
||||
if (!confirm('确定删除?')) return;
|
||||
|
||||
await fetch(`/api/${type}s/${id}`, { method: 'DELETE' });
|
||||
|
||||
if (type === 'model') loadAdminModels();
|
||||
if (type === 'gpu') loadAdminGpus();
|
||||
if (type === 'cpu') loadAdminCpus();
|
||||
|
||||
loadOverview();
|
||||
}
|
||||
|
||||
// 保存项
|
||||
async function saveItem() {
|
||||
const form = document.getElementById('itemForm');
|
||||
const formData = new FormData(form);
|
||||
const data = {};
|
||||
|
||||
formData.forEach((value, key) => {
|
||||
if (value) {
|
||||
// 数值字段转换
|
||||
if (['parameters', 'context_length', 'mmlu', 'humaneval', 'input_price', 'output_price',
|
||||
'memory_gb', 'cuda_cores', 'tensor_cores', 'memory_bandwidth_gbs',
|
||||
'fp32_tflops', 'fp16_tflops', 'int8_perf_tops', 'price_usd', 'release_year',
|
||||
'cores', 'threads', 'base_clock_ghz', 'boost_clock_ghz', 'l3_cache_mb', 'tdp_watts'].includes(key)) {
|
||||
data[key] = parseFloat(value);
|
||||
} else if (key === 'is_open_source') {
|
||||
data[key] = value === 'true';
|
||||
} else {
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (currentId) {
|
||||
// 更新
|
||||
await fetch(`/api/${currentType}s/${currentId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
} else {
|
||||
// 创建
|
||||
await fetch(`/api/${currentType}s`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
closeModal();
|
||||
|
||||
if (currentType === 'model') loadAdminModels();
|
||||
if (currentType === 'gpu') loadAdminGpus();
|
||||
if (currentType === 'cpu') loadAdminCpus();
|
||||
|
||||
loadOverview();
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById('editModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// 表单模板
|
||||
function getModelForm(data = {}) {
|
||||
return `
|
||||
<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">名称 *</label>
|
||||
<input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">厂商 *</label>
|
||||
<input type="text" name="organization" value="${data.organization || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">参数量(B) *</label>
|
||||
<input type="number" name="parameters" value="${data.parameters || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">架构</label>
|
||||
<input type="text" name="architecture" value="${data.architecture || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">上下文长度</label>
|
||||
<input type="number" name="context_length" value="${data.context_length || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">类型</label>
|
||||
<select name="is_open_source" class="w-full px-3 py-2 border rounded-lg">
|
||||
<option value="false" ${!data.is_open_source ? 'selected' : ''}>商业</option>
|
||||
<option value="true" ${data.is_open_source ? 'selected' : ''}>开源</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">MMLU分数</label>
|
||||
<input type="number" name="mmlu" value="${data.mmlu || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">HumanEval分数</label>
|
||||
<input type="number" name="humaneval" value="${data.humaneval || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">输入价格($/1K)</label>
|
||||
<input type="number" name="input_price" value="${data.input_price || ''}" step="0.001" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">输出价格($/1K)</label>
|
||||
<input type="number" name="output_price" value="${data.output_price || ''}" step="0.001" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">许可证</label>
|
||||
<input type="text" name="license" value="${data.license || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">描述</label>
|
||||
<textarea name="description" rows="3" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
function getGpuForm(data = {}) {
|
||||
return `
|
||||
<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">名称 *</label>
|
||||
<input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">厂商 *</label>
|
||||
<input type="text" name="manufacturer" value="${data.manufacturer || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">架构</label>
|
||||
<input type="text" name="architecture" value="${data.architecture || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">显存(GB) *</label>
|
||||
<input type="number" name="memory_gb" value="${data.memory_gb || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">CUDA核心</label>
|
||||
<input type="number" name="cuda_cores" value="${data.cuda_cores || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">Tensor核心</label>
|
||||
<input type="number" name="tensor_cores" value="${data.tensor_cores || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">显存带宽(GB/s)</label>
|
||||
<input type="number" name="memory_bandwidth_gbs" value="${data.memory_bandwidth_gbs || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">FP32性能(TF)</label>
|
||||
<input type="number" name="fp32_tflops" value="${data.fp32_tflops || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">FP16性能(TF)</label>
|
||||
<input type="number" name="fp16_tflops" value="${data.fp16_tflops || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">INT8性能(TOP)</label>
|
||||
<input type="number" name="int8_perf_tops" value="${data.int8_perf_tops || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">价格($)</label>
|
||||
<input type="number" name="price_usd" value="${data.price_usd || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">发布年份</label>
|
||||
<input type="number" name="release_year" value="${data.release_year || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">描述</label>
|
||||
<textarea name="description" rows="3" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
function getCpuForm(data = {}) {
|
||||
return `
|
||||
<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">名称 *</label>
|
||||
<input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">厂商 *</label>
|
||||
<input type="text" name="manufacturer" value="${data.manufacturer || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">架构</label>
|
||||
<input type="text" name="architecture" value="${data.architecture || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">核心数 *</label>
|
||||
<input type="number" name="cores" value="${data.cores || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">线程数 *</label>
|
||||
<input type="number" name="threads" value="${data.threads || ''}" required class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">基础频率(GHz)</label>
|
||||
<input type="number" name="base_clock_ghz" value="${data.base_clock_ghz || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">加速频率(GHz)</label>
|
||||
<input type="number" name="boost_clock_ghz" value="${data.boost_clock_ghz || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">L3缓存(MB)</label>
|
||||
<input type="number" name="l3_cache_mb" value="${data.l3_cache_mb || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">TDP功耗(W)</label>
|
||||
<input type="number" name="tdp_watts" value="${data.tdp_watts || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">价格($)</label>
|
||||
<input type="number" name="price_usd" value="${data.price_usd || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">发布年份</label>
|
||||
<input type="number" name="release_year" value="${data.release_year || ''}" class="w-full px-3 py-2 border rounded-lg">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600 mb-1 block">描述</label>
|
||||
<textarea name="description" rows="3" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
// 点击弹窗外部关闭
|
||||
document.getElementById('editModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) closeModal();
|
||||
});
|
||||
|
||||
// 初始化
|
||||
loadOverview();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user