feat: OTP首次绑定 + 三端登录修复 + 管理端权限修复 (2026-07-08)

OTP首次绑定:
- 新增统一 OTP 路由 /auth/otp-* (otp.py + router.py)
- 坐席端 OTP 绑定面板 (OtpBindPanel.vue)
- 管理端 OTP 管理列表 (MfaManage.vue)
- agent_login 签发半认证 token 支持首次绑定流程

三端登录修复:
- 坐席/管理端去掉'返回扫码登录'按钮
- 管理端改为二维码始终可见+轮询扫码状态
- 员工端 /itdesk/ 改为 alias 直接服务 H5 (不再301重定向)
- docker-compose 添加 h5 volume 挂载

管理端权限修复:
- 扫码登录改用 get_user_roles() 替代写死 roles=['agent']
- get_user_roles() 增加 agents.role 回退
- 新增 GET /admin/roles/user-roles 端点
- 角色管理页加载用户角色分配数据

文档更新:
- OTP PRD + 系统设计文档
- 故障排查手册 v1.1 (新增6案例)
- nginx 生产基准配置
This commit is contained in:
Simon
2026-07-08 21:54:57 +08:00
parent 6f0fbbb066
commit 400ce3ddcb
27 changed files with 2822 additions and 312 deletions
+38
View File
@@ -129,6 +129,44 @@ async def get_roles(
return success_response(data=[r.model_dump() for r in role_list])
# ==========================================================================
# 1.5. 用户角色分配列表
# ==========================================================================
# ---------- GET /api/admin/roles/user-roles ----------
@router.get("/user-roles")
async def list_user_role_assignments(
admin: UserInfo = Depends(require_admin),
db: AsyncSession = Depends(get_db),
):
"""获取所有用户角色分配记录。
Returns:
List of user role assignments with employee_id, role info, source, etc.
"""
stmt = (
select(UserRole, Role)
.join(Role, UserRole.role_id == Role.id)
.order_by(UserRole.assigned_at.desc().nulls_last())
)
result = await db.execute(stmt)
rows = result.all()
assignments = []
for user_role, role in rows:
assignments.append({
"employee_id": user_role.employee_id,
"role_name": role.name,
"role_display_name": role.display_name or role.name,
"source": user_role.source or "manual",
"assigned_by": user_role.assigned_by or "",
"assigned_at": user_role.assigned_at.isoformat() if user_role.assigned_at else None,
"expires_at": user_role.expires_at.isoformat() if user_role.expires_at else None,
})
return success_response(data=assignments)
# ==========================================================================
# 2. 用户角色分配/撤销
# ==========================================================================