本次提交包含多项核心更新: 1. 新增微信4.0浅色主题UI模板资源与说明文档,补充了联系人图标、新的朋友入口等四个UI元素的图像匹配模板 2. 重构UI驱动层,将原2375行的单文件拆分为5个职责清晰的子驱动类,提升代码可维护性 3. 新增批量群发消息与聊天记录导出的完整数据模型、路由与后台协程,支持幂等校验与风控配置 4. 为所有业务接口新增post_verify校验逻辑,补充了verified字段返回操作结果 5. 优化媒体文件解密逻辑,修复了导出功能中的数据库错误处理与分辨率硬编码问题 6. 更新版本配置,将媒体发送功能标记为已落地,调整了能力列表与配置项
112 lines
4.6 KiB
Python
112 lines
4.6 KiB
Python
"""发送域模型:发送文本 / 发送文件 / 发送响应。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Optional
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 发送接口
|
||
# ---------------------------------------------------------------------------
|
||
class SendTextRequest(BaseModel):
|
||
"""发送文本消息请求。"""
|
||
|
||
to_wxid: str = Field(description="目标 wxid")
|
||
content: str = Field(description="文本内容")
|
||
display_name: Optional[str] = Field(
|
||
default=None,
|
||
description="可选:用于微信搜索框定位会话的显示名。不传时 bridge 自动按备注->昵称->wxid 查找",
|
||
)
|
||
client_request_id: str = Field(default="", description="客户端幂等去重 ID,空字符串表示不参与幂等校验")
|
||
|
||
|
||
class SendFileRequest(BaseModel):
|
||
"""发送图片/文件请求。"""
|
||
|
||
to_wxid: str = Field(description="目标 wxid")
|
||
file_path: str = Field(description="容器内文件绝对路径")
|
||
display_name: Optional[str] = Field(
|
||
default=None,
|
||
description="可选:用于微信搜索框定位会话的显示名。不传时 bridge 自动按备注->昵称->wxid 查找",
|
||
)
|
||
client_request_id: Optional[str] = Field(
|
||
default=None,
|
||
description="可选:客户端幂等去重 ID,None 或空字符串表示不参与幂等校验",
|
||
)
|
||
|
||
|
||
class SendResponse(BaseModel):
|
||
"""发送消息响应。
|
||
|
||
字段说明:
|
||
- local_send_id:bridge 本地生成的发送 ID,格式 local_<unix秒>_<随机>。
|
||
仅用于客户端幂等去重,**不对应微信原生 msg_id**,禁止用于
|
||
/api/media/{msg_id} 查媒体。
|
||
- placeholder:是否为占位实现(true 表示真实文件/图片内容未传输,
|
||
仅发了提示文本;客户端应走降级处理)。
|
||
"""
|
||
|
||
success: bool = Field(default=False)
|
||
local_send_id: str = Field(default="", description="本地生成的发送 ID,非微信原生 msg_id")
|
||
placeholder: bool = Field(default=False, description="是否为占位实现(真实内容未传输)")
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
verified: bool = Field(default=False, description="是否已通过发送结果验证")
|
||
skipped: bool = Field(default=False, description="是否因幂等去重被跳过")
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 消息撤回(experimental)
|
||
# ---------------------------------------------------------------------------
|
||
class RevokeMessageRequest(BaseModel):
|
||
"""撤回消息请求(experimental)。"""
|
||
|
||
talker: str = Field(description="会话对方 wxid")
|
||
create_time: int = Field(description="消息发送时间戳(Unix 秒),用于校验撤回时限,必须 > 0")
|
||
display_name: Optional[str] = Field(
|
||
default=None,
|
||
description="会话显示名(备注/昵称),用于微信搜索框定位会话;"
|
||
"不传则从 contact.db 解析(优先 remark,其次 nickname,回退 wxid)",
|
||
)
|
||
|
||
|
||
class RevokeMessageResponse(BaseModel):
|
||
"""撤回消息响应。"""
|
||
|
||
success: bool = Field(default=False)
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
verified: Optional[bool] = Field(
|
||
default=None,
|
||
description="post_verify 校验结果:True=已确认撤回标记写入 DB,"
|
||
"False=超时未检测到,None=未执行校验(DB 不可用或未接入)",
|
||
)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 消息转发(experimental)
|
||
# ---------------------------------------------------------------------------
|
||
class ForwardMessageRequest(BaseModel):
|
||
"""转发消息请求(experimental)。"""
|
||
|
||
talker: str = Field(description="源会话对方 wxid")
|
||
target_display_name: str = Field(
|
||
description="转发目标联系人的显示名(备注/昵称)"
|
||
)
|
||
source_display_name: Optional[str] = Field(
|
||
default=None,
|
||
description="源会话显示名,用于搜索框定位源会话;不传则从 contact.db 解析",
|
||
)
|
||
|
||
|
||
class ForwardMessageResponse(BaseModel):
|
||
"""转发消息响应。"""
|
||
|
||
success: bool = Field(default=False)
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
verified: Optional[bool] = Field(
|
||
default=None,
|
||
description="post_verify 校验结果:True=目标会话出现 type=49 转发消息,"
|
||
"False=超时未检测到,None=未执行校验",
|
||
)
|