feat: v1.2.0 新增网站配置管理功能
新功能: - 后台管理新增'网站配置'菜单 - 支持配置:网站名称、副标题、备案号、联系邮箱、GitHub、页脚文字 - 前台页面自动读取配置显示 - 页脚支持备案号链接 配置存储在 data/config.json
This commit is contained in:
41
app.py
41
app.py
@@ -25,6 +25,7 @@ GPUS_FILE = DATA_DIR / 'gpus.json'
|
|||||||
CPUS_FILE = DATA_DIR / 'cpus.json'
|
CPUS_FILE = DATA_DIR / 'cpus.json'
|
||||||
CATEGORIES_FILE = DATA_DIR / 'categories.json'
|
CATEGORIES_FILE = DATA_DIR / 'categories.json'
|
||||||
KNOWLEDGE_FILE = DATA_DIR / 'knowledge.json'
|
KNOWLEDGE_FILE = DATA_DIR / 'knowledge.json'
|
||||||
|
CONFIG_FILE = DATA_DIR / 'config.json'
|
||||||
|
|
||||||
# 大模型配置
|
# 大模型配置
|
||||||
LLM_CONFIG = {
|
LLM_CONFIG = {
|
||||||
@@ -33,6 +34,27 @@ LLM_CONFIG = {
|
|||||||
'model': 'auto',
|
'model': 'auto',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 默认网站配置
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
'site_name': 'ParamHub',
|
||||||
|
'site_subtitle': '参数百科',
|
||||||
|
'footer_text': 'ParamHub - AI大模型与硬件参数速查平台',
|
||||||
|
'icp_number': '',
|
||||||
|
'copyright_year': '2024',
|
||||||
|
'contact_email': '',
|
||||||
|
'github_url': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
def load_config():
|
||||||
|
"""加载网站配置"""
|
||||||
|
if CONFIG_FILE.exists():
|
||||||
|
return json.loads(CONFIG_FILE.read_text(encoding='utf-8'))
|
||||||
|
return DEFAULT_CONFIG.copy()
|
||||||
|
|
||||||
|
def save_config(config):
|
||||||
|
"""保存网站配置"""
|
||||||
|
CONFIG_FILE.write_text(json.dumps(config, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||||
|
|
||||||
def load_data(file_path):
|
def load_data(file_path):
|
||||||
"""加载JSON数据"""
|
"""加载JSON数据"""
|
||||||
if file_path.exists():
|
if file_path.exists():
|
||||||
@@ -863,9 +885,26 @@ def api_toggle_item_visible(category_id, item_id):
|
|||||||
|
|
||||||
return jsonify({'success': True, 'visible': item['visible']})
|
return jsonify({'success': True, 'visible': item['visible']})
|
||||||
|
|
||||||
|
# ============ 网站配置API ============
|
||||||
|
|
||||||
|
@app.route('/api/config')
|
||||||
|
def api_get_config():
|
||||||
|
"""获取网站配置"""
|
||||||
|
return jsonify(load_config())
|
||||||
|
|
||||||
|
@app.route('/api/config', methods=['PUT'])
|
||||||
|
def api_update_config():
|
||||||
|
"""更新网站配置"""
|
||||||
|
data = request.get_json()
|
||||||
|
config = load_config()
|
||||||
|
config.update(data)
|
||||||
|
config['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
save_config(config)
|
||||||
|
return jsonify(config)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("ParamHub - 参数百科 v1.1.0")
|
print("ParamHub - 参数百科 v1.2.0")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print(f"访问地址: http://localhost:19010")
|
print(f"访问地址: http://localhost:19010")
|
||||||
print(f"后台管理: http://localhost:19010/admin")
|
print(f"后台管理: http://localhost:19010/admin")
|
||||||
|
|||||||
@@ -189,6 +189,7 @@
|
|||||||
"is_open_source": false,
|
"is_open_source": false,
|
||||||
"license": "Proprietary",
|
"license": "Proprietary",
|
||||||
"description": "智谱AI大模型,中文能力强",
|
"description": "智谱AI大模型,中文能力强",
|
||||||
"created_at": "2024-01-01"
|
"created_at": "2024-01-01",
|
||||||
|
"visible": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -52,6 +52,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- 网站配置 -->
|
||||||
|
<section id="section-config" class="hidden">
|
||||||
|
<h1 class="text-2xl font-bold text-gray-800 mb-6">网站配置</h1>
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-6">
|
||||||
|
<form id="configForm" class="space-y-6">
|
||||||
|
<div class="grid grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">网站名称</label>
|
||||||
|
<input type="text" name="site_name" id="config_site_name" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="ParamHub">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">网站副标题</label>
|
||||||
|
<input type="text" name="site_subtitle" id="config_site_subtitle" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="参数百科">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">备案号</label>
|
||||||
|
<input type="text" name="icp_number" id="config_icp_number" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="如:京ICP备12345678号">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">联系邮箱</label>
|
||||||
|
<input type="email" name="contact_email" id="config_contact_email" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="admin@example.com">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">GitHub地址</label>
|
||||||
|
<input type="url" name="github_url" id="config_github_url" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="https://github.com/...">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">版权年份</label>
|
||||||
|
<input type="text" name="copyright_year" id="config_copyright_year" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="2024">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">页脚文字</label>
|
||||||
|
<textarea name="footer_text" id="config_footer_text" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="网站底部的版权信息等"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-4">
|
||||||
|
<button type="button" onclick="loadSiteConfig()" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300"><i class="ri-refresh-line mr-1"></i>重置</button>
|
||||||
|
<button type="button" onclick="saveSiteConfig()" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"><i class="ri-save-line mr-1"></i>保存配置</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- 分类管理 -->
|
<!-- 分类管理 -->
|
||||||
<section id="section-categories" class="hidden">
|
<section id="section-categories" class="hidden">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
@@ -326,6 +369,7 @@ GPT-4是OpenAI发布的大语言模型,参数量约1.8万亿,支持128K上
|
|||||||
function renderSidebar() {
|
function renderSidebar() {
|
||||||
const fixedItems = [
|
const fixedItems = [
|
||||||
{id: 'overview', name: '概览', icon: 'ri-home-4-line'},
|
{id: 'overview', name: '概览', icon: 'ri-home-4-line'},
|
||||||
|
{id: 'config', name: '网站配置', icon: 'ri-settings-3-line'},
|
||||||
{id: 'categories', name: '分类管理', icon: 'ri-folder-line'},
|
{id: 'categories', name: '分类管理', icon: 'ri-folder-line'},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -443,12 +487,53 @@ GPT-4是OpenAI发布的大语言模型,参数量约1.8万亿,支持128K上
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (section === 'categories') loadAdminCategories();
|
if (section === 'categories') loadAdminCategories();
|
||||||
|
if (section === 'config') loadSiteConfig();
|
||||||
if (section === 'models') loadAdminModels();
|
if (section === 'models') loadAdminModels();
|
||||||
if (section === 'gpus') loadAdminGpus();
|
if (section === 'gpus') loadAdminGpus();
|
||||||
if (section === 'cpus') loadAdminCpus();
|
if (section === 'cpus') loadAdminCpus();
|
||||||
if (section === 'knowledge') loadAdminKnowledge();
|
if (section === 'knowledge') loadAdminKnowledge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载网站配置
|
||||||
|
async function loadSiteConfig() {
|
||||||
|
const res = await fetch('/api/config');
|
||||||
|
const config = await res.json();
|
||||||
|
|
||||||
|
document.getElementById('config_site_name').value = config.site_name || '';
|
||||||
|
document.getElementById('config_site_subtitle').value = config.site_subtitle || '';
|
||||||
|
document.getElementById('config_icp_number').value = config.icp_number || '';
|
||||||
|
document.getElementById('config_contact_email').value = config.contact_email || '';
|
||||||
|
document.getElementById('config_github_url').value = config.github_url || '';
|
||||||
|
document.getElementById('config_copyright_year').value = config.copyright_year || '';
|
||||||
|
document.getElementById('config_footer_text').value = config.footer_text || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存网站配置
|
||||||
|
async function saveSiteConfig() {
|
||||||
|
const config = {
|
||||||
|
site_name: document.getElementById('config_site_name').value,
|
||||||
|
site_subtitle: document.getElementById('config_site_subtitle').value,
|
||||||
|
icp_number: document.getElementById('config_icp_number').value,
|
||||||
|
contact_email: document.getElementById('config_contact_email').value,
|
||||||
|
github_url: document.getElementById('config_github_url').value,
|
||||||
|
copyright_year: document.getElementById('config_copyright_year').value,
|
||||||
|
footer_text: document.getElementById('config_footer_text').value,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/config', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(config)
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
alert('配置已保存!');
|
||||||
|
} catch (e) {
|
||||||
|
alert('保存失败: ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 加载概览统计
|
// 加载概览统计
|
||||||
async function loadOverview() {
|
async function loadOverview() {
|
||||||
const res = await fetch('/api/stats');
|
const res = await fetch('/api/stats');
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>ParamHub - 参数百科</title>
|
<title id="pageTitle">ParamHub - 参数百科</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
<div class="max-w-7xl mx-auto px-4 py-3 flex justify-between items-center">
|
<div class="max-w-7xl mx-auto px-4 py-3 flex justify-between items-center">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<i class="ri-dashboard-3-line text-2xl text-indigo-600"></i>
|
<i class="ri-dashboard-3-line text-2xl text-indigo-600"></i>
|
||||||
<span class="text-xl font-bold text-gray-800">ParamHub</span>
|
<span class="text-xl font-bold text-gray-800" id="navSiteName">ParamHub</span>
|
||||||
<span class="text-sm text-gray-500">参数百科</span>
|
<span class="text-sm text-gray-500" id="navSiteSubtitle">参数百科</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 text-sm" id="navLinks">
|
<div class="flex gap-4 text-sm" id="navLinks">
|
||||||
<!-- 动态加载 -->
|
<!-- 动态加载 -->
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
<!-- 页脚 -->
|
<!-- 页脚 -->
|
||||||
<footer class="bg-white border-t mt-8 py-6 text-center text-gray-500 text-sm">
|
<footer class="bg-white border-t mt-8 py-6 text-center text-gray-500 text-sm">
|
||||||
ParamHub - 参数百科 | AI模型与硬件参数速查平台
|
<span id="footerText">ParamHub - 参数百科 | AI模型与硬件参数速查平台</span>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -121,13 +121,32 @@
|
|||||||
|
|
||||||
// 加载分类和数据统计
|
// 加载分类和数据统计
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
// 并行加载分类和统计
|
// 并行加载分类、统计、配置
|
||||||
const [catRes, statsRes] = await Promise.all([
|
const [catRes, statsRes, configRes] = await Promise.all([
|
||||||
fetch('/api/categories'),
|
fetch('/api/categories'),
|
||||||
fetch('/api/stats')
|
fetch('/api/stats'),
|
||||||
|
fetch('/api/config')
|
||||||
]);
|
]);
|
||||||
categories = await catRes.json();
|
categories = await catRes.json();
|
||||||
const stats = await statsRes.json();
|
const stats = await statsRes.json();
|
||||||
|
const config = await configRes.json();
|
||||||
|
|
||||||
|
// 更新网站名称等
|
||||||
|
if (config.site_name) {
|
||||||
|
document.getElementById('navSiteName').textContent = config.site_name;
|
||||||
|
}
|
||||||
|
if (config.site_subtitle) {
|
||||||
|
document.getElementById('navSiteSubtitle').textContent = config.site_subtitle;
|
||||||
|
}
|
||||||
|
if (config.site_name && config.site_subtitle) {
|
||||||
|
document.getElementById('pageTitle').textContent = `${config.site_name} - ${config.site_subtitle}`;
|
||||||
|
}
|
||||||
|
if (config.footer_text) {
|
||||||
|
document.getElementById('footerText').textContent = config.footer_text;
|
||||||
|
}
|
||||||
|
if (config.icp_number) {
|
||||||
|
document.getElementById('footerText').innerHTML += ` | <a href="https://beian.miit.gov.cn/" target="_blank" class="hover:text-gray-700">${config.icp_number}</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
// 渲染导航栏
|
// 渲染导航栏
|
||||||
renderNavBar();
|
renderNavBar();
|
||||||
|
|||||||
Reference in New Issue
Block a user