Files
Neo-ZQYY/apps/backend/app/schemas/tenant_users.py
Neo 6f8f12314f feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:03:48 +08:00

118 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
租户管理后台 — 用户审核 + 用户管理 Pydantic Schema。
覆盖:申请列表、关联建议、审核通过/拒绝、用户列表、编辑、绑定、角色列表、人员候选。
需求: 3.2, 4.1
AI_CHANGELOG
- 2026-03-23 17:00:00 | Prompt: P20260323-164500审核弹窗改造| Direct cause新增 roles + site-staff 端点需要响应 Schema | Summary新增 RoleItem角色列表项+ StaffCandidate人员候选项source 区分 assistant/staff| Verify后端 /roles 和 /site-staff 返回正确 JSON 结构
- 2026-03-24 | Prompt: 用户管理绑定功能改造 | Direct causeUserEditRequest 需要同时携带角色+绑定字段 | SummaryUserEditRequest 扩展 assistant_id/staff_id 字段,支持角色+绑定合并提交 | VerifyPATCH /users/{id} 接受 assistantId/staffId 参数
- 2026-03-24 | Prompt: 审核弹窗头像昵称+排版优化 | Direct causeApplicationListItem 缺少 avatar_url | Summary新增 avatar_url 字段 | VerifyGET /applications 返回 avatarUrl
"""
from __future__ import annotations
from pydantic import Field
from app.schemas.base import CamelModel
# ── 用户申请审核 ──────────────────────────────────────────
class ApplicationListItem(CamelModel):
"""申请列表项。"""
id: int
user_id: int
nickname: str | None = None
avatar_url: str | None = None
phone: str | None = None
site_code: str | None = None
applied_role_text: str | None = None
employee_number: str | None = None
created_at: str | None = None
status: str # pending / approved / rejected
class MatchSuggestion(CamelModel):
"""关联匹配建议。"""
assistant_id: int | None = None
staff_id: int | None = None
name: str
number: str | None = None
source_table: str # v_dim_assistant / v_dim_staff
class ApproveRequest(CamelModel):
"""审核通过请求。"""
role: str = Field(..., min_length=1, description="分配角色coach/staff/head_coach/manager")
assistant_id: int | None = Field(None, description="关联助教 ID")
staff_id: int | None = Field(None, description="关联员工 ID")
class RejectRequest(CamelModel):
"""审核拒绝请求。"""
reason: str = Field(..., min_length=1, description="拒绝原因")
# ── 用户管理 ──────────────────────────────────────────────
class UserListItem(CamelModel):
"""用户列表项。"""
id: int
nickname: str | None = None
role: str | None = None # 角色中文名(显示用)
role_code: str | None = None # 角色 code提交用
assistant_id: int | None = None # 当前绑定的助教 ID
staff_id: int | None = None # 当前绑定的员工 ID
assistant_name: str | None = None
site_name: str | None = None
site_id: int | None = None
status: str # approved / disabled
class UserEditRequest(CamelModel):
"""用户编辑请求(合并角色+绑定)。
角色与绑定互斥coach 只能绑 assistant_id其他角色只能绑 staff_id。
换角色时后端自动清除旧绑定。staffBinding="none" 表示解绑。
"""
role: str | None = Field(None, description="新角色 codecoach/staff/head_coach/manager")
site_id: int | None = Field(None, description="新门店 ID")
assistant_id: int | None = Field(None, description="关联助教 ID仅 coach 角色)")
staff_id: int | None = Field(None, description="关联员工 ID仅非 coach 角色)")
# CHANGE 2026-03-23 | 移除 status 字段:租户不能禁用用户,只能移除店铺关系
# CHANGE 2026-03-24 | 合并绑定字段:角色+绑定同一请求提交,换角色自动清除旧绑定
class UserBindingRequest(CamelModel):
"""用户绑定修改请求。"""
assistant_id: int | None = Field(None, description="关联助教 ID")
staff_id: int | None = Field(None, description="关联员工 ID")
# ── 角色 + 人员候选 ──────────────────────────────────────
# [CHANGE P20260323-164500] intent: 审核弹窗角色动态化 + 人员联动所需的响应 Schema
# assumptions: StaffCandidate.source 区分 assistant/staff前端据此构造 staffBinding 值
class RoleItem(CamelModel):
"""角色列表项(从 auth.roles 动态读取)。"""
id: int
code: str
name: str
description: str | None = None
class StaffCandidate(CamelModel):
"""人员候选项(审核弹窗关联下拉用)。"""
id: int = Field(..., description="assistant_id 或 staff_id")
identity_label: str | None = Field(None, description="身份角色level / staff_identity 的原始值)")
name: str = Field(..., description="姓名")
mobile: str | None = Field(None, description="手机号")
entry_time: str | None = Field(None, description="入职时间")
source: str = Field(..., description="assistant / staff")