chore: 整理项目结构,清理归档文件,更新部署配置

This commit is contained in:
Simon
2026-07-04 21:01:39 +08:00
parent 8bd4ab0366
commit 64ff1bf7d5
508 changed files with 43575 additions and 14129 deletions
@@ -0,0 +1,5 @@
# =============================================================================
# 企微智能IT支持服务台 — Schema 包初始化
# =============================================================================
# 说明:导出所有 Pydantic Schema,方便统一导入
# =============================================================================
@@ -0,0 +1,103 @@
# =============================================================================
# 企微智能IT支持服务台 — 坐席 Pydantic Schema
# =============================================================================
# 说明:定义坐席相关的请求/响应数据结构
# 包含:登录、状态更新、响应三种 Schema
# =============================================================================
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator
# --------------------------------------------------------------------------
# 坐席状态合法值
# --------------------------------------------------------------------------
VALID_AGENT_STATUSES = {"online", "offline", "busy"}
# --------------------------------------------------------------------------
# 坐席登录 Schema
# --------------------------------------------------------------------------
class AgentLogin(BaseModel):
"""坐席登录请求 Schema。
第一步使用简单的用户名密码登录。
user_id 对应企微通讯录中的 UserID。
Attributes:
user_id: 企微用户ID
name: 坐席姓名
"""
user_id: str = Field(..., min_length=1, max_length=64, description="企微用户ID")
name: str = Field(..., min_length=1, max_length=128, description="坐席姓名")
# --------------------------------------------------------------------------
# 坐席状态更新 Schema
# --------------------------------------------------------------------------
class AgentStatusUpdate(BaseModel):
"""坐席状态更新请求 Schema。
坐席上线、离线、设为忙碌时使用。
Attributes:
status: 新的坐席状态
"""
status: str = Field(..., description="坐席状态: online/offline/busy")
@field_validator("status")
@classmethod
def validate_status(cls, v: str) -> str:
"""校验坐席状态值是否合法。"""
if v not in VALID_AGENT_STATUSES:
raise ValueError(f"无效的坐席状态: {v},合法值为: {VALID_AGENT_STATUSES}")
return v
# --------------------------------------------------------------------------
# 坐席响应 Schema(返回给前端的数据结构)
# --------------------------------------------------------------------------
class AgentResponse(BaseModel):
"""坐席响应 Schema。
返回给前端的坐席数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 坐席ID
user_id: 企微用户ID
name: 坐席姓名
status: 坐席状态
current_load: 当前服务会话数
max_load: 最大同时服务数
created_at: 创建时间
updated_at: 更新时间
"""
id: str
user_id: str
name: str
status: str
current_load: int
max_load: int
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 坐席列表响应 Schema
# --------------------------------------------------------------------------
class AgentListResponse(BaseModel):
"""坐席列表响应 Schema。
Attributes:
items: 坐席列表
"""
items: List[AgentResponse]
@@ -0,0 +1,247 @@
# =============================================================================
# 企微智能IT支持服务台 — 会话 Pydantic Schema
# =============================================================================
# 说明:定义会话相关的请求/响应数据结构
# 包含:创建、更新、响应三种 Schema
# tags 字段使用 JSONB 结构,定义了详细的子结构
# =============================================================================
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, field_validator
# --------------------------------------------------------------------------
# tags JSONB 字段的子结构定义
# --------------------------------------------------------------------------
class ConversationTags(BaseModel):
"""会话标签集合 — 对应 conversations.tags JSONB 字段。
记录会话的各种标记状态,用于坐席端展示和排序。
Attributes:
hand_raise: 举手标记(员工说"转人工"或点击摇人按钮)
need_intervene: 需介入标记(追问超过N轮)
emotion: 情绪标记(neutral/worried/angry/urgent
emotion_keywords: 触发情绪标记的关键词列表
repeat_count: 追问轮次计数
"""
# 举手标记(员工明确要求转人工)
hand_raise: bool = Field(default=False, description="举手标记")
# 需介入标记(同一问题追问超过阈值)
need_intervene: bool = Field(default=False, description="需介入标记")
# 情绪标记(neutral: 正常, worried: 担忧, angry: 愤怒, urgent: 紧急)
emotion: str = Field(
default="neutral",
description="情绪标记: neutral/worried/angry/urgent",
)
# 触发情绪标记的关键词列表
emotion_keywords: List[str] = Field(
default_factory=list,
description="触发情绪标记的关键词",
)
# 追问轮次计数(同一会话中员工连续追问的次数)
repeat_count: int = Field(default=0, description="追问轮次计数")
# --------------------------------------------------------------------------
# 会话状态枚举值校验
# --------------------------------------------------------------------------
VALID_STATUSES = {"ai_handling", "queued", "serving", "resolved"}
# --------------------------------------------------------------------------
# 创建会话 Schema(从企微消息创建会话时使用)
# --------------------------------------------------------------------------
class ConversationCreate(BaseModel):
"""创建会话请求 Schema。
从企微消息回调创建新会话时使用,
只需要员工ID和姓名,其他信息后续补充。
Attributes:
employee_id: 企微员工UserID
employee_name: 员工姓名
department: 部门
position: 岗位
level: 等级
"""
employee_id: str = Field(..., min_length=1, max_length=64, description="企微员工UserID")
employee_name: str = Field(default="", max_length=128, description="员工姓名")
department: str = Field(default="", max_length=256, description="部门")
position: str = Field(default="", max_length=128, description="岗位")
level: str = Field(default="", max_length=64, description="等级")
# --------------------------------------------------------------------------
# 更新会话 Schema(坐席修改会话信息时使用)
# --------------------------------------------------------------------------
class ConversationUpdate(BaseModel):
"""更新会话请求 Schema。
坐席更新会话信息时使用,所有字段可选(只更新传入的字段)。
Attributes:
employee_name: 员工姓名
department: 部门
position: 岗位
level: 等级
is_vip: VIP标记
tags: 标签集合
urgency_score: 紧急度评分
assigned_agent_id: 分配的坐席ID
last_message_summary: 最后消息摘要
"""
employee_name: Optional[str] = Field(None, max_length=128, description="员工姓名")
department: Optional[str] = Field(None, max_length=256, description="部门")
position: Optional[str] = Field(None, max_length=128, description="岗位")
level: Optional[str] = Field(None, max_length=64, description="等级")
is_vip: Optional[bool] = Field(None, description="VIP标记")
tags: Optional[ConversationTags] = Field(None, description="标签集合")
urgency_score: Optional[int] = Field(None, ge=1, le=5, description="紧急度1-5")
assigned_agent_id: Optional[str] = Field(None, max_length=64, description="分配的坐席ID")
last_message_summary: Optional[str] = Field(None, max_length=256, description="最后消息摘要")
# --------------------------------------------------------------------------
# 更新会话状态 Schema
# --------------------------------------------------------------------------
class ConversationStatusUpdate(BaseModel):
"""更新会话状态请求 Schema。
Attributes:
status: 新的会话状态
"""
status: str = Field(..., description="会话状态: ai_handling/queued/serving/resolved")
@field_validator("status")
@classmethod
def validate_status(cls, v: str) -> str:
"""校验会话状态值是否合法。"""
if v not in VALID_STATUSES:
raise ValueError(f"无效的会话状态: {v},合法值为: {VALID_STATUSES}")
return v
# --------------------------------------------------------------------------
# 坐席接单 Schema
# --------------------------------------------------------------------------
class ConversationAssign(BaseModel):
"""坐席接单请求 Schema。
Attributes:
agent_id: 接单的坐席ID
"""
agent_id: str = Field(..., min_length=1, max_length=64, description="坐席ID")
# --------------------------------------------------------------------------
# 摇人(邀请协作)Schema
# --------------------------------------------------------------------------
class ConversationInvite(BaseModel):
"""摇人邀请请求 Schema。
Attributes:
agent_id: 被邀请的坐席ID
"""
agent_id: str = Field(..., min_length=1, max_length=64, description="被邀请的坐席ID")
# --------------------------------------------------------------------------
# 会话响应 Schema(返回给前端的数据结构)
# --------------------------------------------------------------------------
class ConversationResponse(BaseModel):
"""会话响应 Schema。
返回给前端(坐席端/H5端)的会话数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 会话ID
employee_id: 企微员工UserID
employee_name: 员工姓名
department: 部门
position: 岗位
level: 等级
status: 会话状态
is_vip: VIP标记
is_pinned: 置顶标记
is_todo: 代办标记
urgency_score: 紧急度评分
tags: 标签集合
assigned_agent_id: 分配的坐席ID
collaborating_agent_ids: 协作坐席ID列表
last_message_at: 最后消息时间
last_message_summary: 最后消息摘要
created_at: 创建时间
updated_at: 更新时间
"""
id: str
employee_id: str
employee_name: str
department: str
position: str
level: str
status: str
is_vip: bool
is_pinned: bool
is_todo: bool
urgency_score: int
tags: Dict[str, Any]
assigned_agent_id: Optional[str] = None
collaborating_agent_ids: List[str] = Field(default_factory=list, description="协作坐席ID列表")
last_message_at: Optional[datetime] = None
last_message_summary: str
created_at: datetime
updated_at: datetime
# ----- 坐席会话全局可见扩展字段 -----
# 是否为当前坐席的会话
is_mine: bool = Field(default=False, description="是否为当前坐席的会话")
# 分配的坐席姓名(其他坐席会话显示用)
assigned_agent_name: Optional[str] = Field(default=None, description="分配的坐席姓名")
# 是否可以接手(其他坐席已接单的会话为 True)
can_grab: bool = Field(default=False, description="是否可以接手")
# ----- 多坐席协作扩展字段 -----
# 协作坐席姓名映射(agent_id → name
collaborating_agent_names: Dict[str, str] = Field(
default_factory=dict, description="协作坐席姓名映射"
)
# 当前坐席是否为协作坐席(非主责)
is_collaborator: bool = Field(default=False, description="是否为协作坐席")
# ----- v5.3 新增:影响范围 / 阻断性 / 情绪状态 -----
# 影响范围(受影响人数,0=未评估)
impact_scope: int = Field(default=0, description="影响范围")
# 阻断性标记(问题是否阻断员工正常工作流程)
is_blocking: bool = Field(default=False, description="阻断性标记")
# 情绪状态(normal/worried/angry/urgent
emotion_state: str = Field(default="normal", description="情绪状态")
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 会话列表响应 Schema(包含分页信息)
# --------------------------------------------------------------------------
class ConversationListResponse(BaseModel):
"""会话列表响应 Schema。
包含会话列表和总数,用于分页查询。
Attributes:
items: 会话列表
total: 总数
"""
items: List[ConversationResponse]
total: int
@@ -0,0 +1,118 @@
# =============================================================================
# 企微智能IT支持服务台 — 员工 Pydantic Schema
# =============================================================================
# 说明:定义员工相关的请求/响应数据结构
# 包含:IT等级更新请求、员工响应 Schema
# =============================================================================
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, field_validator
# --------------------------------------------------------------------------
# IT 等级合法值
# --------------------------------------------------------------------------
VALID_IT_LEVELS = {"bronze", "silver", "gold", "platinum", "diamond", "star", "king"}
# --------------------------------------------------------------------------
# 等级来源合法值
# --------------------------------------------------------------------------
VALID_LEVEL_SOURCES = {"system", "manual", "assessment"}
# --------------------------------------------------------------------------
# IT 等级更新请求 Schema
# --------------------------------------------------------------------------
class ItLevelUpdateRequest(BaseModel):
"""IT技能等级更新请求 Schema。
坐席手动调整员工IT技能等级时使用。
Attributes:
it_level: 新的IT技能等级
source: 等级来源(默认 manual
"""
it_level: str = Field(..., description="IT技能等级: bronze/silver/gold/platinum/diamond/star/king")
source: str = Field(default="manual", description="等级来源: system/manual/assessment")
@field_validator("it_level")
@classmethod
def validate_it_level(cls, v: str) -> str:
"""校验IT等级值是否合法。"""
if v not in VALID_IT_LEVELS:
raise ValueError(f"无效的IT等级: {v},合法值为: {VALID_IT_LEVELS}")
return v
@field_validator("source")
@classmethod
def validate_source(cls, v: str) -> str:
"""校验等级来源值是否合法。"""
if v not in VALID_LEVEL_SOURCES:
raise ValueError(f"无效的等级来源: {v},合法值为: {VALID_LEVEL_SOURCES}")
return v
# --------------------------------------------------------------------------
# 员工响应 Schema(返回给前端的数据结构)
# --------------------------------------------------------------------------
class EmployeeResponse(BaseModel):
"""员工响应 Schema。
返回给前端的员工数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 员工记录唯一标识
corp_id: 企业微信企业ID
employee_id: 企微员工UserID
name: 员工姓名
department: 部门
position: 岗位
mobile: 手机号
email: 邮箱
avatar: 头像URL
status: 激活状态
it_level: IT技能等级
it_level_source: 等级来源
notes: 坐席备注
last_login_at: 最后登录时间
created_at: 创建时间
updated_at: 更新时间
"""
id: str
corp_id: str
employee_id: str
name: str
department: str
position: str
mobile: str
email: str
avatar: str
status: int
it_level: str = "silver"
it_level_source: str = "system"
notes: Dict[str, Any] = Field(default_factory=dict, description="坐席备注")
last_login_at: Optional[datetime] = None
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 员工列表响应 Schema
# --------------------------------------------------------------------------
class EmployeeListResponse(BaseModel):
"""员工列表响应 Schema。
Attributes:
items: 员工列表
total: 总数
"""
items: List[EmployeeResponse]
total: int
@@ -0,0 +1,209 @@
# =============================================================================
# 企微智能IT支持服务台 — H5 用户端 Pydantic Schema
# =============================================================================
# 说明:定义H5用户端专用的请求/响应数据结构
# 包含:摇人请求、OAuth回调、审批链接、软件下载、员工信息等
# =============================================================================
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
# --------------------------------------------------------------------------
# 摇人请求 Schema
# --------------------------------------------------------------------------
class ShakeRequest(BaseModel):
"""摇人请求 Schema。
用户点击H5页面摇人按钮时发送的请求。
Attributes:
employee_id: 企微员工UserID
employee_name: 员工姓名
"""
employee_id: str = Field(..., min_length=1, max_length=64, description="企微员工UserID")
employee_name: str = Field(default="", max_length=128, description="员工姓名")
# --------------------------------------------------------------------------
# 摇人响应 Schema
# --------------------------------------------------------------------------
class ShakeResponse(BaseModel):
"""摇人响应 Schema。
摇人成功后返回会话信息和趣味话术。
Attributes:
conversation: 会话信息(包含ID、状态、标签)
funny_phrase: 趣味话术内容
"""
conversation: Dict[str, Any] = Field(..., description="会话信息")
funny_phrase: str = Field(..., description="趣味话术")
# --------------------------------------------------------------------------
# OAuth2 回调请求 Schema
# --------------------------------------------------------------------------
class OAuthCallbackRequest(BaseModel):
"""OAuth2 回调请求 Schema。
H5页面通过企微OAuth2授权后,将code传给后端换取员工身份。
Attributes:
code: 企微OAuth2授权码
"""
code: str = Field(..., min_length=1, description="企微OAuth2授权码")
# --------------------------------------------------------------------------
# OAuth2 回调响应 Schema
# --------------------------------------------------------------------------
class OAuthCallbackResponse(BaseModel):
"""OAuth2 回调响应 Schema。
用授权码换取到的员工身份信息和访问令牌。
Attributes:
employee_id: 企微员工UserID
employee_name: 员工姓名
token: 访问令牌(用于后续API请求的Bearer Token
department: 部门名称
position: 岗位
avatar: 头像URL
"""
employee_id: str = Field(..., description="企微员工UserID")
employee_name: str = Field(default="", description="员工姓名")
token: str = Field(..., description="访问令牌")
department: str = Field(default="", description="部门名称")
position: str = Field(default="", description="岗位")
avatar: str = Field(default="", description="头像URL")
# --------------------------------------------------------------------------
# OAuth2 授权URL响应 Schema
# --------------------------------------------------------------------------
class OAuthAuthorizeResponse(BaseModel):
"""OAuth2 授权URL响应 Schema。
返回企微OAuth2授权链接,前端跳转到此URL进行授权。
Attributes:
authorize_url: 企微OAuth2授权URL
"""
authorize_url: str = Field(..., description="企微OAuth2授权URL")
# --------------------------------------------------------------------------
# 员工信息 Schema
# --------------------------------------------------------------------------
class EmployeeInfo(BaseModel):
"""员工信息 Schema。
从企微通讯录获取的员工详细信息。
Attributes:
employee_id: 企微员工UserID
employee_name: 员工姓名
department: 部门名称(逗号分隔)
position: 岗位
mobile: 手机号
email: 邮箱
avatar: 头像URL
is_vip: 是否VIP员工
"""
employee_id: str = Field(..., description="企微员工UserID")
employee_name: str = Field(default="", description="员工姓名")
department: str = Field(default="", description="部门名称")
position: str = Field(default="", description="岗位")
mobile: str = Field(default="", description="手机号")
email: str = Field(default="", description="邮箱")
avatar: str = Field(default="", description="头像URL")
is_vip: bool = Field(default=False, description="是否VIP员工")
# --------------------------------------------------------------------------
# 审批链接响应 Schema
# --------------------------------------------------------------------------
class ApprovalLinkResponse(BaseModel):
"""审批链接响应 Schema。
H5用户端AI助手面板中的审批流程链接。
Attributes:
id: 链接ID
category: 分类
title: 审批名称
url: 审批链接
sort_order: 排序权重
"""
id: str
category: str
title: str
url: str
sort_order: int
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 软件下载响应 Schema
# --------------------------------------------------------------------------
class SoftwareDownloadResponse(BaseModel):
"""软件下载响应 Schema。
H5用户端AI助手面板中的软件下载入口。
Attributes:
id: 下载入口ID
category: 分类
name: 软件名称
version: 版本号
platform: 平台
download_url: 下载链接
sort_order: 排序权重
"""
id: str
category: str
name: str
version: str
platform: str
download_url: str
sort_order: int
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 审批链接列表响应 Schema
# --------------------------------------------------------------------------
class ApprovalLinkListResponse(BaseModel):
"""审批链接列表响应 Schema。
Attributes:
items: 审批链接列表
"""
items: List[ApprovalLinkResponse]
# --------------------------------------------------------------------------
# 软件下载列表响应 Schema
# --------------------------------------------------------------------------
class SoftwareDownloadListResponse(BaseModel):
"""软件下载列表响应 Schema。
Attributes:
items: 软件下载列表
"""
items: List[SoftwareDownloadResponse]
@@ -0,0 +1,122 @@
# =============================================================================
# 企微智能IT支持服务台 — 消息 Pydantic Schema
# =============================================================================
# 说明:定义消息相关的请求/响应数据结构
# 支持消息类型:文本(text)/图片(image)/文件(file)/系统(system)
# =============================================================================
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator
# --------------------------------------------------------------------------
# 消息类型和发送者类型的合法值
# --------------------------------------------------------------------------
VALID_MSG_TYPES = {"text", "image", "file", "system"}
VALID_SENDER_TYPES = {"employee", "agent", "ai", "system"}
# --------------------------------------------------------------------------
# 创建消息 Schema(坐席发送消息时使用)
# --------------------------------------------------------------------------
class MessageCreate(BaseModel):
"""创建消息请求 Schema。
坐席发送消息时使用。
第一步仅支持文本消息(msg_type 默认为 text)。
Attributes:
content: 消息内容
msg_type: 消息类型(默认 text,预留 image/file
"""
content: str = Field(..., min_length=1, description="消息内容")
# 第一步仅支持文本,但预留图片和文件类型
msg_type: str = Field(default="text", description="消息类型: text/image/file")
@field_validator("msg_type")
@classmethod
def validate_msg_type(cls, v: str) -> str:
"""校验消息类型是否合法。"""
if v not in VALID_MSG_TYPES:
raise ValueError(f"无效的消息类型: {v},合法值为: {VALID_MSG_TYPES}")
return v
# --------------------------------------------------------------------------
# 企微回调消息 Schema(从企微接收到的消息)
# --------------------------------------------------------------------------
class WecomInboundMessage(BaseModel):
"""企微回调消息 Schema。
解析企微回调 XML 后得到的结构化消息。
Attributes:
from_user_id: 发送者企微UserID
content: 消息内容
msg_type: 消息类型(text/image等)
create_time: 消息创建时间
agent_id: 应用AgentID
"""
from_user_id: str = Field(..., description="发送者企微UserID")
content: str = Field(default="", description="消息内容")
msg_type: str = Field(default="text", description="消息类型")
create_time: Optional[int] = Field(None, description="消息创建时间戳")
agent_id: Optional[str] = Field(None, description="应用AgentID")
# --------------------------------------------------------------------------
# 消息响应 Schema(返回给前端的数据结构)
# --------------------------------------------------------------------------
class MessageResponse(BaseModel):
"""消息响应 Schema。
返回给前端的消息数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 消息ID
conversation_id: 所属会话ID
sender_type: 发送者类型
sender_id: 发送者ID
sender_name: 发送者姓名
content: 消息内容
msg_type: 消息类型
ai_suggestion: 是否为AI建议
is_read: 是否已读
created_at: 创建时间
"""
id: str
conversation_id: str
sender_type: str
sender_id: str
sender_name: str
content: str
msg_type: str
ai_suggestion: bool
is_read: bool
created_at: datetime
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 消息列表响应 Schema
# --------------------------------------------------------------------------
class MessageListResponse(BaseModel):
"""消息列表响应 Schema。
包含消息列表和是否还有更多消息的标志,
用于向上加载历史消息。
Attributes:
items: 消息列表
has_more: 是否还有更多历史消息
"""
items: List[MessageResponse]
has_more: bool
@@ -0,0 +1,100 @@
# =============================================================================
# 企微智能IT支持服务台 — 快速回复模板 Pydantic Schema
# =============================================================================
# 说明:定义快速回复模板的请求/响应数据结构
# 支持 CRUD 操作:创建、读取、更新、删除
# =============================================================================
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
# --------------------------------------------------------------------------
# 创建快速回复模板 Schema
# --------------------------------------------------------------------------
class QuickReplyCreate(BaseModel):
"""创建快速回复模板请求 Schema。
Attributes:
category: 分类(账号/网络/软件/硬件/通用)
title: 模板标题
content: 模板内容(支持 {employee_name} 等变量)
variables: 可用变量列表
sort_order: 排序权重
"""
category: str = Field(default="通用", max_length=64, description="分类")
title: str = Field(..., min_length=1, max_length=128, description="模板标题")
content: str = Field(..., min_length=1, description="模板内容")
variables: List[str] = Field(default_factory=list, description="可用变量列表")
sort_order: int = Field(default=0, description="排序权重")
# --------------------------------------------------------------------------
# 更新快速回复模板 Schema
# --------------------------------------------------------------------------
class QuickReplyUpdate(BaseModel):
"""更新快速回复模板请求 Schema。
所有字段可选,只更新传入的字段。
Attributes:
category: 分类
title: 模板标题
content: 模板内容
variables: 可用变量列表
sort_order: 排序权重
"""
category: Optional[str] = Field(None, max_length=64, description="分类")
title: Optional[str] = Field(None, max_length=128, description="模板标题")
content: Optional[str] = Field(None, description="模板内容")
variables: Optional[List[str]] = Field(None, description="可用变量列表")
sort_order: Optional[int] = Field(None, description="排序权重")
# --------------------------------------------------------------------------
# 快速回复模板响应 Schema
# --------------------------------------------------------------------------
class QuickReplyResponse(BaseModel):
"""快速回复模板响应 Schema。
返回给前端的快速回复模板数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 模板ID
category: 分类
title: 模板标题
content: 模板内容
variables: 可用变量列表
sort_order: 排序权重
created_at: 创建时间
updated_at: 更新时间
"""
id: str
category: str
title: str
content: str
variables: List[str]
sort_order: int
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 快速回复模板列表响应 Schema
# --------------------------------------------------------------------------
class QuickReplyListResponse(BaseModel):
"""快速回复模板列表响应 Schema。
Attributes:
items: 模板列表
"""
items: List[QuickReplyResponse]
@@ -0,0 +1,158 @@
# =============================================================================
# 企微智能IT支持服务台 — 待办事项 Pydantic Schema
# =============================================================================
# 说明:定义待办事项的 CRUD 数据结构
# 包含:创建、更新、响应 Schema
# =============================================================================
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, field_validator
# --------------------------------------------------------------------------
# 待办类型和优先级的合法值
# --------------------------------------------------------------------------
VALID_TODO_TYPES = {"ticket", "approval", "device"}
VALID_TODO_PRIORITIES = {"urgent", "high", "normal"}
VALID_TODO_STATUSES = {"pending", "processing", "resolved"}
# --------------------------------------------------------------------------
# 创建待办事项 Schema
# --------------------------------------------------------------------------
class TodoItemCreate(BaseModel):
"""创建待办事项请求 Schema。
Attributes:
type: 待办类型(ticket/approval/device
title: 待办标题
priority: 优先级(urgent/high/normal
description: 详细描述(JSON
assigned_agent_id: 分配的坐席ID(可选)
corp_id: 企业微信企业ID
"""
type: str = Field(default="ticket", description="待办类型: ticket/approval/device")
title: str = Field(..., min_length=1, max_length=256, description="待办标题")
priority: str = Field(default="normal", description="优先级: urgent/high/normal")
description: Dict[str, Any] = Field(default_factory=dict, description="详细描述")
assigned_agent_id: Optional[str] = Field(None, max_length=64, description="分配的坐席ID")
corp_id: str = Field(default="", max_length=64, description="企业微信企业ID")
@field_validator("type")
@classmethod
def validate_type(cls, v: str) -> str:
"""校验待办类型是否合法。"""
if v not in VALID_TODO_TYPES:
raise ValueError(f"无效的待办类型: {v},合法值为: {VALID_TODO_TYPES}")
return v
@field_validator("priority")
@classmethod
def validate_priority(cls, v: str) -> str:
"""校验优先级是否合法。"""
if v not in VALID_TODO_PRIORITIES:
raise ValueError(f"无效的优先级: {v},合法值为: {VALID_TODO_PRIORITIES}")
return v
# --------------------------------------------------------------------------
# 更新待办事项 Schema
# --------------------------------------------------------------------------
class TodoItemUpdate(BaseModel):
"""更新待办事项请求 Schema。
所有字段可选,只更新传入的字段。
Attributes:
type: 待办类型
title: 待办标题
priority: 优先级
description: 详细描述
status: 状态
assigned_agent_id: 分配的坐席ID
"""
type: Optional[str] = Field(None, description="待办类型: ticket/approval/device")
title: Optional[str] = Field(None, max_length=256, description="待办标题")
priority: Optional[str] = Field(None, description="优先级: urgent/high/normal")
description: Optional[Dict[str, Any]] = Field(None, description="详细描述")
status: Optional[str] = Field(None, description="状态: pending/processing/resolved")
assigned_agent_id: Optional[str] = Field(None, max_length=64, description="分配的坐席ID")
@field_validator("type")
@classmethod
def validate_type(cls, v: Optional[str]) -> Optional[str]:
"""校验待办类型是否合法。"""
if v is not None and v not in VALID_TODO_TYPES:
raise ValueError(f"无效的待办类型: {v},合法值为: {VALID_TODO_TYPES}")
return v
@field_validator("priority")
@classmethod
def validate_priority(cls, v: Optional[str]) -> Optional[str]:
"""校验优先级是否合法。"""
if v is not None and v not in VALID_TODO_PRIORITIES:
raise ValueError(f"无效的优先级: {v},合法值为: {VALID_TODO_PRIORITIES}")
return v
@field_validator("status")
@classmethod
def validate_status(cls, v: Optional[str]) -> Optional[str]:
"""校验状态是否合法。"""
if v is not None and v not in VALID_TODO_STATUSES:
raise ValueError(f"无效的状态: {v},合法值为: {VALID_TODO_STATUSES}")
return v
# --------------------------------------------------------------------------
# 待办事项响应 Schema
# --------------------------------------------------------------------------
class TodoItemResponse(BaseModel):
"""待办事项响应 Schema。
返回给前端的待办事项数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 待办唯一标识
type: 待办类型
title: 待办标题
priority: 优先级
description: 详细描述
status: 状态
assigned_agent_id: 分配的坐席ID
corp_id: 企业微信企业ID
created_at: 创建时间
updated_at: 更新时间
"""
id: str
type: str
title: str
priority: str
description: Dict[str, Any]
status: str
assigned_agent_id: Optional[str] = None
corp_id: str
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 待办事项列表响应 Schema
# --------------------------------------------------------------------------
class TodoItemListResponse(BaseModel):
"""待办事项列表响应 Schema。
Attributes:
items: 待办事项列表
total: 总数
"""
items: List[TodoItemResponse]
total: int
@@ -0,0 +1,128 @@
# =============================================================================
# 企微智能IT支持服务台 — 排障模板 Pydantic Schema
# =============================================================================
# 说明:定义排障模板的 CRUD 数据结构
# 包含:创建、更新、响应 Schema
# =============================================================================
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, field_validator
# --------------------------------------------------------------------------
# 排障模板分类合法值
# --------------------------------------------------------------------------
VALID_TEMPLATE_CATEGORIES = {"vpn", "email", "system", "account"}
# --------------------------------------------------------------------------
# 创建排障模板 Schema
# --------------------------------------------------------------------------
class TroubleshootingTemplateCreate(BaseModel):
"""创建排障模板请求 Schema。
Attributes:
name: 模板名称
category: 分类(vpn/email/system/account
path_steps: 排障步骤路径
flowchart: 流程图定义
is_active: 是否启用
"""
name: str = Field(..., min_length=1, max_length=256, description="模板名称")
category: str = Field(default="system", description="分类: vpn/email/system/account")
path_steps: List[Dict[str, Any]] = Field(
default_factory=list, description="排障步骤路径"
)
flowchart: Dict[str, Any] = Field(
default_factory=dict, description="流程图定义"
)
is_active: bool = Field(default=True, description="是否启用")
@field_validator("category")
@classmethod
def validate_category(cls, v: str) -> str:
"""校验分类是否合法。"""
if v not in VALID_TEMPLATE_CATEGORIES:
raise ValueError(f"无效的分类: {v},合法值为: {VALID_TEMPLATE_CATEGORIES}")
return v
# --------------------------------------------------------------------------
# 更新排障模板 Schema
# --------------------------------------------------------------------------
class TroubleshootingTemplateUpdate(BaseModel):
"""更新排障模板请求 Schema。
所有字段可选,只更新传入的字段。
Attributes:
name: 模板名称
category: 分类
path_steps: 排障步骤路径
flowchart: 流程图定义
is_active: 是否启用
"""
name: Optional[str] = Field(None, max_length=256, description="模板名称")
category: Optional[str] = Field(None, description="分类: vpn/email/system/account")
path_steps: Optional[List[Dict[str, Any]]] = Field(None, description="排障步骤路径")
flowchart: Optional[Dict[str, Any]] = Field(None, description="流程图定义")
is_active: Optional[bool] = Field(None, description="是否启用")
@field_validator("category")
@classmethod
def validate_category(cls, v: Optional[str]) -> Optional[str]:
"""校验分类是否合法。"""
if v is not None and v not in VALID_TEMPLATE_CATEGORIES:
raise ValueError(f"无效的分类: {v},合法值为: {VALID_TEMPLATE_CATEGORIES}")
return v
# --------------------------------------------------------------------------
# 排障模板响应 Schema
# --------------------------------------------------------------------------
class TroubleshootingTemplateResponse(BaseModel):
"""排障模板响应 Schema。
返回给前端的排障模板数据结构。
使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。
Attributes:
id: 模板唯一标识
name: 模板名称
category: 分类
path_steps: 排障步骤路径
flowchart: 流程图定义
is_active: 是否启用
created_at: 创建时间
updated_at: 更新时间
"""
id: str
name: str
category: str
path_steps: List[Dict[str, Any]] = Field(default_factory=list, description="排障步骤路径")
flowchart: Dict[str, Any] = Field(default_factory=dict, description="流程图定义")
is_active: bool
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 排障模板列表响应 Schema
# --------------------------------------------------------------------------
class TroubleshootingTemplateListResponse(BaseModel):
"""排障模板列表响应 Schema。
Attributes:
items: 排障模板列表
total: 总数
"""
items: List[TroubleshootingTemplateResponse]
total: int
@@ -0,0 +1,79 @@
# =============================================================================
# 企微智能IT支持服务台 — 企微回调消息 Pydantic Schema
# =============================================================================
# 说明:定义企微回调消息的数据结构
# 包含:GET验证请求、POST消息体、加解密相关
# =============================================================================
from typing import Optional
from pydantic import BaseModel, Field
# --------------------------------------------------------------------------
# 企微回调验证请求 Schema(GET 请求)
# --------------------------------------------------------------------------
class WecomCallbackVerify(BaseModel):
"""企微回调URL验证请求 Schema。
企微管理后台配置回调URL时,会发送GET请求验证。
需要验证签名并返回解密后的 echostr。
Attributes:
msg_signature: 企微签名(用于验证请求来源)
timestamp: 时间戳
nonce: 随机数
echostr: 加密的验证字符串(解密后返回给企微)
"""
msg_signature: str = Field(..., description="企微签名")
timestamp: str = Field(..., description="时间戳")
nonce: str = Field(..., description="随机数")
echostr: str = Field(..., description="加密的验证字符串")
# --------------------------------------------------------------------------
# 企微回调消息体 Schema(POST 请求解析后)
# --------------------------------------------------------------------------
class WecomCallbackMessage(BaseModel):
"""企微回调消息体 Schema。
企微推送消息时发送的XML解析后的结构。
包含加密的消息内容。
Attributes:
to_user_name: 接收方(企业ID
agent_id: 应用AgentID
encrypt: 加密的消息内容
"""
to_user_name: str = Field(default="", description="接收方企业ID")
agent_id: str = Field(default="", description="应用AgentID")
encrypt: str = Field(..., description="加密的消息内容")
# --------------------------------------------------------------------------
# 企微消息内容 Schema(解密后的消息)
# --------------------------------------------------------------------------
class WecomMessageContent(BaseModel):
"""企微消息内容 Schema(解密后)。
AES解密后的XML消息解析结果。
Attributes:
to_user_name: 接收方
from_user_name: 发送者企微UserID
create_time: 消息创建时间戳
msg_type: 消息类型(text/image等)
content: 消息内容
msg_id: 消息ID
agent_id: 应用AgentID
"""
to_user_name: str = Field(default="", description="接收方")
from_user_name: str = Field(..., description="发送者企微UserID")
create_time: int = Field(default=0, description="消息创建时间戳")
msg_type: str = Field(default="text", description="消息类型")
content: str = Field(default="", description="消息内容")
msg_id: str = Field(default="", description="消息ID")
agent_id: str = Field(default="", description="应用AgentID")