添加分类管理导出导入功能

This commit is contained in:
2026-07-10 23:59:53 +08:00
parent 7d376533f3
commit cfe463ae8b
21 changed files with 512 additions and 4 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+272 -3
View File
@@ -2,10 +2,11 @@
分类管理 API
"""
import uuid
import json
from datetime import datetime
from flask import Blueprint, request, jsonify
from config import CATEGORIES_FILE
from utils import load_data, save_data
from flask import Blueprint, request, jsonify, Response
from config import CATEGORIES_FILE, DATA_DIR
from utils import load_data, save_data, load_config
cat_bp = Blueprint('api_categories', __name__)
@@ -70,3 +71,271 @@ def api_toggle_category_visible(category_id):
category['visible'] = not category.get('visible', True)
save_data(CATEGORIES_FILE, categories)
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'
}
)
return response
except Exception as e:
return jsonify({'error': str(e)}), 500
@cat_bp.route('/api/categories/export/<category_id>', 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)
if not category:
return jsonify({'error': 'Category not found'}), 404
export_data = {
'category': category,
'export_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'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'
}
)
return response
except Exception as e:
return jsonify({'error': str(e)}), 500
# ─── 导入分类相关数据 ───────────────────────────────────────────────────────
@cat_bp.route('/api/categories/import', methods=['POST'])
def api_import_categories():
"""导入分类及其相关数据"""
try:
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': []
}
# 处理分类
existing_categories = load_data(CATEGORIES_FILE)
imported_categories = import_data['categories']
for cat in imported_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'])
else:
# 合并模式:跳过已存在的分类
result['skipped'].append(cat['id'])
else:
# 新分类:添加
existing_categories.append(cat)
result['imported_categories'] += 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
@cat_bp.route('/api/categories/import/<category_id>', methods=['POST'])
def api_import_single_category(category_id):
"""导入单个分类数据"""
try:
import_data = request.get_json()
if not import_data:
return jsonify({'error': '无导入数据'}), 400
if 'category' not in import_data:
return jsonify({'error': '缺少 category 字段'}), 400
mode = request.args.get('mode', 'merge')
result = {
'success': True,
'imported_items': 0,
'updated_items': 0
}
# 处理分类
categories = load_data(CATEGORIES_FILE)
imported_cat = import_data['category']
existing = next((c for c in categories if c['id'] == category_id), None)
if existing:
if mode == 'replace':
existing.update(imported_cat)
else:
categories.append(imported_cat)
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