Commit e13c1477 authored by uuo00_n's avatar uuo00_n

feat(仪表盘): 添加学生周课表查询功能

添加 TERM_START_DATE 配置项用于学期开始日期计算
实现学生周课表查询接口,支持按周次查询课表
完善学生实体查询的 ObjectId 处理逻辑
parent 76324c68
# 数据库配置
# 注意:生产环境请通过安全的环境变量管理传递凭据,避免将敏感信息提交到版本库
# MONGODB_URL=mongodb://llm:fSjFMwyShmcH4GdR@datacenter.dldzxx.cn:27017/llm?authSource=llm
MONGODB_URL=mongodb://localhost:27017/
MONGODB_URL=mongodb://llm:fSjFMwyShmcH4GdR@datacenter.dldzxx.cn:27017/llm?authSource=llm
# MONGODB_URL=mongodb://localhost:27017/
DB_NAME=llm
# JWT配置
......@@ -9,6 +9,9 @@ SECRET_KEY=your_secret_key_here
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# 学期配置
TERM_START_DATE=2025-09-01
# Ollama配置
OLLAMA_BASE_URL=http://datacenter.dldzxx.cn:11434/
OLLAMA_MODEL=deepseek-r1:14b
\ No newline at end of file
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel
from typing import List, Optional, Dict, Any
from app.api.deps import require_edition_for_mode, require_role, require_binding
from app.services.dashboard import (
student_today_summary,
student_week_schedule,
homeroom_current_summary,
department_overview,
campus_overview,
......@@ -34,6 +35,21 @@ class StudentTodaySummary(BaseModel):
today_attendance: List[StudentTodayAttendance]
today_conduct: Dict[str, Any]
class StudentWeekScheduleItem(BaseModel):
lesson_id: Optional[str] = None
period: Optional[int] = None
course_name: Optional[str] = None
location: Optional[str] = None
start_time: Optional[str] = None
end_time: Optional[str] = None
teacher_person_id: Optional[str] = None
class StudentWeekSummary(BaseModel):
student: Dict[str, Optional[str]]
current_week: int
week_dates: Dict[int, str]
schedule: Dict[str, List[StudentWeekScheduleItem]]
class HomeroomLesson(BaseModel):
class_id: Optional[str]
course_name: Optional[str]
......@@ -98,6 +114,23 @@ class CampusOverview(BaseModel):
async def student_today(current_user: dict = Depends(require_role(1)), _b: dict = Depends(require_binding("student"))) -> StudentTodaySummary:
return await student_today_summary(current_user)
@router.get(
"/student/week",
summary="学生端:周课表查询",
description="需角色等级≥1且主绑定为学生;返回指定周次(默认当前周)的完整课表,支持 'week' 参数查询下一周。",
response_model=StudentWeekSummary,
responses={
401: {"description": "未认证", "content": {"application/json": {"example": {"detail": "无效的认证凭据"}}}},
403: {"description": "权限不足或未绑定学生", "content": {"application/json": {"example": {"detail": "实体绑定不存在或类型不匹配"}}}},
}
)
async def student_week(
week: Optional[int] = Query(None, description="周次(如 1, 2, ...),不传则默认为当前周"),
current_user: dict = Depends(require_role(1)),
_b: dict = Depends(require_binding("student"))
) -> StudentWeekSummary:
return await student_week_schedule(current_user, week)
@router.get(
"/homeroom/current",
summary="班主任端:当前节次课程与地点、出勤率、请假、指示",
......
......@@ -32,5 +32,8 @@ class Settings(BaseSettings):
CORS_ALLOWED_ORIGINS: str = os.getenv("CORS_ALLOWED_ORIGINS", "*")
GITHUB_DEFAULT_REPO: str = os.getenv("GITHUB_DEFAULT_REPO", "")
GITHUB_TOKEN: str = os.getenv("GITHUB_TOKEN", "")
# 学期配置
TERM_START_DATE: str = os.getenv("TERM_START_DATE", "2025-09-01") # 默认开学日期
settings = Settings()
from datetime import datetime
from datetime import datetime, timedelta
from typing import Dict, List, Any
from bson import ObjectId
from fastapi import HTTPException
from app.db.mongodb import db
from app.core.config import settings
async def _today_iso() -> str:
return datetime.now().date().isoformat()
......@@ -10,6 +11,34 @@ async def _today_iso() -> str:
async def _weekday() -> int:
return datetime.now().isoweekday()
async def _get_current_week() -> int:
try:
start_date = datetime.strptime(settings.TERM_START_DATE, "%Y-%m-%d").date()
today = datetime.now().date()
delta = today - start_date
if delta.days < 0:
return 1
return (delta.days // 7) + 1
except Exception:
return 1
def _is_week_valid(week: int, week_range: str) -> bool:
if not week_range:
return True
try:
parts = week_range.split(',')
for part in parts:
if '-' in part:
start, end = map(int, part.split('-'))
if start <= week <= end:
return True
else:
if int(part) == week:
return True
except:
pass
return False
async def _current_period() -> int:
h = datetime.now().hour
if h < 10:
......@@ -27,13 +56,21 @@ async def _get_primary_binding(account_id: ObjectId) -> Dict[str, Any]:
return b
async def _get_student_entity(account_id: ObjectId, binding: Dict[str, Any]) -> Dict[str, Any]:
s = await db.db.students.find_one({"person_id": binding.get("person_id")})
pid = binding.get("person_id")
if isinstance(pid, str) and ObjectId.is_valid(pid):
pid = ObjectId(pid)
s = await db.db.students.find_one({"person_id": pid})
if s:
return s
raise HTTPException(status_code=404, detail="未找到学生实体")
async def _get_teacher_entity(account_id: ObjectId, binding: Dict[str, Any]) -> Dict[str, Any]:
t = await db.db.teachers.find_one({"person_id": binding.get("person_id")})
pid = binding.get("person_id")
if isinstance(pid, str) and ObjectId.is_valid(pid):
pid = ObjectId(pid)
t = await db.db.teachers.find_one({"person_id": pid})
if t:
return t
raise HTTPException(status_code=404, detail="未找到教师实体")
......@@ -97,6 +134,63 @@ async def student_today_summary(current_user: Dict[str, Any]) -> Dict[str, Any]:
"today_conduct": conduct,
}
async def student_week_schedule(current_user: Dict[str, Any], week: int = None) -> Dict[str, Any]:
if week is None:
week = await _get_current_week()
student = await _get_student_by_user(current_user["_id"])
class_id = student.get("class_id") if student else None
try:
start_date = datetime.strptime(settings.TERM_START_DATE, "%Y-%m-%d").date()
monday_of_week = start_date + timedelta(weeks=week-1)
except:
monday_of_week = datetime.now().date()
week_dates = {}
for i in range(1, 8):
d = monday_of_week + timedelta(days=i-1)
week_dates[i] = d.isoformat()
schedules_by_day = {str(i): [] for i in range(1, 8)}
if class_id:
cursor = db.db.schedules.find({"classes.class_id": class_id}).sort("period", 1)
async for doc in cursor:
w_range = doc.get("week_range", "")
if not _is_week_valid(week, w_range):
continue
wd = doc.get("weekday")
loc = None
for c in doc.get("classes", []):
if c.get("class_id") == class_id:
loc = c.get("location")
break
item = {
"lesson_id": doc.get("lesson_id"),
"period": doc.get("period"),
"course_name": doc.get("course_name"),
"location": loc,
"start_time": doc.get("start_time"),
"end_time": doc.get("end_time"),
"teacher_person_id": str(doc.get("teacher_person_id")) if doc.get("teacher_person_id") else None
}
if str(wd) in schedules_by_day:
schedules_by_day[str(wd)].append(item)
return {
"student": {
"student_id": student.get("student_id") if student else None,
"name": student.get("name") if student else None,
"class_id": class_id,
},
"current_week": week,
"week_dates": week_dates,
"schedule": schedules_by_day
}
async def homeroom_current_summary(current_user: Dict[str, Any]) -> Dict[str, Any]:
today = await _today_iso()
weekday = await _weekday()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment