diff --git a/modules/routes/__pycache__/api_categories.cpython-310.pyc b/modules/routes/__pycache__/api_categories.cpython-310.pyc index 32fc2d1..9c4cdb8 100644 Binary files a/modules/routes/__pycache__/api_categories.cpython-310.pyc and b/modules/routes/__pycache__/api_categories.cpython-310.pyc differ diff --git a/modules/routes/api_categories.py b/modules/routes/api_categories.py index 9e83f1e..89ba454 100644 --- a/modules/routes/api_categories.py +++ b/modules/routes/api_categories.py @@ -5,8 +5,8 @@ import uuid import json from datetime import datetime from flask import Blueprint, request, jsonify, Response -from config import CATEGORIES_FILE, DATA_DIR -from utils import load_data, save_data, load_config +from config import CATEGORIES_FILE +from utils import load_data, save_data cat_bp = Blueprint('api_categories', __name__) @@ -73,54 +73,27 @@ def api_toggle_category_visible(category_id): return jsonify({'success': True, 'visible': category['visible']}) -# ─── 导出分类相关数据 ─────────────────────────────────────────────────────── +# ─── 导出分类数据 ─────────────────────────────────────────────────────── @cat_bp.route('/api/categories/export', methods=['GET']) def api_export_categories(): - """导出所有分类及其相关数据(子类别、参数字段、关联数据项)""" + """导出所有分类配置(仅分类本身,不含数据项)""" try: - # 获取所有分类 categories = load_data(CATEGORIES_FILE) - # 获取各类别下的数据 export_data = { 'categories': categories, 'export_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'version': '1.0' } - # 加载各类别数据文件 - # 内置分类:AI模型、GPU、CPU - models_file = DATA_DIR / 'models.json' - gpus_file = DATA_DIR / 'gpus.json' - cpus_file = DATA_DIR / 'cpus.json' - - if models_file.exists(): - export_data['models'] = load_data(models_file) - if gpus_file.exists(): - export_data['gpus'] = load_data(gpus_file) - if cpus_file.exists(): - export_data['cpus'] = load_data(cpus_file) - - # 动态分类数据(每个自定义分类有独立的数据文件) - for cat in categories: - cat_id = cat['id'] - # 排除内置分类 - if cat_id in ['ai-models', 'gpus', 'cpus']: - continue - # 查找该分类的数据文件 - cat_data_file = DATA_DIR / f'{cat_id}.json' - if cat_data_file.exists(): - export_data[cat_id] = load_data(cat_data_file) - - # 导出为 JSON 文件 json_str = json.dumps(export_data, ensure_ascii=False, indent=2) response = Response( json_str, mimetype='application/json', headers={ - 'Content-Disposition': f'attachment; filename=param-hub-categories-export-{datetime.now().strftime("%Y%m%d%H%M%S")}.json' + 'Content-Disposition': f'attachment; filename=param-hub-categories-{datetime.now().strftime("%Y%m%d%H%M%S")}.json' } ) return response @@ -130,7 +103,7 @@ def api_export_categories(): @cat_bp.route('/api/categories/export/', methods=['GET']) def api_export_single_category(category_id): - """导出单个分类及其相关数据""" + """导出单个分类配置""" try: categories = load_data(CATEGORIES_FILE) category = next((c for c in categories if c['id'] == category_id), None) @@ -143,32 +116,13 @@ def api_export_single_category(category_id): 'version': '1.0' } - # 加载该分类的数据 - if category_id == 'ai-models': - models_file = DATA_DIR / 'models.json' - if models_file.exists(): - export_data['items'] = load_data(models_file) - elif category_id == 'gpus': - gpus_file = DATA_DIR / 'gpus.json' - if gpus_file.exists(): - export_data['items'] = load_data(gpus_file) - elif category_id == 'cpus': - cpus_file = DATA_DIR / 'cpus.json' - if cpus_file.exists(): - export_data['items'] = load_data(cpus_file) - else: - # 动态分类 - cat_data_file = DATA_DIR / f'{category_id}.json' - if cat_data_file.exists(): - export_data['items'] = load_data(cat_data_file) - json_str = json.dumps(export_data, ensure_ascii=False, indent=2) response = Response( json_str, mimetype='application/json', headers={ - 'Content-Disposition': f'attachment; filename={category_id}-export-{datetime.now().strftime("%Y%m%d%H%M%S")}.json' + 'Content-Disposition': f'attachment; filename={category_id}-{datetime.now().strftime("%Y%m%d%H%M%S")}.json' } ) return response @@ -176,33 +130,42 @@ def api_export_single_category(category_id): return jsonify({'error': str(e)}), 500 -# ─── 导入分类相关数据 ─────────────────────────────────────────────────────── +# ─── 导入分类数据 ─────────────────────────────────────────────────────── -@cat_bp.route('/api/categories/import', methods=['POST']) +@cat_bp.route('/api/categories/import', methods=['GET', 'POST']) def api_import_categories(): - """导入分类及其相关数据""" + """导入分类配置(仅分类本身,不含数据项)""" try: + if request.method == 'GET': + # 返回导入接口说明 + return jsonify({ + 'endpoint': '/api/categories/import', + 'method': 'POST', + 'params': { + 'mode': 'merge(合并)或 replace(替换)' + }, + 'body': { + 'categories': '分类数组' + } + }) + import_data = request.get_json() if not import_data: return jsonify({'error': '无导入数据'}), 400 - # 验证数据结构 if 'categories' not in import_data: return jsonify({'error': '缺少 categories 字段'}), 400 - # 导入模式:merge(合并)或 replace(替换) mode = request.args.get('mode', 'merge') result = { 'success': True, - 'imported_categories': 0, - 'imported_items': 0, - 'skipped': [], - 'updated': [] + 'imported': 0, + 'updated': 0, + 'skipped': [] } - # 处理分类 existing_categories = load_data(CATEGORIES_FILE) imported_categories = import_data['categories'] @@ -210,68 +173,16 @@ def api_import_categories(): existing = next((c for c in existing_categories if c['id'] == cat['id']), None) if existing: if mode == 'replace': - # 替换模式:更新现有分类 existing.update(cat) - result['updated'].append(cat['id']) + result['updated'] += 1 else: - # 合并模式:跳过已存在的分类 result['skipped'].append(cat['id']) else: - # 新分类:添加 existing_categories.append(cat) - result['imported_categories'] += 1 + result['imported'] += 1 save_data(CATEGORIES_FILE, existing_categories) - # 导入各类别数据 - data_mappings = { - 'models': 'models.json', - 'gpus': 'gpus.json', - 'cpus': 'cpus.json' - } - - for key, filename in data_mappings.items(): - if key in import_data: - data_file = DATA_DIR / filename - existing_items = load_data(data_file) if data_file.exists() else [] - imported_items = import_data[key] - - for item in imported_items: - existing = next((i for i in existing_items if i['id'] == item['id']), None) - if existing: - if mode == 'replace': - existing.update(item) - else: - continue # 合并模式跳过 - else: - existing_items.append(item) - result['imported_items'] += 1 - - save_data(data_file, existing_items) - - # 导入动态分类数据 - for cat in imported_categories: - cat_id = cat['id'] - if cat_id in ['ai-models', 'gpus', 'cpus']: - continue - if cat_id in import_data: - data_file = DATA_DIR / f'{cat_id}.json' - existing_items = load_data(data_file) if data_file.exists() else [] - imported_items = import_data[cat_id] - - for item in imported_items: - existing = next((i for i in existing_items if i['id'] == item['id']), None) - if existing: - if mode == 'replace': - existing.update(item) - else: - continue - else: - existing_items.append(item) - result['imported_items'] += 1 - - save_data(data_file, existing_items) - return jsonify(result) except Exception as e: return jsonify({'error': str(e)}), 500 @@ -279,7 +190,7 @@ def api_import_categories(): @cat_bp.route('/api/categories/import/', methods=['POST']) def api_import_single_category(category_id): - """导入单个分类数据""" + """导入单个分类配置""" try: import_data = request.get_json() @@ -293,11 +204,10 @@ def api_import_single_category(category_id): result = { 'success': True, - 'imported_items': 0, - 'updated_items': 0 + 'imported': False, + 'updated': False } - # 处理分类 categories = load_data(CATEGORIES_FILE) imported_cat = import_data['category'] @@ -305,37 +215,13 @@ def api_import_single_category(category_id): if existing: if mode == 'replace': existing.update(imported_cat) + result['updated'] = True else: categories.append(imported_cat) + result['imported'] = True save_data(CATEGORIES_FILE, categories) - # 处理数据项 - if 'items' in import_data: - if category_id == 'ai-models': - data_file = DATA_DIR / 'models.json' - elif category_id == 'gpus': - data_file = DATA_DIR / 'gpus.json' - elif category_id == 'cpus': - data_file = DATA_DIR / 'cpus.json' - else: - data_file = DATA_DIR / f'{category_id}.json' - - existing_items = load_data(data_file) if data_file.exists() else [] - imported_items = import_data['items'] - - for item in imported_items: - existing = next((i for i in existing_items if i['id'] == item['id']), None) - if existing: - if mode == 'replace': - existing.update(item) - result['updated_items'] += 1 - else: - existing_items.append(item) - result['imported_items'] += 1 - - save_data(data_file, existing_items) - return jsonify(result) except Exception as e: - return jsonify({'error': str(e)}), 500 + return jsonify({'error': str(e)}), 500 \ No newline at end of file diff --git a/templates/admin.html b/templates/admin.html index a734441..e1104d6 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -2828,26 +2828,6 @@ html += `
单个分类: ${importData.category.name}
`; } - // 数据项 - const itemTypes = ['models', 'gpus', 'cpus', 'items']; - let totalItems = 0; - itemTypes.forEach(type => { - if (importData[type] && importData[type].length > 0) { - totalItems += importData[type].length; - html += `
${type}: ${importData[type].length} 条
`; - } - }); - - // 动态分类数据 - const dynamicCats = Object.keys(importData).filter(k => - k !== 'categories' && k !== 'category' && k !== 'export_time' && k !== 'version' && - !itemTypes.includes(k) && Array.isArray(importData[k]) - ); - dynamicCats.forEach(catId => { - totalItems += importData[catId].length; - html += `
${catId}: ${importData[catId].length} 条
`; - }); - html += `
导出时间: ${importData.export_time || '未知'}
`; html += '';content.innerHTML = html; } @@ -2860,15 +2840,14 @@ } const mode = document.getElementById('importMode').value; - const categoryId = document.getElementById('importCategoryId').value; try { let endpoint; - if (categoryId && importData.category) { + if (importData.category) { // 导入单个分类 - endpoint = `/api/categories/import/${categoryId}?mode=${mode}`; + endpoint = `/api/categories/import/${importData.category.id}?mode=${mode}`; } else { - // 导入全部 + // 导入全部分类 endpoint = `/api/categories/import?mode=${mode}`; } @@ -2884,7 +2863,7 @@ alert('导入失败: ' + result.error); } else { let msg = '导入成功!\n'; - msg += `新增分类: ${result.imported_categories || 0}\n`;msg += `新增数据: ${result.imported_items || 0}\n`;msg += `更新数据: ${result.updated_items || 0}`; + msg += `新增分类: ${result.imported || 0}\n`;msg += `更新分类: ${result.updated || 0}`; if (result.skipped && result.skipped.length > 0) { msg += `\n跳过已存在分类: ${result.skipped.join(', ')}`; } @@ -2894,7 +2873,6 @@ await loadCategories(); renderSidebar(); loadAdminCategories(); - loadOverview(); } } catch (e) { alert('导入失败: ' + e.message);