| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- from pydantic import BaseModel, Field, model_validator
- from typing import Optional, Union, Any, List
- from datetime import datetime
- from enum import Enum
- class MessageType(str, Enum):
- MESSAGE = "MESSAGE"
- NOTIFICATION = "NOTIFICATION"
- class ContentType(str, Enum):
- TEXT = "TEXT"
- IMAGE = "IMAGE"
- VIDEO = "VIDEO"
- FILE = "FILE"
- # 用户在应用内发起的“申请通知”,用于在私信界面展示通知样式(携带 action_url/action_text)
- USER_NOTIFICATION = "USER_NOTIFICATION"
- class MessageBase(BaseModel):
- title: str = Field(..., max_length=255)
- content: Union[str, dict, Any] = Field(..., description="内容")
- content_type: ContentType = ContentType.TEXT
-
- type: MessageType = MessageType.MESSAGE
- app_id: Optional[str] = None # 改为字符串类型,支持开发者保存的字符串 app_id
-
- action_url: Optional[str] = None
- action_text: Optional[str] = None
-
- # SSO 扩展
- target_url: Optional[str] = None
- auto_sso: bool = False
- class MessageCreate(MessageBase):
- receiver_id: Optional[int] = None
- app_user_id: Optional[str] = None
- sender_app_user_id: Optional[str] = None # 应用发信时可选:帐内发起人,解析后写入 sender_id,用于审计和会话聚合
- is_broadcast: bool = False
-
- @model_validator(mode='after')
- def check_receiver(self):
- if self.is_broadcast:
- return self
- if not self.receiver_id and not (self.app_user_id and self.app_id):
- raise ValueError("非广播消息必须提供 receiver_id,或者同时提供 app_user_id 和 app_id")
- return self
- class MessageUpdate(BaseModel):
- is_read: Optional[bool] = None
- class MessageResponse(BaseModel):
- id: int
- sender_id: Optional[int]
- receiver_id: int
- app_id: Optional[int]
- app_name: Optional[str] = None # 应用名称,用于前端显示
-
- type: MessageType
- content_type: ContentType
-
- title: str
- content: str # DB 中存的是字符串
-
- action_url: Optional[str]
- action_text: Optional[str]
-
- is_read: bool
- created_at: datetime
- read_at: Optional[datetime]
- class Config:
- from_attributes = True
- class ConversationResponse(BaseModel):
- user_id: int
- username: str
- full_name: Optional[str]
- unread_count: int
- last_message: str
- last_message_type: ContentType
- updated_at: datetime
- # 系统会话标记及应用信息(用于拆分不同平台的系统通知会话)
- is_system: bool = False
- app_id: Optional[int] = None
- app_name: Optional[str] = None
- # 业务侧 Application.app_id 字符串(与 SSO / 客户端缓存键一致);仅按应用拆分的系统会话可能有值
- application_app_id: Optional[str] = None
- icon_url: Optional[str] = None
- icon_object_key: Optional[str] = None
- # 列表副文案:有 app 的应用通知为「应用通知」;无 app 的旧系统会话为空;用户会话为对端组织名,无组织为空
- remarks: Optional[str] = None
- class Config:
- from_attributes = True
- class AdminMessageItem(BaseModel):
- """运维消息查询返回的单条消息(含发送者/接收者/应用基础信息)。"""
- id: int
- type: MessageType
- content_type: ContentType
- title: str
- content: str
- action_url: Optional[str] = None
- action_text: Optional[str] = None
- is_read: bool
- created_at: datetime
- read_at: Optional[datetime] = None
- sender_id: Optional[int] = None
- sender_mobile: Optional[str] = None
- sender_name: Optional[str] = None
- receiver_id: int
- receiver_mobile: Optional[str] = None
- receiver_name: Optional[str] = None
- app_id: Optional[int] = None
- app_app_id: Optional[str] = None
- app_name: Optional[str] = None
- class Config:
- from_attributes = True
- class AdminMessageList(BaseModel):
- total: int
- items: List[AdminMessageItem]
- # Device Schema
- class DeviceRegister(BaseModel):
- device_token: str
- platform: str
- device_name: Optional[str] = None
|