Files
qiji/backend/app/api/auth.py
T
v6ole 2187be7aeb feat: 操作日志系统 + 日期修复 + 协同去重 + 主题持久化 + 计划自动完成
本次累积提交包含以下功能:

1. 修复:el-date-picker 缺失 value-format 导致日期保存偏移(8处)
2. 新增:协同拜访 visit_group_id 去重机制(完整副本 + 周报合并 + 亮灯去重)
3. 新增:计划自动完成(创建计划检测已有拜访 / 编辑拜访触发)
4. 新增:拜访表单选择客户后自动预填过期计划内容
5. 新增:移动端主题切换按钮 + 后端持久化
6. 新增:操作日志系统 (audit_logs),全覆盖 8 个模块 CRUD
7. 新增:PC端「我的数据」支局长/领导视角客户经理列

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-30 12:01:14 +08:00

76 lines
2.9 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.schemas.user import TokenResponse, WecomLoginRequest, CasdoorLoginRequest, WecomBindRequest
from app.services.auth import (
exchange_casdoor_code, get_or_create_user_from_casdoor,
get_user_by_wecom_id, bind_wecom_user, build_token_for_user,
)
from app.services.wecom import wecom_client
from app.config import settings
router = APIRouter(prefix="/auth", tags=["Authentication"])
@router.post("/casdoor-login", response_model=TokenResponse)
async def casdoor_login(req: CasdoorLoginRequest, db: AsyncSession = Depends(get_db)):
"""Standard Casdoor OIDC login — exchange code for userinfo, get or create user, return JWT."""
userinfo = await exchange_casdoor_code(req.code)
if not userinfo:
raise HTTPException(status_code=400, detail="Failed to exchange code with Casdoor")
casdoor_id = userinfo.get("sub") or userinfo.get("id")
if not casdoor_id:
raise HTTPException(status_code=400, detail="Invalid userinfo from Casdoor")
name = userinfo.get("name") or userinfo.get("preferred_username") or casdoor_id
role = userinfo.get("role", "manager")
user = await get_or_create_user_from_casdoor(db, casdoor_id, name, role)
token = build_token_for_user(user)
return TokenResponse(
access_token=token,
user_id=str(user.id),
name=user.name,
role=user.role,
theme=user.theme or "editorial",
)
@router.post("/wecom-login")
async def wecom_login(req: WecomLoginRequest, db: AsyncSession = Depends(get_db)):
"""WeChat Work silent login — exchange wecom code for userid, find bound user, return JWT."""
userinfo = await wecom_client.get_userinfo_by_code(req.code)
if not userinfo:
raise HTTPException(status_code=400, detail="Failed to exchange wecom code")
wecom_userid = userinfo.get("UserId") or userinfo.get("userid")
if not wecom_userid:
raise HTTPException(status_code=400, detail="Could not get userid from wecom")
user = await get_user_by_wecom_id(db, wecom_userid)
if user:
token = build_token_for_user(user)
return TokenResponse(
access_token=token,
user_id=str(user.id),
name=user.name,
role=user.role,
theme=user.theme or "editorial",
)
raise HTTPException(
status_code=403,
detail="企业微信账号尚未绑定。请在企业微信内使用一次性绑定链接完成绑定。",
)
@router.post("/bind-wecom")
async def bind_wecom(req: WecomBindRequest, db: AsyncSession = Depends(get_db)):
"""Deprecated unsafe binding flow. Use /wecom/bind-confirm with a one-time token."""
raise HTTPException(
status_code=410,
detail="该绑定接口已停用,请使用企业微信一次性绑定链接。",
)