""" 用户模型 """ from datetime import datetime from typing import Optional from pydantic import BaseModel, EmailStr, Field class User(BaseModel): """用户模型""" id: Optional[int] = None username: str = Field(..., max_length=50) email: EmailStr phone: str = Field(..., max_length=255) wechat_openid: Optional[str] = Field(None, max_length=100) wechat_unionid: Optional[str] = Field(None, max_length=100) wechat_nickname: Optional[str] = Field(None, max_length=100) wechat_avatar_url: Optional[str] = None display_name: Optional[str] = Field(None, max_length=100) avatar_url: Optional[str] = None bio: Optional[str] = None is_active: bool = True email_verified: bool = False is_search: bool = Field(False, description="是否启用联网搜索") created_at: Optional[datetime] = None updated_at: Optional[datetime] = None last_login_at: Optional[datetime] = None hashed_password: Optional[str] = Field(None, max_length=255) # 企业版 enterprise_id: Optional[int] = None department_id: Optional[int] = None role: str = Field("employee", description="admin | leader | employee") is_first_login: bool = True allow_kb_upload: bool = Field(True, description="是否允许上传文件到知识库") class Config: from_attributes = True class UserCreate(BaseModel): """创建用户请求模型""" username: str = Field(..., max_length=50) email: EmailStr phone: str = Field(..., max_length=255) password: str = Field(..., min_length=6) display_name: Optional[str] = Field(None, max_length=100) class PhoneRegisterRequest(BaseModel): """手机号注册请求模型""" phone: str = Field(..., pattern=r'^1[3-9]\d{9}$', description="手机号") code: str = Field(..., min_length=4, max_length=6, description="验证码") password: str = Field(..., min_length=6, description="密码") username: Optional[str] = Field(None, max_length=50, description="用户名,可选") class PhoneLoginRequest(BaseModel): """手机号登录请求模型""" phone: str = Field(..., pattern=r'^1[3-9]\d{9}$', description="手机号") code: Optional[str] = Field(None, min_length=4, max_length=6, description="验证码") password: Optional[str] = Field(None, min_length=6, description="密码") class SendSmsCodeRequest(BaseModel): """发送短信验证码请求模型""" phone: str = Field(..., pattern=r'^1[3-9]\d{9}$', description="手机号") scene: str = Field("login", description="场景:login/register/reset") captcha_id: str = Field(..., description="图形验证码 ID") captcha_code: str = Field(..., min_length=4, max_length=6, description="图形验证码") class WechatLoginRequest(BaseModel): """微信小程序登录请求模型""" code: str = Field(..., description="微信登录凭证 (wx.login 获取)") phone_code: Optional[str] = Field(None, description="手机号授权码 (getPhoneNumber 获取,用于账号合并)") class UserLogin(BaseModel): """用户登录请求模型""" username: str password: str class UserDepartmentInfo(BaseModel): """用户所属部门信息""" id: int name: str parent_id: Optional[int] = None leader_user_id: Optional[int] = None leader_name: Optional[str] = None class UserResponse(BaseModel): """用户响应模型(不包含敏感信息)""" id: int username: str email: str phone: str display_name: Optional[str] = None avatar_url: Optional[str] = None bio: Optional[str] = None is_active: bool email_verified: bool is_search: bool = False created_at: datetime updated_at: datetime last_login_at: Optional[datetime] = None enterprise_id: Optional[int] = None department_id: Optional[int] = None department_name: Optional[str] = None department: Optional[UserDepartmentInfo] = None role: str = "employee" is_first_login: bool = True class Config: from_attributes = True class TokenResponse(BaseModel): """Token 响应模型""" access_token: str token_type: str = "bearer" user: UserResponse