chore: initial baseline with P0-safety .gitignore
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — Schema 包初始化
|
||||
# =============================================================================
|
||||
# 说明:导出所有 Pydantic Schema,方便统一导入
|
||||
# =============================================================================
|
||||
@@ -0,0 +1,492 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 管理后台 Pydantic Schema
|
||||
# =============================================================================
|
||||
# 说明:定义管理后台专用请求/响应数据结构
|
||||
# 包含:仪表盘、配置管理、坐席管理、集成配置、快速回复审核、
|
||||
# 分配模式、会话监控、全局搜索等全部 Schema
|
||||
# =============================================================================
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 配置管理 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class ConfigItemResponse(BaseModel):
|
||||
"""单个配置项响应 Schema。
|
||||
|
||||
Attributes:
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
description: 配置说明
|
||||
value_type: 值类型(boolean/number/string/json_array/json_object)
|
||||
"""
|
||||
|
||||
key: str = Field(..., description="配置键")
|
||||
value: str = Field(..., description="配置值")
|
||||
description: str = Field(default="", description="配置说明")
|
||||
value_type: str = Field(default="string", description="值类型: boolean/number/string/json_array/json_object")
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class ConfigGroupResponse(BaseModel):
|
||||
"""配置分组响应 Schema。
|
||||
|
||||
按功能前缀将配置项分组,方便前端展示。
|
||||
|
||||
Attributes:
|
||||
name: 分组名称
|
||||
key_prefix: 配置键前缀
|
||||
items: 该分组下的配置项列表
|
||||
"""
|
||||
|
||||
name: str = Field(..., description="分组名称")
|
||||
key_prefix: str = Field(..., description="配置键前缀")
|
||||
items: List[ConfigItemResponse] = Field(default_factory=list, description="配置项列表")
|
||||
|
||||
|
||||
class ConfigUpdateRequest(BaseModel):
|
||||
"""配置更新请求 Schema。
|
||||
|
||||
Attributes:
|
||||
value: 新的配置值
|
||||
"""
|
||||
|
||||
value: str = Field(..., min_length=1, description="新的配置值")
|
||||
|
||||
|
||||
class ConfigHistoryItem(BaseModel):
|
||||
"""配置变更历史条目 Schema。
|
||||
|
||||
Attributes:
|
||||
id: 日志ID
|
||||
config_key: 配置键
|
||||
old_value: 变更前的值
|
||||
new_value: 变更后的值
|
||||
changed_by: 变更操作人 agent_id
|
||||
changed_by_name: 变更操作人姓名
|
||||
changed_at: 变更时间
|
||||
"""
|
||||
|
||||
id: str = Field(..., description="日志ID")
|
||||
config_key: str = Field(..., description="配置键")
|
||||
old_value: str = Field(..., description="变更前的值")
|
||||
new_value: str = Field(..., description="变更后的值")
|
||||
changed_by: str = Field(..., description="变更操作人 agent_id")
|
||||
changed_by_name: str = Field(default="", description="变更操作人姓名")
|
||||
changed_at: datetime = Field(..., description="变更时间")
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class ConfigHistoryResponse(BaseModel):
|
||||
"""配置变更历史响应 Schema。
|
||||
|
||||
Attributes:
|
||||
items: 变更历史条目列表
|
||||
"""
|
||||
|
||||
items: List[ConfigHistoryItem] = Field(default_factory=list, description="变更历史列表")
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 坐席管理 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class AgentCreateRequest(BaseModel):
|
||||
"""创建坐席请求 Schema。
|
||||
|
||||
Attributes:
|
||||
user_id: 企微用户ID
|
||||
name: 坐席姓名
|
||||
role: 角色(admin=组长, agent=坐席)
|
||||
skill_tags: 技能标签列表
|
||||
max_load: 最大同时服务数
|
||||
"""
|
||||
|
||||
user_id: str = Field(..., min_length=1, max_length=64, description="企微用户ID")
|
||||
name: str = Field(..., min_length=1, max_length=128, description="坐席姓名")
|
||||
role: str = Field(default="agent", description="角色: admin=组长, agent=坐席")
|
||||
skill_tags: List[str] = Field(default_factory=list, description="技能标签列表")
|
||||
max_load: int = Field(default=5, ge=1, le=50, description="最大同时服务数")
|
||||
|
||||
|
||||
class AgentUpdateRequest(BaseModel):
|
||||
"""更新坐席请求 Schema。
|
||||
|
||||
所有字段可选,只更新传入的字段。
|
||||
|
||||
Attributes:
|
||||
role: 角色
|
||||
skill_tags: 技能标签列表
|
||||
max_load: 最大同时服务数
|
||||
"""
|
||||
|
||||
role: Optional[str] = Field(None, description="角色: admin=组长, agent=坐席")
|
||||
skill_tags: Optional[List[str]] = Field(None, description="技能标签列表")
|
||||
max_load: Optional[int] = Field(None, ge=1, le=50, description="最大同时服务数")
|
||||
|
||||
|
||||
class AdminAgentResponse(BaseModel):
|
||||
"""管理后台坐席响应 Schema(含角色/技能标签/今日结单数)。
|
||||
|
||||
Attributes:
|
||||
id: 坐席ID
|
||||
user_id: 企微用户ID
|
||||
name: 坐席姓名
|
||||
status: 坐席状态
|
||||
role: 角色
|
||||
skill_tags: 技能标签列表
|
||||
current_load: 当前服务会话数
|
||||
max_load: 最大同时服务数
|
||||
today_resolved: 今日结单数
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
user_id: str
|
||||
name: str
|
||||
status: str
|
||||
role: str = "agent"
|
||||
skill_tags: List[str] = []
|
||||
current_load: int = 0
|
||||
max_load: int = 5
|
||||
today_resolved: int = 0
|
||||
otp_secret: Optional[str] = None
|
||||
otp_enabled: bool = False
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# 集成配置 Schema
|
||||
# =========================================================================
|
||||
|
||||
class IntegrationConfig(BaseModel):
|
||||
"""集成系统配置 Schema(通用,支持 url_key 和 access_key 两种模式)。
|
||||
|
||||
Attributes:
|
||||
# url_key 模式(Dify / RAGFlow)
|
||||
api_url: API 地址
|
||||
api_key_set: API Key 是否已设置
|
||||
|
||||
# access_key 模式(火绒安全)
|
||||
access_key_id_set: AccessKey ID 是否已设置
|
||||
access_key_secret_set: AccessKey Secret 是否已设置
|
||||
base_url: 内网 Base URL
|
||||
"""
|
||||
# url_key 模式(Dify / RAGFlow)
|
||||
api_url: str = Field(default="", description="API 地址")
|
||||
api_key_set: bool = Field(default=False, description="API Key 是否已设置")
|
||||
|
||||
# access_key 模式(火绒安全)
|
||||
access_key_id_set: bool = Field(default=False, description="AccessKey ID 是否已设置")
|
||||
access_key_secret_set: bool = Field(default=False, description="AccessKey Secret 是否已设置")
|
||||
base_url: Optional[str] = Field(default=None, description="内网 Base URL")
|
||||
|
||||
# account_password 模式(联软LV7000)
|
||||
api_account_set: bool = Field(default=False, description="API账号是否已设置")
|
||||
api_password_set: bool = Field(default=False, description="API密码是否已设置")
|
||||
|
||||
|
||||
class IntegrationResponse(BaseModel):
|
||||
"""集成系统响应 Schema。
|
||||
|
||||
Attributes:
|
||||
id: 集成系统ID(如 dify/ragflow/huorong)
|
||||
name: 集成系统名称
|
||||
status: 连接状态(connected/partial/disconnected/pending)
|
||||
configurable: 是否可配置
|
||||
config_type: 配置类型(url_key/access_key),前端据此显示不同表单
|
||||
config: 配置信息(不可配置时为 None)
|
||||
"""
|
||||
|
||||
id: str = Field(..., description="集成系统ID")
|
||||
name: str = Field(..., description="集成系统名称")
|
||||
status: str = Field(default="disconnected", description="连接状态: connected/partial/disconnected/pending")
|
||||
configurable: bool = Field(default=False, description="是否可配置")
|
||||
config_type: Optional[str] = Field(default=None, description="配置类型: url_key/access_key/account_password")
|
||||
config: Optional[IntegrationConfig] = Field(default=None, description="配置信息")
|
||||
|
||||
|
||||
class IntegrationUpdateRequest(BaseModel):
|
||||
"""集成系统配置更新请求 Schema。
|
||||
|
||||
支持三种模式:
|
||||
- url_key 模式(Dify / RAGFlow):传入 api_url + api_key
|
||||
- access_key 模式(火绒安全):传入 access_key_id + access_key_secret + base_url
|
||||
- account_password 模式(联软LV7000):传入 api_account + api_password + base_url + validate_key(可选)
|
||||
|
||||
Attributes:
|
||||
# url_key 模式
|
||||
api_url: API 地址(可选,火绒/联软模式不需要)
|
||||
api_key: API Key(可选,火绒/联软模式不需要)
|
||||
|
||||
# access_key 模式(火绒)
|
||||
access_key_id: AccessKey ID(可选)
|
||||
access_key_secret: AccessKey Secret(可选)
|
||||
base_url: 内网 Base URL(可选)
|
||||
|
||||
# account_password 模式(联软)
|
||||
api_account: API账号(可选,联软模式)
|
||||
api_password: API密码(可选,联软模式)
|
||||
validate_key: 验证密钥(可选,联软模式)
|
||||
"""
|
||||
|
||||
# url_key 模式(Dify / RAGFlow)
|
||||
api_url: Optional[str] = Field(default=None, description="API 地址(Dify/RAGFlow 模式)")
|
||||
api_key: Optional[str] = Field(default=None, description="API Key(Dify/RAGFlow 模式)")
|
||||
|
||||
# access_key 模式(火绒安全)
|
||||
access_key_id: Optional[str] = Field(default=None, description="AccessKey ID(火绒模式)")
|
||||
access_key_secret: Optional[str] = Field(default=None, description="AccessKey Secret(火绒模式)")
|
||||
base_url: Optional[str] = Field(default=None, description="内网 Base URL(火绒/联软模式)")
|
||||
|
||||
# account_password 模式(联软LV7000)
|
||||
api_account: Optional[str] = Field(default=None, description="API账号(联软模式)")
|
||||
api_password: Optional[str] = Field(default=None, description="API密码(联软模式)")
|
||||
validate_key: Optional[str] = Field(default=None, description="验证密钥(联软模式,可选)")
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 快速回复审核 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class QuickReplyReviewRequest(BaseModel):
|
||||
"""快速回复审核请求 Schema。
|
||||
|
||||
Attributes:
|
||||
action: 审核动作(approve=通过, reject=驳回)
|
||||
reason: 审核原因/意见(驳回时建议填写)
|
||||
"""
|
||||
|
||||
action: str = Field(..., description="审核动作: approve/reject")
|
||||
reason: str = Field(default="", description="审核原因/意见")
|
||||
|
||||
|
||||
class AdminQuickReplyResponse(BaseModel):
|
||||
"""管理后台快速回复响应 Schema(含审核信息)。
|
||||
|
||||
Attributes:
|
||||
id: 模板ID
|
||||
category: 分类
|
||||
title: 模板标题
|
||||
content: 模板内容
|
||||
variables: 可用变量列表
|
||||
status: 状态
|
||||
version: 版本号
|
||||
submitted_by: 提交人 agent_id
|
||||
submitted_by_name: 提交人姓名
|
||||
sort_order: 排序权重
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
category: str
|
||||
title: str
|
||||
content: str
|
||||
variables: List[str]
|
||||
status: str = "approved"
|
||||
version: int = 1
|
||||
submitted_by: Optional[str] = None
|
||||
submitted_by_name: str = ""
|
||||
sort_order: int = 0
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 分配模式 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class AssignmentModeItem(BaseModel):
|
||||
"""分配模式条目 Schema。
|
||||
|
||||
Attributes:
|
||||
id: 模式ID
|
||||
name: 模式名称
|
||||
enabled: 是否启用
|
||||
locked: 是否锁定(阶段一锁定部分模式)
|
||||
unlock_at: 解锁阶段说明
|
||||
"""
|
||||
|
||||
id: str = Field(..., description="模式ID")
|
||||
name: str = Field(..., description="模式名称")
|
||||
enabled: bool = Field(default=False, description="是否启用")
|
||||
locked: bool = Field(default=True, description="是否锁定")
|
||||
unlock_at: str = Field(default="", description="解锁阶段说明")
|
||||
|
||||
|
||||
class AssignmentModeResponse(BaseModel):
|
||||
"""分配模式响应 Schema。
|
||||
|
||||
Attributes:
|
||||
current_mode: 当前启用的分配模式
|
||||
modes: 所有分配模式列表
|
||||
"""
|
||||
|
||||
current_mode: str = Field(default="manual", description="当前分配模式")
|
||||
modes: List[AssignmentModeItem] = Field(default_factory=list, description="分配模式列表")
|
||||
|
||||
|
||||
class AssignmentModeUpdateRequest(BaseModel):
|
||||
"""分配模式更新请求 Schema。
|
||||
|
||||
Attributes:
|
||||
mode: 要切换的分配模式ID
|
||||
"""
|
||||
|
||||
mode: str = Field(..., description="分配模式ID")
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 仪表盘 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class SystemAlertItem(BaseModel):
|
||||
"""单条系统告警 Schema。
|
||||
|
||||
与前端 SystemAlert 接口对齐,支持结构化告警展示。
|
||||
|
||||
Attributes:
|
||||
type: 告警类型(如 quick_reply_pending / agent_offline / system_error)
|
||||
content: 告警内容描述
|
||||
submitter: 提交人姓名(仅快速回复待审核类告警有值)
|
||||
time: 告警发生时间(ISO 8601 格式)
|
||||
severity: 严重程度(info/warning/critical)
|
||||
"""
|
||||
|
||||
type: str = Field(..., description="告警类型")
|
||||
content: str = Field(..., description="告警内容")
|
||||
submitter: Optional[str] = Field(default=None, description="提交人")
|
||||
time: str = Field(..., description="告警时间")
|
||||
severity: str = Field(default="info", description="严重程度: info/warning/critical")
|
||||
|
||||
|
||||
class IntegrationHealthItem(BaseModel):
|
||||
"""集成系统健康状态条目 Schema。
|
||||
|
||||
Attributes:
|
||||
system: 系统名称
|
||||
status: 连接状态
|
||||
"""
|
||||
|
||||
system: str = Field(..., description="系统名称")
|
||||
status: str = Field(default="disconnected", description="连接状态")
|
||||
|
||||
|
||||
class DashboardOverviewResponse(BaseModel):
|
||||
"""仪表盘总览响应 Schema。
|
||||
|
||||
Attributes:
|
||||
online_agents: 在线坐席数
|
||||
today_conversations: 今日会话数
|
||||
avg_response_time: 平均响应时间(阶段一占位)
|
||||
ai_hit_rate: AI 命中率(阶段一占位)
|
||||
pending_reviews: 待审核快速回复数
|
||||
system_alerts: 系统告警列表
|
||||
integrations_health: 集成系统健康状态
|
||||
"""
|
||||
|
||||
online_agents: int = Field(default=0, description="在线坐席数")
|
||||
today_conversations: int = Field(default=0, description="今日会话数")
|
||||
avg_response_time: str = Field(default="—", description="平均响应时间(阶段一占位)")
|
||||
ai_hit_rate: str = Field(default="—", description="AI命中率(阶段一占位)")
|
||||
pending_reviews: int = Field(default=0, description="待审核快速回复数")
|
||||
system_alerts: List[SystemAlertItem] = Field(default_factory=list, description="系统告警列表")
|
||||
integrations_health: List[IntegrationHealthItem] = Field(default_factory=list, description="集成系统健康状态")
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 会话监控 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class SessionStats(BaseModel):
|
||||
"""会话统计 Schema。
|
||||
|
||||
Attributes:
|
||||
in_progress: 服务中会话数
|
||||
queued: 排队中会话数
|
||||
resolved_today: 今日已结单数
|
||||
alerts: 告警数
|
||||
"""
|
||||
|
||||
in_progress: int = Field(default=0, description="服务中会话数")
|
||||
queued: int = Field(default=0, description="排队中会话数")
|
||||
resolved_today: int = Field(default=0, description="今日已结单数")
|
||||
alerts: int = Field(default=0, description="告警数")
|
||||
|
||||
|
||||
class SessionItem(BaseModel):
|
||||
"""会话条目 Schema(监控列表用)。
|
||||
|
||||
Attributes:
|
||||
id: 会话ID
|
||||
employee_name: 员工姓名
|
||||
status: 会话状态
|
||||
assigned_agent_name: 负责坐席姓名
|
||||
urgency_score: 紧急度评分
|
||||
created_at: 创建时间
|
||||
last_message_summary: 最后消息摘要
|
||||
"""
|
||||
|
||||
id: str = Field(..., description="会话ID")
|
||||
employee_name: str = Field(default="", description="员工姓名")
|
||||
status: str = Field(default="queued", description="会话状态")
|
||||
assigned_agent_name: str = Field(default="", description="负责坐席姓名")
|
||||
urgency_score: int = Field(default=1, description="紧急度评分")
|
||||
created_at: datetime = Field(..., description="创建时间")
|
||||
last_message_summary: str = Field(default="", description="最后消息摘要")
|
||||
|
||||
|
||||
class MonitorSessionsResponse(BaseModel):
|
||||
"""会话监控响应 Schema。
|
||||
|
||||
Attributes:
|
||||
stats: 会话统计
|
||||
items: 会话列表
|
||||
"""
|
||||
|
||||
stats: SessionStats = Field(..., description="会话统计")
|
||||
items: List[SessionItem] = Field(default_factory=list, description="会话列表")
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# 全局搜索 Schema
|
||||
# ==========================================================================
|
||||
|
||||
class SearchItem(BaseModel):
|
||||
"""搜索结果条目 Schema。
|
||||
|
||||
Attributes:
|
||||
type: 结果类型(config/agent/quick_reply)
|
||||
id: 对象ID
|
||||
name: 对象名称/标题
|
||||
route: 前端路由路径
|
||||
"""
|
||||
|
||||
type: str = Field(..., description="结果类型: config/agent/quick_reply")
|
||||
id: str = Field(..., description="对象ID")
|
||||
name: str = Field(..., description="对象名称/标题")
|
||||
route: str = Field(..., description="前端路由路径")
|
||||
|
||||
|
||||
class SearchResponse(BaseModel):
|
||||
"""搜索结果响应 Schema。
|
||||
|
||||
Attributes:
|
||||
items: 搜索结果列表
|
||||
"""
|
||||
|
||||
items: List[SearchItem] = Field(default_factory=list, description="搜索结果列表")
|
||||
@@ -0,0 +1,111 @@
|
||||
# =============================================================================
|
||||
# 企微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。
|
||||
admin 角色需要 OTP 二次验证。
|
||||
|
||||
Attributes:
|
||||
user_id: 企微用户ID
|
||||
name: 坐席姓名
|
||||
otp_code: OTP 动态码(admin 角色必填)
|
||||
"""
|
||||
|
||||
user_id: str = Field(..., min_length=1, max_length=64, description="企微用户ID")
|
||||
name: str = Field(..., min_length=1, max_length=128, description="坐席姓名")
|
||||
otp_code: Optional[str] = Field(None, min_length=6, max_length=6, description="OTP动态码(6位数字)")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 坐席状态更新 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: 坐席状态
|
||||
role: 角色(admin=组长, agent=坐席)
|
||||
skill_tags: 技能标签列表
|
||||
current_load: 当前服务会话数
|
||||
max_load: 最大同时服务数
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
user_id: str
|
||||
name: str
|
||||
status: str
|
||||
role: str = "agent"
|
||||
skill_tags: List[str] = []
|
||||
current_load: int
|
||||
max_load: int
|
||||
otp_enabled: bool = False # OTP 是否已启用
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 坐席列表响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class AgentListResponse(BaseModel):
|
||||
"""坐席列表响应 Schema。
|
||||
|
||||
Attributes:
|
||||
items: 坐席列表
|
||||
"""
|
||||
|
||||
items: List[AgentResponse]
|
||||
@@ -0,0 +1,319 @@
|
||||
# =============================================================================
|
||||
# 企微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(P0-09~P0-11 邀请功能)
|
||||
# --------------------------------------------------------------------------
|
||||
class ParticipantInfo(BaseModel):
|
||||
"""被邀请人信息。
|
||||
|
||||
Attributes:
|
||||
id: 企微员工UserID 或部门ID
|
||||
name: 姓名 或 部门名称
|
||||
department: 部门(仅员工类型有)
|
||||
type: 类型 — employee(个人)或 department(部门)
|
||||
avatar: 头像URL(从企微通讯录或employees表获取)
|
||||
joined: 是否已加入(邀请后、点击加入前为 False)
|
||||
joined_at: 加入时间(ISO 格式字符串)
|
||||
"""
|
||||
|
||||
id: str = Field(..., min_length=1, max_length=64, description="企微员工UserID或部门ID")
|
||||
name: str = Field(..., min_length=1, max_length=128, description="姓名或部门名称")
|
||||
department: str = Field(default="", max_length=256, description="部门(仅员工类型)")
|
||||
type: str = Field(default="employee", description="类型: employee/department")
|
||||
avatar: str = Field(default="", max_length=512, description="头像URL")
|
||||
joined: Optional[bool] = Field(default=None, description="是否已加入")
|
||||
joined_at: Optional[str] = Field(default=None, description="加入时间(ISO格式)")
|
||||
|
||||
|
||||
class InviteParticipantRequest(BaseModel):
|
||||
"""邀请员工/部门加入会话请求 Schema。
|
||||
|
||||
Attributes:
|
||||
participants: 被邀请人列表
|
||||
history_mode: 历史消息共享模式 — recent10(最近10条)/ all(全部)/ none(不共享)
|
||||
"""
|
||||
|
||||
participants: List[ParticipantInfo] = Field(
|
||||
..., min_length=1, max_length=20, description="被邀请人列表"
|
||||
)
|
||||
history_mode: str = Field(
|
||||
default="recent10",
|
||||
description="历史消息共享模式: recent10/all/none",
|
||||
)
|
||||
|
||||
@field_validator("history_mode")
|
||||
@classmethod
|
||||
def validate_history_mode(cls, v: str) -> str:
|
||||
"""校验历史共享模式。"""
|
||||
valid_modes = {"recent10", "all", "none"}
|
||||
if v not in valid_modes:
|
||||
raise ValueError(f"无效的历史共享模式: {v},合法值为: {valid_modes}")
|
||||
return v
|
||||
|
||||
@field_validator("participants")
|
||||
@classmethod
|
||||
def validate_participants_unique(cls, v: List[ParticipantInfo]) -> List[ParticipantInfo]:
|
||||
"""校验参与者ID不重复。"""
|
||||
ids = [p.id for p in v]
|
||||
if len(ids) != len(set(ids)):
|
||||
raise ValueError("参与者ID不能重复")
|
||||
return v
|
||||
|
||||
|
||||
class JoinConversationRequest(BaseModel):
|
||||
"""被邀请人加入会话请求 Schema。
|
||||
|
||||
Attributes:
|
||||
employee_id: 被邀请人的企微UserID
|
||||
"""
|
||||
|
||||
employee_id: str = Field(..., min_length=1, max_length=64, description="企微员工UserID")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 会话响应 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列表")
|
||||
# 被邀请参与会话的人员列表(邀请功能 P0-09~P0-11)
|
||||
participants: List[ParticipantInfo] = Field(default_factory=list, description="被邀请参与会话的人员列表")
|
||||
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,145 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 消息 Pydantic Schema
|
||||
# =============================================================================
|
||||
# 说明:定义消息相关的请求/响应数据结构
|
||||
# 支持消息类型:文本(text)/图片(image)/文件(file)/系统(system)
|
||||
# =============================================================================
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, 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。
|
||||
|
||||
坐席发送消息时使用。
|
||||
支持文本消息和文件/图片消息。
|
||||
|
||||
Attributes:
|
||||
content: 消息内容(文本消息为正文,文件消息为文件URL或描述)
|
||||
msg_type: 消息类型(默认 text,支持 image/file)
|
||||
media_url: 媒体文件URL(图片/文件消息时使用)
|
||||
file_name: 文件名(文件消息时使用)
|
||||
file_size: 文件大小(字节,文件消息时使用)
|
||||
"""
|
||||
|
||||
content: str = Field(..., min_length=1, description="消息内容")
|
||||
# 支持文本、图片、文件类型
|
||||
msg_type: str = Field(default="text", description="消息类型: text/image/file")
|
||||
# M1 新增:文件上传相关字段
|
||||
media_url: Optional[str] = Field(None, description="媒体文件URL(图片/文件消息时使用)")
|
||||
file_name: Optional[str] = Field(None, description="文件名")
|
||||
file_size: Optional[int] = Field(None, description="文件大小(字节)")
|
||||
# M1 新增:引用回复
|
||||
reply_to_id: Optional[str] = Field(None, description="引用回复:被回复的消息ID")
|
||||
|
||||
@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: 消息类型
|
||||
media_url: 媒体文件URL
|
||||
file_name: 文件名
|
||||
file_size: 文件大小
|
||||
extra_data: 扩展元数据
|
||||
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
|
||||
# M1 新增:媒体/文件相关字段
|
||||
media_url: Optional[str] = None
|
||||
file_name: Optional[str] = None
|
||||
file_size: Optional[int] = None
|
||||
extra_data: Optional[Dict[str, Any]] = None
|
||||
# M1 新增:引用回复
|
||||
reply_to_id: Optional[str] = None
|
||||
ai_suggestion: bool
|
||||
is_read: bool
|
||||
created_at: datetime
|
||||
# M2 新增:消息状态和可撤回时间
|
||||
status: str = "sent"
|
||||
recallable_until: Optional[datetime] = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 消息列表响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class MessageListResponse(BaseModel):
|
||||
"""消息列表响应 Schema。
|
||||
|
||||
包含消息列表和是否还有更多消息的标志,
|
||||
用于向上加载历史消息。
|
||||
|
||||
Attributes:
|
||||
items: 消息列表
|
||||
has_more: 是否还有更多历史消息
|
||||
"""
|
||||
|
||||
items: List[MessageResponse]
|
||||
has_more: bool
|
||||
@@ -0,0 +1,106 @@
|
||||
# =============================================================================
|
||||
# 企微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: 排序权重
|
||||
status: 状态(draft/pending_review/approved/rejected)
|
||||
version: 版本号
|
||||
submitted_by: 提交人 agent_id
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
category: str
|
||||
title: str
|
||||
content: str
|
||||
variables: List[str]
|
||||
sort_order: int
|
||||
status: str = "approved"
|
||||
version: int = 1
|
||||
submitted_by: Optional[str] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 快速回复模板列表响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class QuickReplyListResponse(BaseModel):
|
||||
"""快速回复模板列表响应 Schema。
|
||||
|
||||
Attributes:
|
||||
items: 模板列表
|
||||
"""
|
||||
|
||||
items: List[QuickReplyResponse]
|
||||
@@ -0,0 +1,239 @@
|
||||
# =============================================================================
|
||||
# 角色 Pydantic Schema
|
||||
# =============================================================================
|
||||
# 说明:定义角色相关的请求/响应数据结构
|
||||
# 包含:角色响应、角色分配、角色映射规则等 Schema
|
||||
# =============================================================================
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class RoleResponse(BaseModel):
|
||||
"""角色响应 Schema。
|
||||
|
||||
Attributes:
|
||||
id: 角色ID
|
||||
name: 角色标识(user/agent/admin)
|
||||
display_name: 显示名称(用户/坐席/管理员)
|
||||
description: 角色描述
|
||||
permissions: 权限列表
|
||||
is_default: 是否默认角色
|
||||
user_count: 拥有该角色的用户数(可选)
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
display_name: str
|
||||
description: Optional[str] = None
|
||||
permissions: List[str] = []
|
||||
is_default: bool = False
|
||||
user_count: Optional[int] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 用户角色响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class UserRoleResponse(BaseModel):
|
||||
"""用户角色响应 Schema。
|
||||
|
||||
Attributes:
|
||||
id: 记录ID
|
||||
employee_id: 企微 UserID
|
||||
role_id: 角色 ID
|
||||
role_name: 角色标识
|
||||
role_display_name: 角色显示名称
|
||||
source: 角色来源(auto/tag/ehr/manual)
|
||||
assigned_by: 分配者
|
||||
assigned_at: 分配时间
|
||||
expires_at: 过期时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
employee_id: str
|
||||
role_id: str
|
||||
role_name: str
|
||||
role_display_name: str
|
||||
source: str
|
||||
assigned_by: Optional[str] = None
|
||||
assigned_at: datetime
|
||||
expires_at: Optional[datetime] = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色分配请求 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class RoleAssignRequest(BaseModel):
|
||||
"""角色分配请求 Schema。
|
||||
|
||||
Attributes:
|
||||
employee_id: 企微 UserID
|
||||
role_name: 角色标识(user/agent/admin)
|
||||
reason: 分配原因(可选)
|
||||
"""
|
||||
|
||||
employee_id: str = Field(..., min_length=1, max_length=100, description="企微 UserID")
|
||||
role_name: str = Field(..., min_length=1, max_length=50, description="角色标识")
|
||||
reason: Optional[str] = Field(None, max_length=500, description="分配原因")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色撤销请求 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class RoleRevokeRequest(BaseModel):
|
||||
"""角色撤销请求 Schema。
|
||||
|
||||
Attributes:
|
||||
employee_id: 企微 UserID
|
||||
role_name: 角色标识(user/agent/admin)
|
||||
reason: 撤销原因(可选)
|
||||
"""
|
||||
|
||||
employee_id: str = Field(..., min_length=1, max_length=100, description="企微 UserID")
|
||||
role_name: str = Field(..., min_length=1, max_length=50, description="角色标识")
|
||||
reason: Optional[str] = Field(None, max_length=500, description="撤销原因")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色映射规则响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class RoleMappingRuleResponse(BaseModel):
|
||||
"""角色映射规则响应 Schema。
|
||||
|
||||
Attributes:
|
||||
id: 规则ID
|
||||
role_id: 目标角色 ID
|
||||
role_name: 目标角色标识
|
||||
source_type: 来源类型(wecom_tag/ehr_position)
|
||||
source_value: 来源值(标签名/岗位关键词)
|
||||
priority: 优先级
|
||||
is_active: 是否启用
|
||||
created_at: 创建时间
|
||||
"""
|
||||
|
||||
id: str
|
||||
role_id: str
|
||||
role_name: str
|
||||
source_type: str
|
||||
source_value: str
|
||||
priority: int = 0
|
||||
is_active: bool = True
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色映射规则创建/更新请求 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class RoleMappingRuleRequest(BaseModel):
|
||||
"""角色映射规则创建/更新请求 Schema。
|
||||
|
||||
Attributes:
|
||||
role_name: 目标角色标识(user/agent/admin)
|
||||
source_type: 来源类型(wecom_tag/ehr_position)
|
||||
source_value: 来源值(标签名/岗位关键词)
|
||||
priority: 优先级(数值越大优先级越高)
|
||||
is_active: 是否启用
|
||||
"""
|
||||
|
||||
role_name: str = Field(..., min_length=1, max_length=50, description="目标角色标识")
|
||||
source_type: str = Field(..., min_length=1, max_length=50, description="来源类型")
|
||||
source_value: str = Field(..., min_length=1, max_length=200, description="来源值")
|
||||
priority: int = Field(0, ge=0, le=100, description="优先级(0-100)")
|
||||
is_active: bool = Field(True, description="是否启用")
|
||||
|
||||
@field_validator("source_type")
|
||||
@classmethod
|
||||
def validate_source_type(cls, v: str) -> str:
|
||||
"""校验来源类型是否合法。"""
|
||||
allowed_types = {"wecom_tag", "ehr_position"}
|
||||
if v not in allowed_types:
|
||||
raise ValueError(f"无效的来源类型: {v},合法值为: {allowed_types}")
|
||||
return v
|
||||
|
||||
@field_validator("role_name")
|
||||
@classmethod
|
||||
def validate_role_name(cls, v: str) -> str:
|
||||
"""校验角色标识是否合法。"""
|
||||
allowed_roles = {"user", "agent", "admin"}
|
||||
if v not in allowed_roles:
|
||||
raise ValueError(f"无效的角色标识: {v},合法值为: {allowed_roles}")
|
||||
return v
|
||||
|
||||
@field_validator("source_value")
|
||||
@classmethod
|
||||
def validate_source_value(cls, v: str) -> str:
|
||||
"""校验来源值是否包含恶意内容。"""
|
||||
# 过滤特殊字符
|
||||
forbidden_chars = {"<", ">", ";", "'", '"', "\\", "/", "(", ")"}
|
||||
for char in v:
|
||||
if char in forbidden_chars:
|
||||
raise ValueError(f"来源值包含非法字符: {char}")
|
||||
return v
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Portal 用户信息响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class PortalUserInfo(BaseModel):
|
||||
"""Portal 用户信息响应 Schema。
|
||||
|
||||
用于路由选择页展示用户信息和角色列表。
|
||||
|
||||
Attributes:
|
||||
employee_id: 企微 UserID
|
||||
name: 姓名
|
||||
department: 部门
|
||||
avatar: 头像URL
|
||||
roles: 角色列表
|
||||
current_role: 当前选择的角色
|
||||
"""
|
||||
|
||||
employee_id: str
|
||||
name: str
|
||||
department: Optional[str] = None
|
||||
avatar: Optional[str] = None
|
||||
roles: List[RoleResponse] = []
|
||||
current_role: str = "user"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色切换请求 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class SwitchRoleRequest(BaseModel):
|
||||
"""角色切换请求 Schema。
|
||||
|
||||
Attributes:
|
||||
new_role: 目标角色标识
|
||||
"""
|
||||
|
||||
new_role: str = Field(..., min_length=1, max_length=50, description="目标角色标识")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 角色切换响应 Schema
|
||||
# --------------------------------------------------------------------------
|
||||
class SwitchRoleResponse(BaseModel):
|
||||
"""角色切换响应 Schema。
|
||||
|
||||
Attributes:
|
||||
current_role: 切换后的角色标识
|
||||
redirect_url: 重定向URL
|
||||
"""
|
||||
|
||||
current_role: str
|
||||
redirect_url: str
|
||||
@@ -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")
|
||||
Reference in New Issue
Block a user