7264184315
绑定流程改为 rural-optical-rectify 方案:
- 企微菜单「绑定账号」发送 click 事件(而非 OAuth 跳转)
- 回调 POST 接收事件 → 生成绑定 token → 推送绑定链接
- 前端 WecomBind.vue (/wecom-bind) 确认绑定
- 新增 POST /api/wecom/bind-confirm (JWT 保护)
支局长手动管理:
- 新增 PUT /api/users/{id}/wecom 绑定/解绑端点
- UserManage.vue 编辑对话框新增企微 UserID 字段
- 表格操作列新增「解绑」按钮
- 重复绑定检测
wecom.py 新增:
- in-memory bind token store (TTL 600s)
- send_text_card() 卡片消息方法
- access_token 属性暴露
Co-Authored-By: Claude <noreply@anthropic.com>
122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
import uuid
|
|
from typing import Optional
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
from app.database import get_db
|
|
from app.middleware.auth import get_current_user, require_director
|
|
from app.models.user import User
|
|
from app.schemas.customer import UserOut
|
|
|
|
router = APIRouter(prefix="/users", tags=["Users"])
|
|
|
|
|
|
class UpdateUserRoleRequest(BaseModel):
|
|
role: str # manager / director / leader
|
|
department: str = ""
|
|
|
|
|
|
@router.get("/", response_model=list[UserOut])
|
|
async def list_users(
|
|
role: Optional[str] = Query(None),
|
|
current_user: dict = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""List all users. Used for companion selection, assignment, etc."""
|
|
query = select(User)
|
|
if role:
|
|
query = query.where(User.role == role)
|
|
query = query.order_by(User.name)
|
|
result = await db.execute(query)
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.get("/me")
|
|
async def get_current_user_info(
|
|
current_user: dict = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Get current user's full profile."""
|
|
result = await db.execute(select(User).where(User.id == uuid.UUID(current_user["user_id"])))
|
|
user = result.scalar_one_or_none()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return {
|
|
"id": str(user.id),
|
|
"casdoor_id": user.casdoor_id,
|
|
"name": user.name,
|
|
"role": user.role,
|
|
"department": user.department,
|
|
"wecom_userid": user.wecom_userid,
|
|
}
|
|
|
|
|
|
@router.put("/{user_id}/role")
|
|
async def update_user_role(
|
|
user_id: str,
|
|
data: UpdateUserRoleRequest,
|
|
current_user: dict = Depends(require_director),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Director updates a user's role. Only director can do this."""
|
|
if data.role not in ("manager", "director", "leader"):
|
|
raise HTTPException(status_code=400, detail="Invalid role. Must be manager/director/leader")
|
|
|
|
result = await db.execute(select(User).where(User.id == uuid.UUID(user_id)))
|
|
user = result.scalar_one_or_none()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
|
|
user.role = data.role
|
|
if data.department:
|
|
user.department = data.department
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
|
|
return {
|
|
"id": str(user.id),
|
|
"name": user.name,
|
|
"role": user.role,
|
|
"department": user.department,
|
|
}
|
|
|
|
|
|
class UpdateWecomRequest(BaseModel):
|
|
wecom_userid: Optional[str] = None # None or "" to unbind
|
|
|
|
|
|
@router.put("/{user_id}/wecom")
|
|
async def update_user_wecom(
|
|
user_id: str,
|
|
data: UpdateWecomRequest,
|
|
current_user: dict = Depends(require_director),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Director binds or unbinds a user's WeChat Work account."""
|
|
result = await db.execute(select(User).where(User.id == uuid.UUID(user_id)))
|
|
user = result.scalar_one_or_none()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
|
|
new_id = (data.wecom_userid or "").strip()
|
|
|
|
# Check duplicate
|
|
if new_id:
|
|
dup = await db.execute(
|
|
select(User).where(User.wecom_userid == new_id, User.id != uuid.UUID(user_id))
|
|
)
|
|
existing = dup.scalar_one_or_none()
|
|
if existing:
|
|
raise HTTPException(status_code=400, detail=f"该企微ID已被「{existing.name}」绑定")
|
|
|
|
user.wecom_userid = new_id if new_id else None
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
|
|
return {
|
|
"id": str(user.id),
|
|
"name": user.name,
|
|
"wecom_userid": user.wecom_userid,
|
|
}
|