Files
piano-plan/app/routes/settings.py
T
hmo 18351212e8 feat: 问题数据迁移到数据库;学员详情页URL导航改造;侧边栏统一
- 问题从文件系统迁移到数据库 problems 表
- 移除 PROBLEMS_DIR 配置和文件读取逻辑
- student.html 完整重写:编辑/添加/删除问题,生成方案进度显示
- 学员详情页支持独立URL访问 (/student/<id>)
- 统一侧边栏到 base.html
- 更新文档:DEPLOYMENT_SOP, MODELS, STRUCTURE, FRONTEND_ARCH
- 部署到生产环境 v1.2.0
2026-04-23 06:35:32 +08:00

228 lines
6.6 KiB
Python

# 问题配置路由 - 完整CRUD
import os
import shutil
from datetime import datetime
from flask import request, jsonify, render_template, current_app, session, redirect
from app.routes import main_bp
from app.models import db, Problem, StudentProblem
from app.config import load_api_config, save_api_config
from app.routes.auth import login_required_json, admin_required
@main_bp.route("/settings")
@login_required_json
def settings():
"""问题配置页面 - 所有登录用户可访问"""
return render_template("settings.html", active_nav="settings")
@main_bp.route("/api-settings")
@admin_required
def api_settings_page():
"""API设置页面 - 仅管理员"""
return render_template("api_settings.html", active_nav="api-settings")
# ==================== API配置接口 ====================
@main_bp.route("/api/config", methods=["GET"])
@admin_required
def get_api_config():
"""获取API配置"""
config = load_api_config(current_app.config)
# 不返回完整的api_key,只返回前5位和后5位
if config.get("api_key"):
api_key = config["api_key"]
if len(api_key) > 10:
config["api_key_preview"] = api_key[:5] + "..." + api_key[-5:]
else:
config["api_key_preview"] = "****"
return jsonify(config)
@main_bp.route("/api/config", methods=["POST"])
@admin_required
def update_api_config():
"""更新API配置"""
data = request.get_json()
# 验证必填字段
if not data.get("api_key"):
return jsonify({"error": "API Key不能为空"}), 400
# 根据provider设置默认endpoint
provider = data.get("provider", "volcengine")
default_endpoints = {
"minimax": "https://api.minimaxi.com/anthropic/v1",
"volcengine": "https://ark.cn-beijing.volces.com/api/coding/v3",
"deepseek": "https://api.deepseek.com/v1",
"openrouter": "https://openrouter.ai/api/v1",
}
default_endpoint = default_endpoints.get(provider, "https://ark.cn-beijing.volces.com/api/coding/v3")
# 保存配置
config = {
"provider": provider,
"api_key": data.get("api_key", ""),
"base_url": data.get("base_url", default_endpoint),
"model": data.get("model", "doubao-seed-2.0-pro"),
"temperature": float(data.get("temperature", 0.7)),
"prompt_template": data.get("prompt_template", ""),
}
save_api_config(config, current_app.config)
return jsonify({"message": "配置保存成功"})
@main_bp.route("/api/problems", methods=["GET"])
@login_required_json
def get_problems():
"""获取问题列表(从数据库读取)"""
from app.models import Problem
problems = Problem.query.order_by(Problem.no).all()
return jsonify([p.to_dict() for p in problems])
@main_bp.route("/api/problems/<int:problem_id>", methods=["GET"])
@login_required_json
def get_problem_detail(problem_id):
"""获取单个问题的详细信息"""
from app.models import Problem
problem = Problem.query.get(problem_id)
if not problem:
return jsonify({"error": "问题不存在"}), 404
return jsonify({
"id": problem.id,
"no": problem.no,
"name": problem.name,
"category": problem.category,
"content": problem.content,
})
@main_bp.route("/api/problems", methods=["POST"])
@admin_required
def create_problem():
"""创建新问题 - 仅管理员"""
from app.models import Problem
data = request.get_json()
no = data.get("no", "").strip()
name = data.get("name", "").strip()
category = data.get("category", "技术类")
content = data.get("content", "")
if not no or not name:
return jsonify({"error": "编号和名称不能为空"}), 400
# 检查编号是否已存在
existing = Problem.query.filter_by(no=no).first()
if existing:
return jsonify({"error": "该编号已存在"}), 400
# 创建问题
problem = Problem(no=no, name=name, category=category, content=content)
db.session.add(problem)
db.session.commit()
return jsonify({"message": "创建成功", "id": problem.id, "no": problem.no, "name": problem.name})
@main_bp.route("/api/problems/<int:problem_id>", methods=["PUT"])
@login_required_json
def update_problem(problem_id):
"""更新问题"""
from app.models import Problem
problem = Problem.query.get(problem_id)
if not problem:
return jsonify({"error": "问题不存在"}), 404
data = request.get_json()
if "name" in data:
problem.name = data["name"].strip()
if "category" in data:
problem.category = data["category"]
if "content" in data:
problem.content = data["content"]
db.session.commit()
return jsonify({"message": "更新成功"})
@main_bp.route("/api/problems/<int:problem_id>", methods=["DELETE"])
@admin_required
def delete_problem(problem_id):
"""删除问题"""
from app.models import Problem
problem = Problem.query.get(problem_id)
if not problem:
return jsonify({"error": "问题不存在"}), 404
# 检查是否有关联数据
from app.models import StudentProblem
if StudentProblem.query.filter_by(problem_db_id=problem_id).first():
return jsonify({"error": "该问题已被学员使用,无法删除"}), 400
db.session.delete(problem)
db.session.commit()
return jsonify({"message": "删除成功"})
# ==================== AI测试接口 ====================
@main_bp.route("/api/config/test", methods=["POST"])
@admin_required
def test_api_connection():
"""测试API连接"""
import requests
config = load_api_config(current_app.config)
provider = config.get("provider", "volcengine")
headers = {
"Authorization": f"Bearer {config.get('api_key', '')}",
"Content-Type": "application/json",
}
payload = {
"model": config.get("model", "doubao-seed-2.0-pro"),
"messages": [{"role": "user", "content": "你好"}],
"max_tokens": 50,
}
try:
# MiniMax 使用 Anthropic 格式的 API
if provider == "minimax":
endpoint = f"{config.get('base_url')}/messages"
payload["max_tokens"] = 50
else:
endpoint = f"{config.get('base_url')}/chat/completions"
response = requests.post(
endpoint,
headers=headers,
json=payload,
timeout=30,
)
if response.status_code == 200:
return jsonify({"success": True, "message": "连接成功"})
else:
return jsonify(
{"success": False, "error": f"API返回错误: {response.status_code}"}
)
except Exception as e:
return jsonify({"success": False, "error": str(e)})