智教助手平台:完整初始化

- 前端:Vue3 + TS + Element Plus,24 个页面路由(课件/组题/教案/动画/思维导图/作文批改/命题/课堂/资源/社区等)
- 后端:FastAPI + SQLAlchemy + SQLite,17 个路由模块,AI 服务层含降级模板
- AI:glm-5.x 推理模型已禁用思维链,确保输出真实内容
- 修复:ai_service 两处请求体注入 enable_thinking/thinking disabled
- 测试账号:13900999999 / test1234
This commit is contained in:
Zhang Jing Xuan
2026-07-29 16:29:10 +08:00
commit 0841b1a103
193 changed files with 44995 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
import logging
from datetime import datetime, timedelta, timezone
from jose import jwt, JWTError
import bcrypt
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from config import get_settings
from database import get_db
from models.user import User
logger = logging.getLogger(__name__)
security = HTTPBearer()
optional_security = HTTPBearer(auto_error=False)
settings = get_settings()
def get_password_hash(password: str) -> str:
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password.encode("utf-8"), salt)
return hashed.decode("utf-8")
def verify_password(plain_password: str, hashed_password: str) -> bool:
return bcrypt.checkpw(plain_password.encode("utf-8"), hashed_password.encode("utf-8"))
def create_access_token(user_id: int) -> str:
expire = datetime.now(timezone.utc) + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
payload = {"sub": str(user_id), "exp": expire, "type": "access"}
token = jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
logger.info(f"Created token for user {user_id}")
return token
def create_refresh_token(user_id: int) -> str:
expire = datetime.now(timezone.utc) + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
payload = {"sub": str(user_id), "exp": expire, "type": "refresh"}
return jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db),
) -> User:
token = credentials.credentials
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
user_id = int(payload.get("sub"))
logger.info(f"Token decoded for user {user_id}")
except JWTError as e:
logger.error(f"JWT decode error: {e}")
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的认证凭证")
except (TypeError, ValueError) as e:
logger.error(f"Invalid sub claim: {e}")
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的认证凭证")
user = db.query(User).filter(User.id == user_id).first()
if user is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在")
if not user.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账号已被禁用")
return user
def get_optional_current_user(
credentials: HTTPAuthorizationCredentials | None = Depends(optional_security),
db: Session = Depends(get_db),
) -> User | None:
if credentials is None:
return None
try:
payload = jwt.decode(credentials.credentials, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
user_id = int(payload.get("sub"))
except (JWTError, TypeError, ValueError):
return None
user = db.query(User).filter(User.id == user_id).first()
if user is None or not user.is_active:
return None
return user
def get_admin_user(user: User = Depends(get_current_user)) -> User:
if user.role != "admin":
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="需要管理员权限")
return user