from datetime import datetime import json import os from pathlib import Path from typing import List from uuid import uuid4 from fastapi import ( APIRouter, Depends, File, Form, HTTPException, Request, UploadFile, status, ) from fastapi.responses import HTMLResponse, RedirectResponse from starlette.templating import Jinja2Templates from services.services import XBXS from config import BASE_DIR from exceptions.unauthorized import UnauthorizedError router = APIRouter() templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) def get_xbxs(request: Request) -> XBXS: token = request.cookies.get("xbxs_token") if not token: # 没有 token 跳转到登录页面 raise HTTPException( status_code=status.HTTP_303_SEE_OTHER, detail="Redirect to login", headers={"Location": "/login"}, ) return XBXS(token=token) @router.get("/home") async def home( request: Request, xbxs: XBXS = Depends(get_xbxs), ): return templates.TemplateResponse( "home.html", { "request": request, "active": "home", }, ) @router.get("/profile") async def profile( request: Request, xbxs: XBXS = Depends(get_xbxs), ): try: student = await xbxs.get_student_info_cached() return templates.TemplateResponse( "profile.html", { "request": request, "student": student, "active": "profile", }, ) except UnauthorizedError as e: raise HTTPException( status_code=401, detail=e.message, ) @router.get("/sign") async def sign_list( request: Request, xbxs: XBXS = Depends(get_xbxs), ): try: result = await xbxs.get_know_list() except UnauthorizedError as e: raise HTTPException( status_code=401, detail=e.message, ) rows = result.get("rows", []) now = datetime.now() for item in rows: # 1️⃣ 计算是否结束(核心) end_str = f"{item['endDate']} {item['endTime']}" end_time = datetime.strptime(end_str, "%Y-%m-%d %H:%M") item["isEnded"] = now > end_time return templates.TemplateResponse( "sign_list.html", { "request": request, "list": rows, "total": result.get("total", 0), }, ) @router.get("/sign/{knowing_id}", response_class=HTMLResponse) async def sign_detail( knowing_id: int, request: Request, xbxs: XBXS = Depends(get_xbxs), ): try: know_detail = await xbxs.get_know(str(knowing_id)) except UnauthorizedError as e: raise HTTPException( status_code=401, detail=e.message, ) data = know_detail.get("data", {}) # 获取具体的数据 knowing_name = data.get("knowingName", "未知签到") start_date = data.get("startDate", "未知") start_time = data.get("startTime", "未知") end_time = data.get("endTime", "未知") send_name = data.get("sendName", "未知") send_role = data.get("sendRole", "未知") is_check = data.get("isCheck", 0) is_picture = data.get("isPicture", 0) # is_finish_know = data.get("isFinishKnowing", 0) locations = json.loads(data.get("location", [])) return templates.TemplateResponse( "sign_detail.html", { "request": request, "know_id": knowing_id, "knowing_name": knowing_name, "start_date": start_date, "start_time": start_time, "end_time": end_time, "send_name": send_name, "send_role": send_role, "is_check": is_check, "is_picture": is_picture, "locations": locations, # "is_finish_know": is_finish_know, }, ) # 完善的 sign 完成接口 @router.post("/sign/{know_id}/complete") async def complete_sign( know_id: int, request: Request, location: str = Form(...), # 获取经纬度,必填 address: str = Form(...), # 获取经纬度,必填 remark: str = Form(...), # 获取备注,必填 images: List[UploadFile] = File(...), # 获取上传的图片,支持多张 xbxs: XBXS = Depends(get_xbxs), ): # 备注必填,未填写时返回错误 if not remark: raise HTTPException(status_code=400, detail="备注是必填项") try: await xbxs.update_student_know(str(know_id), remark, address, location, images) except UnauthorizedError as e: raise HTTPException( status_code=401, detail=e.message, ) except Exception as e: raise HTTPException(status_code=500, detail="保存签到数据失败") # 成功后跳转到签到列表 return RedirectResponse(url="/sign", status_code=status.HTTP_303_SEE_OTHER)