diff --git a/templates/admin.html b/templates/admin.html index 72407bf..daf02ea 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -185,23 +185,8 @@
- - - - - - - - - - - - - - - - - +
置顶名称厂商子类别参数量上下文类型发布日期热度显示操作
加载中...
+
加载中...
@@ -221,23 +206,8 @@
- - - - - - - - - - - - - - - - - +
置顶名称厂商子类别显存架构价格发布日期热度显示操作
加载中...
+
加载中...
@@ -257,23 +227,8 @@
- - - - - - - - - - - - - - - - - +
置顶名称厂商子类别核心/线程主频价格发布日期热度显示操作
加载中...
+
加载中...
@@ -676,8 +631,11 @@ // 显示动态分类数据 async function showDynamicCategory(categoryId) { dynamicCategoryId = categoryId; - dynamicSubcategoryFilter = ''; // 重置筛选 + dynamicSubcategoryFilter = ''; const cat = categories.find(c => c.id === categoryId); + const fields = cat ? (cat.fields || []) : []; + const fixedFields = ['id', 'created_at', 'updated_at', 'visible', 'raw_text', 'category_id', 'subcategory_id', 'is_pinned', 'images']; + const displayFields = fields.filter(f => !fixedFields.includes(f.key)); document.querySelectorAll('section').forEach(s => s.classList.add('hidden')); document.getElementById('section-dynamic').classList.remove('hidden'); @@ -694,7 +652,6 @@ document.getElementById('dynamic-title').textContent = cat.name + '管理'; - // 渲染子类别筛选按钮 if (cat.subcategories && cat.subcategories.length > 0) { document.getElementById('dynamic-filter-area').classList.remove('hidden'); renderSubcategoryFilters(categoryId, 'dynamic-subcategory-filters', 'filterDynamicBySubcategory'); @@ -702,42 +659,50 @@ document.getElementById('dynamic-filter-area').classList.add('hidden'); } - // 加载该分类的数据(后台显示全部,包括隐藏的) const res = await fetch(`/api/items/${categoryId}?all=1`); let items = await res.json(); - // 子类别筛选 if (dynamicSubcategoryFilter) { items = items.filter(i => i.subcategory_id === dynamicSubcategoryFilter); } if (items.length === 0) { - document.getElementById('admin-dynamic-table').innerHTML = '暂无数据,点击上方"添加数据"按钮添加'; + document.getElementById('admin-dynamic-table').innerHTML = '暂无数据'; } else { - const keys = Object.keys(items[0]).filter(k => !['id', 'created_at', 'updated_at', 'visible', 'raw_text', 'subcategory_id'].includes(k)); let html = ``; - // 添加子类别列 if (cat.subcategories && cat.subcategories.length > 0) { html += `子类别`; } - keys.forEach(k => { html += `${k}`; }); + displayFields.forEach(f => { + html += `${f.label}`; + }); html += `显示`; html += `操作`; items.forEach(item => { html += ``; - // 子类别显示 if (cat.subcategories && cat.subcategories.length > 0) { - const subName = getSubcategoryName(categoryId, item.subcategory_id); - const subIcon = getSubcategoryIcon(categoryId, item.subcategory_id); - html += `${item.subcategory_id ? `${subName}` : '-'}`; + html += `${item.subcategory_id ? `${getSubcategoryName(categoryId, item.subcategory_id)}` : '-'}`; } - keys.forEach(k => { html += `${item[k] || '-'}`; }); + displayFields.forEach(f => { + const value = item[f.key]; + let displayValue = '-'; + if (value !== null && value !== undefined && value !== '') { + if (f.type === 'boolean') { + displayValue = value ? '' : ''; + } else if (f.type === 'json') { + displayValue = typeof value === 'object' ? JSON.stringify(value).substring(0, 30) + '...' : String(value).substring(0, 30); + } else { + displayValue = String(value).substring(0, 30); + } + } + html += `${displayValue}`; + }); html += ` - - ${item.raw_text ? `` : ''} + ${item.raw_text ? `` : ''} `; html += ` @@ -928,6 +893,12 @@ // 加载模型列表 async function loadAdminModels() { renderSubcategoryFilters('ai-models', 'model-subcategory-filters', 'filterModelsBySubcategory'); + + // 获取类别字段配置 + const cat = categories.find(c => c.id === 'ai-models'); + const fields = cat ? (cat.fields || []) : []; + const subcats = cat ? (cat.subcategories || []) : []; + const res = await fetch('/api/models?all=1'); let models = await res.json(); @@ -936,36 +907,80 @@ models = models.filter(m => m.subcategory_id === modelSubcategoryFilter); } - if (models.length === 0) { document.getElementById('admin-models-table').innerHTML = '暂无数据'; return; } - document.getElementById('admin-models-table').innerHTML = models.map(m => ` - - - - - ${m.name} - ${m.organization} - - ${m.subcategory_id ? `${getSubcategoryName('ai-models', m.subcategory_id)}` : '-'} - - ${m.parameters}B - ${m.context_length || '-'} - ${m.is_open_source ? '开源' : '商业'} - ${m.publish_date || '-'} - ${m.views || 0} - - - ${m.raw_text ? `` : ''} - - - - - - - `).join(''); + if (models.length === 0) { + document.getElementById('admin-models-table').innerHTML = '暂无数据'; + return; + } + + // 动态生成表头 + const fixedFields = ['subcategory_id', 'id', 'images']; // 固定字段 + const displayFields = fields.filter(f => !fixedFields.includes(f.key)); + + let headerHtml = ` + + + 置顶 + 名称 + 子类别`; + + // 添加动态字段列(只显示前6个关键字段) + displayFields.slice(0, 6).forEach(f => { + headerHtml += `${f.label}`; + }); + + headerHtml += ` + 显示 + 操作 + + `; + + // 动态生成表格内容 + let bodyHtml = ''; + models.forEach(m => { + bodyHtml += ` + + + + + ${m.name || '-'} + + ${m.subcategory_id ? `${getSubcategoryName('ai-models', m.subcategory_id)}` : '-'} + `; + + // 添加动态字段值 + displayFields.slice(0, 6).forEach(f => { + const value = m[f.key]; + let displayValue = '-'; + if (value !== null && value !== undefined && value !== '') { + if (f.type === 'boolean') { + displayValue = value ? '' : ''; + } else if (f.type === 'number') { + displayValue = value; + } else { + displayValue = String(value).substring(0, 20); + } + } + bodyHtml += `${displayValue}`; + }); + + bodyHtml += ` + + + ${m.raw_text ? `` : ''} + + + + + + `; + }); + bodyHtml += ''; + + document.getElementById('admin-models-table').innerHTML = headerHtml + bodyHtml; } function filterModelsBySubcategory(subId) { @@ -976,44 +991,68 @@ // 加载GPU列表 async function loadAdminGpus() { renderSubcategoryFilters('gpus', 'gpu-subcategory-filters', 'filterGpusBySubcategory'); + + const cat = categories.find(c => c.id === 'gpus'); + const fields = cat ? (cat.fields || []) : []; + const fixedFields = ['subcategory_id', 'id', 'images']; + const displayFields = fields.filter(f => !fixedFields.includes(f.key)); + const res = await fetch('/api/gpus?all=1'); let gpus = await res.json(); - // 子类别筛选 if (gpuSubcategoryFilter) { gpus = gpus.filter(g => g.subcategory_id === gpuSubcategoryFilter); } + + if (gpus.length === 0) { + document.getElementById('admin-gpus-table').innerHTML = '暂无数据'; + return; + } - if (gpus.length === 0) { document.getElementById('admin-gpus-table').innerHTML = '暂无数据'; return; } - document.getElementById('admin-gpus-table').innerHTML = gpus.map(g => ` - + let headerHtml = ` + 置顶 + 名称 + 子类别`; + displayFields.slice(0, 6).forEach(f => { + headerHtml += `${f.label}`; + }); + headerHtml += `显示 + 操作`; + + let bodyHtml = ''; + gpus.forEach(g => { + bodyHtml += ` - - ${g.name} - ${g.manufacturer} + ${g.name || '-'} ${g.subcategory_id ? `${getSubcategoryName('gpus', g.subcategory_id)}` : '-'} - - ${g.memory_gb}GB - ${g.architecture || '-'} - ${formatPrice(g)} - ${g.publish_date || '-'} - ${g.views || 0} - - - ${g.raw_text ? `` : ''} + ${g.raw_text ? `` : ''} - - - `).join(''); + `; + }); + bodyHtml += ''; + + document.getElementById('admin-gpus-table').innerHTML = headerHtml + bodyHtml; } function filterGpusBySubcategory(subId) { @@ -1024,44 +1063,68 @@ // 加载CPU列表 async function loadAdminCpus() { renderSubcategoryFilters('cpus', 'cpu-subcategory-filters', 'filterCpusBySubcategory'); + + const cat = categories.find(c => c.id === 'cpus'); + const fields = cat ? (cat.fields || []) : []; + const fixedFields = ['subcategory_id', 'id', 'images']; + const displayFields = fields.filter(f => !fixedFields.includes(f.key)); + const res = await fetch('/api/cpus?all=1'); let cpus = await res.json(); - // 子类别筛选 if (cpuSubcategoryFilter) { cpus = cpus.filter(c => c.subcategory_id === cpuSubcategoryFilter); } - if (cpus.length === 0) { document.getElementById('admin-cpus-table').innerHTML = '暂无数据'; return; } - document.getElementById('admin-cpus-table').innerHTML = cpus.map(c => ` - + if (cpus.length === 0) { + document.getElementById('admin-cpus-table').innerHTML = '暂无数据'; + return; + } + + let headerHtml = ` + 置顶 + 名称 + 子类别`; + displayFields.slice(0, 6).forEach(f => { + headerHtml += `${f.label}`; + }); + headerHtml += `显示 + 操作`; + + let bodyHtml = ''; + cpus.forEach(c => { + bodyHtml += ` - - ${c.name} - ${c.manufacturer} + ${c.name || '-'} ${c.subcategory_id ? `${getSubcategoryName('cpus', c.subcategory_id)}` : '-'} - - ${c.cores}/${c.threads} - ${c.base_clock_ghz || '-'}-${c.boost_clock_ghz || '-'}GHz - ${formatPrice(c)} - ${c.publish_date || '-'} - ${c.views || 0} - - - ${c.raw_text ? `` : ''} + ${c.raw_text ? `` : ''} - - - `).join(''); + `; + }); + bodyHtml += ''; + + document.getElementById('admin-cpus-table').innerHTML = headerHtml + bodyHtml; } function filterCpusBySubcategory(subId) { @@ -1782,23 +1845,64 @@ return `
`; } + // 根据类别字段配置动态生成表单字段 + function generateFormFields(categoryId, data = {}, subcategoryId = '') { + const cat = categories.find(c => c.id === categoryId); + if (!cat) return ''; + + const fields = cat.fields || []; + const fixedFields = ['id', 'subcategory_id', 'images', 'visible', 'created_at', 'updated_at', 'raw_text', 'is_pinned', 'views']; + + // 合并子类别额外字段 + let allFields = fields; + if (subcategoryId) { + const subcat = cat.subcategories?.find(s => s.id === subcategoryId); + if (subcat && subcat.extra_fields) { + allFields = [...fields, ...subcat.extra_fields]; + } + } + + const formFields = allFields.filter(f => !fixedFields.includes(f.key)); + + return formFields.map(field => { + const value = data[field.key] || ''; + const required = field.required ? 'required' : ''; + const requiredMark = field.required ? '*' : ''; + const desc = field.description ? `

${field.description}

` : ''; + + let inputHtml = ''; + if (field.type === 'boolean') { + inputHtml = ``; + } else if (field.type === 'number') { + inputHtml = ``; + } else if (field.type === 'date') { + inputHtml = ``; + } else if (field.type === 'json') { + inputHtml = ``; + } else if (field.type === 'url') { + inputHtml = ``; + } else { + inputHtml = ``; + } + + return `
${inputHtml}${desc}
`; + }).join(''); + } + function getDynamicForm(data = {}) { const cat = categories.find(c => c.id === dynamicCategoryId); currentImages = data.images || []; const subcategorySelect = getSubcategorySelect(dynamicCategoryId, data.subcategory_id); + const formFields = generateFormFields(dynamicCategoryId, data, data.subcategory_id); return `
${subcategorySelect} -
-
-
-
-
-
+ ${formFields}
-
-
${getImageUploadComponent(currentImages, 'dynamic')}
`; } @@ -1806,25 +1910,13 @@ function getModelForm(data = {}) { currentImages = data.images || []; const subcategorySelect = getSubcategorySelect('ai-models', data.subcategory_id); + const formFields = generateFormFields('ai-models', data, data.subcategory_id); return `
${subcategorySelect} -
-
-
-
-
-
-
-
-
-
-
-
-
+ ${formFields}
-
${getImageUploadComponent(currentImages, 'model')}
`; } @@ -1832,31 +1924,13 @@ function getGpuForm(data = {}) { currentImages = data.images || []; const subcategorySelect = getSubcategorySelect('gpus', data.subcategory_id); + const formFields = generateFormFields('gpus', data, data.subcategory_id); return `
${subcategorySelect} -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ${formFields}
-
${getImageUploadComponent(currentImages, 'gpu')}
`; } @@ -1864,32 +1938,13 @@ function getCpuForm(data = {}) { currentImages = data.images || []; const subcategorySelect = getSubcategorySelect('cpus', data.subcategory_id); + const formFields = generateFormFields('cpus', data, data.subcategory_id); return `
${subcategorySelect} -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ${formFields}
-
${getImageUploadComponent(currentImages, 'cpu')}
`; }