# -*- 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 cause:UserEditRequest 需要同时携带角色+绑定字段 | Summary:UserEditRequest 扩展 assistant_id/staff_id 字段,支持角色+绑定合并提交 | Verify:PATCH /users/{id} 接受 assistantId/staffId 参数 - 2026-03-24 | Prompt: 审核弹窗头像昵称+排版优化 | Direct cause:ApplicationListItem 缺少 avatar_url | Summary:新增 avatar_url 字段 | Verify:GET /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="新角色 code(coach/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")