学生端选课进课闭环

This commit is contained in:
CakeCN
2025-09-06 21:27:28 +08:00
parent a0d154b434
commit 6883a999e9
24 changed files with 634 additions and 217 deletions

View File

@@ -43,6 +43,13 @@ def login_teacher_post():
return jsonify({"success": ok, "message": msg})
@bp.get("/switch-role/<role>")
@require_role
def switch_role(role):
if role == "teacher":
return redirect(url_for("main.dashboard"))
else:
return redirect(url_for("material.teacherboard"))
@bp.get("/logout")
def logout():
logout_user()

View File

@@ -1,12 +1,22 @@
# myapp/views/dashboard.py
import json
from flask import Blueprint, render_template, request, jsonify, redirect, url_for
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, current_app, session
from ..auth.decorators import require_role
from ..services.user_service import get_or_load_current_user, add_course_for_current_user
from ..services.course_service import load_course, user_selected_course_briefs
from ..services.course_service import load_material, user_selected_course_briefs, get_new_edit_materials,user_selected_course
bp = Blueprint("main", __name__) # 根路径蓝图
@bp.post("/dashboard/get_course_progress")
@require_role
def get_course_progress():
user_obj = get_or_load_current_user()
course_id = request.json.get("course_id")
if not course_id:
return jsonify({"success": False, "message": "缺少 course_id"}), 400
return jsonify({"success": True, "message": "获取课程进度成功", "data": user_obj.get_course_progress(course_id)}), 200
@bp.get("/dashboard")
@require_role
def dashboard():
@@ -14,17 +24,18 @@ def dashboard():
if user_obj is None:
return redirect(url_for("auth.login"))
user_course_data = user_selected_course_briefs(user_obj)
user_course_data = user_selected_course(user_obj)
return render_template(
"dashboard.html",
user_data=user_obj.to_json_without_dialog(),
user_data=user_obj.__json__(),
user_course_data=json.dumps(user_course_data, ensure_ascii=False),
user_selected_course=user_course_data
)
@bp.get("/course/<course_id>")
@require_role
def course(course_id):
c = load_course(course_id)
c = load_material(course_id)
return render_template("course.html", course_id=course_id, course_data=c)
@bp.post("/select_course")
@@ -35,8 +46,13 @@ def select_course():
if not course_id:
return jsonify({"success": False, "message": "缺少 course_id"}), 400
course_data = load_course(course_id)
ok = add_course_for_current_user(course_id, course_data)
# course_data = load_material(course_id)
user_list = current_app.extensions["users_list"]
uuid2username = current_app.extensions["uuid2username"]
username = uuid2username[session["user_uuid"]]
user_obj = user_list.get_user_by_name(username)
ok = user_obj.select_new_course(course_id, load_material(course_id))
if not ok:
return jsonify({"success": False, "message": "未登录或会话失效"}), 401
return jsonify({"success": True, "message": "课程选择成功"})
@@ -49,10 +65,8 @@ def home_index():
return redirect(url_for("auth.login"))
selected_courses = list(getattr(user_obj, "select_course", []))
# 课程目录:依据你的 CourseList 暴露的接口进行传递(这里直接传对象,模板里用)
from flask import current_app
course_list = current_app.extensions["course_list"]
course_list = get_new_edit_materials(10)
print(course_list)
return render_template(
"index.html",
courses_data=course_list,

View File

@@ -2,32 +2,25 @@ import os
from flask import Blueprint, jsonify, current_app, send_from_directory
from ..services.markdown_service import (
convert_markdown_to_html, wrap_with_styles,
save_html, copy_images
save_html, copy_images, load_markdown_file
)
bp = Blueprint("markdown", __name__)
@bp.route("/<course_id>-<filename>-markdown", methods=["GET"])
def convert_md(course_id, filename):
md_file_path = os.path.join(current_app.config["MARKDOWN_DIR"], course_id, f"{filename}.md")
if not os.path.exists(md_file_path):
return jsonify({"error": "Markdown file not found"}), 404
@bp.route("/<course_id>-<chapter_name>-<lesson_name>-markdown", methods=["GET"])
def convert_md(course_id, chapter_name, lesson_name):
print(f"convert_md: {course_id}, {chapter_name}, {lesson_name}")
md_file = load_markdown_file(course_id, chapter_name, lesson_name)
# 转换 markdown -> html
html = convert_markdown_to_html(md_file_path)
html = convert_markdown_to_html(md_file)
html_with_styles = wrap_with_styles(html)
# 保存 HTML 文件到 static
html_output_path = os.path.join(current_app.config["STATIC_DIR"], f"{filename}.html")
html_output_path = os.path.join(current_app.config["STATIC_DIR"], f"{chapter_name}-{lesson_name}.html")
save_html(html_with_styles, html_output_path)
# 拷贝图片资源
image_source = os.path.join(current_app.config["MARKDOWN_DIR"], course_id, current_app.config["IMAGE_DIR"], filename)
image_target = os.path.join(current_app.config["STATIC_DIR"], current_app.config["IMAGE_DIR"], filename)
copy_images(image_source, image_target)
return jsonify({"html_url": f"/static/{filename}.html"})
return jsonify({"html_url": f"/static/{chapter_name}-{lesson_name}.html"})
# 提供静态文件访问
@bp.route("/static/<path:filename>")

View File

@@ -5,8 +5,8 @@ from ..services.backboard_service import realtime_response
bp = Blueprint("vscode", __name__)
@bp.route("/desktop/<user_uuid>/<course_id>/<chapter_id>")
def desktop(user_uuid, course_id, chapter_id):
@bp.route("/desktop/<user_uuid>/<course_id>/<chapter_name>/<lesson_name>")
def desktop(user_uuid, course_id, chapter_name, lesson_name):
username2uuid = current_app.extensions["username2uuid"]
uuid2username = current_app.extensions["uuid2username"]
userid_recorder = current_app.extensions["userid_recorder"]
@@ -23,7 +23,7 @@ def desktop(user_uuid, course_id, chapter_id):
# 按课程/章节创建工作目录
base_root = current_app.config["STUDENT_WORKSPACE_ROOT"]
path_dir = os.path.join(base_root, user_id, course_id, chapter_id)
path_dir = os.path.join(base_root, user_id, course_id, chapter_name)
os.makedirs(path_dir, exist_ok=True)
# 写 .config并按需要转换为 WSL 路径)
@@ -37,7 +37,8 @@ def desktop(user_uuid, course_id, chapter_id):
tmpd = {
"user_uuid": session["user_uuid"],
"course_id": course_id,
"chapter_id": chapter_id,
"chapter_name": chapter_name,
"lesson_name": lesson_name,
"path": path_for_vscode
}
with open(config_path, "w", encoding="utf-8") as f:
@@ -48,16 +49,16 @@ def desktop(user_uuid, course_id, chapter_id):
return render_template(
"desktop.html",
vscode_web_url=current_app.config["VSCODE_WEB_URL"],
user_uuid=session["user_uuid"], course_id=course_id, chapter_id=chapter_id,
workspace_path=path_for_vscode
user_uuid=session["user_uuid"], course_id=course_id, chapter_name=chapter_name, lesson_name=lesson_name,
workspace_path=path_for_vscode,
)
@bp.route("/desktop_nouser/<course_id>/<chapter_id>")
def desktop_nouser(course_id, chapter_id):
@bp.route("/desktop_nouser/<course_id>/<chapter_name>/<lesson_name>")
def desktop_nouser(course_id, chapter_name, lesson_name):
if "user_uuid" not in session:
return redirect(url_for("auth.login")) # 如果你有 auth 蓝图
user_uuid = session["user_uuid"]
return redirect(url_for("vscode.desktop", user_uuid=user_uuid, course_id=course_id, chapter_id=chapter_id))
return redirect(url_for("vscode.desktop", user_uuid=user_uuid, course_id=course_id, chapter_name=chapter_name, lesson_name=lesson_name))
@bp.route("/vscode_data", methods=["POST"])
def vscode_data():