diff --git a/app/.gitignore b/app/.gitignore
index 932d7b054..e5127ff9c 100755
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1,5 +1,6 @@
.env
.local-workstation/
+resources/local-asr/
.venv/
.venv-build/
.venv-win7-check/
diff --git a/app/artifacts/patient_appointment_density/appointments_1024x640.png b/app/artifacts/patient_appointment_density/appointments_1024x640.png
index 83cfc4cee..64ef0aa17 100755
Binary files a/app/artifacts/patient_appointment_density/appointments_1024x640.png and b/app/artifacts/patient_appointment_density/appointments_1024x640.png differ
diff --git a/app/artifacts/patient_appointment_density/appointments_1366x768.png b/app/artifacts/patient_appointment_density/appointments_1366x768.png
index f927c4fa3..1a435e4c8 100755
Binary files a/app/artifacts/patient_appointment_density/appointments_1366x768.png and b/app/artifacts/patient_appointment_density/appointments_1366x768.png differ
diff --git a/app/artifacts/patient_appointment_density/patients_1024x640.png b/app/artifacts/patient_appointment_density/patients_1024x640.png
index bec10d926..a2e433bdb 100755
Binary files a/app/artifacts/patient_appointment_density/patients_1024x640.png and b/app/artifacts/patient_appointment_density/patients_1024x640.png differ
diff --git a/app/artifacts/patient_appointment_density/patients_1366x768.png b/app/artifacts/patient_appointment_density/patients_1366x768.png
index 9a8e0100d..d74ac6456 100755
Binary files a/app/artifacts/patient_appointment_density/patients_1366x768.png and b/app/artifacts/patient_appointment_density/patients_1366x768.png differ
diff --git a/app/artifacts/prescription_list_density/prescriptions_1366x768.png b/app/artifacts/prescription_list_density/prescriptions_1366x768.png
index 76ab87598..ff03f3f63 100755
Binary files a/app/artifacts/prescription_list_density/prescriptions_1366x768.png and b/app/artifacts/prescription_list_density/prescriptions_1366x768.png differ
diff --git a/app/artifacts/reception_ai_exact/reception.png b/app/artifacts/reception_ai_exact/reception.png
index dbd6c3b85..b1b47b8b9 100755
Binary files a/app/artifacts/reception_ai_exact/reception.png and b/app/artifacts/reception_ai_exact/reception.png differ
diff --git a/app/artifacts/subwindow_exact/prescription_ai_report_920x760.png b/app/artifacts/subwindow_exact/prescription_ai_report_920x760.png
index a16214673..1dc7109a1 100755
Binary files a/app/artifacts/subwindow_exact/prescription_ai_report_920x760.png and b/app/artifacts/subwindow_exact/prescription_ai_report_920x760.png differ
diff --git a/app/artifacts/subwindow_exact/prescription_detail_920x780.png b/app/artifacts/subwindow_exact/prescription_detail_920x780.png
index c0143bd85..029dd3ca9 100755
Binary files a/app/artifacts/subwindow_exact/prescription_detail_920x780.png and b/app/artifacts/subwindow_exact/prescription_detail_920x780.png differ
diff --git a/app/artifacts/subwindow_exact/prescription_editor_860x900.png b/app/artifacts/subwindow_exact/prescription_editor_860x900.png
index faac679bd..750cac325 100755
Binary files a/app/artifacts/subwindow_exact/prescription_editor_860x900.png and b/app/artifacts/subwindow_exact/prescription_editor_860x900.png differ
diff --git a/app/packaging/doctor_workstation.spec b/app/packaging/doctor_workstation.spec
index e9080ec1d..7fa9d3f4e 100755
--- a/app/packaging/doctor_workstation.spec
+++ b/app/packaging/doctor_workstation.spec
@@ -10,11 +10,14 @@ modules, Qt6Multimedia shared libraries/frameworks, multimedia plugins, and
their platform media backends.
"""
+import importlib.util
import os
import re
import sys
from pathlib import Path
+from PyInstaller.utils.hooks import collect_all
+
PROJECT_ROOT = Path(SPEC).resolve().parent.parent
SOURCE_ROOT = PROJECT_ROOT / "src"
@@ -108,15 +111,24 @@ qt_multimedia_hiddenimports = [
"PySide6.QtMultimediaWidgets",
]
+# Cloud transcription only needs offline character conversion on the client.
+if importlib.util.find_spec("opencc") is None:
+ raise SystemExit("Install the project dependencies before packaging (missing opencc)")
+transcript_datas, transcript_binaries, transcript_hiddenimports = collect_all("opencc")
+client_resources = [
+ (str(entry), f"resources/{entry.name}" if entry.is_dir() else "resources")
+ for entry in RESOURCES.iterdir()
+ if entry.name != "local-asr"
+]
+
analysis = Analysis(
[str(ENTRY_POINT)],
pathex=[str(SOURCE_ROOT)],
- binaries=python_runtime_binaries,
+ binaries=python_runtime_binaries + transcript_binaries,
datas=[
(str(VIDEO_DIST), "video_companion_dist"),
- (str(RESOURCES), "resources"),
- ],
- hiddenimports=qt_webengine_hiddenimports + qt_multimedia_hiddenimports,
+ ] + client_resources + transcript_datas,
+ hiddenimports=qt_webengine_hiddenimports + qt_multimedia_hiddenimports + transcript_hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[str(MEDIA_SMOKE_HOOK)],
diff --git a/app/pyproject.toml b/app/pyproject.toml
index 3ec7f4265..9fcd95be8 100755
--- a/app/pyproject.toml
+++ b/app/pyproject.toml
@@ -13,12 +13,16 @@ authors = [{ name = "Zhenyangtang" }]
dependencies = [
"httpx>=0.27.2,<1",
"keyring>=25.5,<26",
+ "opencc-python-reimplemented==0.1.7",
"platformdirs>=4.3,<5",
"PySide6>=6.8.2,<7",
"python-dotenv>=1.0.1,<2",
]
[project.optional-dependencies]
+local-asr = [
+ "faster-whisper==1.2.1",
+]
dev = [
"pytest>=8.3,<9",
"pytest-cov>=6,<7",
diff --git a/app/research/client-ui-design.md b/app/research/client-ui-design.md
new file mode 100644
index 000000000..0a780bbb3
--- /dev/null
+++ b/app/research/client-ui-design.md
@@ -0,0 +1,72 @@
+# 医生工作站客户端设计规范
+
+本轮覆盖现有 PySide6 客户端与 Vue 视频伴随窗口。按 `redesign-existing-projects` 审查现有页面,结合 `minimalist-ui` 的扁平化原则实施;医疗工作台保留信息密度,不套用营销页面的大留白、装饰动效或布局模板。
+
+## 审查结论
+
+- 主框架与业务页面原先并存科技蓝、紫蓝及多套中性色;登录、AI、诊单的控件也各自定义配色。
+- 页面内圆角、边框和层级不统一,部分阴影、悬浮位移和过渡使操作显得跳动。
+- 小窗口的表格、诊单与视频操作需要分别验证,不能依靠整体缩小解决。
+- 键盘焦点、禁用与选择状态应始终可识别,不通过改变控件几何位置表达状态。
+
+## 视觉系统
+
+设计变量以 `src/doctor_workstation/ui/design_system.py` 为准。旧页面通过 `clinical_stylesheet` 迁移已知的浅色主题颜色,新样式使用命名变量。医学数据曲线、模型标识色和深色主题不进行全局替色。
+
+| 角色 | 值 | 使用场景 |
+| --- | --- | --- |
+| 主色 | `#4267B2` | 主操作、选中项、重要链接 |
+| 主色浅底 | `#EAF0FB` | 选中背景、轻量状态 |
+| 画布 | `#F5F7FA` | 主窗口背景 |
+| 表面 | `#FFFFFF` | 内容区、对话框 |
+| 次级表面 | `#F7F9FC` | 筛选栏、分组、只读区域 |
+| 侧栏 | `#F0F3F8` | 导航区域 |
+| 标题 / 正文 | `#223047` / `#344258` | 文字层级 |
+| 次级文字 | `#647287` | 说明、辅助信息 |
+| 边框 / 强边框 | `#E6EAF0` / `#D4DCE8` | 低对比结构线、输入边界 |
+| 成功 / 警示 / 危险 | `#287B65` / `#96601D` / `#B54A59` | 保留明确语义,不只依赖颜色 |
+
+- 圆角:标签 6 px、输入与按钮 10 px、内容面板 16 px、独立窗口 20 px。
+- 间距:8 / 12 / 16 / 24 px,根据现有表格密度调整,不整体放大行高。
+- 字体:继续使用打包的中文字体与现有可读字号;标题层级通过字重、字号和间距体现。
+- 表面:纯色为主,轻边框划分区域,减少嵌套卡片与装饰阴影。
+- 按钮:每个操作组主次清晰;次要操作使用浅底或边框;终止、删除等危险操作保留语义色。
+
+## 交互规范
+
+- 悬浮、按下和焦点反馈不移动布局、不改变控件尺寸。
+- 动画短而克制;滚动可被键盘、拖动、程序定位与反向滚动即时打断;尊重减少动画设置。
+- 切换页面保留原有路由、权限和数据加载机制。
+- 登录表单保留密码存储、服务器设置与提交保护;组合密码框使用实际 Qt 焦点状态。
+- 大小窗口都必须能找到主要操作,优先局部滚动而非把全部内容压小。
+- 视频保留原有截图捕获、确认上传、大预览和小窗关闭返回大窗逻辑;视觉样式不改变媒体内容或尺寸计算。
+
+## 覆盖范围
+
+1. 登录与品牌区:扁平品牌面板、简洁功能说明、清晰表单与焦点。
+2. 主框架:导航、顶部搜索、工具按钮、标签与 AI 入口。
+3. 列表:挂号、接诊记录、患者、处方库、已开处方、业务订单及患者进度。
+4. 诊疗:接诊台、预约抽屉、诊单编辑与只读、指标和保存状态。
+5. 辅助窗口:AI 问诊、处方编辑、处方解读与报告控制台。
+6. 视频:通话控制、聊天、录制提示与截图确认。
+
+## 验收方式
+
+`scripts/render_client_design.py` 使用演示仓库生成 1440 × 900、1024 × 640 的真实页面,以及 1280 × 800、860 × 640 的登录页;输出 `artifacts/client-design/index.html` 与原尺寸 PNG。诊疗和 AI 弹窗使用现有专用渲染脚本验证。
+
+检查重点:小窗操作可达、中文可读、表格信息密度、长文本换行、键盘焦点、布局稳定、登录与页面路由契约、视频截图与窗口状态回归。生产服务与真实患者资料不用于视觉验收。
+
+本轮共享组件还覆盖筛选展开按钮、列表加载状态、聊天通知、更新提示、本机录音队列、媒体预览和上传进度。860 × 640 登录表单完整显示,不需要为纯留白滚动。
+
+## 验证记录与边界
+
+- 主框架、登录、遮罩与动效首轮 100 项通过;新增组合密码框键盘焦点检查通过。
+- 小窗登录与焦点补测 2 项、最终登录及主框架复查 68 项通过。
+- 筛选、无限列表、通知、更新窗口与本机录音队列 37 项通过。
+- 原生视频截图、截图预览尺寸、小窗关闭与视频契约 199 项通过。
+- 视频前端 26 项检查通过,生产 dist 已重新构建。
+- 当前视频 dist 在 1120 × 760、540 × 356、440 × 300 的合成画面中完成 27 项布局检查,截图与关闭事件正常,未访问外部服务。
+- 临床页面、AI、处方及图表分别完成专项测试和真实控件渲染,详细记录位于 `artifacts/client-design/*-report.md`。
+- 最终修改文件的 Ruff 与 `git diff --check` 均通过;AI 工作区及快捷操作权限最后复查 24 项通过。
+
+此记录不表示整仓所有历史测试全部通过。扩展测试中存在已用原始 HEAD 复现的 AI 流式/延迟生命周期失败、共享 QApplication 样式引发的图表测试顺序依赖,以及 Windows Qt 网络模块异常;本轮没有改变相关业务行为。未连接真实面诊服务,也未重新打包或安装 Windows 客户端。
diff --git a/app/research/cloud-transcription-restore.md b/app/research/cloud-transcription-restore.md
new file mode 100644
index 000000000..fa8b43945
--- /dev/null
+++ b/app/research/cloud-transcription-restore.md
@@ -0,0 +1,21 @@
+# 腾讯云实时转写恢复(2026-10-30)
+
+用户明确选择“恢复腾讯云实时转写,保留简体中文”。本次仅替换识别通路,保留 IM AI、实时 AI 辅助、复盘、本机录音、视频录制、截图和窗口交互。
+
+## 当前行为
+
+- 使用当前固定 SDK 的 `getAITranscriberManager()` 和 `startRealtimeTranscriber({sourceLanguage: 'zh'})`。不再启动本地 PCM 识别或加载 Whisper/Nano 模型,本机语音录音保持独立。
+- 最终转写片段先经过原生可信页面及会话校验,以宿主的医生/患者用户 ID 确定角色,再用本机 OpenCC 转为简体并保存。仅持久化成功的确认回传简体文字,字幕和本次 AI 引用使用同一保存原文;历史记录查看仍显示简体。
+- 同一通话的云端重试复用原转写会话,保留已保存字幕和 AI 结果;云端中断不提前封存存储,真正挂断时才排空并归档。出错期间可能漏记的通话最终标记 partial。
+- 云端启动成功通过 `transcription-ready` 更新原生状态,避免重试成功仍显示失败;旧页面、旧会话、旧监听器及本地 ASR 命令不能混入当前会话。
+- 启动/打包脚本不再默认启用 `local-asr` 额外依赖;仍打包简体转换字典。`resources/local-asr` 从发布资源中排除。已有开发模型和独立测试模块保留,不默认使用。
+
+## 验证及生效
+
+仅用合成身份/文字与 SDK 替身验证启停、重试、尾段排空、成功保存后的六参数 ACK、简体转换、说话人归属、AI 更新和隔离边界。截图、大小窗及录音回归继续通过,前端类型检查和生产资源重建完成。
+
+详细结果见 `app/artifacts/im-ai/cloud-transcription-restore-frontend.md`、`cloud-transcription-restore-native-tests.md`。没有发起真实患者通话或验证线上腾讯云识别效果,没有生成新的完整安装包。
+
+最终整合验证:338 项 Python 回归、128 项前端测试通过,Vue 类型检查及生产构建通过。已核对真实 Qt 六参数转写信号,以及 PyInstaller 资源展开结果:图标、字体和简体词典保留,本地识别模型不进入发布资源。
+
+源码客户端需要在结束当前通话后退出并重新启动整个客户端,原生 Python 代码与新前端资源才能一起生效。已冻结安装包需重新构建,不能只更换网页资源。
diff --git a/app/research/im-ai-assistance.md b/app/research/im-ai-assistance.md
new file mode 100644
index 000000000..19774606a
--- /dev/null
+++ b/app/research/im-ai-assistance.md
@@ -0,0 +1,75 @@
+# IM 问诊 AI 辅助
+
+用户确认范围:在现有 IM 问诊窗口内增加「总结病情」「建议追问」「起草回复」。结果供医生审阅,医生主动填入输入框后编辑并手动发送。
+
+## 集成契约
+
+- 复用 `stream_diagnosis_ai`:总结使用 `summary`,追问和回复使用 `custom`。不新增模型配置、不把凭据传到浏览器、不新增服务端路由。
+- 每次生成前,通过 `sync_im_chat_messages(scope="current", sync_token=...)` 完成当前账号对话归档;响应 `completed=true` 且没有错误后才能调用 AI。准备失败明确报错,不静默降级为旧聊天。服务器按授权诊单聚合临床资料与归档 IM,提示词限定本次医生账号的近期对话。
+- 三项提示词保持 500 字以内;不在提示词中挤入、截断完整聊天或未发送草稿。
+- AI 独立后台 worker,不占用通话、录音和消息发送的队列。
+
+原生配置 `DoctorCallConfig.imAi`:`{version:1, enabled:boolean, sessionId:string, reason?:string}`。宿主生成 sessionId,每个新窗口独立。上层将 AI 权限布尔值贯穿 launcher;默认拒绝。
+
+浏览器到原生:
+
+```json
+{"source":"doctor-call","event":"im-ai-request","sessionId":"host-uuid","requestId":"uuid","contextKey":"frontend-context","diagnosisId":"501","appointmentId":101,"action":"summary"}
+```
+
+取消使用同一组身份字段及 `event="im-ai-cancel"`。只允许 `summary | followup | reply`。宿主核验可信文档、窗口未关闭、AI 权限、会话、诊单、挂号和请求格式;实际 repository 调用始终使用宿主绑定诊单。
+
+原生通过 `window.doctorConsultation.imAiResult(payload)` 返回相同身份字段与:
+
+```text
+status: loading | streaming | success | error | cancelled
+text?: 累积正文(流式及最终)
+message?: 简短进度或错误
+modelLabel?: 服务端模型标签
+warnings?: string[]
+```
+
+所有数据使用 JSON 序列化,桥接正文仍为原始文本。页面通过受限 Markdown 渲染器显示标题、重点、列表和表格;原始 HTML 被转义,链接和图片只保留文字,不执行内容或加载外部资源。客户端截止时间 180 秒,超时发送取消;原生聊天同步有独立有界预算,AI 沿用现有 105 秒传输预算。取消请求由独立线程发送,GUI 不等待网络。停止只是停止本次接收,不冒称上游工作已确认停止。
+
+## 界面与状态
+
+- 宽屏右侧约 330 px 辅助区;窄屏可收起抽屉,独立滚动,操作和关闭可达。沿用现有蓝色、圆角和轻边框。
+- AI loading 不阻塞 IM 输入、发送、加载更多和视频控制。
+- 只有完整成功结果允许填入;追问与回复可填入,病情总结默认只读。非空草稿明确追加,超过 3000 字拒绝追加而不截断原文。
+- 切换会话清空 AI 状态和草稿;迟到、重复、身份不匹配结果全部忽略。
+- 异步手动发送成功仅清空当时提交且没有继续修改的草稿。
+- 结果注明医生复核,展示服务端临床复核提示;不会自动发送、写病历或开处方。
+
+## 验证要求
+
+离线 fake repository 验证同步续拉、失败不生成、取消、终态、身份隔离、权限与关闭;Node 测试验证桥接状态/计时器、草稿追加和发送隔离;使用真实构建产物和合成消息验证宽屏与紧凑窗口。回归截图、录音收尾、通话权限与 IM 流程。验证不得访问真实患者、IM 或 AI 服务。
+
+## 交付与验证结果(2026-10-29)
+
+- `app.py` 在实际打开窗口时读取当前账号的 `tcm.diagnosis/aiAssistant` 权限,经 launcher 传入原生窗口;未配置权限时默认关闭,不采用聊天载荷中的权限标记。
+- 三项功能已接入真实 Qt bridge 和现有流式服务;宽屏常驻侧栏,980 px 及以下窗口使用可收起抽屉。中文输入法选词时按 Enter 不发送,异步发送不会清除医生随后编辑的草稿。
+- 合并后 Python 回归 **364 项通过**:包括新增 AI 服务/仓库/窗口、权限入口、IM、视频契约、截图、小窗关闭及大预览等。运行使用独立 `artifacts/im-ai/final-integration-tmp`,未访问外部服务。
+- 前端 **45 项 Node 行为测试通过**,`vue-tsc` 与 Vite 构建通过;实际 dist 在 1120×760、980×640、540×356、440×300 下 **42 项界面检查通过**。离线夹具只使用合成消息和结果,外部请求尝试为 0。
+- Ruff 与 `git diff --check` 通过。首次交付构建入口:`index-CnqWQu6O.js`、`index-BwArpbVK.css`。
+- 截图、可复现夹具和详细报告存放在 `app/artifacts/im-ai/`。未验证真实账号的模型响应;未生成 Windows 安装包。源码运行需重启客户端,已安装版本需重新打包后安装。
+
+停止接收后,原生端会独立请求取消;在旧请求实际退出前重试会提示稍后再试,避免重复模型请求。聊天同步失败时不使用旧归档静默生成,助手显示错误并允许重试。
+
+## 结果排版与切换改进(2026-10-29)
+
+- 模型输出的 Markdown 标题、加粗、列表、引用、代码和简单表格转换为安全的结构化展示;重点以加粗和浅蓝底色标记,结构标题使用蓝色引导线。不依据医学关键词自行推断重点。未闭合的流式片段保持可读原文。
+- 三项操作在当前窗口会话内分别保留状态、正文、模型标签和复核提示。顶部按钮首次点击生成,之后只切换查看;底部“重新生成/重试”才会再发请求。生成中可以阅读其他已完成结果,后台更新不能覆盖当前阅读页。
+- 每项保留独立滚动位置,换患者、关闭或重开会话时清空。结果仅保存在内存中,不增加本地患者内容持久化。
+- 填入草稿前去除 Markdown 排版符号,保留原文、数值和列表含义,再执行 3000 字长度检查;仍不覆盖原稿、不自动发送。
+- 本次前端 **61 项行为测试通过**,包含安全渲染、草稿转换、缓存、显式重生成、后台流式隔离及现有截图/通话守卫;TypeScript 与 Vite 构建通过。
+- 真实 dist 配合生产 AI controller 源码和离线宿主替身,在四种窗口尺寸完成 **20 项可点击/布局检查**,以及切换不发请求、显式刷新、后台生成、独立阅读位置、原稿追加及注入防护断言。外部请求为 0。
+- 证据:`artifacts/im-ai/refinements-visual-checks.json`、`render_im_ai_refinements.py` 与 `im-ai-styled-cached-*.png`。未打包安装程序。
+
+## 可调宽度、首次总结与指标强调(2026-10-29)
+
+- 聊天与助手之间增加可左右拖动的分隔线,宽屏保留至少 480 px 聊天区域;窄屏抽屉也可调整,最大宽度仍留出可操作的边缘。支持方向键、Home/End、Enter 或双击恢复默认,Escape 取消本次拖动。窗口变更、失焦与关闭释放指针捕获。宽屏和抽屉宽度分别记忆在当前窗口内。
+- 进入有权限的 IM 会话后,首次总结等待当前登录、聊天、Qt 通道及原生 `imAiReady(sessionId)` 确认;准备等待最多 30 秒。每个会话只自动尝试一次,不因重连、标签切换、展开面板或失败自动重试。医生提前手动操作会取消待启动的自动总结。关闭和换会话清理计时器及旧结果。
+- 普通文本中的血糖、血压、糖化血红蛋白、体重等指标名称及带单位的数值自动强调,支持范围、小数和血压组合。名称加深,数值加粗并显示浅蓝底色,不依赖模型输出 Markdown。原始数值、单位、否定和不确定表述保持不变;没有新增医学阈值判断或自动风险分级。
+- **97 项前端测试、318 项客户端回归通过**,TypeScript、Vite 和 Ruff 检查通过,`git diff --check` 无问题。当前构建:`index-C_tMrPfb.js`、`index-CMN1CXTr.css`。
+- 实际构建页面在 1634×1008、1120×760、980×640、540×356、440×300 下完成真实 Qt 鼠标拖动、键盘调整、取消、跨断点释放及指标样式检查,**15 项布局/点击检查通过**,自动选择与请求次数断言通过,外部请求为 0。
+- 证据:`artifacts/im-ai/render_im_ai_resizing.py`、`resizing-visual-checks.json`、`im-ai-metrics-resizable-*.png`。本轮未生成安装包;原生就绪握手需重启使用最新源码的客户端。
diff --git a/app/research/live-ai-response-improvements.md b/app/research/live-ai-response-improvements.md
new file mode 100644
index 000000000..1704b5a1d
--- /dev/null
+++ b/app/research/live-ai-response-improvements.md
@@ -0,0 +1,72 @@
+# 实时问诊 AI:响应与建议质量改进
+
+日期:2026-10-30。最新范围调整:仅视频接通后的实时 AI 使用本次通话文字;IM、病历分析与通话后复盘保持原范围。见末尾“纯对话实时模式”。
+
+## 问题证据
+
+从本机服务端当天运行日志中仅提取错误码和耗时,共发现 10 条 `LIVE_RESULT_INVALID` 记录:最短 12,833 ms,中位 15,002 ms,最长 29,465 ms。这说明部分等待最终消耗在无效结果上;原日志没有校验细项,不能断言具体是哪一种格式或引用错误。
+
+代码另有两处可确认的问题:有结果后的新增对话要等待 8 秒才发起下一轮;“症状要点”允许放入医生的完整问句。模型还会重复询问已有年龄,且只有整份 JSON 通过后才显示结果。
+
+## 已实现
+
+- 首次已保存转写后等待约 0.8 秒发起分析,后续更新等待改为 2 秒。等待从第一段新增内容起算,持续说话不会无限推迟。每个窗口仍只有一个在途分析,期间新内容合并,已到期的下一轮不会在上一轮结束后再次等待。
+- 服务端完整验证一条带合法分隔符的结果后,通过 `live_update` 提前交付累计内容,不再等待整个数组闭合。按实际可展示条目增加发送,实时最多 12 次、复盘最多 15 次,最终仍需 `done`。原始 JSON 片段不展示;客户端同样验证诊单、通话、转写会话、版本及所有引用。失败保留已经可核对的内容,并标明本轮尚未完成。
+- 优先生成最多三条“下一步追问”,给出简短理由;实时辅助依据完整本次对话减少重复,通话后复盘仍结合授权病历。保留发病年龄、历史年龄和家属信息等必要的追问空间。
+- 患者摘要由已校验的引用 ID 还原完整原话,不采用模型改写的事实。省略医生、未知说话人和单纯问题选段。合法 JSON 代码块包装可以解析;引用、数据范围和内容校验继续执行。
+- 侧栏首问突出显示,再展示患者关键信息、待核实及复盘。显示实际已用时间、待处理分段和内容依据时间;区分连接、超时、格式、引用、权限等失败,不再统一提示升级服务端。
+- 去除模型输入中当前转写和授权历史的重复副本,保留完整来源、资料权限、附件清单和现有超时预算。增加首条有效建议及整轮耗时的安全日志,不记录患者原文或模型正文。
+- 沟通追问可帮助了解患者诉求、理解困难和执行顾虑,不预设需要新增治疗、检查或购买项目。腾讯云实时转写、简体中文及现有通话流程保持原配置。
+
+## 验证与构建
+
+- 客户端 Python 相关回归:277 项通过;Ruff 通过。
+- 前端组件、通话和布局等测试:136 项通过;Vue 类型检查、生产构建通过。
+- 服务端质量测试:421 个累计断言;流式集成:851 个累计断言;真实请求构造的响应契约测试:167 个累计检查。它们包含各自复用的基础断言,不能简单相加视为独立用例数。前一轮 SSE 协议、错误回执、心跳、计时、请求生命周期回归通过。
+- `git diff --check` 通过;未提交或撤销其他开发中的功能。
+- 构建产物:`app/video_companion/dist/index.html`,脚本 `index-DZWRwUZ-.js`,样式 `index-BbhpEZgS.css`。Vite 仍提示现有视频 SDK 主包体积较大;构建成功。
+
+测试使用合成资料,未发送真实患者资料,未发起真实通话。第二轮另做了下述一次成功的纯文字在线合成验收。浏览器工具未完成本次视觉验收,组件与布局验证已完成。未重启医生客户端或部署远程服务端。
+
+## 针对 16 秒反馈的第二轮定位与处理
+
+11:13 的成功请求在客户端耗时 16,922 ms,首条有效内容 14,952 ms。对应服务端聚合仅 79 ms,未做历史压缩;附件处理 2,800 ms,其中 OCR 2,233 ms;Dify 传输 13,630 ms,其中模型节点开始到首正文约 8,098 ms。这些是相互包含的阶段,不能把嵌套指标重复相加。客户端与服务端按时间及状态关联,不是通过同一 trace ID 直接关联。
+
+此次新增处理:
+
+1. 修复公共 Dify 传输给实时任务附加长报告诊疗规则的冲突。仅服务端选定 `response_contract=live_consultation` 的问诊/复盘使用简短的实时结构化契约,普通诊疗报告保持原规则。当前完整资料、附件、否定/日期/角色及“不采脉”边界均保留。
+2. 逐条交付第一条已校验内容,不等后续问题和整组输出。医生/未知来源不能被理由改写成“患者自述”,明确的无患者依据事实前提会省略。
+3. 增加 300 秒 OCR 私有缓存,按凭据、应用端点、用户、原图内容、识别配置和运行环境绑定。每次仍重新校验当前来源;失败或识别预算耗尽不缓存。正常无文字图片可按原 unreadable 状态复用,原图仍发送,未减少医学资料。缓存上限 64 个槽位、32 MiB;实际图片内容及模型身份变化即失效。
+4. 客户端分别显示首条有效结果和整轮完成时间,未知首条时间不显示为零。
+
+OCR 新增 45 个离线断言通过;原桥接 25、预算 13、上传复用 62 项检查通过。两项外围测试仍失败,已用 Git HEAD 对应实现复现相同失败,未掩盖或计入通过:`DifyImageTextEvidenceTest.php:30` 的既有索引文案断言,以及 `DifyRequiredAttachmentUploadTest.php:519` 的既有“全缺失附件 + 无效配置”断言。后者在沙箱内先受回环测试服务器限制,在正常回环环境下才到达该断言。
+
+在线合成验收使用现有 Qwen/Dify、无图片、无真实患者资料。一次成功请求的首条有效结果为 **1,306 ms**、整轮 **2,181 ms**,JSON 与引用校验通过。沙箱内两次连接立即失败,随后允许网络的同一合成脚本成功;不把失败连接算作模型速度样本。该结果只证明轻量文字请求可以快速且按契约返回,不能证明原来带图病例的 16.9 秒已降到 2.2 秒,也不是控制变量前后对比。实际带图问诊的缓存收益、首条和整轮耗时仍待部署后的相同场景验证。
+
+## 生效与验收
+
+客户端需要加载本次构建并重新启动;使用远程 PHP 服务时需同步服务端改动。旧服务端仍可通过最终 `done` 返回结果,但不能提前交付建议。
+
+下一次实际使用应比较“已保存转写至首条有效建议”的耗时和校验失败率,同时由医生检查追问相关性、信息遗漏及患者理解情况。0.8 秒、2 秒仅为发起请求前的等待,不是模型响应承诺。本轮不声称已经验证诊断准确率或成单率提升。
+
+## 纯对话实时模式
+
+根据用户“仅限视频接通后的 AI 那一块”的明确限定,只有 `live_consultation` 改为 `current_call_only`。视频中的自动更新与重新生成只提交本次会话已保存的全部转写;不读取诊单详情、历史病历,不做病历压缩、OCR 或附件上传。权限、有效诊单、通话归属、会话身份与完整转写快照的校验仍在;原有 1 MiB 容量超限会明确拒绝,不截断早期文字。
+
+`live_review` 保持 `authorized_case`,继续结合授权病历与图片;IM 总结、追问、起草回复及普通病历 AI 未改。实时提示词不再包含未提供的病历块,明确只依照本次对话、跳过已答问题。代价是没有在对话提及的历史过敏、用药、检查等资料不会纳入实时建议,不能将建议视作完整病历评估。
+
+服务端在 start、live_update、done 返回可信分析范围。客户端只在结果校验通过后更新“当前内容仅依据本次通话文字,不含历史病历和图片”的说明;复盘等待或失败时不会把旧结果标成另一范围。旧服务端未提供范围时也不会误标为纯对话。同一请求中范围不一致会拒绝更新。
+
+验证:纯对话服务端专测 328 个累计断言,包括 220 个完整分段、超过旧历史压缩阈值的长文本逐字一致、拒绝任何病历详情/历史读取、零附件,以及普通 summary 和完整复盘隔离。真实 Dify 构包测试 203 个累计检查;进度与质量回归仍为 851、421 个累计断言。客户端 277 项、前端 136 项均通过。服务端完整记录在 `app/artifacts/im-ai/dialogue-only-server.md`;其中两组普通临床策略测试的额外既有失败已隔离复现,没有将它们计入通过或改变其行为。
+
+在线测速仅使用 6 段完全合成的对话,经真实请求构造器及 `streamPreparedAssistant` 的完整流式校验路径请求现有 Qwen/Dify。没有查询真实诊单、患者转写或图片。三轮结果:
+
+| 轮次 | 首条已校验结果 | 整轮完成 | 结果 |
+| --- | --- | --- | --- |
+| 1 | 859 ms | 2,130 ms | 引用与结构校验通过 |
+| 2 | 785 ms | 2,001 ms | 引用与结构校验通过 |
+| 3 | 806 ms | 2,021 ms | 引用与结构校验通过 |
+
+计时包括纯请求构造与真实流式模型处理,不含语音转写、保存分段、触发等待和客户端渲染。每轮 query 为 5,526 bytes、6 个分段、零附件,首轮与后续轮次均使用独立合成上游用户标识。这不是实际长通话延迟保证,也不是与原带图病例的控制变量对照。数据记录在 `app/artifacts/im-ai/live-dialogue-only-online-timing-20261030.json`。
+
+尚未部署远程服务端或重启正在运行的医生客户端。需要服务端加载最新代码、客户端加载本次构建后才会生效;腾讯云实时转写与简体中文配置保持原样。
diff --git a/app/research/local-transcription-setup.md b/app/research/local-transcription-setup.md
new file mode 100644
index 000000000..0a9f8a939
--- /dev/null
+++ b/app/research/local-transcription-setup.md
@@ -0,0 +1,92 @@
+# 本地离线语音转写:安装、打包与验证
+
+> 当前状态(2026-10-30):用户已明确要求恢复腾讯云实时转写、保留简体中文。客户端默认通路已经恢复腾讯云,启动/打包不再自动安装本地 ASR,也不把本地模型加入发布资源。本文后续内容保留为此前本地方案的开发、安装与评估记录,并非当前默认行为。当前通路见 `cloud-transcription-restore.md`。
+
+运行时使用 faster-whisper 1.2.1,在医生电脑的 CPU 上以 int8 加载本地 Whisper 模型。音频为浏览器桥接传入的单声道、16 kHz、有符号 PCM16 小端字节流;不写临时音频、不发送至 ASR 服务。模型安装和下载只能通过下面的显式命令执行,视频通话不会触发安装、下载或腾讯云语音识别。
+
+## 开发环境安装
+
+在已安装医生工作站依赖的 `app` 目录运行:
+
+```powershell
+.venv\Scripts\python.exe scripts/setup_local_transcription.py --install-dependencies --download --model-size small --check
+```
+
+此命令明确允许联网安装 `faster-whisper==1.2.1` 及其传递依赖,并从官方 `Systran/faster-whisper-small` 仓库下载模型,然后禁用网络验证 CPU/int8 模型和 Silero VAD 的加载。`tiny`、`base`、`small`、`medium`、`large-v3` 均可选择;中文场景不要使用英文专用 `.en` 模型。开发默认选择 `small`,实际识别准确率和延迟仍需在目标电脑与实际通话音频上验收。
+
+`--install-dependencies` 仅安装至执行命令的 Python 环境;`--download` 才下载模型。不传操作参数只显示帮助。可用 `--revision <官方仓库提交哈希>` 固定下载版本。
+
+模型查找顺序为 `DOCTOR_ASR_MODEL_PATH`、开发目录或安装包内的 `resources/local-asr/model`、最后为 `platformdirs.user_data_path("ZhenyangDoctorWorkstation", appauthor="ZhenYangTang") / "local-asr" / "model"`。可以指定独立目录:
+
+```powershell
+$env:DOCTOR_ASR_MODEL_PATH = 'D:\DoctorModels\whisper-small'
+.venv\Scripts\python.exe scripts/setup_local_transcription.py --download --model-size small --check
+```
+
+`--model-path` 只覆盖本次安装/检查命令;工作站仍按上述顺序查找。下载后会记录 `doctor-asr-install.json`,包含仓库、请求的版本、运行库版本和时间,不包含音频。运行时要求目录存在,且 `model.bin`、`config.json`、`tokenizer.json`、`vocabulary.txt` 或 `vocabulary.json` 非空。缺失时直接报错。`tokenizer.json` 必须随模型提供,以阻止上游缺失 tokenizer 时的自动获取回退。
+
+离线电脑可通过离线安装包安装运行库,再复制完整模型目录;不要在通话过程中初始化下载。离线检查:
+
+```powershell
+.venv\Scripts\python.exe scripts/setup_local_transcription.py --check
+```
+
+## 桌面安装包
+
+为应用配置 `local-asr` 可选依赖(`faster-whisper==1.2.1`),并在实际 PyInstaller 构建环境安装该额外依赖。运行库需要 NumPy、CTranslate2、tokenizers、ONNX Runtime、PyAV 等上游依赖。不能仅在开发 `.venv` 安装后假设 `.venv-build` 或已冻结的 exe 自动拥有这些依赖。
+
+PyInstaller spec 已加入 `faster_whisper` 数据文件(包括 Silero VAD)及 `ctranslate2`、`onnxruntime`、`av`、`tokenizers` 的 `collect_all`,缺少运行库时构建会明确失败。Windows/macOS 运行环境准备与打包脚本已加入 `--extra local-asr`,依赖锁文件同步更新。构建前可把完整模型放在 `app/resources/local-asr/model`,随现有 resources 打入安装包;也可在目标电脑独立安装到应用数据目录或管理员指定目录。模型不纳入 Git。该模块导入依赖是延迟执行的,没有安装本地 ASR 运行库也不会阻止工作站、视频和录音模块启动。
+
+本轮未生成新 exe 或安装包。发布前仍需验证运行库、模型和 VAD 在成品内真实可用,不能把开发环境通过的单元测试作为成品 ASR 可用性的证明。旧系统兼容性取决于这些原生依赖的官方 wheel 和操作系统支持,不自动沿用工作站其他部分的兼容性声明。
+
+## 验证
+
+```powershell
+.venv\Scripts\python.exe -m pytest tests/test_local_transcription.py
+.venv\Scripts\python.exe -m ruff check src/doctor_workstation/video/local_transcription.py tests/test_local_transcription.py scripts/setup_local_transcription.py
+.venv\Scripts\python.exe scripts/setup_local_transcription.py --check --smoke-wav D:\ASR-Test\non-sensitive-16k-mono.wav
+```
+
+smoke WAV 必须是单声道 16 kHz PCM16,最长 12 秒。该命令阻止网络连接并输出识别结果;请使用无患者信息的人工测试音频。建议覆盖短回答“有”“不”、否定句、药物名称、0.5/5、剂量单位、静音、背景噪声,以及医生和患者同时说话。录音通道的角色来源于浏览器端音轨身份,模型不做声纹识别。
+
+单元测试使用替代引擎,验证会话隔离、异步回调、队列上限、序号验证、排空停止、错误脱敏、静音和数字/否定词的原样输出。替代引擎测试不证明实际模型准确率。启动和推理只能在后台执行;Qt 接收方通过 signal 转交主线程。`close()` 立即取消回调,正在执行的原生推理可能在守护线程中完成,不能在 UI 线程等待它。
+
+2026-10-29 已在本仓库 `.venv` 安装运行库,并在 `app/resources/local-asr/model` 安装官方 `Systran/faster-whisper-small`。CPU/int8 模型和 VAD 加载检查通过;使用 [FunASR 官方示例](https://github.com/modelscope/FunASR)提供的[公开中文音频](https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav)完成真实识别,检查及推理期间阻断网络。输出为“欢迎大家来体验打磨院推出的语音识别模型”,出现“达摩院”的同音误识;这验证了本机推理链路,不能代替医疗词汇、噪声、双向通话及目标电脑负载验收。没有发送真实患者资料,尚未测试真实 AI 服务响应。
+
+## 视频 AI 接入与验收
+
+现有腾讯音视频通信、IM 和云端录制继续使用;语音转写改由本地音轨 PCM 和本机模型完成。完成分段保存成功后才触发 AI,约八秒合并更新一次,无新增原文时不重复请求。使用现有 `tcm.diagnosis/aiAssistantStream` 的 `live_consultation`/`live_review` 任务;服务端按医生、诊单、通话及转写会话读取完整原文,再连同授权病历交给已授权的现有 Dify 服务。AI 不发送消息或自动写入病历。
+
+客户端新增 AI 辅助、对话原文、患者资料标签、可调侧栏宽度和窄屏抽屉。挂断后在 IM 顶部打开“本次通话复盘”;点击复盘按钮请求复盘草稿。每条辅助结果可以查看完整引用原话,转写未完整保存时明确显示状态。模型缺失、AI 服务未更新或没有权限时显示具体状态,视频通话可继续。
+
+生效需要部署本轮服务端代码,并重启使用新构建资源的客户端。开发验证只使用合成通话数据及公开音频,不连接真实患者。上线验收需在医生测试账号和合成患者下确认双方音轨归属、转写时延、挂断排空、服务端 AI JSON 格式、取消与复盘。
+
+模型/存储准备阶段先采集到最多 12 个 PCM 分段的内存缓冲;超限明确标记转写不完整。挂断后等待原生识别线程排空才封存文字,15 秒仅提示等待,不提前关闭文字存储。关闭应用时沿用 190 秒异常收尾上限,强制退出会把未完成转写标记为 partial。同会话的存储启动临时失败可以显式重试,正在执行或已成功的启动请求仍复用。
+
+音轨接入适配当前锁定的 CallEngine 3.5.9 / TRTCCloud 2.10.19:`getTRTCCloudInstance()` 返回包装对象,音轨 API 来自其 `_trtc`。`resolveTrtcAudioSource` 先验证实际能力,并保留方法所属实例;升级 SDK 时需重新运行真实包装对象的隔离验证。前端采集失败优先覆盖旧的 native running 状态,并保留独立错误文字和重试入口。持续声音或非零底噪的 PCM 提交窗口为约 4 秒,之后才排队识别,因此字幕按分段追加,不是逐字流式识别。无需提高音量来触发分段,轻声和短否定词不会因前端音量阈值被丢弃。
+
+该音轨修复后,118 项前端测试和 63 项转写桥接/通话回归通过,生产资源已重建。公开语音在隔离 Qt 中贯通了实际 SDK 包装适配、生产音频采集、真实 WebChannel、本地 faster-whisper、Qt 信号及实际 App 字幕 DOM,双方共 8 段均显示;首段实测 6.494 秒。SDK 实例的媒体获取替换为公开音频双轨,存储使用内存,因此仍不代表真实 RTC 发布/订阅与在线持久化已验收。详细材料为 `app/artifacts/im-ai/asr-fixed-end-to-end.md`。已打开的通话页面不会自动载入新脚本,结束当前通话后需关闭并重新打开 IM/视频窗口。
+
+本轮回归:384 项 Python 用例、113 项前端用例通过;PHP 新流式链路 440 项合成断言及 13 组既有回归通过。另有两个既有 PHP 套件在未修改的 HEAD 上同样失败,详见 `app/artifacts/im-ai/live-ai-server-implementation.md`,未将它们计入通过数。Vue 类型检查、前端生产构建、Python Ruff 和 diff 空白检查通过。隔离 QtWebEngine 加载本地合成页面,验证挂断入口、打开不重新生成、完整引用、弹窗 Tab 焦点循环、Escape 返回焦点和 440px 下按钮可见,截图位于 `app/artifacts/im-ai/video-ai-final-*.png`。未执行 macOS 真机构建或冻结安装包验收。
+
+## 核对的官方来源(2026-10-29)
+
+- [faster-whisper v1.2.1 模型和转写接口](https://github.com/SYSTRAN/faster-whisper/blob/v1.2.1/faster_whisper/transcribe.py):本地目录、`local_files_only`、CPU/int8 参数、数组音频输入、惰性 segments、tokenizer 回退。
+- [faster-whisper v1.2.1 本地 VAD](https://github.com/SYSTRAN/faster-whisper/blob/v1.2.1/faster_whisper/vad.py):Silero ONNX 资产和 VAD 参数。保留 `min_speech_duration_ms=0`,避免额外丢弃短否定词。
+- [faster-whisper 下载实现](https://github.com/SYSTRAN/faster-whisper/blob/master/faster_whisper/utils.py):官方模型映射与模型文件列表。
+- [Systran/faster-whisper-small 文件清单](https://huggingface.co/Systran/faster-whisper-small/tree/main):本地模型、tokenizer 和词表文件。
+
+## 简体输出与多方言边界(2026-10-30)
+
+`opencc-python-reimplemented==0.1.7` 是客户端基础依赖。使用随包配置/词典进行本地 `t2s` 字形转换,在原生转写 controller 发出字幕/保存事件前统一为简体;实时字幕、存储和新通话 AI 引用使用同一份文字。已有通话记录打开“面诊对话文字”时以简体显示,不批量改写历史数据库。数字、剂量、否定词、标点和方言词语保留,不使用大模型改写原话。字形转换不能修复误听,也不把粤语词汇翻译成普通话。
+
+安装工具已包含该依赖,PyInstaller 收集 `opencc` 配置和词典;模型启动时预加载转换资源,缺失则明确报错。不要同时安装同样提供 `opencc` 导入名的原生 `opencc` 分发。基础依赖与锁文件更新后,源码运行需要结束通话并重启客户端;单独重新打开网页不会重载原生 Python 代码。已冻结的安装包需要重新构建。
+
+当前通用 Whisper small 不等于多方言专项模型。7 类方言/26 种地域口音的 Fun-ASR-Nano 是本地替代候选,具体能力范围、CPU 成本和离线测试方案见 `app/artifacts/im-ai/dialect-asr-research.md`;未通过目标电脑的双路时延及对应方言准确率验收前,不应声称“所有方言准确识别”。
+
+本机已在隔离环境完成 Nano CPU float32 公开普通话/粤语测试,固定官方权重通过 SHA-256 校验,加载/推理均禁网。Nano 可以保留这条粤语样本词形,但普通话“开放时间”误成“开饭时间”,没有 VAD 的粤语尾段生成额外“对。”。4 秒双路负载预算也缺乏余量;这些结果不支持默认切换。详细输出、耗时和内存见 `app/artifacts/im-ai/dialect-asr-benchmark.md`。该评估没有修改应用运行环境,没有宣称四川/湖南已验收。
+
+后续同机 VAD + 动态 int8 有界实测完成 24 个案例,15 次正常生成、9 次无语音输入被 VAD 跳过;短样本平均耗时下降,但量化期间峰值工作集约 5.7 GiB,且输出词形改变。未验证四川/湖南、医疗数字/否定语音和持续视频负载,因此保持默认引擎。完整结果为 `app/artifacts/im-ai/dialect-asr-quantized-benchmark.md`。评估环境、公开样本及权重保存在 `app/artifacts/im-ai/nano-*`,不会随客户端 resources 打包。
+
+- [转换库发布者文档与固定版本](https://pypi.org/project/opencc-python-reimplemented/0.1.7/):纯 Python、离线词典、t2s 配置。
+- [Fun-ASR-Nano 官方模型卡](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512):明确列出的多方言/地域口音范围。
diff --git a/app/scripts/render_client_design.py b/app/scripts/render_client_design.py
new file mode 100644
index 000000000..4414ce522
--- /dev/null
+++ b/app/scripts/render_client_design.py
@@ -0,0 +1,143 @@
+"""Render the real native client with synthetic data for UI design review."""
+
+from __future__ import annotations
+
+import argparse
+import html
+import json
+import os
+from pathlib import Path
+
+os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
+os.environ.setdefault("DOCTOR_MOTION", "off")
+
+from PySide6.QtCore import QSettings, QThreadPool
+from PySide6.QtGui import QImage
+from PySide6.QtTest import QTest
+from PySide6.QtWidgets import QApplication
+
+from doctor_workstation.services import DemoDoctorRepository
+from doctor_workstation.ui import ShellWindow, apply_theme
+from doctor_workstation.ui.login import LoginWindow
+
+ROUTES = {
+ "appointments": "挂号列表",
+ "consultations": "问诊列表",
+ "patients": "我的患者",
+ "prescription_library": "我的处方库",
+ "prescriptions": "已开处方",
+ "reception": "接诊台",
+}
+
+
+def settle(app: QApplication) -> None:
+ for _ in range(4):
+ QThreadPool.globalInstance().waitForDone(3000)
+ app.processEvents()
+ QTest.qWait(75)
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--output", type=Path, default=Path("artifacts/client-design"))
+ args = parser.parse_args()
+ output = args.output.resolve()
+ output.mkdir(parents=True, exist_ok=True)
+ app = QApplication.instance() or QApplication([])
+ apply_theme(app)
+ repo = DemoDoctorRepository()
+ records = []
+
+ def capture(window, name: str, title: str) -> None:
+ settle(app)
+ filename = f"{name}.png"
+ if not window.grab().save(str(output / filename)):
+ raise RuntimeError(f"Could not save {filename}")
+ records.append({
+ "title": title, "file": filename,
+ "width": window.width(), "height": window.height(),
+ })
+
+ # Isolate preview settings from the user's saved account and credentials.
+ settings = QSettings(str(output / "preview-login.ini"), QSettings.Format.IniFormat)
+ settings.clear()
+ login = LoginWindow(repo, settings=settings)
+ login.show()
+ for width, height in ((1280, 800), (860, 640)):
+ login.resize(width, height)
+ capture(login, f"login-{width}", "登录工作站")
+ login.close()
+
+ session = repo.login(repo.DEMO_ACCOUNT, repo.DEMO_PASSWORD)
+ shell = ShellWindow(
+ repo, {"session": session, "demo_mode": True}, permissions=session.permissions,
+ )
+ shell.show()
+ try:
+ for width, height in ((1440, 900), (1024, 640)):
+ shell.resize(width, height)
+ for route, title in ROUTES.items():
+ shell.navigate(route)
+ capture(shell, f"{route}-{width}", title)
+ finally:
+ settle(app)
+ shell.close()
+
+ # Include independently rendered dialog/media fixtures when available.
+ supplementary = [
+ ("patient_orders_1366x768.png", "患者业务订单"),
+ ("patient_progress_1366x768.png", "患者进度"),
+ ("clinical-after/appointment_drawer_1440x900.png", "预约编辑"),
+ ("clinical-after/diagnosis_edit_1440x900.png", "诊单编辑"),
+ ("clinical-after/diagnosis_edit_1024x640.png", "诊单编辑 · 紧凑窗口"),
+ ("clinical-after/diagnosis_index_1440x900.png", "诊单列表"),
+ ("assistant-1440.png", "AI 问诊"),
+ ("assistant-1080.png", "AI 问诊 · 紧凑窗口"),
+ ("../subwindow_exact/prescription_editor_860x900.png", "处方编辑"),
+ ("../subwindow_exact/prescription_ai_report_920x760.png", "处方报告"),
+ ("video-call-1120x760.png", "视频面诊"),
+ ("video-call-440x300.png", "视频面诊 · 小窗"),
+ ("video-chat-440x300.png", "视频聊天 · 小窗"),
+ ("video-preview-1120x760.png", "视频截图确认"),
+ ]
+ for filename, title in supplementary:
+ preview = QImage(str(output / filename))
+ if not preview.isNull():
+ records.append({
+ "title": title, "file": filename,
+ "width": preview.width(), "height": preview.height(),
+ })
+
+ (output / "gallery.json").write_text(
+ json.dumps(records, ensure_ascii=False, indent=2), encoding="utf-8",
+ )
+ cards = []
+ for record in records:
+ filename = html.escape(record["file"])
+ title = html.escape(record["title"])
+ cards.append(
+ f'{title} {record["width"]} × {record["height"]}'
+ f'
'
+ ''
+ )
+ (output / "index.html").write_text(
+ ''
+ ''
+ '
医生工作站 · 客户端设计验收医生工作站 · 客户端设计验收
'
+ '使用演示数据渲染的真实客户端。点击图片查看原始尺寸。
'
+ + "".join(cards)
+ + '',
+ encoding="utf-8",
+ )
+ print(output / "index.html")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/app/scripts/setup_local_transcription.py b/app/scripts/setup_local_transcription.py
new file mode 100644
index 000000000..5fed9f28b
--- /dev/null
+++ b/app/scripts/setup_local_transcription.py
@@ -0,0 +1,193 @@
+"""Explicit installation/download/check CLI; never invoked by a live call.
+
+Run with --help for examples. With no action flags this only prints help.
+"""
+
+from __future__ import annotations
+
+import argparse
+import importlib.util
+import json
+import os
+import shutil
+import subprocess
+import sys
+import wave
+from datetime import UTC, datetime
+from pathlib import Path
+from unittest.mock import patch
+
+APP_ROOT = Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(APP_ROOT / "src"))
+
+MODEL_REPOS = {
+ size: f"Systran/faster-whisper-{size}"
+ for size in ("tiny", "base", "small", "medium", "large-v3")
+}
+RUNTIME_REQUIREMENT = "faster-whisper==1.2.1"
+TEXT_REQUIREMENT = "opencc-python-reimplemented==0.1.7"
+
+
+def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
+ parser = argparse.ArgumentParser(
+ description="Install or verify local CPU/int8 speech recognition before making calls.",
+ epilog=(
+ "Example: python scripts/setup_local_transcription.py "
+ "--install-dependencies --download --model-size small --check. "
+ "Offline check: python scripts/setup_local_transcription.py --check. "
+ "A packaged app must ship the runtime; installing into another Python "
+ "does not alter a frozen executable."
+ ),
+ )
+ parser.add_argument(
+ "--install-dependencies",
+ action="store_true",
+ help="Explicitly run pip in this Python environment.",
+ )
+ parser.add_argument(
+ "--download",
+ action="store_true",
+ help="Explicitly download the selected official model from Hugging Face.",
+ )
+ parser.add_argument("--model-size", choices=tuple(MODEL_REPOS), default="small")
+ parser.add_argument(
+ "--model-path",
+ type=Path,
+ help="Override DOCTOR_ASR_MODEL_PATH or the app data model directory.",
+ )
+ parser.add_argument(
+ "--revision", default="main", help="Official repository revision/commit for model download."
+ )
+ parser.add_argument(
+ "--check",
+ action="store_true",
+ help="Load the local model and VAD on CPU with networking disabled.",
+ )
+ parser.add_argument(
+ "--smoke-wav",
+ type=Path,
+ help="Optional non-sensitive mono 16 kHz PCM16 WAV, at most 12 seconds; recognized text is printed.",
+ )
+ args = parser.parse_args(argv)
+ if not (args.install_dependencies or args.download or args.check or args.smoke_wav):
+ parser.print_help()
+ return args
+
+
+def main(argv: list[str] | None = None) -> int:
+ args = parse_args(argv)
+ if not (args.install_dependencies or args.download or args.check or args.smoke_wav):
+ return 0
+ if args.install_dependencies:
+ installer = [sys.executable, "-m", "pip", "install"]
+ if importlib.util.find_spec("pip") is None:
+ uv = shutil.which("uv")
+ if not uv:
+ print(
+ "This environment has no pip. Install with uv pip install --python "
+ f"{RUNTIME_REQUIREMENT} {TEXT_REQUIREMENT}",
+ file=sys.stderr,
+ )
+ return 1
+ installer = [uv, "pip", "install", "--python", sys.executable]
+ subprocess.run(
+ [*installer, RUNTIME_REQUIREMENT, TEXT_REQUIREMENT, "platformdirs>=4.3,<5"],
+ check=True,
+ )
+
+ from doctor_workstation.core.transcript_text import simplified_transcript
+ from doctor_workstation.video.local_transcription import (
+ MAX_PCM_BYTES,
+ SAMPLE_RATE,
+ FasterWhisperEngine,
+ LocalTranscriptionError,
+ default_model_path,
+ local_transcription_readiness,
+ )
+
+ path = args.model_path.expanduser().resolve() if args.model_path else default_model_path()
+ try:
+ if args.download:
+ from huggingface_hub import snapshot_download
+
+ path.mkdir(parents=True, exist_ok=True)
+ repo = MODEL_REPOS[args.model_size]
+ print(f"Downloading {repo} into {path}")
+ snapshot_download(
+ repo_id=repo,
+ revision=args.revision,
+ local_dir=str(path),
+ allow_patterns=[
+ "config.json",
+ "preprocessor_config.json",
+ "model.bin",
+ "tokenizer.json",
+ "vocabulary.*",
+ "README.md",
+ "LICENSE*",
+ ],
+ token=False,
+ )
+ (path / "doctor-asr-install.json").write_text(
+ json.dumps(
+ {
+ "repository": repo,
+ "requestedRevision": args.revision,
+ "runtimeRequirement": RUNTIME_REQUIREMENT,
+ "textRequirement": TEXT_REQUIREMENT,
+ "installedAt": datetime.now(UTC).isoformat(),
+ },
+ indent=2,
+ )
+ + "\n",
+ encoding="utf-8",
+ )
+ if args.check or args.smoke_wav or args.download:
+ # This affects only the explicit setup/check process. The runtime
+ # already requires complete local files and local_files_only=True.
+ os.environ["HF_HUB_OFFLINE"] = "1"
+ os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
+ print(json.dumps(local_transcription_readiness(path), ensure_ascii=False, indent=2))
+ # The hub may already have been imported during --download, so its
+ # offline environment flag alone is not a sufficient verification.
+ # Block sockets in this standalone check process as well.
+ blocked = RuntimeError("Network access is disabled during local ASR verification")
+ with (
+ patch("socket.socket.connect", side_effect=blocked),
+ patch("socket.socket.connect_ex", side_effect=blocked),
+ patch("socket.getaddrinfo", side_effect=blocked),
+ ):
+ engine = FasterWhisperEngine(path)
+ print("Local model and VAD loaded successfully (CPU/int8; network blocked).")
+ if args.smoke_wav:
+ with wave.open(str(args.smoke_wav), "rb") as audio:
+ if (
+ audio.getnchannels(),
+ audio.getsampwidth(),
+ audio.getframerate(),
+ audio.getcomptype(),
+ ) != (1, 2, SAMPLE_RATE, "NONE"):
+ raise ValueError("Smoke WAV must be mono 16 kHz uncompressed PCM16.")
+ if not 0 < audio.getnframes() <= MAX_PCM_BYTES // 2:
+ raise ValueError(
+ "Smoke WAV must contain between one sample and 12 seconds."
+ )
+ pcm = audio.readframes(audio.getnframes())
+ print(f"Recognized text: {simplified_transcript(engine.transcribe(pcm))}")
+ return 0
+ except LocalTranscriptionError as error:
+ print(f"Local ASR setup failed ({error.code}): {error}", file=sys.stderr)
+ except ImportError:
+ print(
+ "Required packages are missing; run with --install-dependencies first.", file=sys.stderr
+ )
+ except (OSError, ValueError, RuntimeError) as error:
+ print(
+ f"Local ASR setup failed: {type(error).__name__}. Check model files, WAV format, and connectivity for explicit downloads.",
+ file=sys.stderr,
+ )
+ return 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/app/src/doctor_workstation/__init__.py b/app/src/doctor_workstation/__init__.py
index 51494716c..952bd12ec 100755
--- a/app/src/doctor_workstation/__init__.py
+++ b/app/src/doctor_workstation/__init__.py
@@ -3,7 +3,7 @@
__all__ = ["DEBUG_MODE", "ONLINE_API_BASE_URL", "__version__"]
# Single source of truth for runtime, package, installer, and executable versions.
-__version__ = "1.5.0"
+__version__ = "1.5.1"
# 调试模式开启时,登录页显示“演示模式”和“服务器设置”。
# 正式发布请保持 False;此时程序只使用下面配置的线上域名。
diff --git a/app/src/doctor_workstation/app.py b/app/src/doctor_workstation/app.py
index 69d72af52..af97365f5 100755
--- a/app/src/doctor_workstation/app.py
+++ b/app/src/doctor_workstation/app.py
@@ -41,6 +41,7 @@ from doctor_workstation.ui.widgets import (
friendly_error,
gender_text,
get_value,
+ has_permission,
run_async,
set_authentication_expired_handler,
show_toast,
@@ -939,6 +940,11 @@ class ApplicationController(QObject):
open_im=open_im,
patient_name=patient_name,
patient_case=patient_case,
+ can_ai_assistant=has_permission(
+ getattr(self.shell_window, "permissions", None),
+ "tcm.diagnosis/aiAssistant",
+ default=False,
+ ),
on_open_diagnosis=lambda current_id=diagnosis_id, current_key=call_key: (
self._open_video_diagnosis(current_id, call_key=current_key)
),
@@ -1024,11 +1030,14 @@ class ApplicationController(QObject):
lambda _result, expected=generation: self._restore_video_preview(expected)
)
try:
+ set_close_handler = getattr(video_window, "set_compact_close_handler", None)
+ if callable(set_close_handler):
+ set_close_handler(lambda expected=generation: self._restore_video_preview(expected))
video_window.raise_()
dialog.raise_()
dialog.activateWindow()
except RuntimeError:
- self._video_preview_state = None
+ self._restore_video_preview(generation, activate=False)
def _restore_video_preview(
self,
@@ -1045,6 +1054,12 @@ class ApplicationController(QObject):
self._video_preview_generation += 1
window = state.get("window")
try:
+ set_close_handler = getattr(window, "set_compact_close_handler", None)
+ if callable(set_close_handler):
+ set_close_handler(None)
+ restore_screenshot = getattr(window, "restore_screenshot_preview", None)
+ if callable(restore_screenshot):
+ restore_screenshot()
window.setWindowFlag(
Qt.WindowType.WindowStaysOnTopHint,
bool(state.get("stays_on_top")),
diff --git a/app/src/doctor_workstation/core/transcript_text.py b/app/src/doctor_workstation/core/transcript_text.py
new file mode 100644
index 000000000..96fedd7b2
--- /dev/null
+++ b/app/src/doctor_workstation/core/transcript_text.py
@@ -0,0 +1,23 @@
+"""Offline script conversion for speech transcripts, without paraphrasing."""
+
+from __future__ import annotations
+
+from threading import local
+
+_converters = local()
+
+
+def simplified_transcript(text: str) -> str:
+ """Convert character forms only; retain dialect words, numbers and negations.
+
+ Each thread owns its converter. Cache dictionaries, never patient text.
+ The t2s configuration deliberately excludes regional vocabulary rewriting.
+ Missing package data is an error, rather than silently mixing scripts.
+ """
+ converter = getattr(_converters, "simplified", None)
+ if converter is None:
+ from opencc import OpenCC
+
+ converter = OpenCC("t2s")
+ _converters.simplified = converter
+ return converter.convert(text)
diff --git a/app/src/doctor_workstation/services/mock_repository.py b/app/src/doctor_workstation/services/mock_repository.py
index 023fd9a73..3c40de4ad 100755
--- a/app/src/doctor_workstation/services/mock_repository.py
+++ b/app/src/doctor_workstation/services/mock_repository.py
@@ -4,6 +4,7 @@ from __future__ import annotations
import hashlib
import json
+import re
import struct
import zlib
from collections.abc import Callable, Mapping, Sequence
@@ -2846,11 +2847,22 @@ class DemoDoctorRepository:
}
)
- def sync_im_chat_messages(self, diagnosis_id: int) -> dict[str, Any]:
- """Acknowledge the same asynchronous sync contract in demo mode."""
+ def sync_im_chat_messages(
+ self, diagnosis_id: int, *, scope: str = "", sync_token: str = ""
+ ) -> dict[str, Any]:
+ """Complete synthetic archive sync while retaining the legacy receipt."""
self._find_consultation(diagnosis_id)
- return {"queued": True, "diagnosis_id": diagnosis_id}
+ if scope not in {"", "current"}:
+ raise ValueError("IM sync scope must be empty or current")
+ if not isinstance(sync_token, str) or (
+ sync_token and re.fullmatch(r"[a-f0-9]{48}", sync_token) is None
+ ):
+ raise ValueError("IM sync token is invalid")
+ return {
+ "queued": True, "diagnosis_id": diagnosis_id,
+ "completed": True, "phase": "completed", "errors": [],
+ }
def list_diagnosis_appointment_logs(self, diagnosis_id: int) -> list[dict[str, Any]]:
"""Build demo audit rows from the diagnosis appointments."""
diff --git a/app/src/doctor_workstation/services/repository.py b/app/src/doctor_workstation/services/repository.py
index aa3e01765..72ee10964 100755
--- a/app/src/doctor_workstation/services/repository.py
+++ b/app/src/doctor_workstation/services/repository.py
@@ -214,6 +214,13 @@ class DoctorRepository(Protocol):
def cancel_diagnosis_ai(self, diagnosis_id: int, request_id: str) -> dict[str, Any]:
"""Request server/upstream cancellation of one correlated stream."""
+ def stream_video_ai(
+ self, diagnosis_id: int, *, call_record_id: int,
+ transcription_session_id: str, task: str = "live_consultation",
+ request_id: str, cancelled: Callable[[], bool] | None = None,
+ ) -> Iterator[dict[str, Any]]:
+ """Analyze the server-owned snapshot of this exact video call."""
+
def generate_ai_prescription(self, diagnosis_id: int) -> dict[str, Any]:
"""Generate a server-validated prescription draft for doctor review."""
@@ -692,8 +699,10 @@ class DoctorRepository(Protocol):
) -> dict[str, Any]:
"""Return diagnosis IM messages, defaulting to the fast archive-only path."""
- def sync_im_chat_messages(self, diagnosis_id: int) -> Any:
- """Queue the server-side IM archive synchronisation job."""
+ def sync_im_chat_messages(
+ self, diagnosis_id: int, *, scope: str = "", sync_token: str = ""
+ ) -> Any:
+ """Advance one server-side archive page; inspect completed before using it."""
def list_diagnosis_appointment_logs(self, diagnosis_id: int) -> list[dict[str, Any]]:
"""Return per-diagnosis registration / cancellation audit rows."""
@@ -1476,6 +1485,42 @@ class RemoteDoctorRepository:
yield {"event": "delta", "text": answer, "fallback": True}
yield {**result, "event": "done", "fallback": True}
+ def stream_video_ai(
+ self, diagnosis_id: int, *, call_record_id: int,
+ transcription_session_id: str, task: str = "live_consultation",
+ request_id: str, cancelled: Callable[[], bool] | None = None,
+ ) -> Iterator[dict[str, Any]]:
+ """No legacy fallback: an older route cannot bind a live call safely."""
+
+ if (isinstance(diagnosis_id, bool) or not isinstance(diagnosis_id, int)
+ or diagnosis_id <= 0 or isinstance(call_record_id, bool)
+ or not isinstance(call_record_id, int) or call_record_id <= 0):
+ raise ValueError("diagnosis and call_record_id must be positive integers")
+ if (not isinstance(transcription_session_id, str)
+ or re.fullmatch(r"[A-Za-z0-9_-]{1,128}", transcription_session_id) is None):
+ raise ValueError("invalid transcription session")
+ if task not in {"live_consultation", "live_review"}:
+ raise ValueError("unsupported video AI task")
+ body = {
+ "id": diagnosis_id, "task": task,
+ "prompt": "请依据本次通话已保存的原文整理症状、追问和待核实信息,供医生复核。",
+ "call_record_id": call_record_id,
+ "transcription_session_id": transcription_session_id,
+ "request_id": request_id,
+ }
+ for raw in self.client.post_event_stream(
+ "tcm.diagnosis/aiAssistantStream", body, timeout=105.0, cancelled=cancelled,
+ ):
+ if cancelled is not None and cancelled():
+ return
+ event = _normalise_diagnosis_ai_event(raw)
+ if event is not None:
+ yield event
+ if event["event"] == "done":
+ return
+ if cancelled is None or not cancelled():
+ raise ApiProtocolError("video AI stream ended before done")
+
def cancel_diagnosis_ai(self, diagnosis_id: int, request_id: str) -> dict[str, Any]:
"""Use an independent short request, even while the stream is idle."""
@@ -2602,12 +2647,27 @@ class RemoteDoctorRepository:
)
return dict(_require_mapping(payload, "tcm.diagnosis/getImChatMessages"))
- def sync_im_chat_messages(self, diagnosis_id: int) -> Any:
- """Queue the confirmed shutdown-function archive sync endpoint."""
+ def sync_im_chat_messages(
+ self, diagnosis_id: int, *, scope: str = "", sync_token: str = ""
+ ) -> Any:
+ """Advance a bounded archive page, preserving legacy no-option callers."""
if diagnosis_id <= 0:
raise ValueError("diagnosis_id must be positive")
- return self.client.post("tcm.diagnosis/triggerImChatSync", {"diagnosis_id": diagnosis_id})
+ if scope not in {"", "current"}:
+ raise ValueError("IM sync scope must be empty or current")
+ if not isinstance(sync_token, str) or (
+ sync_token and re.fullmatch(r"[a-f0-9]{48}", sync_token) is None
+ ):
+ raise ValueError("IM sync token is invalid")
+ payload: dict[str, Any] = {"diagnosis_id": diagnosis_id}
+ if scope:
+ payload["scope"] = scope
+ if sync_token:
+ payload["sync_token"] = sync_token
+ return _client_request(
+ self.client, "post", "tcm.diagnosis/triggerImChatSync", payload, timeout=15.0
+ )
def list_diagnosis_appointment_logs(self, diagnosis_id: int) -> list[dict[str, Any]]:
"""Return registration/cancellation logs from ``guahaoLogList``."""
@@ -3043,10 +3103,10 @@ def _normalise_diagnosis_ai_event(raw: Mapping[str, Any]) -> dict[str, Any] | No
if not isinstance(text, str):
raise ApiProtocolError("AI assistant delta content must be text", data=data)
return {"event": "delta", "text": text}
- if kind == "done":
+ if kind in {"live_update", "done"}:
payload.pop("event", None)
payload.pop("type", None)
- return {**payload, "event": "done"}
+ return {**payload, "event": kind}
if kind == "error":
message = (
data
diff --git a/app/src/doctor_workstation/ui/appointment_drawer.py b/app/src/doctor_workstation/ui/appointment_drawer.py
index 19bcadfe1..aba2a6b9b 100755
--- a/app/src/doctor_workstation/ui/appointment_drawer.py
+++ b/app/src/doctor_workstation/ui/appointment_drawer.py
@@ -23,7 +23,6 @@ from PySide6.QtWidgets import (
QComboBox,
QDialog,
QFrame,
- QGraphicsDropShadowEffect,
QGraphicsOpacityEffect,
QHBoxLayout,
QLabel,
@@ -43,6 +42,7 @@ from PySide6.QtWidgets import (
)
from ..core.appointment_modes import APPOINTMENT_MODES
+from .design_system import clinical_stylesheet
from .theme import main_window_target_rect
from .widgets import (
display_text,
@@ -84,8 +84,8 @@ QDialog#AppointmentDrawerOverlay QToolButton#AppointmentDrawerClose {
min-height: 32px;
max-height: 32px;
padding: 0;
- border: 0;
- border-radius: 4px;
+ border: 1px solid transparent;
+ border-radius: $ds_radius_control;
background-color: transparent;
color: #606163;
font-size: 22px;
@@ -95,6 +95,10 @@ QDialog#AppointmentDrawerOverlay QToolButton#AppointmentDrawerClose {
QDialog#AppointmentDrawerOverlay QToolButton#AppointmentDrawerClose:hover {
color: #1A1C1F;
background-color: #F0F0F0;
+}
+QDialog#AppointmentDrawerOverlay QToolButton#AppointmentDrawerClose:focus {
+ border-color: $ds_focus;
+ background-color: $ds_accent_soft;
}
QDialog#AppointmentDrawerOverlay QScrollArea#AppointmentDrawerBody,
@@ -110,7 +114,7 @@ QDialog#AppointmentDrawerOverlay QWidget#AppointmentDrawerBodyContent {
}
QDialog#AppointmentDrawerOverlay QLabel[appointmentLabel="true"] {
- color: #1A1C1F;
+ color: $ds_muted;
font-size: 14px;
font-weight: 500;
}
@@ -125,7 +129,7 @@ QDialog#AppointmentDrawerOverlay QPlainTextEdit {
min-height: 30px;
padding: 0 11px;
border: 1px solid #EDEDEE;
- border-radius: 9px;
+ border-radius: 10px;
background-color: #FFFFFF;
color: #1A1C1F;
selection-background-color: #EEF1FA;
@@ -145,7 +149,14 @@ QDialog#AppointmentDrawerOverlay QPlainTextEdit:hover {
QDialog#AppointmentDrawerOverlay QComboBox:focus,
QDialog#AppointmentDrawerOverlay QLineEdit:focus,
QDialog#AppointmentDrawerOverlay QPlainTextEdit:focus {
- border: 2px solid #8B9AD9;
+ border: 1px solid #8B9AD9;
+}
+QDialog#AppointmentDrawerOverlay QComboBox:disabled,
+QDialog#AppointmentDrawerOverlay QLineEdit:disabled,
+QDialog#AppointmentDrawerOverlay QPlainTextEdit:disabled {
+ color: $ds_disabled;
+ background-color: $ds_disabled_surface;
+ border-color: $ds_line;
}
QDialog#AppointmentDrawerOverlay QComboBox::drop-down {
@@ -197,7 +208,7 @@ QDialog#AppointmentDrawerOverlay QPushButton[appointmentDate="true"] {
max-height: 38px;
padding: 0;
border: 1px solid #EDEDEE;
- border-radius: 8px;
+ border-radius: 10px;
background-color: #FFFFFF;
color: #1A1C1F;
font-size: 14px;
@@ -221,15 +232,15 @@ QDialog#AppointmentDrawerOverlay QPushButton[appointmentDate="true"]:checked {
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentSlotsPanel {
- background-color: #F7F7F7;
+ background-color: $ds_surface_alt;
border: 0;
- border-radius: 8px;
+ border-radius: $ds_radius_panel;
}
QDialog#AppointmentDrawerOverlay QLabel#AppointmentSlotsTitle {
color: #1A1C1F;
font-size: 15px;
- font-weight: 500;
+ font-weight: 600;
}
QDialog#AppointmentDrawerOverlay QPushButton#AppointmentRefreshSlots {
@@ -247,13 +258,17 @@ QDialog#AppointmentDrawerOverlay QPushButton#AppointmentRefreshSlots {
QDialog#AppointmentDrawerOverlay QPushButton#AppointmentRefreshSlots:hover {
background-color: #EEF1FA;
}
+QDialog#AppointmentDrawerOverlay QPushButton#AppointmentRefreshSlots:focus {
+ background-color: $ds_accent_soft;
+ border: 1px solid $ds_focus;
+}
QDialog#AppointmentDrawerOverlay QPushButton[appointmentSlot="true"] {
min-width: 110px;
min-height: 70px;
padding: 0 8px;
border: 2px solid #EDEDEE;
- border-radius: 8px;
+ border-radius: 10px;
background-color: #FFFFFF;
color: #1A1C1F;
}
@@ -330,25 +345,25 @@ QDialog#AppointmentDrawerOverlay QLabel#AppointmentEmptyText {
QDialog#AppointmentDrawerOverlay QFrame#AppointmentAlert[kind="info"] {
background-color: #EEF1FA;
border: 1px solid #EDEDEE;
- border-radius: 9px;
+ border-radius: 10px;
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentAlert[kind="warning"] {
background-color: #FFF5E6;
border: 1px solid #F6E3C4;
- border-radius: 9px;
+ border-radius: 10px;
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentAlert[kind="danger"] {
background-color: #FFF1F3;
border: 1px solid #F7D7DC;
- border-radius: 9px;
+ border-radius: 10px;
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentAlert[kind="success"] {
background-color: #EAF9F3;
border: 1px solid #D4F0E5;
- border-radius: 9px;
+ border-radius: 10px;
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentAlert[kind="info"] QLabel {
@@ -378,7 +393,7 @@ QDialog#AppointmentDrawerOverlay QFrame#AppointmentDrawerFooter QPushButton {
max-height: 30px;
padding: 0 15px;
border: 1px solid #EDEDEE;
- border-radius: 9px;
+ border-radius: 10px;
background-color: #FFFFFF;
color: #1A1C1F;
font-size: 13px;
@@ -408,9 +423,14 @@ QDialog#AppointmentDrawerOverlay QFrame#AppointmentDrawerFooter QPushButton[prim
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentDrawerFooter QPushButton:disabled {
- color: #FFFFFF;
- border-color: #EDEDEE;
- background-color: #8E8F90;
+ color: $ds_disabled;
+ border-color: $ds_line;
+ background-color: $ds_disabled_surface;
+}
+QDialog#AppointmentDrawerOverlay QFrame#AppointmentDrawerFooter QPushButton[primary="true"]:pressed {
+ color: $ds_surface;
+ background-color: $ds_accent_pressed;
+ border-color: $ds_accent_pressed;
}
QDialog#AppointmentDrawerOverlay QFrame#AppointmentLoadingOverlay {
@@ -487,6 +507,7 @@ _APPOINTMENT_DARK_REPLACEMENTS = (
)
# Light is the default application theme. Keep the replacement table available
# for a future explicit dark-mode switch, but do not mutate the light source QSS.
+APPOINTMENT_DRAWER_QSS = clinical_stylesheet(APPOINTMENT_DRAWER_QSS)
def _as_int(value: Any, default: int = 0) -> int:
@@ -733,35 +754,7 @@ class _EmptyIllustration(QWidget):
painter.end()
-class _HoverLiftButton(QPushButton):
- """Button with a subtle two-pixel lift and blue-tinted shadow on hover."""
-
- def __init__(self, text: str = "", parent: QWidget | None = None) -> None:
- super().__init__(text, parent)
- self._lifted = False
- self._base_position = QPoint()
-
- def enterEvent(self, event: QEvent) -> None: # noqa: N802 - Qt API
- if self.isEnabled() and not self._lifted:
- self._base_position = self.pos()
- self.move(self.x(), self.y() - 2)
- shadow = QGraphicsDropShadowEffect(self)
- shadow.setBlurRadius(12)
- shadow.setOffset(0, 4)
- shadow.setColor(QColor(26, 28, 31, 72))
- self.setGraphicsEffect(shadow)
- self._lifted = True
- super().enterEvent(event)
-
- def leaveEvent(self, event: QEvent) -> None: # noqa: N802 - Qt API
- if self._lifted:
- self.move(self._base_position)
- self.setGraphicsEffect(None)
- self._lifted = False
- super().leaveEvent(event)
-
-
-class _SlotCard(_HoverLiftButton):
+class _SlotCard(QPushButton):
"""Two-line time card matching Element's independent time/status typography."""
def __init__(self, time_text: str, status_text: str) -> None:
@@ -819,8 +812,8 @@ class AppointmentDrawer(QDialog):
self._today_blocking = False
self._channel_names: dict[str, str] = {}
self._doctor_buttons: dict[int, QRadioButton] = {}
- self._date_buttons: dict[str, _HoverLiftButton] = {}
- self._slot_buttons: dict[str, _HoverLiftButton] = {}
+ self._date_buttons: dict[str, QPushButton] = {}
+ self._slot_buttons: dict[str, QPushButton] = {}
self._slot_available: dict[str, bool] = {}
self._slot_restore_selection = ""
self._active_loading = ""
@@ -1426,7 +1419,7 @@ class AppointmentDrawer(QDialog):
continue
label = f"{parsed.toString('MM月dd日')} ({week_days[parsed.dayOfWeek() % 7]})"
self.date_combo.addItem(label, value)
- button = _HoverLiftButton(label)
+ button = QPushButton(label)
button.setProperty("appointmentDate", True)
button.setCheckable(True)
button.setFixedSize(130, 40)
diff --git a/app/src/doctor_workstation/ui/appointments_style.py b/app/src/doctor_workstation/ui/appointments_style.py
index 194fd7bdc..134f8e343 100755
--- a/app/src/doctor_workstation/ui/appointments_style.py
+++ b/app/src/doctor_workstation/ui/appointments_style.py
@@ -2,143 +2,155 @@
from string import Template
+from .design_system import clinical_stylesheet
from .reception_style import body_family, heading_family
def appointments_stylesheet() -> str:
- return Template(_QSS).substitute(body=body_family(), heading=heading_family())
+ return clinical_stylesheet(Template(_QSS).safe_substitute(body=body_family(), heading=heading_family()))
_QSS = """
-#AppointmentsPage { background: #F3F7FD; color: #273244; }
+#AppointmentsPage { background: $ds_canvas; color: $ds_text; }
#AppointmentsPage QLabel, #AppointmentsPage QPushButton,
#AppointmentsPage QLineEdit, #AppointmentsPage QComboBox,
#AppointmentsPage QTabBar, #AppointmentsPage QTableWidget {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
}
#AppointmentsPage QWidget#PageHeader QLabel[role="pageTitle"] {
- font-family: "$heading"; font-size: 20px; font-weight: 600; color: #202C3F;
+ font-family: "$heading"; font-size: 20px; font-weight: 600; color: $ds_heading;
}
#AppointmentsPage QWidget#PageHeader QLabel[role="muted"],
#AppointmentsPage QWidget#PageHeader QLabel[role="breadcrumb"],
#AppointmentsPage QWidget#PageHeader QLabel[role="breadcrumbSeparator"],
#AppointmentsPage QWidget#PageHeader QLabel[role="breadcrumbCurrent"] {
- color: #5D6B80; font-size: 13px; font-weight: 400;
+ color: $ds_muted; font-size: 13px; font-weight: 400;
}
#AppointmentsPage QFrame#AppointmentFilterPanel,
#AppointmentsPage QFrame#AppointmentMainCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
}
#AppointmentsPage QPushButton {
- min-height: 30px; padding: 0 12px; border: 1px solid #DBE5F2;
- border-radius: 6px; background: #FFFFFF;
+ min-height: 30px; padding: 0 12px; border: 1px solid transparent;
+ border-radius: $ds_radius_control; background: $ds_surface_alt;
}
-#AppointmentsPage QPushButton:hover { color: #1555B6; background: #F2F7FF; border-color: #B6CDEE; }
-#AppointmentsPage QPushButton:pressed { background: #DCEAFF; }
-#AppointmentsPage QPushButton:focus { border-color: #75A5F0; }
+#AppointmentsPage QPushButton:hover { color: $ds_accent; background: $ds_surface_alt; border-color: $ds_line_strong; }
+#AppointmentsPage QPushButton:pressed { background: $ds_accent_soft; }
+#AppointmentsPage QPushButton:focus { border-color: $ds_focus; }
#AppointmentsPage QPushButton[variant="primary"] {
- background: #1769E8; color: #FFFFFF; border-color: #1769E8;
+ background: $ds_accent; color: $ds_surface; border-color: $ds_accent;
}
-#AppointmentsPage QPushButton[variant="primary"]:hover { background: #155BCC; }
-#AppointmentsPage QPushButton[variant="primary"]:pressed { background: #124EA9; }
+#AppointmentsPage QPushButton[variant="primary"]:hover { background: $ds_accent_hover; }
+#AppointmentsPage QPushButton[variant="primary"]:pressed { background: $ds_accent_pressed; }
+#AppointmentsPage QPushButton[variant="primary"]:focus { border-color: $ds_focus; }
#AppointmentsPage QPushButton[variant="danger"] {
- color: #B84652; background: #FFFFFF; border-color: #EFC8CE;
+ color: $ds_danger; background: $ds_danger_soft; border-color: transparent;
}
-#AppointmentsPage QPushButton[variant="danger"]:hover { background: #FFF0F2; }
+#AppointmentsPage QPushButton[variant="danger"]:hover { background: $ds_danger_soft; }
+#AppointmentsPage QPushButton[variant="danger"]:pressed { border-color: $ds_danger; }
#AppointmentsPage QPushButton[variant="ghost"] { background: transparent; border-color: transparent; }
-#AppointmentsPage QPushButton:disabled {
- color: #8A97A9; background: #F6F8FC; border-color: #E2E9F2;
+#AppointmentsPage QPushButton[variant="ghost"]:hover { background: $ds_accent_soft; }
+#AppointmentsPage QPushButton[variant="ghost"]:focus { border-color: $ds_focus; }
+#AppointmentsPage QPushButton:disabled, #AppointmentsPage QPushButton[variant="primary"]:disabled,
+#AppointmentsPage QPushButton[variant="danger"]:disabled {
+ color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line;
}
#AppointmentsPage QLineEdit, #AppointmentsPage QComboBox {
- min-height: 32px; padding: 0 10px; color: #273244; background: #FFFFFF;
- border: 1px solid #DBE5F2; border-radius: 6px; selection-background-color: #DCEAFF;
+ min-height: 32px; padding: 0 10px; color: $ds_text; background: $ds_surface;
+ border: 1px solid $ds_line; border-radius: $ds_radius_control; selection-background-color: $ds_accent_soft;
}
-#AppointmentsPage QLineEdit:focus, #AppointmentsPage QComboBox:focus { border-color: #75A5F0; }
+#AppointmentsPage QLineEdit:focus, #AppointmentsPage QComboBox:focus { border-color: $ds_focus; }
#AppointmentsPage QLineEdit QToolButton {
min-width: 0; min-height: 0; padding: 0; border: 0; background: transparent;
}
-#AppointmentsPage QLineEdit QToolButton:focus { background: #EAF2FF; }
+#AppointmentsPage QLineEdit QToolButton:focus { background: $ds_accent_soft; }
#AppointmentsPage QPushButton#AppointmentSearchButton {
min-height: 39px; max-height: 39px; min-width: 52px;
}
#AppointmentsPage QLineEdit#AppointmentPatientSearch { min-height: 39px; max-height: 39px; }
#AppointmentsPage QPushButton[appointmentStat="true"] {
- min-height: 34px; max-height: 34px; padding: 0 10px; background: #F4F7FC;
- border-color: transparent; color: #5D6B80; font-size: 13px;
+ min-height: 34px; max-height: 34px; padding: 0 10px; background: $ds_canvas;
+ border-color: transparent; color: $ds_muted; font-size: 13px;
}
-#AppointmentsPage QPushButton[appointmentStat="true"]:hover { color: #1555B6; background: #EAF2FF; }
+#AppointmentsPage QPushButton[appointmentStat="true"]:hover { color: $ds_accent; background: $ds_accent_soft; }
#AppointmentsPage QPushButton[appointmentStat="true"]:checked {
- color: #FFFFFF; background: #1769E8; border-color: #1769E8;
+ color: $ds_accent; background: $ds_accent_soft; border-color: transparent; font-weight: 600;
}
#AppointmentsPage QPushButton[appointmentStatKind="warning"][hasPending="true"]:!checked {
- color: #9C681F; background: #FFF6E7; border-color: #EEDCBF;
+ color: $ds_warning; background: $ds_warning_soft; border-color: $ds_warning_soft;
}
-#AppointmentsPage QLabel#FilterRowLabel { color: #5D6B80; font-size: 13px; }
-#AppointmentsPage QLabel#FilterDivider { color: #DBE5F2; padding: 0 10px; }
+#AppointmentsPage QLabel#FilterRowLabel { color: $ds_muted; font-size: 13px; }
+#AppointmentsPage QLabel#FilterDivider { color: $ds_line; padding: 0 10px; }
#AppointmentsPage QTabBar#AppointmentStatusTabs::tab {
- min-width: 52px; min-height: 32px; padding: 0 12px; color: #5D6B80;
+ min-width: 52px; min-height: 32px; padding: 0 12px; color: $ds_muted;
background: transparent; border: 0; border-bottom: 2px solid transparent; font-size: 13px;
}
-#AppointmentsPage QTabBar#AppointmentStatusTabs::tab:hover { color: #1555B6; background: #F7FAFE; }
+#AppointmentsPage QTabBar#AppointmentStatusTabs::tab:hover { color: $ds_accent; background: $ds_surface_alt; }
#AppointmentsPage QTabBar#AppointmentStatusTabs::tab:selected {
- color: #1769E8; background: transparent; border-bottom-color: #1769E8;
+ color: $ds_accent; background: transparent; border-bottom-color: $ds_accent;
}
#AppointmentsPage QPushButton[filterChoice="true"] {
- min-height: 30px; max-height: 30px; padding: 0 12px; color: #5D6B80;
+ min-height: 30px; max-height: 30px; padding: 0 12px; color: $ds_muted;
background: transparent; border-color: transparent; font-size: 13px;
}
-#AppointmentsPage QPushButton[filterChoice="true"]:checked { color: #1555B6; background: #EAF2FF; }
+#AppointmentsPage QPushButton[filterChoice="true"]:checked { color: $ds_accent; background: $ds_accent_soft; }
+#AppointmentsPage QPushButton[filterChoice="true"]:focus,
+#AppointmentsPage QPushButton[appointmentStat="true"]:focus { border-color: $ds_focus; }
#AppointmentsPage QFrame#AppointmentToolbar { background: transparent; border: 0; }
#AppointmentsPage QPushButton[compactAction="true"] {
min-height: 36px; max-height: 36px; padding: 0 17px; font-size: 13px;
}
#AppointmentsPage QFrame#AppointmentToolbar QPushButton[variant="secondary"]:enabled {
- color: #1769E8; border-color: #ADC8F0;
+ color: $ds_text; border-color: transparent;
}
+#AppointmentsPage QFrame#AppointmentToolbar QPushButton[variant="secondary"]:hover { color: $ds_accent; background: $ds_accent_soft; }
+#AppointmentsPage QFrame#AppointmentToolbar QPushButton[variant="secondary"]:focus { border-color: $ds_focus; }
#AppointmentsPage QTableWidget#AppointmentTable {
- background: #FFFFFF; alternate-background-color: #FFFFFF; border: 0; border-radius: 0;
- gridline-color: #E6EDF6; selection-background-color: #EAF2FF; selection-color: #273244;
+ background: $ds_surface; alternate-background-color: $ds_surface; border: 0; border-radius: 0;
+ gridline-color: $ds_line; selection-background-color: $ds_accent_soft; selection-color: $ds_text;
}
-#AppointmentsPage QTableWidget#AppointmentTable::item { padding: 0; border: 0; border-bottom: 1px solid #E6EDF6; }
-#AppointmentsPage QTableWidget#AppointmentTable::item:selected { background: #EAF2FF; color: #273244; }
+#AppointmentsPage QTableWidget#AppointmentTable::item { padding: 0; border: 0; border-bottom: 1px solid $ds_line; }
+#AppointmentsPage QTableWidget#AppointmentTable::item:selected { background: $ds_accent_soft; color: $ds_text; }
#AppointmentsPage QTableWidget#AppointmentTable QHeaderView::section {
- min-height: 40px; padding: 0; background: #F5F8FD; color: #5D6B80;
- border: 0; border-top: 1px solid #E1E9F4; border-bottom: 1px solid #E1E9F4;
+ min-height: 40px; padding: 0; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-top: 1px solid $ds_line; border-bottom: 1px solid $ds_line;
font-family: "$body"; font-size: 13px; font-weight: 400;
}
#AppointmentsPage QWidget[appointmentSelectionHost="true"] {
background: transparent; border-left: 3px solid transparent;
}
-#AppointmentsPage QWidget[appointmentSelectionHost="true"][selected="true"] { border-left-color: #1769E8; }
+#AppointmentsPage QWidget[appointmentSelectionHost="true"][selected="true"] { border-left-color: $ds_accent; }
#AppointmentsPage QCheckBox[appointmentSelector="true"]::indicator {
- width: 16px; height: 16px; background: #FFFFFF; border: 1px solid #C8D5E6; border-radius: 3px;
+ width: 16px; height: 16px; background: $ds_surface; border: 1px solid $ds_line_strong; border-radius: 3px;
}
-#AppointmentsPage QCheckBox[appointmentSelector="true"]::indicator:checked { background: #1769E8; border-color: #1769E8; }
+#AppointmentsPage QCheckBox[appointmentSelector="true"]::indicator:checked { background: $ds_accent; border-color: $ds_accent; }
#AppointmentsPage QWidget[appointmentInfoHost="true"],
#AppointmentsPage QWidget[appointmentImHost="true"] { background: transparent; }
#AppointmentsPage QLabel[tableAppointmentStatus="true"] {
- min-height: 20px; max-height: 20px; padding: 0 6px; color: #1555B6;
- background: #EAF2FF; border-radius: 4px; font-size: 13px;
+ min-height: 20px; max-height: 20px; padding: 0 6px; color: $ds_accent;
+ background: $ds_accent_soft; border-radius: $ds_radius_small; font-size: 13px;
}
-#AppointmentsPage QLabel[tableAppointmentStatusKind="warning"] { color: #9C681F; background: #FFF3DD; }
-#AppointmentsPage QLabel[tableAppointmentStatusKind="muted"] { color: #66758A; background: #EEF2F7; }
-#AppointmentsPage QLabel[tableAppointmentMeta="true"] { color: #5D6B80; font-size: 13px; }
+#AppointmentsPage QLabel[tableAppointmentStatusKind="warning"] { color: $ds_warning; background: $ds_warning_soft; }
+#AppointmentsPage QLabel[tableAppointmentStatusKind="muted"] { color: $ds_muted; background: $ds_disabled_surface; }
+#AppointmentsPage QLabel[tableAppointmentMeta="true"] { color: $ds_muted; font-size: 13px; }
#AppointmentsPage QPushButton[tableCancelAction="true"] {
- min-height: 20px; max-height: 20px; padding: 0 5px; color: #B84652;
- background: #FFF0F2; border: 0; border-radius: 4px; font-size: 13px;
+ min-height: 20px; max-height: 20px; padding: 0 5px; color: $ds_danger;
+ background: $ds_danger_soft; border: 0; border-radius: $ds_radius_small; font-size: 13px;
}
#AppointmentsPage QPushButton[appointmentImAction="true"] {
min-width: 62px; min-height: 32px; max-height: 32px; padding: 0 10px;
- color: #1555B6; background: #EAF2FF; border-color: #C9DCF7; font-size: 13px;
+ color: $ds_accent; background: $ds_accent_soft; border-color: transparent; font-size: 13px;
}
-#AppointmentsPage QPushButton[appointmentImAction="true"]:hover { color: #FFFFFF; background: #1769E8; }
-#AppointmentsPage QPushButton[appointmentImAction="true"]:disabled { color: #8A97A9; background: #F3F6FB; border-color: #DFE7F2; }
-#AppointmentsPage QWidget#Pager { background: #FFFFFF; border: 0; border-top: 1px solid #E1E9F4; }
-#AppointmentsPage QWidget#Pager QLabel { color: #5D6B80; font-size: 13px; border: 0; }
+#AppointmentsPage QPushButton[appointmentImAction="true"]:hover { color: $ds_accent_hover; border-color: $ds_line_strong; }
+#AppointmentsPage QPushButton[appointmentImAction="true"]:focus { border-color: $ds_focus; }
+#AppointmentsPage QPushButton[appointmentImAction="true"]:disabled { color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line; }
+#AppointmentsPage QWidget#Pager { background: $ds_surface; border: 0; border-top: 1px solid $ds_line; }
+#AppointmentsPage QWidget#Pager QLabel { color: $ds_muted; font-size: 13px; border: 0; }
#AppointmentsPage QWidget#Pager QPushButton {
min-width: 30px; max-width: 30px; min-height: 32px; max-height: 32px;
- padding: 0; border: 1px solid #DBE5F2; background: #FFFFFF; color: #5D6B80; font-size: 13px;
+ padding: 0; border: 1px solid $ds_line; background: $ds_surface; color: $ds_muted; font-size: 13px;
}
-#AppointmentsPage QWidget#Pager QPushButton[active="true"] { color: #FFFFFF; background: #1769E8; border-color: #1769E8; }
-#AppointmentsPage QWidget#Pager QPushButton:disabled { color: #9AA6B7; background: #F7F9FC; }
+#AppointmentsPage QWidget#Pager QPushButton[active="true"] { color: $ds_accent; background: $ds_accent_soft; border-color: transparent; font-weight: 600; }
+#AppointmentsPage QWidget#Pager QPushButton:focus { border-color: $ds_focus; }
+#AppointmentsPage QWidget#Pager QPushButton:disabled { color: $ds_disabled; background: $ds_surface_alt; }
"""
diff --git a/app/src/doctor_workstation/ui/chat_notifications.py b/app/src/doctor_workstation/ui/chat_notifications.py
index c5f2526fa..a29f21717 100755
--- a/app/src/doctor_workstation/ui/chat_notifications.py
+++ b/app/src/doctor_workstation/ui/chat_notifications.py
@@ -24,6 +24,7 @@ from PySide6.QtWidgets import (
QWidget,
)
+from .design_system import clinical_stylesheet
from .widgets import display_text, first_value, run_async
# 后台 ChatNotifyLogic 写入的三种 type。
@@ -260,7 +261,7 @@ class ChatNotificationCenter(QWidget):
super().__init__(host)
self.repository = repository
self.setObjectName("ChatNotifyLayer")
- self.setStyleSheet(CHAT_NOTIFICATION_QSS)
+ self.setStyleSheet(clinical_stylesheet(CHAT_NOTIFICATION_QSS))
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, False)
self._cards: dict[str, _NotificationCard] = {}
self._pending: list[ChatNotification] = []
diff --git a/app/src/doctor_workstation/ui/consultations_style.py b/app/src/doctor_workstation/ui/consultations_style.py
index 92359094d..286713d09 100755
--- a/app/src/doctor_workstation/ui/consultations_style.py
+++ b/app/src/doctor_workstation/ui/consultations_style.py
@@ -2,59 +2,67 @@
from string import Template
+from .design_system import clinical_stylesheet
from .reception_style import body_family, heading_family
def consultations_stylesheet() -> str:
- return Template(_QSS).substitute(body=body_family(), heading=heading_family())
+ return clinical_stylesheet(Template(_QSS).safe_substitute(body=body_family(), heading=heading_family()))
_QSS = """
#DiagnosisIndex, #DiagnosisIndexContent, #DiagnosisPageScroll {
- background: #F3F7FD; color: #273244; border: 0;
+ background: $ds_canvas; color: $ds_text; border: 0;
}
#DiagnosisIndex QLabel, #DiagnosisIndex QPushButton, #DiagnosisIndex QToolButton,
#DiagnosisIndex QLineEdit, #DiagnosisIndex QComboBox, #DiagnosisIndex QDateEdit,
#DiagnosisIndex QSpinBox, #DiagnosisIndex QTableView {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
}
#DiagnosisIndex QWidget#PageHeader QLabel[role="pageTitle"] {
- font-family: "$heading"; font-size: 20px; font-weight: 600; color: #202C3F;
+ font-family: "$heading"; font-size: 20px; font-weight: 600; color: $ds_heading;
}
#DiagnosisIndex QLabel[role="muted"], #DiagnosisIndex QLabel[role="breadcrumb"],
#DiagnosisIndex QLabel[role="breadcrumbCurrent"], #DiagnosisIndex QLabel[role="breadcrumbSeparator"],
#DiagnosisIndex QLabel[filterGroup="true"], #DiagnosisIndex QLabel[pagerMuted="true"] {
- color: #5D6B80; font-size: 13px;
+ color: $ds_muted; font-size: 13px;
}
#DiagnosisIndex QFrame#DiagnosisFilterCard, #DiagnosisIndex QFrame#DiagnosisListCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
}
#DiagnosisIndex QFrame#DiagnosisStatusCard, #DiagnosisIndex QFrame#DiagnosisQuickFilters,
#DiagnosisIndex QFrame#DiagnosisListToolbar { background: transparent; border: 0; }
#DiagnosisIndex QFrame#DiagnosisAdvancedFilters {
- background: transparent; border: 0; border-top: 1px solid #E6EDF6; border-radius: 0;
+ background: transparent; border: 0; border-top: 1px solid $ds_line; border-radius: 0;
}
#DiagnosisIndex QPushButton {
- min-height: 34px; padding: 0 13px; border: 1px solid #DBE5F2;
- border-radius: 6px; background: #FFFFFF;
+ min-height: 34px; padding: 0 13px; border: 1px solid transparent;
+ border-radius: $ds_radius_control; background: $ds_surface_alt;
}
-#DiagnosisIndex QPushButton:hover { color: #1555B6; background: #F2F7FF; border-color: #B6CDEE; }
-#DiagnosisIndex QPushButton:pressed { background: #DCEAFF; }
-#DiagnosisIndex QPushButton:focus { border-color: #75A5F0; }
-#DiagnosisIndex QPushButton[variant="primary"] { color: #FFFFFF; background: #1769E8; border-color: #1769E8; }
-#DiagnosisIndex QPushButton[variant="primary"]:hover { background: #155BCC; }
-#DiagnosisIndex QPushButton[consultationTool="true"] { color: #1555B6; border-color: #C2D5EF; }
-#DiagnosisIndex QPushButton[consultationDanger="true"] { color: #BE4B58; border-color: #EBCDD2; }
-#DiagnosisIndex QPushButton:disabled, #DiagnosisIndex QPushButton[consultationDanger="true"]:disabled {
- color: #8A97A9; background: #F6F8FC; border-color: #E2E9F2;
+#DiagnosisIndex QPushButton:hover { color: $ds_accent; background: $ds_surface_alt; border-color: $ds_line_strong; }
+#DiagnosisIndex QPushButton:pressed { background: $ds_accent_soft; }
+#DiagnosisIndex QPushButton:focus { border-color: $ds_focus; }
+#DiagnosisIndex QPushButton[variant="primary"] { color: $ds_surface; background: $ds_accent; border-color: $ds_accent; }
+#DiagnosisIndex QPushButton[variant="primary"]:hover { background: $ds_accent_hover; }
+#DiagnosisIndex QPushButton[variant="primary"]:pressed { background: $ds_accent_pressed; }
+#DiagnosisIndex QPushButton[variant="primary"]:focus { border-color: $ds_focus; }
+#DiagnosisIndex QPushButton[consultationTool="true"] { color: $ds_text; border-color: transparent; }
+#DiagnosisIndex QPushButton[consultationTool="true"]:hover { color: $ds_accent; background: $ds_accent_soft; }
+#DiagnosisIndex QPushButton[consultationDanger="true"] { color: $ds_danger; background: $ds_danger_soft; border-color: transparent; }
+#DiagnosisIndex QPushButton[consultationDanger="true"]:hover { border-color: $ds_danger; }
+#DiagnosisIndex QPushButton[consultationTool="true"]:focus,
+#DiagnosisIndex QPushButton[consultationDanger="true"]:focus { border-color: $ds_focus; }
+#DiagnosisIndex QPushButton:disabled, #DiagnosisIndex QPushButton[consultationDanger="true"]:disabled,
+#DiagnosisIndex QPushButton[variant="primary"]:disabled, #DiagnosisIndex QPushButton[consultationTool="true"]:disabled {
+ color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line;
}
#DiagnosisIndex QLineEdit, #DiagnosisIndex QComboBox, #DiagnosisIndex QDateEdit, #DiagnosisIndex QSpinBox {
- min-height: 32px; padding: 0 10px; color: #273244; background: #FFFFFF;
- border: 1px solid #DBE5F2; border-radius: 6px; selection-background-color: #DCEAFF;
+ min-height: 32px; padding: 0 10px; color: $ds_text; background: $ds_surface;
+ border: 1px solid $ds_line; border-radius: $ds_radius_control; selection-background-color: $ds_accent_soft;
font-size: 13px;
}
#DiagnosisIndex QLineEdit:focus, #DiagnosisIndex QComboBox:focus,
-#DiagnosisIndex QDateEdit:focus, #DiagnosisIndex QSpinBox:focus { border-color: #75A5F0; }
+#DiagnosisIndex QDateEdit:focus, #DiagnosisIndex QSpinBox:focus { border-color: $ds_focus; }
#DiagnosisIndex QLineEdit QToolButton {
min-width: 0; min-height: 0; padding: 0; border: 0; background: transparent;
}
@@ -62,70 +70,77 @@ _QSS = """
width: 22px; border: 0; background: transparent;
}
#DiagnosisIndex QComboBox QAbstractItemView {
- color: #273244; background: #FFFFFF; border: 1px solid #DBE5F2;
- selection-background-color: #EAF2FF; selection-color: #1555B6; outline: 0;
+ color: $ds_text; background: $ds_surface; border: 1px solid $ds_line;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_accent; outline: 0;
}
#DiagnosisIndex QWidget#DiagnosisStatusSearch QLineEdit,
#DiagnosisIndex QWidget#DiagnosisStatusSearch QPushButton { min-height: 39px; max-height: 39px; }
#DiagnosisIndex QToolButton { min-width: 0; min-height: 0; border: 0; padding: 0; background: transparent; }
#DiagnosisIndex QToolButton[diagnosisChip="true"] {
min-height: 32px; max-height: 32px; padding: 0 14px; border: 1px solid transparent;
- border-radius: 5px; color: #5D6B80; background: transparent; font-size: 13px;
+ border-radius: $ds_radius_control; color: $ds_muted; background: transparent; font-size: 13px;
}
-#DiagnosisIndex QToolButton[diagnosisChip="true"]:hover { background: #F2F7FF; color: #1555B6; }
-#DiagnosisIndex QToolButton[diagnosisChip="true"]:checked { background: #1769E8; color: #FFFFFF; }
-#DiagnosisIndex QToolButton[dateChoice="true"] { padding: 0 17px; border-color: #E1E9F4; }
-#DiagnosisIndex QToolButton[dateChoice="true"]:checked { border-color: #1769E8; }
+#DiagnosisIndex QToolButton[diagnosisChip="true"]:hover { background: $ds_surface_alt; color: $ds_accent; }
+#DiagnosisIndex QToolButton[diagnosisChip="true"]:checked { background: $ds_accent_soft; color: $ds_accent; font-weight: 600; }
+#DiagnosisIndex QToolButton[dateChoice="true"] { padding: 0 17px; background: $ds_surface_alt; border-color: transparent; }
+#DiagnosisIndex QToolButton[dateChoice="true"]:checked { background: $ds_accent_soft; border-color: transparent; }
+#DiagnosisIndex QToolButton[diagnosisChip="true"]:focus { border-color: $ds_focus; }
#DiagnosisIndex QToolButton[statusTab="true"] {
min-height: 44px; max-height: 44px; padding: 0 20px; border: 0;
border-bottom: 2px solid transparent; border-radius: 0; background: transparent;
}
#DiagnosisIndex QToolButton[statusTab="true"]:checked {
- color: #1769E8; background: transparent; border-bottom-color: #1769E8;
+ color: $ds_accent; background: transparent; border-bottom-color: $ds_accent;
}
+#DiagnosisIndex QToolButton[statusTab="true"]:focus { background: $ds_accent_soft; }
#DiagnosisIndex QToolButton#DiagnosisMoreFilter {
- min-height: 32px; padding: 0 6px; color: #5D6B80; font-size: 13px;
+ min-height: 32px; padding: 0 6px; color: $ds_muted; font-size: 13px;
}
-#DiagnosisIndex QToolButton#DiagnosisMoreFilter:hover { color: #1769E8; background: #F2F7FF; }
-#DiagnosisIndex QFrame#DiagnosisFilterDivider { min-width: 1px; max-width: 1px; min-height: 20px; background: #E1E9F4; border: 0; }
+#DiagnosisIndex QToolButton#DiagnosisMoreFilter:hover { color: $ds_accent; background: $ds_surface_alt; }
+#DiagnosisIndex QFrame#DiagnosisFilterDivider { min-width: 1px; max-width: 1px; min-height: 20px; background: $ds_line; border: 0; }
#DiagnosisIndex QFrame#DiagnosisDateRange {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 6px;
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_control;
}
#DiagnosisIndex QDateEdit[diagnosisRangePart="true"] { min-height: 30px; padding: 0 4px; border: 0; }
#DiagnosisIndex QTableView {
- background: #FFFFFF; alternate-background-color: #FFFFFF; border: 0; border-radius: 0;
- gridline-color: #E6EDF6; selection-background-color: #EAF2FF; selection-color: #273244;
+ background: $ds_surface; alternate-background-color: $ds_surface; border: 0; border-radius: 0;
+ gridline-color: $ds_line; selection-background-color: $ds_accent_soft; selection-color: $ds_text;
}
#DiagnosisIndex QTableView QHeaderView::section {
- min-height: 41px; padding: 0; background: #F5F8FD; color: #5D6B80;
- border: 0; border-bottom: 1px solid #E1E9F4;
+ min-height: 41px; padding: 0; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-bottom: 1px solid $ds_line;
font-family: "$body"; font-size: 13px; font-weight: 400;
}
#DiagnosisIndex QToolButton[rowLink], #DiagnosisIndex QToolButton[appointmentCancel="true"] {
- color: #1769E8; min-height: 26px; padding: 0 4px; border: 0; background: transparent; font-size: 13px;
+ color: $ds_accent; min-height: 26px; padding: 0 4px; border: 1px solid transparent;
+ border-radius: $ds_radius_small; background: transparent; font-size: 13px;
}
-#DiagnosisIndex QToolButton[appointmentCancel="true"] { color: #BE4B58; }
-#DiagnosisIndex QToolButton[rowLink]:hover { color: #1555B6; background: #DCEAFF; border-radius: 4px; }
+#DiagnosisIndex QToolButton[appointmentCancel="true"] { color: $ds_danger; }
+#DiagnosisIndex QToolButton[appointmentCancel="true"]:hover { background: $ds_danger_soft; }
+#DiagnosisIndex QToolButton[rowLink]:hover { color: $ds_accent; background: $ds_accent_soft; border-radius: $ds_radius_small; }
+#DiagnosisIndex QToolButton[rowLink]:focus,
+#DiagnosisIndex QToolButton[appointmentCancel="true"]:focus { border-color: $ds_focus; }
#DiagnosisIndex QToolButton[rowLink="muted"], #DiagnosisIndex QLabel[fixedMuted="true"] {
- color: #5D6B80; font-size: 13px;
+ color: $ds_muted; font-size: 13px;
}
#DiagnosisIndex QToolButton#DiagnosisRowMore { padding-right: 18px; }
#DiagnosisIndex QWidget#DiagnosisFixedCell { background: transparent; }
-#DiagnosisIndex QLabel#DiagnosisTableEmpty { color: #5D6B80; background: #FFFFFF; }
-#DiagnosisIndex QLabel#DiagnosisTableEmpty[stateKind="error"] { color: #BE4B58; }
-#DiagnosisIndex QTableView#DiagnosisFixedTable { border-left: 1px solid #E1E9F4; }
-#DiagnosisIndex QWidget#DiagnosisPager { background: #FFFFFF; border-top: 1px solid #E6EDF6; }
+#DiagnosisIndex QLabel#DiagnosisTableEmpty { color: $ds_muted; background: $ds_surface; }
+#DiagnosisIndex QLabel#DiagnosisTableEmpty[stateKind="error"] { color: $ds_danger; }
+#DiagnosisIndex QTableView#DiagnosisFixedTable { border-left: 1px solid $ds_line; }
+#DiagnosisIndex QWidget#DiagnosisPager { background: $ds_surface; border-top: 1px solid $ds_line; }
#DiagnosisIndex QToolButton[pagerButton="true"] {
min-width: 30px; max-width: 30px; min-height: 30px; max-height: 30px;
- border: 1px solid #DBE5F2; border-radius: 5px; color: #5D6B80; background: #FFFFFF;
+ border: 1px solid $ds_line; border-radius: $ds_radius_control; color: $ds_muted; background: $ds_surface;
}
-#DiagnosisIndex QToolButton[pagerButton="true"][active="true"] { color: #FFFFFF; background: #1769E8; border-color: #1769E8; }
-#DiagnosisIndex QToolButton[pagerButton="true"]:disabled { color: #A4B0C0; background: #F6F8FC; }
+#DiagnosisIndex QToolButton[pagerButton="true"][active="true"] { color: $ds_accent; background: $ds_accent_soft; border-color: transparent; font-weight: 600; }
+#DiagnosisIndex QToolButton[pagerButton="true"]:focus { border-color: $ds_focus; }
+#DiagnosisIndex QToolButton[pagerButton="true"]:disabled { color: $ds_disabled; background: $ds_disabled_surface; }
#DiagnosisIndex QComboBox#DiagnosisPageSize { min-width: 95px; min-height: 30px; }
#DiagnosisIndex QSpinBox#DiagnosisPageJumper { min-height: 30px; padding: 0 8px; }
-#DiagnosisIndex QScrollBar:vertical { background: #F4F7FC; width: 7px; margin: 0; }
-#DiagnosisIndex QScrollBar:horizontal { background: #F4F7FC; height: 7px; margin: 0; }
-#DiagnosisIndex QScrollBar::handle { background: #C8D5E6; border-radius: 3px; min-width: 24px; min-height: 24px; }
+#DiagnosisIndex QScrollBar:vertical { background: $ds_canvas; width: 7px; margin: 0; }
+#DiagnosisIndex QScrollBar:horizontal { background: $ds_canvas; height: 7px; margin: 0; }
+#DiagnosisIndex QScrollBar::handle { background: $ds_line_strong; border-radius: 3px; min-width: 24px; min-height: 24px; }
#DiagnosisIndex QScrollBar::add-line, #DiagnosisIndex QScrollBar::sub-line { width: 0; height: 0; }
#DiagnosisIndex QScrollBar::add-page, #DiagnosisIndex QScrollBar::sub-page { background: transparent; }
"""
diff --git a/app/src/doctor_workstation/ui/design_system.py b/app/src/doctor_workstation/ui/design_system.py
new file mode 100644
index 000000000..0319c8a9e
--- /dev/null
+++ b/app/src/doctor_workstation/ui/design_system.py
@@ -0,0 +1,76 @@
+"""Clinical desktop design tokens, shared by native pages and dialog chrome.
+
+Keep data-series colours and video pixels outside this palette. Existing scoped
+QSS can adopt the system without changing selectors, layout or permissions.
+New rules should use the named ``$ds_*`` tokens rather than legacy colours.
+"""
+
+from __future__ import annotations
+
+import re
+from string import Template
+
+PALETTE = {
+ "canvas": "#F5F7FA",
+ "surface": "#FFFFFF",
+ "surface_alt": "#F7F9FC",
+ "sidebar": "#F0F3F8",
+ "line": "#E6EAF0",
+ "line_strong": "#D4DCE8",
+ "heading": "#223047",
+ "text": "#344258",
+ "muted": "#647287",
+ "disabled": "#8B96A6",
+ "disabled_surface": "#F0F2F5",
+ "accent": "#4267B2",
+ "accent_hover": "#355995",
+ "accent_pressed": "#2C4C82",
+ "accent_soft": "#EAF0FB",
+ "focus": "#6D8CCB",
+ "success": "#287B65",
+ "success_soft": "#EDF7F2",
+ "warning": "#96601D",
+ "warning_soft": "#FBF4E8",
+ "danger": "#B54A59",
+ "danger_soft": "#FCF0F2",
+}
+
+RADII = {"small": 6, "control": 10, "panel": 16, "window": 20}
+SPACING = {"small": 8, "control": 12, "group": 16, "section": 24}
+
+TOKENS = {f"ds_{name}": value for name, value in PALETTE.items()}
+TOKENS.update({f"ds_radius_{name}": f"{value}px" for name, value in RADII.items()})
+TOKENS.update({f"ds_space_{name}": f"{value}px" for name, value in SPACING.items()})
+
+# Explicit migration of the two existing native palettes. This adapter only
+# touches six-digit colour literals; selectors and metrics stay page-owned.
+_LEGACY_ROLES = {
+ "accent": ("1769E8", "4F63D9", "5761F4", "5267DF"),
+ "accent_hover": ("155BCC", "1555B6", "4156C4", "4356C4", "4055CA"),
+ "accent_pressed": ("124EA9", "354BB4"),
+ "accent_soft": ("EAF2FF", "EEF1FA", "EEF0FF", "F0F2FF", "DCEAFF", "EDF0FC"),
+ "focus": ("75A5F0", "8B9AD9"),
+ "canvas": ("F3F7FD", "F4F6FA", "F6F6F6"),
+ "surface_alt": ("F7F7F7", "F7FAFE", "F5F8FD", "F7F9FE", "F2F7FF"),
+ "sidebar": ("EDF4FF",),
+ "line": ("DBE5F2", "EDEDEE", "E5ECF6", "E6EDF6", "E7EDF7", "EDF0F5", "E7EBF2", "E6EAF5"),
+ "line_strong": ("E4E4E5", "C8D5E6", "C9DCF7", "ADC8F0", "B6CDEE"),
+ "heading": ("1A1C1F", "202C3F", "111F46"),
+ "text": ("273244", "263551", "24334A", "233149", "3F4E75"),
+ "muted": ("606163", "6A6B6D", "5D6B80", "7886AA", "708097"),
+ "disabled": ("8E8F90", "8A97A9", "9AA6B7"),
+ "disabled_surface": ("F2F2F2", "F0F0F0"),
+ "success_soft": ("EEF7F3", "EAF9F3"),
+ "warning": ("A9691D", "9C681F"),
+ "warning_soft": ("FCF5E9", "FFF5E6", "FFF6E7"),
+ "danger": ("BE4B58", "B84652"),
+ "danger_soft": ("FFF0F2", "FFF1F3"),
+}
+_LEGACY = {colour.lower(): PALETTE[role] for role, colours in _LEGACY_ROLES.items() for colour in colours}
+_HEX = re.compile(r"#([0-9a-fA-F]{6})(?![0-9a-fA-F])")
+
+
+def clinical_stylesheet(source: str) -> str:
+ """Resolve clinical tokens and migrate known legacy light-theme colours."""
+ resolved = Template(source).safe_substitute(TOKENS)
+ return _HEX.sub(lambda match: _LEGACY.get(match[1].lower(), match[0]), resolved)
diff --git a/app/src/doctor_workstation/ui/diagnosis_drawer.py b/app/src/doctor_workstation/ui/diagnosis_drawer.py
index 231731f30..38dae4767 100755
--- a/app/src/doctor_workstation/ui/diagnosis_drawer.py
+++ b/app/src/doctor_workstation/ui/diagnosis_drawer.py
@@ -64,6 +64,7 @@ from PySide6.QtWidgets import (
)
from .chat_items import ChatItem, parse_chat_item
+from .design_system import PALETTE, clinical_stylesheet
from .diagnosis_editors import FlowLayout
from .diagnosis_media import shared_image_manager
from .diagnosis_terms import FIELD_DICTIONARIES, format_timestamp, shared_terms
@@ -80,10 +81,7 @@ QFrame#DiagnosisDrawer {
border-left: 1px solid #EDEDEE;
}
QFrame#DiagnosisDrawerHeader {
- background-color: qlineargradient(
- x1:0, y1:0, x2:0, y2:1,
- stop:0 #FFFFFF, stop:1 #F7F7F7
- );
+ background-color: #FFFFFF;
border-bottom: 1px solid #EDEDEE;
}
QFrame#DiagnosisDrawerFooter {
@@ -105,7 +103,7 @@ QLabel#DiagnosisDrawerModeBadge,
QLabel#DiagnosisReadonlyStatus,
QLabel[diagnosisTag="true"] {
padding: 4px 9px;
- border-radius: 9px;
+ border-radius: $ds_radius_small;
font-size: 12px;
font-weight: 500;
}
@@ -159,8 +157,8 @@ QDialog QPushButton:pressed {
border-color: #354BB4;
}
QDialog QPushButton:disabled {
- color: #E4E4E5;
- background-color: #FFFFFF;
+ color: $ds_disabled;
+ background-color: $ds_disabled_surface;
border-color: #EDEDEE;
}
QDialog QPushButton[variant="primary"] {
@@ -176,9 +174,9 @@ QDialog QPushButton[variant="primary"]:focus {
border-color: #4156C4;
}
QDialog QPushButton[variant="primary"]:disabled {
- color: #FFFFFF;
- background-color: #F0F0F0;
- border-color: #F0F0F0;
+ color: $ds_disabled;
+ background-color: $ds_disabled_surface;
+ border-color: $ds_line;
}
QDialog QPushButton[variant="secondary"] {
color: #4F63D9;
@@ -267,9 +265,9 @@ QDialog#DiagnosisDialogRoot QPushButton#DiagnosisSaveButton:focus {
border-color: #4156C4;
}
QDialog#DiagnosisDialogRoot QPushButton#DiagnosisSaveButton:disabled {
- color: #FFFFFF;
- background-color: #F0F0F0;
- border-color: #F0F0F0;
+ color: $ds_disabled;
+ background-color: $ds_disabled_surface;
+ border-color: $ds_line;
}
QDialog#DiagnosisDialogRoot QPushButton#DiagnosisFooterCloseButton {
color: #606163;
@@ -383,10 +381,10 @@ QFrame#DiagnosisFormHost {
QFrame[diagnosisSection="true"] {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 12px;
+ border-radius: 16px;
}
QLabel[diagnosisFieldLabel="true"] {
- color: #1A1C1F;
+ color: $ds_muted;
font-size: 12px;
font-weight: 500;
}
@@ -426,7 +424,7 @@ QDoubleSpinBox[diagnosisField="true"]:focus,
QSpinBox[diagnosisField="true"]:focus,
QTimeEdit[diagnosisField="true"]:focus {
border: 1px solid #8B9AD9;
- background-color: #F7F7F7;
+ background-color: $ds_surface;
}
QLineEdit[diagnosisField="true"][invalid="true"],
QComboBox[diagnosisField="true"][invalid="true"],
@@ -452,8 +450,8 @@ QLabel#DiagnosisSectionTitle {
background-color: transparent;
border: 0;
padding: 0;
- font-size: 13px;
- font-weight: 500;
+ font-size: 14px;
+ font-weight: 600;
letter-spacing: 0.02em;
}
QFrame#DiagnosisSectionAccent {
@@ -470,9 +468,9 @@ QFrame#DiagnosisReadonlyPage {
background-color: #F6F6F6;
}
QFrame#DiagnosisReadonlyHero {
- background-color: #F7F7F7;
- border: 1px solid #F0F0F0;
- border-radius: 12px;
+ background-color: $ds_surface;
+ border: 1px solid $ds_line;
+ border-radius: $ds_radius_panel;
}
QLabel#DiagnosisReadonlyTitle {
color: #1A1C1F;
@@ -542,7 +540,7 @@ QFrame#DiagnosisReadonlyCaseCard,
QFrame[diagnosisReadonlyCard="true"] {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 14px;
+ border-radius: 16px;
}
QLabel#DiagnosisReadonlyCardTitle {
color: #1A1C1F;
@@ -771,7 +769,7 @@ QWidget[diagnosisChoiceHost="true"] QPushButton {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 999px;
+ border-radius: 10px;
font-size: 12px;
}
QWidget[diagnosisChoiceHost="true"] QPushButton:hover,
@@ -1068,6 +1066,7 @@ _DIAGNOSIS_BLUE_REPLACEMENTS = (
)
for _source_color, _theme_color in _DIAGNOSIS_BLUE_REPLACEMENTS:
DIAGNOSIS_QSS = DIAGNOSIS_QSS.replace(_source_color, _theme_color)
+DIAGNOSIS_QSS = clinical_stylesheet(DIAGNOSIS_QSS)
def _text(value: Any, default: str = "—") -> str:
@@ -1147,12 +1146,19 @@ class DiagnosisSwitch(QAbstractButton):
track = QRectF(1, 3, self.width() - 2, self.height() - 6)
checked = self.isChecked()
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#4F63D9" if checked else "#E4E4E5"))
+ painter.setBrush(QColor(PALETTE["accent"] if checked else PALETTE["line_strong"]))
+ if not self.isEnabled():
+ painter.setOpacity(0.6)
painter.drawRoundedRect(track, track.height() / 2, track.height() / 2)
diameter = track.height() - 4
x = track.right() - diameter - 2 if checked else track.left() + 2
painter.setBrush(QColor("#FFFFFF"))
painter.drawEllipse(QRectF(x, track.top() + 2, diameter, diameter))
+ if self.hasFocus():
+ painter.setOpacity(1)
+ painter.setPen(QPen(QColor(PALETTE["focus"]), 1))
+ painter.setBrush(Qt.BrushStyle.NoBrush)
+ painter.drawRoundedRect(QRectF(self.rect()).adjusted(0.5, 0.5, -0.5, -0.5), 11, 11)
painter.end()
@@ -1190,13 +1196,19 @@ class SaveStateButton(QPushButton):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
enabled = self.isEnabled()
+ idle_color = PALETTE["accent_pressed"] if self.isDown() else PALETTE["accent"]
color = {
- "success": "#287B65",
- "error": "#BE4B58",
- }.get(self._state, "#4F63D9" if enabled else "#8E8F90")
+ "success": PALETTE["success"],
+ "error": PALETTE["danger"],
+ "loading": PALETTE["accent"],
+ }.get(self._state, idle_color if enabled else PALETTE["disabled_surface"])
painter.setPen(Qt.PenStyle.NoPen)
painter.setBrush(QColor(color))
painter.drawRoundedRect(QRectF(self.rect()).adjusted(1, 1, -1, -1), 10, 10)
+ if self.hasFocus():
+ painter.setPen(QPen(QColor(PALETTE["focus"]), 1))
+ painter.setBrush(Qt.BrushStyle.NoBrush)
+ painter.drawRoundedRect(QRectF(self.rect()).adjusted(0.5, 0.5, -0.5, -0.5), 10, 10)
label = {
"loading": "正在保存",
"success": "保存成功",
@@ -1220,7 +1232,9 @@ class SaveStateButton(QPushButton):
else:
painter.drawLine(x + 3, center_y - 5, x + 12, center_y + 5)
painter.drawLine(x + 12, center_y - 5, x + 3, center_y + 5)
- painter.setPen(QColor("#FFFFFF"))
+ painter.setPen(QColor(
+ PALETTE["disabled"] if not enabled and self._state == "idle" else PALETTE["surface"]
+ ))
painter.drawText(
QRect(x + icon_width, 0, metrics.horizontalAdvance(label), self.height()),
Qt.AlignmentFlag.AlignCenter,
@@ -1815,10 +1829,10 @@ class MessageStrip(QFrame):
self.glyph = QLabel("i")
self.glyph.setFixedWidth(18)
self.glyph.setAlignment(Qt.AlignmentFlag.AlignCenter)
- self.glyph.setStyleSheet("font-weight:700; color:#4F63D9;")
+ self.glyph.setStyleSheet(clinical_stylesheet("font-weight:700; color:$ds_accent;"))
self.label = QLabel()
self.label.setWordWrap(True)
- self.label.setStyleSheet("color:#1A1C1F; font-size:13px;")
+ self.label.setStyleSheet(clinical_stylesheet("color:$ds_text; font-size:13px;"))
layout.addWidget(self.glyph)
layout.addWidget(self.label, 1)
self.action_button = QPushButton()
@@ -1894,7 +1908,7 @@ class LoadingOverlay(QFrame):
layout.setSpacing(8)
self.glyph = _LoadingSpinner(self)
label = QLabel(text)
- label.setStyleSheet("color:#606163; font-size:13px;")
+ label.setStyleSheet(clinical_stylesheet("color:$ds_muted; font-size:13px;"))
layout.addWidget(self.glyph)
layout.addWidget(label)
self.hide()
@@ -1985,15 +1999,15 @@ class RecordTable(QTableWidget):
Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter
)
if column_index in danger_columns:
- item.setForeground(QColor("#BE4B58"))
+ item.setForeground(QColor(PALETTE["danger"]))
kind = semantic.get(column_index)
if kind:
palette = {
- "success": ("#287B65", "#EAF9F3"),
- "warning": ("#A9691D", "#FFF5E6"),
- "danger": ("#BE4B58", "#FFF1F3"),
- "info": ("#4F63D9", "#EEF1FA"),
- "neutral": ("#6A6B6D", "#F7F7F7"),
+ "success": (PALETTE["success"], PALETTE["success_soft"]),
+ "warning": (PALETTE["warning"], PALETTE["warning_soft"]),
+ "danger": (PALETTE["danger"], PALETTE["danger_soft"]),
+ "info": (PALETTE["accent"], PALETTE["accent_soft"]),
+ "neutral": (PALETTE["muted"], PALETTE["surface_alt"]),
}
foreground, background = palette.get(kind, palette["neutral"])
item.setForeground(QColor(foreground))
@@ -2033,20 +2047,20 @@ class BloodTrendChart(QWidget):
plot = self.rect().adjusted(48, 24, -22, -38)
values = [value for value in (*self._fasting, *self._postprandial) if value is not None]
if not values or plot.width() <= 0 or plot.height() <= 0:
- painter.setPen(QColor("#606163"))
+ painter.setPen(QColor(PALETTE["muted"]))
painter.drawText(self.rect(), Qt.AlignmentFlag.AlignCenter, "当前时间范围暂无血糖数据")
painter.end()
return
upper = max(12.0, max(values) * 1.15)
- painter.setPen(QPen(QColor("#EDEDEE"), 1))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1))
for step in range(5):
y = plot.bottom() - round(plot.height() * step / 4)
painter.drawLine(plot.left(), y, plot.right(), y)
- painter.setPen(QColor("#606163"))
+ painter.setPen(QColor(PALETTE["muted"]))
painter.drawText(
4, y - 8, 40, 16, Qt.AlignmentFlag.AlignRight, f"{upper * step / 4:.0f}"
)
- painter.setPen(QPen(QColor("#EDEDEE"), 1))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1))
count = max(1, len(self._dates) - 1)
def point(index: int, value: float) -> QPointF:
@@ -2076,7 +2090,7 @@ class BloodTrendChart(QWidget):
painter.setPen(QColor("#A9691D"))
painter.drawText(plot.left() + 100, 4, 110, 18, Qt.AlignmentFlag.AlignLeft, "● 餐后血糖")
if self._dates:
- painter.setPen(QColor("#606163"))
+ painter.setPen(QColor(PALETTE["muted"]))
painter.drawText(
plot.left(),
plot.bottom() + 8,
@@ -2279,7 +2293,7 @@ class DailyRecordPanel(QFrame):
self.todo_table.setMinimumHeight(180)
todo_layout.addWidget(self.todo_table)
self.todo_summary = QLabel("共 0 条")
- self.todo_summary.setStyleSheet("color:#606163; font-size:13px;")
+ self.todo_summary.setStyleSheet(clinical_stylesheet("color:$ds_muted; font-size:13px;"))
todo_layout.addWidget(self.todo_summary, 0, Qt.AlignmentFlag.AlignRight)
root.addWidget(todo_card)
self.clear()
@@ -2437,8 +2451,8 @@ class DailyRecordPanel(QFrame):
for row_index, (metric, label) in enumerate(self.METRICS):
label_item = QTableWidgetItem(label)
label_item.setFont(label_font)
- label_item.setForeground(QColor("#606163"))
- label_item.setBackground(QColor("#F7F7F7"))
+ label_item.setForeground(QColor(PALETTE["muted"]))
+ label_item.setBackground(QColor(PALETTE["surface_alt"]))
self.matrix.setItem(row_index, 0, label_item)
for date_index, date in enumerate(dates, 1):
b = blood.get(date)
@@ -2491,11 +2505,11 @@ class DailyRecordPanel(QFrame):
item = QTableWidgetItem(value)
item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
if high:
- item.setForeground(QColor("#BE4B58"))
- item.setBackground(QColor("#FFF1F3"))
+ item.setForeground(QColor(PALETTE["danger"]))
+ item.setBackground(QColor(PALETTE["danger_soft"]))
elif value.endswith("· 自录"):
- item.setForeground(QColor("#1A1C1F"))
- item.setBackground(QColor("#F7F7F7"))
+ item.setForeground(QColor(PALETTE["text"]))
+ item.setBackground(QColor(PALETTE["surface_alt"]))
edit_kind = ""
edit_source: Any = None
if metric in {"fasting", "postprandial", "other", "bp", "western", "insulin"}:
@@ -3022,7 +3036,7 @@ class ChatPanel(QWidget):
toolbar_layout.setContentsMargins(0, 0, 0, 0)
toolbar_layout.setSpacing(8)
archive = QLabel("仅展示服务端已归档消息(only_archived=1)")
- archive.setStyleSheet("color:#606163;font-size:12px;")
+ archive.setStyleSheet(clinical_stylesheet("color:$ds_muted;font-size:12px;"))
toolbar_layout.addWidget(archive)
toolbar_layout.addStretch(1)
self.sync_button = QPushButton("同步最新(后台异步)")
@@ -3298,7 +3312,7 @@ class CaseGrid(QFrame):
if group_index:
divider = QFrame()
divider.setFrameShape(QFrame.Shape.HLine)
- divider.setStyleSheet("border:0; border-top:1px dashed #E4E4E5;")
+ divider.setStyleSheet(clinical_stylesheet("border:0; border-top:1px solid $ds_line;"))
self.root.addWidget(divider)
group_title = QLabel(f"● {group_name}")
group_title.setProperty("diagnosisCaseGroup", True)
@@ -3456,11 +3470,11 @@ def readonly_card(title: str, object_name: str, body: QWidget) -> QFrame:
def set_tag_item(item: QTableWidgetItem, kind: str) -> None:
palette = {
- "success": ("#287B65", "#EAF9F3"),
- "warning": ("#A9691D", "#FFF5E6"),
- "danger": ("#BE4B58", "#FFF1F3"),
- "info": ("#4F63D9", "#EEF1FA"),
- "neutral": ("#6A6B6D", "#F7F7F7"),
+ "success": (PALETTE["success"], PALETTE["success_soft"]),
+ "warning": (PALETTE["warning"], PALETTE["warning_soft"]),
+ "danger": (PALETTE["danger"], PALETTE["danger_soft"]),
+ "info": (PALETTE["accent"], PALETTE["accent_soft"]),
+ "neutral": (PALETTE["muted"], PALETTE["surface_alt"]),
}
foreground, background = palette.get(kind, palette["neutral"])
item.setForeground(QColor(foreground))
diff --git a/app/src/doctor_workstation/ui/diagnosis_index_widgets.py b/app/src/doctor_workstation/ui/diagnosis_index_widgets.py
index a2ecb96be..9a420b56d 100755
--- a/app/src/doctor_workstation/ui/diagnosis_index_widgets.py
+++ b/app/src/doctor_workstation/ui/diagnosis_index_widgets.py
@@ -67,21 +67,22 @@ from ..core.appointment_modes import (
can_appointment_video,
)
from . import icons
+from .design_system import PALETTE, clinical_stylesheet
from .reception_style import TECH_BLUE, body_family, heading_family
from .widgets import display_text, first_value, gender_text, get_value
-PRIMARY = QColor("#4F63D9")
-TEXT = QColor("#1A1C1F")
-SECONDARY = QColor("#606163")
-PLACEHOLDER = QColor("#8E8F90")
+PRIMARY = QColor(PALETTE["accent"])
+TEXT = QColor(PALETTE["text"])
+SECONDARY = QColor(PALETTE["muted"])
+PLACEHOLDER = QColor(PALETTE["disabled"])
_INVALID_INDEX = QModelIndex()
# The last two columns form the compact frozen pane. Video status and ending
# time occupy separate lines; actions keep two inline links plus 更多, with
# the remaining actions in its menu so clinical columns retain more space.
_TABLE_COLUMN_WIDTHS = (48, 70, 60, 100, 175, 88, 120, 100, 72, 110, 96, 160)
_BLUE_COLUMN_WIDTHS = (48, 70, 82, 102, 244, 90, 84, 90, 88, 122, 92, 158)
-_BLUE_WARNING = QColor("#A9691D")
-_BLUE_DANGER = QColor("#BE4B58")
+_BLUE_WARNING = QColor(PALETTE["warning"])
+_BLUE_DANGER = QColor(PALETTE["danger"])
def _blue_font(pixels: int = 13, *, medium: bool = False) -> QFont:
@@ -248,14 +249,14 @@ class _DiagnosisActionMenu(QMenu):
return
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
- painter.fillRect(rect, QColor("#FFFFFF"))
+ painter.fillRect(rect, QColor(PALETTE["surface"]))
item_rect = rect
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#F7F7F7") if self.activeAction() is action else QColor("#FFFFFF"))
+ painter.setBrush(QColor(PALETTE["surface_alt"]) if self.activeAction() is action else QColor(PALETTE["surface"]))
painter.drawRoundedRect(item_rect, 3, 3)
icon_rect = QRect(item_rect.left() + 8, item_rect.center().y() - 9, 18, 18)
action.icon().paint(painter, icon_rect)
- painter.setPen(QColor("#BE4B58" if action.isEnabled() else "#8E8F90"))
+ painter.setPen(QColor(PALETTE["danger"] if action.isEnabled() else PALETTE["disabled"]))
painter.drawText(
item_rect.adjusted(34, 0, -10, 0),
Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft,
@@ -823,6 +824,8 @@ class DiagnosisTableModel(QAbstractTableModel):
default="",
)
return f"最近渠道:{channel}" if channel else ""
+ if column == 6:
+ return DiagnosisTableModel._display(row, column)
if column == 7:
return display_text(first_value(row, "assistant_name"), "")
if column == 9:
@@ -849,7 +852,7 @@ class DiagnosisHeader(QHeaderView):
def paintSection(self, painter: QPainter, rect: QRect, logical_index: int) -> None: # noqa: N802
if self.tech_blue:
painter.save()
- painter.fillRect(rect, QColor("#F5F8FD"))
+ painter.fillRect(rect, QColor(PALETTE["surface_alt"]))
painter.setPen(QPen(QColor(TECH_BLUE["line"]), 1))
painter.drawLine(rect.bottomLeft(), rect.bottomRight())
painter.setFont(_blue_font())
@@ -870,7 +873,7 @@ class DiagnosisHeader(QHeaderView):
painter.save()
painter.setPen(Qt.PenStyle.NoPen)
primary = QColor(TECH_BLUE["accent"]) if self.tech_blue else PRIMARY
- secondary = QColor(TECH_BLUE["muted"]) if self.tech_blue else QColor("#606163")
+ secondary = QColor(TECH_BLUE["muted"]) if self.tech_blue else QColor(PALETTE["muted"])
painter.setBrush(primary if direction == "asc" else secondary)
painter.drawPolygon(
QPolygon(
@@ -953,7 +956,7 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
painter,
option.rect,
"已确认" if _confirmed(record) else "未确认",
- QColor("#287B65") if _confirmed(record) else QColor("#A9691D"),
+ QColor(PALETTE["success"]) if _confirmed(record) else QColor(PALETTE["warning"]),
)
elif index.column() == 6:
self._paint_followup(painter, option.rect, record)
@@ -1023,16 +1026,16 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
) -> None:
hovered = model.hover_row == row
base = (
- QColor("#EEF1FA")
+ QColor(PALETTE["accent_soft"])
if selected
- else QColor("#F7F7F7" if hovered else "#F7F7F7" if row % 2 else "#FFFFFF")
+ else QColor(PALETTE["surface_alt"] if hovered or row % 2 else PALETTE["surface"])
)
special = not _confirmed(record) or not _has_appointment(record)
painter.fillRect(rect, base)
if special and column == 0:
- stripe = QColor("#A9691D") if not _confirmed(record) else QColor("#4F63D9")
+ stripe = QColor(PALETTE["warning"]) if not _confirmed(record) else QColor(PALETTE["accent"])
painter.fillRect(QRect(rect.left(), rect.top(), 3, rect.height()), stripe)
- painter.setPen(QPen(QColor("#EDEDEE"), 1))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1))
painter.drawLine(QLine(rect.bottomLeft(), rect.bottomRight()))
@staticmethod
@@ -1070,8 +1073,8 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
painter,
QRect(left, content.center().y() - 10, 31, 20),
"NEW",
- QColor("#BE4B58"),
- QColor("#FFFFFF"),
+ QColor(PALETTE["danger"]),
+ QColor(PALETTE["surface"]),
10,
)
@@ -1081,17 +1084,17 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
self._draw_text(painter, content, "未挂号", PLACEHOLDER, 13)
return
rows = _appointments(record)
- painter.setPen(QPen(QColor("#EDEDEE"), 1))
- painter.setBrush(QColor("#FFFFFF"))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1))
+ painter.setBrush(QColor(PALETTE["surface"]))
painter.drawRoundedRect(content, 6, 6)
y = content.top() + 4
for position, appointment in enumerate(rows or [{}]):
status = _as_int(first_value(appointment, "status", "appointment_status"), -1)
label, fg, bg = {
- 1: ("已预约", QColor("#4F63D9"), QColor("#EEF1FA")),
- 3: ("已完成", QColor("#287B65"), QColor("#E8F6F1")),
- 4: ("已过号", QColor("#A9691D"), QColor("#FFF4D8")),
- }.get(status, ("未知", SECONDARY, QColor("#F7F7F7")))
+ 1: ("已预约", QColor(PALETTE["accent"]), QColor(PALETTE["accent_soft"])),
+ 3: ("已完成", QColor(PALETTE["success"]), QColor(PALETTE["success_soft"])),
+ 4: ("已过号", QColor(PALETTE["warning"]), QColor(PALETTE["warning_soft"])),
+ }.get(status, ("未知", SECONDARY, QColor(PALETTE["surface_alt"])))
self._draw_tag(painter, QRect(content.left() + 6, y, 46, 20), label, bg, fg, 12)
doctor = display_text(first_value(appointment, "doctor_name"), "-")
time_text = display_text(first_value(appointment, "time_text", "appointment_time"), "-")
@@ -1106,12 +1109,12 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
painter,
QRect(content.left() + 6, y + 19, max(20, content.width() - 12), 17),
time_text,
- QColor("#A9691D") if status == 4 else SECONDARY,
+ QColor(PALETTE["warning"]) if status == 4 else SECONDARY,
13,
)
y += 42
if position < len(rows) - 1:
- painter.setPen(QPen(QColor("#EDEDEE"), 1, Qt.PenStyle.DashLine))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1, Qt.PenStyle.DashLine))
painter.drawLine(content.left() + 6, y - 2, content.right() - 6, y - 2)
channel = first_value(
record,
@@ -1153,7 +1156,7 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
painter,
QRect(content.left(), content.top() + 38, 72, 18),
"处方已作废",
- QColor("#F7F7F7"),
+ QColor(PALETTE["surface_alt"]),
SECONDARY,
11,
outlined=True,
@@ -1166,11 +1169,11 @@ class DiagnosisItemDelegate(QStyledItemDelegate):
else:
days = _as_int(value)
color = (
- QColor("#287B65")
+ QColor(PALETTE["success"])
if days <= 2
- else QColor("#A9691D")
+ else QColor(PALETTE["warning"])
if days <= 6
- else QColor("#BE4B58")
+ else QColor(PALETTE["danger"])
)
text, bold = str(days), days > 6
self._draw_text(
@@ -1320,6 +1323,8 @@ class _TechBlueDiagnosisDelegate(DiagnosisItemDelegate):
painter, content, "已确认" if _confirmed(record) else "未确认", pixels=13,
color="text" if _confirmed(record) else _BLUE_WARNING.name(),
)
+ elif column == 6:
+ self._followup(painter, content, display_text(index.data(), "—"))
elif column == 8:
prescribed = _as_bool(first_value(record, "has_prescription"))
self._text(painter, content, "已开方" if prescribed else "未开方",
@@ -1348,6 +1353,28 @@ class _TechBlueDiagnosisDelegate(DiagnosisItemDelegate):
medium=column == 2)
painter.restore()
+ @staticmethod
+ def _followup(painter: QPainter, rect: QRect, text: str) -> None:
+ """Break at the date/time boundary, never in the middle of a number.
+
+ Keep the established row metrics. Long time ranges or doctor names
+ elide within their line; the model tooltip retains the complete text.
+ """
+ painter.setFont(_blue_font(13))
+ painter.setPen(QColor(TECH_BLUE["muted"]))
+ metrics = painter.fontMetrics()
+ lines = text.splitlines()
+ if lines and metrics.horizontalAdvance(lines[0]) > rect.width():
+ lines[:1] = lines[0].split(maxsplit=1)
+ line_height = metrics.height()
+ top = rect.top() + max(0, (rect.height() - line_height * len(lines)) // 2)
+ for offset, line in enumerate(lines):
+ painter.drawText(
+ QRect(rect.left(), top + offset * line_height, rect.width(), line_height),
+ int(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter | Qt.TextFlag.TextSingleLine),
+ metrics.elidedText(line, Qt.TextElideMode.ElideRight, rect.width()),
+ )
+
def _appointments(self, painter: QPainter, rect: QRect, record: Any) -> None:
content = rect.adjusted(8, 0, -8, 0)
if not _has_appointment(record):
@@ -1688,7 +1715,9 @@ class DiagnosisTableHost(QFrame):
self.main.horizontalHeader().sectionResized.connect(self._columns_resized)
self._fixed_render_signature: tuple[Any, ...] | None = None
if tech_blue:
- self.setStyleSheet(_TECH_BLUE_TABLE_QSS.replace("BODY_FAMILY", body_family()))
+ self.setStyleSheet(clinical_stylesheet(
+ _TECH_BLUE_TABLE_QSS.replace("BODY_FAMILY", body_family())
+ ))
def set_rows(self, rows: Iterable[Any]) -> None:
previous_id = DiagnosisTableModel.record_id(self.main.current_data())
@@ -1904,6 +1933,7 @@ class DiagnosisTableHost(QFrame):
.replace("#8E8F90", TECH_BLUE["muted"])
+ f'QMenu {{ font-family: "{body_family()}"; font-weight: 400; }}'
)
+ menu.setStyleSheet(clinical_stylesheet(menu.styleSheet()))
for label, action, _semantic in demoted_actions:
_add_menu_action(
menu,
@@ -2630,19 +2660,19 @@ DIAGNOSIS_INDEX_QSS += """
#DiagnosisIndex QFrame#DiagnosisFilterCard,
#DiagnosisIndex QFrame#DiagnosisListCard {
border: 1px solid #EDEDEE;
- border-radius: 13px;
+ border-radius: $ds_radius_panel;
}
#DiagnosisIndex QLineEdit,
#DiagnosisIndex QComboBox,
#DiagnosisIndex QDateEdit,
#DiagnosisIndex QSpinBox,
#DiagnosisIndex QPushButton {
- border-radius: 8px;
+ border-radius: $ds_radius_control;
}
-#DiagnosisIndex QToolButton[diagnosisChip="true"] { border-radius: 8px; }
+#DiagnosisIndex QToolButton[diagnosisChip="true"] { border-radius: $ds_radius_small; }
#DiagnosisIndex QFrame#DiagnosisListToolbar {
- border-top-left-radius: 13px;
- border-top-right-radius: 13px;
+ border-top-left-radius: $ds_radius_panel;
+ border-top-right-radius: $ds_radius_panel;
}
#DiagnosisIndex QToolButton[diagnosisChip="true"]:checked[semantic="primary"],
#DiagnosisIndex QToolButton[diagnosisChip="true"]:checked[semantic="info"],
@@ -2650,7 +2680,27 @@ DIAGNOSIS_INDEX_QSS += """
#DiagnosisIndex QPushButton[variant="success"] {
color: #FFFFFF;
}
+#DiagnosisIndex QLineEdit:focus,
+#DiagnosisIndex QComboBox:focus,
+#DiagnosisIndex QDateEdit:focus,
+#DiagnosisIndex QSpinBox:focus,
+#DiagnosisIndex QPushButton:focus {
+ border-color: $ds_focus;
+}
+#DiagnosisIndex QPushButton[variant="primary"]:pressed {
+ color: $ds_surface;
+ background-color: $ds_accent_pressed;
+ border-color: $ds_accent_pressed;
+}
+#DiagnosisIndex QPushButton:disabled,
+#DiagnosisIndex QPushButton[variant="primary"]:disabled,
+#DiagnosisIndex QPushButton[variant="success"]:disabled {
+ color: $ds_disabled;
+ background-color: $ds_disabled_surface;
+ border-color: $ds_line;
+}
"""
+DIAGNOSIS_INDEX_QSS = clinical_stylesheet(DIAGNOSIS_INDEX_QSS)
__all__ = [
diff --git a/app/src/doctor_workstation/ui/diagnosis_media.py b/app/src/doctor_workstation/ui/diagnosis_media.py
index d072dd38a..ebbe39ddc 100755
--- a/app/src/doctor_workstation/ui/diagnosis_media.py
+++ b/app/src/doctor_workstation/ui/diagnosis_media.py
@@ -32,6 +32,8 @@ from PySide6.QtWidgets import (
QWidget,
)
+from .design_system import clinical_stylesheet
+
try:
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
@@ -223,7 +225,7 @@ class InlineRecordingPlayer(QWidget):
self.setMinimumHeight(158)
self.setMaximumHeight(180)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
- self.setStyleSheet(_INLINE_PLAYER_QSS)
+ self.setStyleSheet(clinical_stylesheet(_INLINE_PLAYER_QSS))
root = QVBoxLayout(self)
root.setContentsMargins(1, 1, 1, 5)
@@ -466,11 +468,11 @@ class RecordingPlaybackCell(QWidget):
separator = QFrame()
separator.setObjectName("DiagnosisRecordingAlternateSeparator")
separator.setFrameShape(QFrame.Shape.HLine)
- separator.setStyleSheet("color:#EDEDEE;")
+ separator.setStyleSheet(clinical_stylesheet("color:$ds_line;"))
layout.addWidget(separator)
label = QLabel("备用地址")
label.setObjectName("DiagnosisRecordingAlternateLabel")
- label.setStyleSheet("color:#606163; font-size:12px;")
+ label.setStyleSheet(clinical_stylesheet("color:$ds_muted; font-size:12px;"))
layout.addWidget(label)
links = QHBoxLayout()
links.setContentsMargins(0, 0, 0, 0)
@@ -490,7 +492,7 @@ class RecordingPlaybackCell(QWidget):
layout.addLayout(links)
self.link_status = QLabel("")
self.link_status.setObjectName("DiagnosisRecordingLinkStatus")
- self.link_status.setStyleSheet("color:#BE4B58; font-size:11px;")
+ self.link_status.setStyleSheet(clinical_stylesheet("color:$ds_danger; font-size:11px;"))
self.link_status.setWordWrap(True)
self.link_status.hide()
layout.addWidget(self.link_status)
@@ -807,7 +809,7 @@ class ImagePreviewDialog(QDialog):
self.setObjectName("DiagnosisImagePreview")
self.setWindowTitle(title)
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
- self.setStyleSheet(_IMAGE_PREVIEW_QSS)
+ self.setStyleSheet(clinical_stylesheet(_IMAGE_PREVIEW_QSS))
self.resize(880, 660)
root = QVBoxLayout(self)
diff --git a/app/src/doctor_workstation/ui/dialogs/ai_consult.py b/app/src/doctor_workstation/ui/dialogs/ai_consult.py
index 9ad112149..3119a475d 100755
--- a/app/src/doctor_workstation/ui/dialogs/ai_consult.py
+++ b/app/src/doctor_workstation/ui/dialogs/ai_consult.py
@@ -62,6 +62,7 @@ from shiboken6 import isValid
from .. import icons
from ..chat_items import parse_chat_item as _parse_chat_item
+from ..design_system import clinical_stylesheet
from ..diagnosis_drawer import CaseGrid, _RemoteImageButton
from ..diagnosis_index_widgets import FlowWidget
from ..diagnosis_media import (
@@ -94,6 +95,9 @@ from ..widgets import (
show_toast,
)
from .ai_consult_charts import GlucoseChartData
+from .ai_consult_drug_names import TCM as DRUG_TCM
+from .ai_consult_drug_names import WESTERN as DRUG_WESTERN
+from .ai_consult_drug_names import summarize_drugs
from .ai_consult_metric_state import (
ABNORMAL_COLOR,
NORMAL_COLOR,
@@ -101,7 +105,6 @@ from .ai_consult_metric_state import (
combined_metric_state,
risk_color,
)
-from .ai_consult_drug_names import TCM as DRUG_TCM, WESTERN as DRUG_WESTERN, summarize_drugs
from .ai_consult_metric_text import MetricTextState, metric_text_context, metric_text_html
from .ai_consult_report_visuals import (
ReportVisual,
@@ -114,10 +117,10 @@ from .prescription_ai import (
diagnosis_ai_task,
)
-AI_CONSULT_QSS = """
+AI_CONSULT_QSS = clinical_stylesheet("""
QDialog#AiConsultDialog {
- color: #1A1C1F;
- background-color: #F7F7F7; font-size: 14px;
+ color: $ds_text;
+ background-color: $ds_canvas; font-size: 14px;
}
QDialog#AiConsultDialog QScrollArea,
QDialog#AiConsultDialog QScrollArea > QWidget,
@@ -149,7 +152,7 @@ QDialog#AiConsultDialog QScrollBar::sub-page:vertical {
background-color: transparent;
}
QDialog#AiConsultDialog QFrame#AiConsultShell {
- background-color: #F7F7F7;
+ background-color: $ds_canvas;
border: 0;
}
QDialog#AiConsultDialog QLabel#AiConsultCrumb {
@@ -171,7 +174,7 @@ QDialog#AiConsultDialog QPushButton#AiConsultBack {
color: #1A1C1F;
background-color: #F0F0F0;
border: 0;
- border-radius: 8px;
+ border-radius: $ds_radius_control;
font-weight: 500;
}
QDialog#AiConsultDialog QPushButton#AiConsultBack:hover { background-color: #EEF1FA; }
@@ -183,7 +186,7 @@ QDialog#AiConsultDialog QFrame#AiConsultHero {
QDialog#AiConsultDialog QLabel#AiConsultAvatar {
color: #FFFFFF;
background-color: #4F63D9;
- border-radius: 22px;
+ border-radius: $ds_radius_control;
font-size: 16px;
font-weight: 600;
}
@@ -201,7 +204,7 @@ QDialog#AiConsultDialog QLabel#AiConsultMeta {
QDialog#AiConsultDialog QLabel#AiConsultChip {
color: #6A6B6D;
background-color: #F7F7F7;
- border-radius: 8px;
+ border-radius: $ds_radius_small;
padding: 4px 8px;
font-size: 13px;
}
@@ -240,7 +243,7 @@ QDialog#AiConsultDialog QPushButton#AiConsultChatFilter {
color: #4F63D9;
background-color: #FFFFFF;
border: 1px solid #E1E5F4;
- border-radius: 8px;
+ border-radius: $ds_radius_control;
font-size: 13px;
}
QDialog#AiConsultDialog QPushButton#AiConsultChatFilter:hover {
@@ -275,7 +278,7 @@ QDialog#AiConsultDialog QLabel#AiConsultRole {
max-width: 30px;
min-height: 30px;
max-height: 30px;
- border-radius: 15px;
+ border-radius: $ds_radius_small;
color: #FFFFFF;
font-size: 13px;
font-weight: 500;
@@ -331,7 +334,7 @@ QDialog#AiConsultDialog QLabel#AiConsultClinicalMeta {
QDialog#AiConsultDialog QLabel#AiConsultClinicalBadge {
color: #4F63D9;
background-color: #EEF1FA;
- border-radius: 7px;
+ border-radius: $ds_radius_small;
padding: 4px 8px;
font-size: 13px;
font-weight: 500;
@@ -346,10 +349,10 @@ QDialog#AiConsultDialog QLabel#AiConsultClinicalSectionTitle {
color: #1A1C1F;
background-color: transparent;
font-size: 14px;
- font-weight: 500;
+ font-weight: 600;
}
QDialog#AiConsultDialog QLabel#AiConsultClinicalSummaryBody {
- color: #1A1C1F;
+ color: $ds_text;
background-color: transparent;
font-size: 14px;
font-weight: 400;
@@ -411,7 +414,7 @@ QDialog#AiConsultDialog QLabel#AiConsultHypothesisTag {
QDialog#AiConsultDialog QLabel#AiConsultClinicalBody,
QDialog#AiConsultDialog QLabel#AiConsultWorkflowBody,
QDialog#AiConsultDialog QLabel#AiConsultRiskBody {
- color: #1A1C1F;
+ color: $ds_text;
background-color: transparent;
font-size: 14px;
font-weight: 400;
@@ -456,23 +459,23 @@ QDialog#AiConsultDialog QLabel#AiConsultRiskTitle {
font-weight: 600;
}
QDialog#AiConsultDialog QLabel#AiConsultRiskBody {
- color: #1A1C1F; font-size: 14px;
+ color: $ds_text; font-size: 14px;
}
QDialog#AiConsultDialog QLabel#AiConsultRiskTitle {
color: #BE4B58;
}
QDialog#AiConsultDialog QLabel#AiConsultRiskBody {
- color: #1A1C1F; font-size: 14px;
+ color: $ds_text; font-size: 14px;
}
/* 结构化报告:正文按阅读节奏排版,不再每句话套一个方框。 */
QDialog#AiConsultDialog QFrame#AiConsultReportIntro {
- background-color: #F7F7F7;
+ background-color: $ds_accent_soft;
border: 1px solid #EDEDEE;
border-left: 3px solid #4F63D9;
- border-radius: 9px;
+ border-radius: $ds_radius_control;
}
QDialog#AiConsultDialog QLabel#AiConsultReportIntroBody {
- color: #1A1C1F;
+ color: $ds_text;
background-color: transparent;
font-size: 14px;
font-weight: 400;
@@ -497,7 +500,7 @@ QDialog#AiConsultDialog QLabel#AiConsultReportSectionTitle {
color: #1A1C1F;
background-color: transparent;
font-size: 15px;
- font-weight: 500;
+ font-weight: 600;
}
QDialog#AiConsultDialog QFrame#AiConsultReportRule {
background-color: #EDEDEE;
@@ -518,7 +521,7 @@ QDialog#AiConsultDialog QLabel#AiConsultReportBullet {
font-weight: 500;
}
QDialog#AiConsultDialog QLabel#AiConsultReportBody {
- color: #1A1C1F;
+ color: $ds_text;
background-color: transparent;
font-size: 14px;
font-weight: 400;
@@ -541,18 +544,18 @@ QDialog#AiConsultDialog QLabel#AiConsultClinicalDisclaimer {
font-weight: 400;
}
QDialog#AiConsultDialog QFrame#AiConsultReportProvenance {
- background-color: #F7F8FC;
- border: 1px solid #E4E8F2;
- border-radius: 9px;
+ background-color: $ds_surface_alt;
+ border: 1px solid $ds_line;
+ border-radius: $ds_radius_control;
}
QDialog#AiConsultDialog QLabel#AiConsultReportProvenanceTitle {
- color: #27336B;
+ color: $ds_heading;
background-color: transparent;
font-size: 12px;
font-weight: 600;
}
QDialog#AiConsultDialog QLabel#AiConsultReportProvenanceLine {
- color: #555B68;
+ color: $ds_muted;
background-color: transparent;
font-size: 12px;
}
@@ -647,7 +650,7 @@ QDialog#AiConsultDialog QLabel#AiConsultSection {
font-weight: 500;
}
QDialog#AiConsultDialog QLabel#AiConsultBody {
- color: #1A1C1F;
+ color: $ds_text;
background-color: transparent;
font-size: 14px;
line-height: 1.6;
@@ -681,7 +684,7 @@ QDialog#AiConsultDialog QLabel#AiConsultInsightPlaceholder {
QDialog#AiConsultDialog QLabel#AiConsultTag[level="high"] {
color: #BE4B58;
background-color: #FFF1F3;
- border-radius: 8px;
+ border-radius: $ds_radius_small;
padding: 2px 8px;
font-size: 13px;
font-weight: 600;
@@ -689,7 +692,7 @@ QDialog#AiConsultDialog QLabel#AiConsultTag[level="high"] {
QDialog#AiConsultDialog QLabel#AiConsultTag[level="medium"] {
color: #A9691D;
background-color: #FFF5E6;
- border-radius: 8px;
+ border-radius: $ds_radius_small;
padding: 2px 8px;
font-size: 13px;
font-weight: 500;
@@ -697,7 +700,7 @@ QDialog#AiConsultDialog QLabel#AiConsultTag[level="medium"] {
QDialog#AiConsultDialog QLabel#AiConsultTag[level="low"] {
color: #287B65;
background-color: #EAF9F3;
- border-radius: 8px;
+ border-radius: $ds_radius_small;
padding: 2px 8px;
font-size: 13px;
font-weight: 500;
@@ -705,7 +708,7 @@ QDialog#AiConsultDialog QLabel#AiConsultTag[level="low"] {
QDialog#AiConsultDialog QLabel#AiConsultTag[level="warn"] {
color: #BE4B58;
background-color: #FFF1F3;
- border-radius: 8px;
+ border-radius: $ds_radius_small;
padding: 2px 8px;
font-size: 13px;
font-weight: 600;
@@ -713,7 +716,7 @@ QDialog#AiConsultDialog QLabel#AiConsultTag[level="warn"] {
QDialog#AiConsultDialog QLabel#AiConsultTag[level="unknown"] {
color: #6A6B6D;
background-color: #F0F0F0;
- border-radius: 8px;
+ border-radius: $ds_radius_small;
padding: 2px 8px;
font-size: 13px;
}
@@ -739,7 +742,7 @@ QDialog#AiConsultDialog QLineEdit#AiConsultInput {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 12px;
+ border-radius: $ds_radius_control;
font-size: 14px;
}
QDialog#AiConsultDialog QLineEdit#AiConsultInput:focus {
@@ -763,7 +766,7 @@ QDialog#AiConsultDialog QPushButton#AiConsultIconButton {
max-height: 36px;
padding: 0;
border: 0;
- border-radius: 18px;
+ border-radius: $ds_radius_control;
background-color: #F7F7F7;
}
QDialog#AiConsultDialog QPushButton#AiConsultIconButton:hover { background-color: #EEF1FA; }
@@ -774,7 +777,7 @@ QDialog#AiConsultDialog QPushButton#AiConsultSend {
max-height: 40px;
padding: 0;
border: 0;
- border-radius: 20px;
+ border-radius: $ds_radius_control;
background-color: #4F63D9;
}
QDialog#AiConsultDialog QPushButton#AiConsultSend:hover { background-color: #4156C4; }
@@ -783,7 +786,7 @@ QDialog#AiConsultDialog QLabel#AiConsultSideTitle {
color: #1A1C1F;
background-color: transparent;
font-size: 16px;
- font-weight: 500;
+ font-weight: 600;
}
QDialog#AiConsultDialog QLabel#AiConsultSideSubtitle {
color: #6A6B6D;
@@ -871,7 +874,7 @@ QDialog#AiConsultDialog QPushButton#AiConsultSideClose {
max-height: 28px;
padding: 0;
border: 0;
- border-radius: 8px;
+ border-radius: $ds_radius_control;
color: #606163;
background-color: transparent;
font-size: 16px;
@@ -917,10 +920,10 @@ QDialog#AiConsultDialog QLabel#AiConsultRecordTitle {
color: #1A1C1F;
background-color: transparent;
font-size: 13px;
- font-weight: 500;
+ font-weight: 600;
}
QDialog#AiConsultDialog QLabel#AiConsultRecordBody {
- color: #1A1C1F;
+ color: $ds_text;
background-color: transparent;
font-size: 14px;
}
@@ -951,7 +954,7 @@ QDialog#AiConsultDialog QPushButton#AiConsultMediaOpen {
color: #4F63D9;
background-color: #EEF1FA;
border: 0;
- border-radius: 8px;
+ border-radius: $ds_radius_control;
font-weight: 500;
}
QDialog#AiConsultDialog QPushButton#AiConsultRecordRetry:hover,
@@ -1000,10 +1003,11 @@ QDialog#AiConsultDialog QLabel#AiConsultDataLabel {
font-size: 13px;
}
QDialog#AiConsultDialog QLabel#AiConsultDataValue {
- color: #1A1C1F;
+ color: $ds_text;
font-size: 13px;
}
-"""
+QDialog#AiConsultDialog QPushButton:focus { border-color: $ds_focus; }
+""")
QUICK_PROMPTS: tuple[tuple[str, str], ...] = (
("总结当前病情", "请根据当前病历总结患者病情、证候与风险。"),
@@ -1053,8 +1057,8 @@ _DOCTOR_DOCUMENT_CSS = (
# 模型回复几乎都是“分节标题 + 两层要点”的长文。早期样式里标题只比正文大 1px、
# 段落与列表项的间距也几乎相同,整段读起来就是一堵字墙。这里把层级、行距和分节
# 留白拉开:标题明显更大更重,顶层小节之间留出整行空白,嵌套要点单独收紧缩进。
-_AI_DOCUMENT_CSS = (
- "body { color:#1A1C1F; font-size:14px; line-height:200%; } "
+_AI_DOCUMENT_CSS = clinical_stylesheet(
+ "body { color:$ds_text; font-size:14px; line-height:200%; } "
"h1,h2 { color:#1A1C1F; font-size:17px; margin:22px 0 10px; line-height:160%; } "
"h3,h4 { color:#1A1C1F; font-size:15px; margin:18px 0 8px; line-height:160%; } "
"p { margin:10px 0; line-height:200%; } "
@@ -2219,15 +2223,12 @@ def _escape_html(value: str) -> str:
)
-class _FlowRow(QWidget):
+class _FlowRow(FlowWidget):
+ """Keep patient metadata readable when the details pane is narrow."""
+
def __init__(self, parent: QWidget | None = None) -> None:
- super().__init__(parent)
- self._layout = QHBoxLayout(self)
- self._layout.setContentsMargins(0, 0, 0, 0)
- self._layout.setSpacing(8)
- self._layout.setAlignment(
- Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter
- )
+ super().__init__(parent, horizontal_spacing=8, vertical_spacing=6)
+ self._layout = self.flow
def add(self, widget: QWidget) -> None:
self._layout.addWidget(widget)
@@ -2810,7 +2811,7 @@ class _DrugSummaryStrip(QFrame):
layout.addLayout(row)
@staticmethod
- def for_text(text: str, parent: QWidget | None = None) -> "_DrugSummaryStrip | None":
+ def for_text(text: str, parent: QWidget | None = None) -> _DrugSummaryStrip | None:
summary = summarize_drugs(text)
return _DrugSummaryStrip(summary, parent) if any(summary.values()) else None
@@ -3454,11 +3455,11 @@ class _ChatBubble(QWidget):
avatar.setAlignment(Qt.AlignmentFlag.AlignCenter)
_style_surface(avatar)
if role == "doctor":
- avatar.setStyleSheet("background-color:#4F63D9; color:#FFFFFF; border-radius:15px;")
+ avatar.setStyleSheet(clinical_stylesheet("background-color:#4F63D9; color:#FFFFFF; border-radius:6px;"))
elif role == "ai":
- avatar.setStyleSheet("background-color:#EEF1FA; color:#4F63D9; border-radius:15px;")
+ avatar.setStyleSheet(clinical_stylesheet("background-color:#EEF1FA; color:#4F63D9; border-radius:6px;"))
else:
- avatar.setStyleSheet("background-color:#6A6B6D; color:#FFFFFF; border-radius:15px;")
+ avatar.setStyleSheet(clinical_stylesheet("background-color:#6A6B6D; color:#FFFFFF; border-radius:6px;"))
bubble = QFrame()
_style_surface(bubble)
if role == "doctor":
@@ -3629,10 +3630,10 @@ class _ChatBubble(QWidget):
toggle.setCursor(Qt.CursorShape.PointingHandCursor)
toggle.setAccessibleName("展开资料提交回执")
toggle.setStyleSheet(
- "QPushButton {color:#65718A;font-size:12px;text-align:left;"
+ clinical_stylesheet("QPushButton {color:$ds_muted;font-size:12px;text-align:left;"
"background:transparent;border:0;padding:4px 0;}"
"QPushButton:hover {color:#4F63D9;}"
- "QPushButton:focus {border-bottom:1px solid #4F63D9;}"
+ "QPushButton:focus {border-bottom:1px solid #4F63D9;}")
)
layout.addWidget(toggle)
label = QLabel(receipt)
@@ -3643,7 +3644,7 @@ class _ChatBubble(QWidget):
Qt.TextInteractionFlag.TextSelectableByMouse
| Qt.TextInteractionFlag.TextSelectableByKeyboard
)
- label.setStyleSheet("color:#65718A;font-size:12px;")
+ label.setStyleSheet(clinical_stylesheet("color:$ds_muted;font-size:12px;"))
label.hide()
layout.addWidget(label)
self._inner.insertWidget(0, receipt)
@@ -3688,7 +3689,7 @@ class _ChatBubble(QWidget):
label.setTextFormat(Qt.TextFormat.PlainText)
label.setWordWrap(True)
label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
- label.setStyleSheet("color:#BE4B58;background:#FEF3F2;border-radius:6px;padding:8px;")
+ label.setStyleSheet(clinical_stylesheet("color:#BE4B58;background:#FEF3F2;border-radius:6px;padding:8px;"))
self._inner.insertWidget(self._inner.indexOf(self.body), label)
self._stream_failure_label = label
label.setText(f"本次回复未完成\n{text}")
@@ -4949,8 +4950,9 @@ class AiConsultDialog(QDialog):
button.setObjectName("AiConsultChipButton")
button.setCursor(Qt.CursorShape.PointingHandCursor)
button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
+ task_key = QUICK_PROMPT_TASKS.get(label, "")
button.clicked.connect(
- lambda _checked=False, text=prompt, task=QUICK_PROMPT_TASKS.get(label, ""):
+ lambda _checked=False, text=prompt, task=task_key:
self._ask(text, replace_active=True, task=task)
)
chips.addWidget(button, 1)
diff --git a/app/src/doctor_workstation/ui/dialogs/app_update.py b/app/src/doctor_workstation/ui/dialogs/app_update.py
index 485032d64..4d2fd6a67 100755
--- a/app/src/doctor_workstation/ui/dialogs/app_update.py
+++ b/app/src/doctor_workstation/ui/dialogs/app_update.py
@@ -43,6 +43,7 @@ from doctor_workstation.services.app_update import (
validate_installer_download_policy,
validate_windows_installer,
)
+from doctor_workstation.ui.design_system import clinical_stylesheet
from doctor_workstation.ui.widgets import friendly_error, show_toast
LOGGER = logging.getLogger(__name__)
@@ -129,11 +130,11 @@ class AppUpdateDialog(QDialog):
self.badge = QLabel("必须更新后才能继续使用" if offer.force else "发现新版本")
self.badge.setObjectName("UpdateBadge")
- self.badge.setStyleSheet(
+ self.badge.setStyleSheet(clinical_stylesheet(
"color:#A9691D;background:#FFF5E6;border-radius:8px;padding:4px 10px;font-weight:600;"
if offer.force
else "color:#4F63D9;background:#EEF1FA;border-radius:8px;padding:4px 10px;font-weight:600;"
- )
+ ))
root.addWidget(self.badge, 0, Qt.AlignmentFlag.AlignLeft)
self.headline = QLabel(title or "医生工作站有新版本")
@@ -146,7 +147,7 @@ class AppUpdateDialog(QDialog):
latest = offer.latest_version or "新版本"
self.version_label = QLabel(f"当前版本 {current} → 最新版本 {latest}")
self.version_label.setObjectName("UpdateVersionLabel")
- self.version_label.setStyleSheet("color:#606163;")
+ self.version_label.setStyleSheet(clinical_stylesheet("color:$ds_muted;"))
root.addWidget(self.version_label)
self.notes = QTextEdit()
@@ -160,7 +161,7 @@ class AppUpdateDialog(QDialog):
self.status_label = QLabel("")
self.status_label.setObjectName("UpdateStatus")
self.status_label.setWordWrap(True)
- self.status_label.setStyleSheet("color:#1A1C1F;")
+ self.status_label.setStyleSheet(clinical_stylesheet("color:$ds_heading;"))
self.status_label.hide()
root.addWidget(self.status_label)
@@ -175,7 +176,7 @@ class AppUpdateDialog(QDialog):
self.progress_text = QLabel("")
self.progress_text.setObjectName("UpdateProgressText")
- self.progress_text.setStyleSheet("color:#606163;font-size:12px;")
+ self.progress_text.setStyleSheet(clinical_stylesheet("color:$ds_muted;font-size:12px;"))
self.progress_text.hide()
root.addWidget(self.progress_text)
@@ -225,7 +226,7 @@ class AppUpdateDialog(QDialog):
def show_download_progress(self, received: int, total: int) -> None:
self.progress.show()
self.progress_text.show()
- self.status_label.setStyleSheet("color:#1A1C1F;")
+ self.status_label.setStyleSheet(clinical_stylesheet("color:$ds_heading;"))
self.status_label.setText("正在下载安装包…")
self.status_label.show()
if total > 0:
@@ -237,7 +238,7 @@ class AppUpdateDialog(QDialog):
self.progress_text.setText(_format_bytes(received))
def show_status(self, message: str, *, determinate: bool = False) -> None:
- self.status_label.setStyleSheet("color:#1A1C1F;")
+ self.status_label.setStyleSheet(clinical_stylesheet("color:$ds_heading;"))
self.status_label.setText(message)
self.status_label.show()
self.progress.show()
@@ -251,7 +252,7 @@ class AppUpdateDialog(QDialog):
def show_error(self, message: str) -> None:
self._busy = False
self.status_label.setText(message)
- self.status_label.setStyleSheet("color:#BE4B58;")
+ self.status_label.setStyleSheet(clinical_stylesheet("color:$ds_danger;"))
self.status_label.show()
self.progress.hide()
self.progress_text.hide()
diff --git a/app/src/doctor_workstation/ui/dialogs/diagnosis.py b/app/src/doctor_workstation/ui/dialogs/diagnosis.py
index d5e3f50b9..580153723 100755
--- a/app/src/doctor_workstation/ui/dialogs/diagnosis.py
+++ b/app/src/doctor_workstation/ui/dialogs/diagnosis.py
@@ -48,6 +48,8 @@ from PySide6.QtWidgets import (
)
from ...core.appointment_modes import appointment_type_description, appointment_type_value
+from ...core.transcript_text import simplified_transcript
+from ..design_system import clinical_stylesheet
from ..diagnosis_drawer import (
DIAGNOSIS_QSS,
CaseGrid,
@@ -97,6 +99,7 @@ from .issued_prescription_ai import can_open_issued_ai, present_issued_prescript
from .local_audio_queue import LocalAudioQueueDialog
from .prescription_ai import can_open_diagnosis_ai_report, present_diagnosis_ai_report
+
class _UploadProgressRelay(QObject):
"""把后台线程中的分片上传进度转回界面线程(信号跨线程自动排队)。"""
@@ -1541,16 +1544,16 @@ class DiagnosisDialog(QDialog):
"""上传本地回放时的进度条:按分片实时更新,医生能看到上传在进行、进行到哪。"""
frame = QFrame()
frame.setObjectName("DiagnosisVideoUploadProgress")
- frame.setStyleSheet(
+ frame.setStyleSheet(clinical_stylesheet(
"QFrame#DiagnosisVideoUploadProgress { background-color: #EEF1FA;"
- " border: 1px solid #C9D1F3; border-radius: 8px; }"
- "QFrame#DiagnosisVideoUploadProgress QLabel { color: #3347B8; background: transparent;"
+ " border: 1px solid $ds_line_strong; border-radius: $ds_radius_control; }"
+ "QFrame#DiagnosisVideoUploadProgress QLabel { color: $ds_accent_hover; background: transparent;"
" font-size: 13px; font-weight: 500; }"
"QFrame#DiagnosisVideoUploadProgress QProgressBar { background-color: #FFFFFF;"
" border: 0; border-radius: 4px; min-height: 8px; max-height: 8px; }"
"QFrame#DiagnosisVideoUploadProgress QProgressBar::chunk { background-color: #4F63D9;"
" border-radius: 4px; }"
- )
+ ))
row = QVBoxLayout(frame)
row.setContentsMargins(12, 8, 12, 10)
row.setSpacing(6)
@@ -4031,7 +4034,8 @@ class DiagnosisDialog(QDialog):
content = QPlainTextEdit(dialog)
content.setObjectName("DiagnosisCallTranscriptText")
content.setReadOnly(True)
- content.setPlainText(transcript)
+ # Historical records keep their stored source; only the view is converted.
+ content.setPlainText(simplified_transcript(transcript))
layout.addWidget(content, 1)
close_button = QPushButton("关闭")
close_button.setProperty("variant", "primary")
diff --git a/app/src/doctor_workstation/ui/dialogs/issued_prescription_ai_theme.py b/app/src/doctor_workstation/ui/dialogs/issued_prescription_ai_theme.py
index f003977b1..bbdb46f1e 100755
--- a/app/src/doctor_workstation/ui/dialogs/issued_prescription_ai_theme.py
+++ b/app/src/doctor_workstation/ui/dialogs/issued_prescription_ai_theme.py
@@ -21,6 +21,8 @@ from typing import Any
from PySide6.QtGui import QFont
+from ..design_system import PALETTE
+
DARK: dict[str, str] = {
# ground and cards
"canvas": "#080D18",
@@ -62,23 +64,23 @@ DARK: dict[str, str] = {
}
LIGHT: dict[str, str] = {
- "canvas": "#F1F5FC",
- "canvas_soft": "#E7EEFA",
- "surface": "#FFFFFF",
- "surface_2": "#F5F8FE",
- "raised": "#E8EFFA",
- "line": "#D5E1F2",
- "line_soft": "#E3EBF8",
- "heading": "#0A182E",
- "text": "#2A3C56",
- "muted": "#54697F",
- "faint": "#7A8DA3",
- "selected_text": "#0A182E",
- "accent": "#1A5FD0",
- "accent_text": "#124DAE",
- "accent_pressed": "#0E3F90",
- "selection": "#E8EFFA",
- "selection_line": "#AEC7EE",
+ "canvas": PALETTE["canvas"],
+ "canvas_soft": PALETTE["surface_alt"],
+ "surface": PALETTE["surface"],
+ "surface_2": PALETTE["surface_alt"],
+ "raised": PALETTE["sidebar"],
+ "line": PALETTE["line_strong"],
+ "line_soft": PALETTE["line"],
+ "heading": PALETTE["heading"],
+ "text": PALETTE["text"],
+ "muted": PALETTE["muted"],
+ "faint": PALETTE["disabled"],
+ "selected_text": PALETTE["heading"],
+ "accent": PALETTE["accent"],
+ "accent_text": PALETTE["accent_hover"],
+ "accent_pressed": PALETTE["accent_pressed"],
+ "selection": PALETTE["accent_soft"],
+ "selection_line": PALETTE["focus"],
"qwen": "#0C89AC",
"qwen_text": "#086C88",
"qwen_dim": "#E2F5FA",
diff --git a/app/src/doctor_workstation/ui/dialogs/local_audio_queue.py b/app/src/doctor_workstation/ui/dialogs/local_audio_queue.py
index 4af364d26..0f21c06ee 100755
--- a/app/src/doctor_workstation/ui/dialogs/local_audio_queue.py
+++ b/app/src/doctor_workstation/ui/dialogs/local_audio_queue.py
@@ -29,6 +29,7 @@ from ...services.local_audio_queue import (
LocalAudioUploadManager,
get_local_audio_upload_manager,
)
+from ..design_system import clinical_stylesheet
from ..widgets import run_async
_STATUS_LABELS = {
@@ -174,7 +175,7 @@ class LocalAudioQueueDialog(QDialog):
self.setModal(True)
self.setMinimumSize(760, 480)
self.resize(1160, 620)
- self.setStyleSheet(_LOCAL_AUDIO_QSS)
+ self.setStyleSheet(clinical_stylesheet(_LOCAL_AUDIO_QSS))
self._build_ui()
self.poll_timer = QTimer(self)
diff --git a/app/src/doctor_workstation/ui/dialogs/prescription.py b/app/src/doctor_workstation/ui/dialogs/prescription.py
index 77b5fdad2..bd69d795a 100755
--- a/app/src/doctor_workstation/ui/dialogs/prescription.py
+++ b/app/src/doctor_workstation/ui/dialogs/prescription.py
@@ -28,8 +28,8 @@ from PySide6.QtCore import (
QDate,
QEvent,
QIODevice,
- QModelIndex,
QMarginsF,
+ QModelIndex,
QObject,
QPoint,
QRectF,
@@ -98,6 +98,7 @@ from PySide6.QtWidgets import (
)
from .. import icons
+from ..design_system import clinical_stylesheet
from ..diagnosis_terms import shared_terms
from ..infinite_list import InfiniteList
from ..theme import main_window_target_rect
@@ -116,9 +117,9 @@ from ..widgets import (
)
from .diagnosis import DiagnosisDialog as _StructuredDiagnosisDialog
-PRESCRIPTION_DRAWER_QSS = r"""
+PRESCRIPTION_DRAWER_QSS = clinical_stylesheet(r"""
QFrame#PrescriptionDrawerSurface {
- color: #1A1C1F;
+ color: $ds_text;
background-color: #FFFFFF;
border-left: 1px solid #EDEDEE;
font-size: 14px;
@@ -145,7 +146,7 @@ QLabel#PrescriptionLockTag {
color: #BE4B58;
background-color: #FEF0F0;
border: 1px solid #FDE2E2;
- border-radius: 4px;
+ border-radius: $ds_radius_small;
padding: 2px 8px;
font-size: 13px;
}
@@ -175,7 +176,7 @@ QLabel#PrescriptionDrawerMode {
color: #4F63D9;
background-color: #EEF1FA;
border: 1px solid #EDEDEE;
- border-radius: 5px;
+ border-radius: $ds_radius_small;
padding: 4px 9px;
font-size: 13px;
font-weight: 500;
@@ -189,7 +190,7 @@ QPushButton#PrescriptionDrawerClose {
color: #606163;
background-color: transparent;
border: 0;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
font-size: 22px;
font-weight: 400;
}
@@ -208,12 +209,12 @@ QWidget#PrescriptionDrawerContent {
QFrame#PrescriptionFormSection {
background-color: #F7F7F7;
border: 1px solid #EDEDEE;
- border-radius: 10px;
+ border-radius: $ds_radius_panel;
}
QLabel#PrescriptionSectionTitle {
color: #1A1C1F;
font-size: 15px;
- font-weight: 500;
+ font-weight: 600;
}
QLabel#PrescriptionSectionHint {
color: #6A6B6D;
@@ -242,7 +243,7 @@ QLabel#PrescriptionUsageAux {
QFrame#PrescriptionRpToolbar {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 10px;
+ border-radius: $ds_radius_panel;
}
QFrame#PrescriptionRpMarker {
background-color: #4F63D9;
@@ -262,12 +263,12 @@ QLabel#PrescriptionRpLock {
color: #BE4B58;
background-color: #FEF3F2;
border: 1px solid #FECDCA;
- border-radius: 5px;
+ border-radius: $ds_radius_small;
padding: 5px 8px;
font-size: 13px;
}
QLabel#PrescriptionFormulaTag {
- border-radius: 4px;
+ border-radius: $ds_radius_small;
padding: 3px 8px;
font-size: 13px;
font-weight: 500;
@@ -328,7 +329,7 @@ QFrame#PrescriptionDrawerSurface QDoubleSpinBox {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
padding: 0 11px;
selection-background-color: #C9D1F3;
selection-color: #1A1C1F; font-size: 14px;
@@ -338,7 +339,7 @@ QFrame#PrescriptionDrawerSurface QComboBox {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
padding-left: 11px;
padding-right: 28px;
selection-background-color: #C9D1F3;
@@ -379,7 +380,7 @@ QFrame#PrescriptionDatePicker {
min-height: 32px;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
}
QFrame#PrescriptionDatePicker:hover {
border-color: #8B9AD9;
@@ -446,7 +447,7 @@ QFrame#PrescriptionDrawerSurface QPushButton {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
font-weight: 500;
}
QFrame#PrescriptionDrawerSurface QPushButton:hover {
@@ -468,7 +469,7 @@ QFrame#PrescriptionDrawerSurface QPushButton#PrescriptionDrawerClose {
color: #606163;
background-color: transparent;
border: 0;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
font-size: 22px;
font-weight: 400;
}
@@ -496,23 +497,23 @@ QFrame#PrescriptionDrawerSurface QPushButton[variant="primary"]:hover {
border-color: #4156C4;
}
QFrame#PrescriptionDrawerSurface QPushButton[variant="success"] {
- color: #FFFFFF;
- background-color: #287B65;
- border-color: #287B65;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
+ border-color: $ds_line;
}
QFrame#PrescriptionDrawerSurface QPushButton[variant="success"]:hover {
- background-color: #287B65;
- border-color: #287B65;
+ background-color: $ds_accent_soft;
+ border-color: $ds_focus;
}
QFrame#PrescriptionDrawerSurface QPushButton[variant="warning"] {
- color: #A9691D;
+ color: $ds_accent;
background-color: #FFFFFF;
- border-color: #A9691D;
+ border-color: $ds_accent;
}
QFrame#PrescriptionDrawerSurface QPushButton[variant="warning"]:hover {
- color: #FFFFFF;
- background-color: #A9691D;
- border-color: #A9691D;
+ color: $ds_accent_hover;
+ background-color: $ds_accent_soft;
+ border-color: $ds_focus;
}
QFrame#PrescriptionDrawerSurface QPushButton[variant="secondary"] {
color: #4F63D9;
@@ -615,7 +616,8 @@ QFrame#PrescriptionDrawerSurface QFrame#MessageBanner[kind="danger"] {
QFrame#PrescriptionDrawerSurface QFrame#MessageBanner[kind="danger"] QLabel {
color: #BE4B58;
}
-"""
+QFrame#PrescriptionDrawerSurface QPushButton:focus { border: 1px solid $ds_focus; }
+""")
_CHEVRON_PATH: Path | None = None
@@ -647,7 +649,7 @@ def _prescription_drawer_qss() -> str:
def _prescription_calendar_qss() -> str:
- return """
+ return clinical_stylesheet("""
QCalendarWidget {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
@@ -672,13 +674,13 @@ QCalendarWidget QAbstractItemView:enabled {
selection-color: #1A1C1F;
outline: 0;
}
-"""
+""")
-PRESCRIPTION_DIALOG_QSS = """
+PRESCRIPTION_DIALOG_QSS = clinical_stylesheet("""
QDialog#PrescriptionDialogSurface {
color: #1A1C1F;
- background-color: #F7F7F7;
+ background-color: $ds_canvas;
font-size: 14px;
}
QDialog#PrescriptionDialogSurface QLabel {
@@ -740,7 +742,7 @@ QDialog#PrescriptionDialogSurface QTextBrowser {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
selection-background-color: #EEF1FA;
selection-color: #1A1C1F; font-size: 14px;
}
@@ -768,7 +770,7 @@ QDialog#PrescriptionDialogSurface QPushButton {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
font-weight: 500;
}
QDialog#PrescriptionDialogSurface QPushButton:hover {
@@ -798,7 +800,7 @@ QDialog#PrescriptionDialogSurface QPushButton:disabled {
QDialog#PrescriptionDialogSurface QTabWidget::pane {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 9px;
+ border-radius: $ds_radius_panel;
top: -1px;
}
QDialog#PrescriptionDialogSurface QTabBar::tab {
@@ -852,7 +854,8 @@ QDialog#PrescriptionDialogSurface QScrollBar::add-line:vertical,
QDialog#PrescriptionDialogSurface QScrollBar::sub-line:vertical {
height: 0;
}
-"""
+QDialog#PrescriptionDialogSurface QPushButton:focus { border: 1px solid $ds_focus; }
+""")
def _apply_prescription_dialog_style(dialog: QDialog) -> None:
@@ -1531,9 +1534,9 @@ class RemoteMedicineComboBox(QComboBox):
popup = self._completer.popup()
popup.setItemDelegate(_MedicineSuggestionDelegate(popup))
popup.setStyleSheet(
- "QListView { background-color: #FFFFFF; border: 1px solid #E4E7ED; border-radius: 6px;"
+ clinical_stylesheet("QListView { background-color: #FFFFFF; border: 1px solid #E4E7ED; border-radius: 6px;"
" padding: 4px 0; font-size: 14px; outline: 0; }"
- "QListView::item:selected, QListView::item:hover { background-color: #F5F7FA; }"
+ "QListView::item:selected, QListView::item:hover { background-color: #F5F7FA; }")
)
self.lineEdit().setCompleter(self._completer)
self.lineEdit().installEventFilter(self)
@@ -5292,8 +5295,8 @@ class PrescriptionDetailDialog(QDialog):
self.preview.setObjectName("PrescriptionPaperPreview")
self.preview.setOpenExternalLinks(False)
self.preview.setStyleSheet(
- "QTextBrowser#PrescriptionPaperPreview {"
- "background-color:#F7F7F7; border:1px solid #E4E4E5; padding:0;}"
+ clinical_stylesheet("QTextBrowser#PrescriptionPaperPreview {"
+ "background-color:#F7F7F7; border:1px solid #E4E4E5; padding:0;}")
)
self.preview.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.preview.setDocument(self.document)
@@ -5301,8 +5304,8 @@ class PrescriptionDetailDialog(QDialog):
self.user_preview.setObjectName("PrescriptionUserPaperPreview")
self.user_preview.setOpenExternalLinks(False)
self.user_preview.setStyleSheet(
- "QTextBrowser#PrescriptionUserPaperPreview {"
- "background-color:#F7F7F7; border:1px solid #E4E4E5; padding:0;}"
+ clinical_stylesheet("QTextBrowser#PrescriptionUserPaperPreview {"
+ "background-color:#F7F7F7; border:1px solid #E4E4E5; padding:0;}")
)
self.user_preview.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.user_preview.setDocument(self.user_document)
@@ -5320,8 +5323,8 @@ class PrescriptionDetailDialog(QDialog):
self.case_preview.setObjectName("CaseRecordPaperPreview")
self.case_preview.setOpenExternalLinks(False)
self.case_preview.setStyleSheet(
- "QTextBrowser#CaseRecordPaperPreview {"
- "background-color:#F7F7F7; border:1px solid #E4E4E5; padding:0;}"
+ clinical_stylesheet("QTextBrowser#CaseRecordPaperPreview {"
+ "background-color:#F7F7F7; border:1px solid #E4E4E5; padding:0;}")
)
self.case_preview.setDocument(self.case_document)
case_index = self.tabs.addTab(self.case_preview, "详细病历")
diff --git a/app/src/doctor_workstation/ui/dialogs/prescription_ai.py b/app/src/doctor_workstation/ui/dialogs/prescription_ai.py
index 16201b000..db3d98638 100755
--- a/app/src/doctor_workstation/ui/dialogs/prescription_ai.py
+++ b/app/src/doctor_workstation/ui/dialogs/prescription_ai.py
@@ -26,6 +26,7 @@ from PySide6.QtWidgets import (
QWidget,
)
+from ..design_system import clinical_stylesheet
from ..report_provenance import report_provenance_lines
from ..theme import apply_reading_rhythm
from ..widgets import (
@@ -169,10 +170,10 @@ def diagnosis_ai_task(prompt: str) -> str:
return "custom"
-PRESCRIPTION_AI_QSS = """
+PRESCRIPTION_AI_QSS = clinical_stylesheet("""
QDialog#PrescriptionAiDialog {
- color: #1A1C1F;
- background-color: #F7F7F7;
+ color: $ds_text;
+ background-color: $ds_canvas;
font-size: 13px;
}
@@ -182,7 +183,7 @@ QDialog#PrescriptionAiDialog QPushButton {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 7px;
+ border-radius: $ds_radius_control;
font-weight: 500;
}
QDialog#PrescriptionAiDialog QPushButton:hover {
@@ -224,7 +225,7 @@ QLabel#PrescriptionAiSubtitle {
QFrame#PrescriptionAiSnapshot {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 10px;
+ border-radius: $ds_radius_panel;
}
QLabel#PrescriptionAiSnapshotLabel {
color: #1A1C1F;
@@ -232,20 +233,20 @@ QLabel#PrescriptionAiSnapshotLabel {
font-weight: 600;
}
QLabel#PrescriptionAiSnapshotBody {
- color: #1A1C1F;
- font-size: 13px;
+ color: $ds_text;
+ font-size: 14px;
line-height: 1.65;
}
QFrame#PrescriptionAiSummary {
- background-color: #F0F0F0;
+ background-color: $ds_accent_soft;
border: 0;
border-left: 3px solid #4F63D9;
- border-radius: 0 9px 9px 0;
+ border-radius: $ds_radius_control;
}
QFrame#PrescriptionAiCaution {
background-color: #FFF9EE;
border: 1px solid #F3DFB5;
- border-radius: 9px;
+ border-radius: $ds_radius_control;
}
QLabel#PrescriptionAiSectionTitle {
color: #1A1C1F;
@@ -253,17 +254,17 @@ QLabel#PrescriptionAiSectionTitle {
font-weight: 600;
}
QLabel#PrescriptionAiBody {
- color: #1A1C1F;
- font-size: 13px;
+ color: $ds_text;
+ font-size: 14px;
line-height: 1.75;
}
QTextBrowser#PrescriptionAiAnswer {
- color: #1A1C1F;
+ color: $ds_text;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 10px;
- padding: 12px 14px;
- selection-color: #1A1C1F;
+ border-radius: $ds_radius_panel;
+ padding: 16px 18px;
+ selection-color: $ds_text;
selection-background-color: #EEF1FA;
}
QLabel#PrescriptionAiMuted {
@@ -279,7 +280,7 @@ QFrame#PrescriptionAiMeta {
QDialog#PrescriptionAiDialog QTabWidget::pane {
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 10px;
+ border-radius: $ds_radius_panel;
top: -1px;
}
QDialog#PrescriptionAiDialog QTabBar::tab {
@@ -309,7 +310,7 @@ QDialog#PrescriptionAiDialog QTextEdit {
color: #1A1C1F;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 8px;
+ border-radius: $ds_radius_control;
padding: 10px;
selection-background-color: #EEF1FA;
}
@@ -330,10 +331,12 @@ QDialog#PrescriptionAiDialog QScrollBar::add-line:vertical,
QDialog#PrescriptionAiDialog QScrollBar::sub-line:vertical {
height: 0;
}
-"""
+QDialog#PrescriptionAiDialog QPushButton:focus { border: 1px solid $ds_focus; }
+QDialog#PrescriptionAiDialog QPushButton:disabled { color: $ds_disabled; background-color: $ds_disabled_surface; border-color: $ds_line; }
+""")
-_AI_ANSWER_DOCUMENT_CSS = (
- "body { color:#1A1C1F; font-size:14px; line-height:1.72; } "
+_AI_ANSWER_DOCUMENT_CSS = clinical_stylesheet(
+ "body { color:$ds_text; font-size:14px; line-height:1.72; } "
"h1 { color:#1A1C1F; font-size:20px; margin:14px 0 8px; line-height:1.4; } "
"h2 { color:#1A1C1F; font-size:17px; margin:14px 0 7px; line-height:1.42; } "
"h3,h4 { color:#1A1C1F; font-size:15px; margin:12px 0 6px; line-height:1.45; } "
@@ -801,7 +804,7 @@ class PrescriptionAiReportDialog(QDialog):
self.report_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.host = QWidget()
self.host_layout = QVBoxLayout(self.host)
- self.host_layout.setContentsMargins(4, 4, 12, 8)
+ self.host_layout.setContentsMargins(18, 14, 20, 16)
self.host_layout.setSpacing(12)
self.report_scroll.setWidget(self.host)
self.tabs.widget(0).layout().addWidget(self.report_scroll)
@@ -1455,7 +1458,7 @@ class PrescriptionAiReportDialog(QDialog):
label.setTextFormat(Qt.TextFormat.PlainText)
label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
label.setWordWrap(True)
- label.setStyleSheet("color: #555B68; font-size: 12px; padding: 10px 14px; background: #F7F8FC; border: 1px solid #E4E8F2; border-radius: 8px;")
+ label.setStyleSheet(clinical_stylesheet("color: $ds_muted; font-size: 12px; padding: 10px 14px; background: $ds_surface_alt; border: 1px solid $ds_line; border-radius: $ds_radius_control;"))
self.host_layout.addWidget(label)
def reject(self) -> None:
diff --git a/app/src/doctor_workstation/ui/filter_disclosure.py b/app/src/doctor_workstation/ui/filter_disclosure.py
index 0346c76ae..753fc4486 100755
--- a/app/src/doctor_workstation/ui/filter_disclosure.py
+++ b/app/src/doctor_workstation/ui/filter_disclosure.py
@@ -8,6 +8,7 @@ from PySide6.QtCore import QObject, QSize, Qt, Signal
from PySide6.QtWidgets import QApplication, QPushButton, QWidget
from . import icons
+from .design_system import PALETTE, clinical_stylesheet
class FilterDisclosure(QObject):
@@ -35,17 +36,17 @@ class FilterDisclosure(QObject):
self.button.setCursor(Qt.CursorShape.PointingHandCursor)
self.button.setFixedHeight(32)
self.button.setIconSize(QSize(14, 14))
- self.button.setStyleSheet("""
+ self.button.setStyleSheet(clinical_stylesheet("""
QPushButton#FilterDisclosureButton {
color: #1769E8; background: #FFFFFF; border: 1px solid #DBE5F2;
- border-radius: 6px; padding: 0 11px; min-height: 30px; max-height: 30px;
+ border-radius: $ds_radius_control; padding: 0 11px; min-height: 30px; max-height: 30px;
min-width: 92px; font-size: 13px; font-weight: 400;
}
- QPushButton#FilterDisclosureButton:hover { background: #F3F7FD; border-color: #ADC8F2; }
- QPushButton#FilterDisclosureButton:checked { background: #EAF2FF; border-color: #ADC8F2; }
- QPushButton#FilterDisclosureButton:focus { border-color: #1769E8; }
- QPushButton#FilterDisclosureButton:disabled { color: #8B97A8; border-color: #E3E9F1; }
- """)
+ QPushButton#FilterDisclosureButton:hover { background: $ds_canvas; border-color: $ds_line_strong; }
+ QPushButton#FilterDisclosureButton:checked { background: $ds_accent_soft; border-color: $ds_line_strong; }
+ QPushButton#FilterDisclosureButton:focus { border-color: $ds_focus; }
+ QPushButton#FilterDisclosureButton:disabled { color: $ds_disabled; border-color: $ds_line; }
+ """))
self.button.toggled.connect(self.set_expanded)
self._apply()
@@ -78,4 +79,4 @@ class FilterDisclosure(QObject):
self.button.setAccessibleName(label)
self.button.setAccessibleDescription("显示或收起检索条件和统计信息;收起保留当前筛选条件")
self.button.setToolTip("收起保留当前筛选条件" if self._expanded else "展开检索条件和统计信息,当前筛选条件保持不变")
- self.button.setIcon(icons.icon("chevron_up" if self._expanded else "chevron_down", "#1769E8", 14))
+ self.button.setIcon(icons.icon("chevron_up" if self._expanded else "chevron_down", PALETTE["accent"], 14))
diff --git a/app/src/doctor_workstation/ui/infinite_list.py b/app/src/doctor_workstation/ui/infinite_list.py
index 2b6082e36..19f9297e2 100755
--- a/app/src/doctor_workstation/ui/infinite_list.py
+++ b/app/src/doctor_workstation/ui/infinite_list.py
@@ -16,6 +16,7 @@ from PySide6.QtWidgets import (
QWidget,
)
+from .design_system import clinical_stylesheet
from .widgets import first_value, get_value, page_items, page_total, run_async
@@ -54,16 +55,16 @@ class InfiniteList(QWidget):
layout = QHBoxLayout(self)
layout.setContentsMargins(12, 0, 12, 0)
self.summary_label = QLabel("", self)
- self.summary_label.setStyleSheet(
+ self.summary_label.setStyleSheet(clinical_stylesheet(
"color: #5D6B80; font-size: 12px; background: transparent;"
- )
+ ))
layout.addWidget(self.summary_label)
layout.addStretch(1)
self.retry_button = QPushButton("加载失败,点击重试", self)
self.retry_button.setFlat(True)
- self.retry_button.setStyleSheet(
+ self.retry_button.setStyleSheet(clinical_stylesheet(
"color: #1769E8; font-size: 12px; padding: 0 4px; border: none; background: transparent; min-height: 20px; max-height: 20px; min-width: 0;"
- )
+ ))
self.retry_button.hide()
self.retry_button.clicked.connect(self.retry)
layout.addWidget(self.retry_button)
diff --git a/app/src/doctor_workstation/ui/login.py b/app/src/doctor_workstation/ui/login.py
index 24aa407cc..691cc9000 100755
--- a/app/src/doctor_workstation/ui/login.py
+++ b/app/src/doctor_workstation/ui/login.py
@@ -5,26 +5,21 @@ from __future__ import annotations
from contextlib import suppress
from typing import Any
-from PySide6.QtCore import QPoint, QPointF, QRectF, QSettings, Qt, QTimer, Signal
+from PySide6.QtCore import QEvent, QPoint, QPointF, QRectF, QSettings, Qt, QTimer, Signal
from PySide6.QtGui import (
- QBrush,
QColor,
QFont,
QIcon,
- QLinearGradient,
QPainter,
QPainterPath,
QPen,
QPixmap,
- QPolygonF,
- QRadialGradient,
QResizeEvent,
)
from PySide6.QtWidgets import (
QApplication,
QCheckBox,
QFrame,
- QGraphicsDropShadowEffect,
QHBoxLayout,
QLabel,
QLayout,
@@ -45,6 +40,7 @@ from doctor_workstation import __version__
from doctor_workstation.resources import app_icon_path, brand_lockup_path
from . import icons
+from .design_system import PALETTE, clinical_stylesheet
from .widgets import BusyOverlay, MessageBanner, friendly_error, invoke, run_async
@@ -127,7 +123,7 @@ def _round_pen(color: QColor | str, width: float) -> QPen:
class _BrandPanel(QWidget):
- """The quiet medical illustration and copy from the supplied login artwork."""
+ """A flat, readable introduction to the clinician's daily workflow."""
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
@@ -137,228 +133,76 @@ class _BrandPanel(QWidget):
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
self._brand_lockup = QPixmap(str(brand_lockup_path()))
- @staticmethod
- def _draw_cube(painter: QPainter, center: QPointF, size: float, kind: str) -> None:
- x, y = center.x(), center.y()
- top = QPolygonF(
- [
- QPointF(x, y - size * 0.58),
- QPointF(x + size * 0.48, y - size * 0.34),
- QPointF(x, y - size * 0.10),
- QPointF(x - size * 0.48, y - size * 0.34),
- ]
- )
- left = QPolygonF(
- [
- QPointF(x - size * 0.48, y - size * 0.34),
- QPointF(x, y - size * 0.10),
- QPointF(x, y + size * 0.48),
- QPointF(x - size * 0.48, y + size * 0.24),
- ]
- )
- right = QPolygonF(
- [
- QPointF(x, y - size * 0.10),
- QPointF(x + size * 0.48, y - size * 0.34),
- QPointF(x + size * 0.48, y + size * 0.24),
- QPointF(x, y + size * 0.48),
- ]
- )
- painter.setPen(QPen(QColor(185, 196, 247, 205), 1.2))
- painter.setBrush(QColor(235, 239, 255, 218))
- painter.drawPolygon(top)
- painter.setBrush(QColor(210, 218, 255, 205))
- painter.drawPolygon(left)
- painter.setBrush(QColor(224, 230, 255, 220))
- painter.drawPolygon(right)
- painter.setPen(_round_pen(QColor(137, 154, 248, 135), 2.2))
- if kind == "plus":
- painter.drawLine(
- QPointF(x - size * 0.12, y + size * 0.05),
- QPointF(x + size * 0.15, y - size * 0.02),
- )
- painter.drawLine(
- QPointF(x + size * 0.02, y - size * 0.13),
- QPointF(x + size * 0.02, y + size * 0.17),
- )
- else:
- shield = QPainterPath(QPointF(x, y - size * 0.16))
- shield.lineTo(x + size * 0.15, y - size * 0.08)
- shield.lineTo(x + size * 0.10, y + size * 0.17)
- shield.lineTo(x, y + size * 0.26)
- shield.lineTo(x - size * 0.10, y + size * 0.17)
- shield.lineTo(x - size * 0.15, y - size * 0.08)
- shield.closeSubpath()
- painter.drawPath(shield)
-
- def _draw_illustration(
- self, painter: QPainter, width: float, height: float
- ) -> None:
- ox = max(250.0, width - 500.0)
- oy = max(365.0, height - 500.0)
-
- glow = QRadialGradient(QPointF(width - 170, oy + 230), 280)
- glow.setColorAt(0.0, QColor(102, 120, 255, 62))
- glow.setColorAt(1.0, QColor(102, 120, 255, 0))
- painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(glow)
- painter.drawEllipse(QPointF(width - 170, oy + 230), 280, 280)
-
- painter.setPen(QPen(QColor(166, 180, 241, 78), 1))
- for offset in (0, 72, 144):
- painter.drawLine(
- QPointF(ox - 80, oy + 280 + offset),
- QPointF(width + 20, oy + 170 + offset),
- )
- painter.drawLine(QPointF(ox + 10, oy + 400), QPointF(ox + 10, oy + 80))
- painter.drawLine(QPointF(ox + 170, oy + 430), QPointF(ox + 170, oy + 35))
-
- base = QRectF(ox + 80, oy + 365, 430, 88)
- base_gradient = QLinearGradient(base.topLeft(), base.bottomRight())
- base_gradient.setColorAt(0.0, QColor(246, 248, 255, 228))
- base_gradient.setColorAt(1.0, QColor(186, 199, 255, 184))
- painter.setBrush(base_gradient)
- painter.setPen(QPen(QColor(166, 181, 248, 158), 1))
- painter.drawEllipse(base)
- painter.setBrush(QColor(249, 250, 255, 225))
- painter.drawEllipse(QRectF(base.x() + 42, base.y() - 12, base.width() - 84, 70))
-
- painter.save()
- painter.translate(35, 40)
- screen = QPolygonF(
- [
- QPointF(ox + 130, oy + 60),
- QPointF(ox + 435, oy + 100),
- QPointF(ox + 435, oy + 365),
- QPointF(ox + 130, oy + 310),
- ]
- )
- painter.setBrush(QColor(218, 225, 255, 205))
- painter.setPen(QPen(QColor(145, 163, 242, 170), 1.3))
- painter.drawPolygon(screen)
- inner = QPolygonF(
- [
- QPointF(ox + 141, oy + 80),
- QPointF(ox + 425, oy + 117),
- QPointF(ox + 425, oy + 345),
- QPointF(ox + 141, oy + 295),
- ]
- )
- painter.setBrush(QColor(255, 255, 255, 225))
- painter.drawPolygon(inner)
-
- painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor(174, 189, 252, 180))
- painter.drawRoundedRect(QRectF(ox + 148, oy + 89, 270, 15), 7, 7)
- for dot_x in (156, 173, 190):
- painter.setBrush(QColor(255, 255, 255, 200))
- painter.drawEllipse(QPointF(ox + dot_x, oy + 96.5), 3.5, 3.5)
-
- cards = (
- QRectF(ox + 150, oy + 135, 82, 80),
- QRectF(ox + 241, oy + 142, 72, 73),
- QRectF(ox + 322, oy + 151, 95, 72),
- QRectF(ox + 151, oy + 232, 264, 50),
- QRectF(ox + 151, oy + 291, 264, 42),
- )
- painter.setPen(QPen(QColor(188, 199, 246, 160), 1))
- painter.setBrush(QColor(249, 250, 255, 228))
- for card in cards:
- painter.drawRoundedRect(card, 7, 7)
- painter.setPen(_round_pen(QColor(117, 137, 236, 165), 4))
- for idx, bar_height in enumerate((20, 36, 51)):
- x = ox + 164 + idx * 17
- painter.drawLine(QPointF(x, oy + 200), QPointF(x, oy + 200 - bar_height))
- painter.setBrush(QColor(112, 132, 235, 160))
- painter.setPen(Qt.PenStyle.NoPen)
- painter.drawEllipse(QPointF(ox + 277, oy + 167), 10, 10)
- painter.drawRoundedRect(QRectF(ox + 259, oy + 180, 36, 20), 10, 10)
- painter.setPen(_round_pen(QColor(137, 153, 235, 150), 5))
- for y, length in ((170, 54), (186, 42), (249, 89), (307, 72)):
- painter.drawLine(
- QPointF(ox + 340, oy + y), QPointF(ox + 340 + length, oy + y + 5)
- )
-
- self._draw_cube(painter, QPointF(ox + 352, oy - 25), 76, "plus")
- self._draw_cube(painter, QPointF(ox - 8, oy + 210), 76, "shield")
- painter.restore()
-
def paintEvent(self, event: Any) -> None: # noqa: N802 - Qt API
del event
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- painter.setRenderHint(QPainter.RenderHint.TextAntialiasing)
- bounds = QRectF(self.rect()).adjusted(0.5, 0.5, -0.5, -0.5)
- background = QLinearGradient(bounds.topLeft(), bounds.bottomRight())
- background.setColorAt(0.0, QColor("#FFFFFF"))
- background.setColorAt(0.7, QColor("#FFFFFF"))
- background.setColorAt(1.0, QColor("#F7F7F7"))
- painter.setBrush(background)
- painter.setPen(QPen(QColor("#EDEDEE"), 1))
- painter.drawRoundedRect(bounds, 24, 24)
-
- width, height = float(self.width()), float(self.height())
- self._draw_illustration(painter, width, height)
-
- left = 64.0 if width >= 620 else 38.0
- if not self._brand_lockup.isNull():
- logo_width = 180.0
- logo_height = logo_width * (
- self._brand_lockup.height() / self._brand_lockup.width()
- )
- painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
- painter.drawPixmap(
- QRectF(left, 24, logo_width, logo_height),
- self._brand_lockup,
- QRectF(self._brand_lockup.rect()),
- )
-
- tag_rect = QRectF(left, 238, 119, 40)
+ bounds = QRectF(self.rect()).adjusted(1, 1, -1, -1)
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#EEF1FA"))
- painter.drawRoundedRect(tag_rect, 11, 11)
- painter.setFont(_font(17, QFont.Weight.Medium))
- painter.setPen(QColor("#4F63D9"))
- painter.drawText(tag_rect, Qt.AlignmentFlag.AlignCenter, "医生工作站")
+ painter.setBrush(QColor(PALETTE["sidebar"]))
+ painter.drawRoundedRect(bounds, 20, 20)
+ left = 36.0
+ width = max(240.0, self.width() - 72.0)
+ if not self._brand_lockup.isNull():
+ brand = self._brand_lockup.scaled(
+ 226, 58, Qt.AspectRatioMode.KeepAspectRatio,
+ Qt.TransformationMode.SmoothTransformation,
+ )
+ painter.drawPixmap(QPointF(left, 36), brand)
+ else:
+ painter.setFont(_font(22, QFont.Weight.DemiBold))
+ painter.setPen(QColor(PALETTE["heading"]))
+ painter.drawText(QPointF(left, 70), "甄养堂 · 医生工作站")
- copy_left = left + 4
- painter.setFont(_font(48, QFont.Weight.Medium))
- painter.setPen(QColor("#1A1C1F"))
- painter.drawText(QPointF(copy_left, 354), "把诊间工作,")
- painter.drawText(QPointF(copy_left, 424), "留在一个")
- prefix_width = painter.fontMetrics().horizontalAdvance("留在一个")
- highlight = QLinearGradient(
- copy_left + prefix_width,
- 0,
- copy_left + prefix_width + 264,
- 0,
- )
- highlight.setColorAt(0.0, QColor("#4F63D9"))
- highlight.setColorAt(1.0, QColor("#4F63D9"))
- painter.setPen(QPen(QBrush(highlight), 1))
- painter.drawText(QPointF(copy_left + prefix_width, 424), "安静的界面里")
- suffix_x = (
- copy_left
- + prefix_width
- + painter.fontMetrics().horizontalAdvance("安静的界面里")
- )
- painter.setPen(QColor("#1A1C1F"))
- painter.drawText(QPointF(suffix_x, 424), "。")
+ heading_y = max(158.0, min(218.0, self.height() * .27))
+ painter.setPen(QColor(PALETTE["muted"]))
+ painter.setFont(_font(13, QFont.Weight.Medium))
+ painter.drawText(QPointF(left, heading_y - 36), "医 生 工 作 台")
+ painter.setPen(QColor(PALETTE["heading"]))
+ painter.setFont(_font(30, QFont.Weight.DemiBold))
+ painter.drawText(QPointF(left, heading_y), "让诊疗有序,")
+ painter.drawText(QPointF(left, heading_y + 44), "让沟通更专注。")
+ painter.setFont(_font(14))
+ painter.setPen(QColor(PALETTE["muted"]))
+ painter.drawText(QPointF(left, heading_y + 82), "从接诊、病历到处方,在一个工作台完成。")
- body_left = left + 6
- painter.setFont(_font(20))
- painter.setPen(QColor("#606163"))
- painter.drawText(
- QPointF(body_left, 492), "接诊、问诊、患者与处方信息统一呈现,"
- )
- painter.drawText(QPointF(body_left, 525), "帮助医生专注于每一次沟通。")
+ row_y = heading_y + 122
+ for index, (title, detail) in enumerate((
+ ("今日接诊", "快速找到待接诊患者与预约安排"),
+ ("诊疗记录", "病历、随访与面诊资料集中查看"),
+ ("处方协作", "开方与审核流程清晰衔接"),
+ ), start=1):
+ row = QRectF(left, row_y, width, 66)
+ painter.setPen(Qt.PenStyle.NoPen)
+ painter.setBrush(QColor(PALETTE["surface"]))
+ painter.drawRoundedRect(row, 12, 12)
+ painter.setFont(_font(13, QFont.Weight.DemiBold))
+ painter.setPen(QColor(PALETTE["accent"]))
+ painter.drawText(QRectF(left + 16, row_y, 28, 66), Qt.AlignmentFlag.AlignCenter, f"0{index}")
+ painter.setFont(_font(15, QFont.Weight.Medium))
+ painter.setPen(QColor(PALETTE["heading"]))
+ painter.drawText(QPointF(left + 58, row_y + 27), title)
+ painter.setFont(_font(12))
+ painter.setPen(QColor(PALETTE["muted"]))
+ painter.drawText(QPointF(left + 58, row_y + 47), detail)
+ row_y += 78
+ if self.height() > row_y + 50:
+ painter.setFont(_font(12))
+ painter.setPen(QColor(PALETTE["muted"]))
+ painter.drawText(QPointF(left, self.height() - 28), "仅供获授权的医疗人员使用")
+ painter.end()
- painter.setFont(_font(16))
- painter.setPen(QColor("#6A6B6D"))
- painter.drawText(
- QPointF(body_left, height - 85), "本工作站仅供获授权的医疗人员使用"
- )
- painter.drawText(QPointF(body_left, height - 59), "请勿在公共设备保存账号信息")
+
+class _PasswordField(QFrame):
+ """Keep the grouped password control visibly focused for keyboard users."""
+
+ def eventFilter(self, watched: Any, event: QEvent) -> bool: # noqa: N802
+ if event.type() in (QEvent.Type.FocusIn, QEvent.Type.FocusOut):
+ self.setProperty("focused", event.type() == QEvent.Type.FocusIn)
+ self.style().unpolish(self)
+ self.style().polish(self)
+ self.update()
+ return super().eventFilter(watched, event)
class _RevealButton(QToolButton):
@@ -392,8 +236,8 @@ class _ServerButton(QPushButton):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
rect = QRectF(self.rect()).adjusted(0.75, 0.75, -0.75, -0.75)
- painter.setBrush(QColor("#FFFFFF") if self.underMouse() else QColor("#FFFFFF"))
- painter.setPen(QPen(QColor("#E4E4E5"), 1.5))
+ painter.setBrush(QColor(PALETTE["accent_soft"] if self.underMouse() else PALETTE["surface"]))
+ painter.setPen(QPen(QColor(PALETTE["focus"] if self.hasFocus() else PALETTE["line_strong"]), 1))
painter.drawRoundedRect(rect, 12, 12)
color = QColor("#1A1C1F" if self.isEnabled() else "#8E8F90")
painter.setPen(_round_pen("#6A6B6D", 1.8))
@@ -536,7 +380,7 @@ class LoginWindow(QMainWindow):
border: 1px solid #E4E4E5;
border-radius: 12px;
}
- QFrame#PasswordField:focus-within { border-color: #8B9AD9; }
+ QFrame#PasswordField[focused="true"] { border-color: #8B9AD9; }
QFrame#LoginCard QCheckBox {
color: #606163;
spacing: 13px;
@@ -606,6 +450,9 @@ class LoginWindow(QMainWindow):
self.login_root.addWidget(self.brand_panel, 60)
self.login_root.addWidget(self._build_login_area(), 40)
self._restore_settings()
+ for widget in (canvas, *canvas.findChildren(QWidget)):
+ if widget.styleSheet():
+ widget.setStyleSheet(clinical_stylesheet(widget.styleSheet()))
def resizeEvent(self, event: QResizeEvent) -> None: # noqa: N802 - Qt API
"""Preserve the reference composition while remaining usable on small screens."""
@@ -625,18 +472,15 @@ class LoginWindow(QMainWindow):
# Keep the form fully visible when the 60/40 desktop split would
# otherwise crop its fixed-width card. Small windows focus on login.
self.brand_panel.setVisible(width >= 1120)
+ compact_height = event.size().height() < 720
+ self.card.setMinimumHeight(580 if compact_height else 620)
self.login_area_layout.setContentsMargins(
- 0, min(104, max(24, (event.size().height() - 694) // 2)), 0, 12
+ 0, 12 if compact_height else min(104, max(24, (event.size().height() - 694) // 2)), 0, 12
)
super().resizeEvent(event)
def _build_brand_panel(self) -> QWidget:
panel = _BrandPanel()
- shadow = QGraphicsDropShadowEffect(panel)
- shadow.setBlurRadius(32)
- shadow.setOffset(0, 10)
- shadow.setColor(QColor(67, 82, 154, 18))
- panel.setGraphicsEffect(shadow)
return panel
def _build_login_area(self) -> QWidget:
@@ -660,11 +504,6 @@ class LoginWindow(QMainWindow):
self.card.setFixedWidth(480)
self.card.setMinimumHeight(620)
self.card.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
- card_shadow = QGraphicsDropShadowEffect(self.card)
- card_shadow.setBlurRadius(38)
- card_shadow.setOffset(0, 16)
- card_shadow.setColor(QColor(59, 77, 139, 24))
- self.card.setGraphicsEffect(card_shadow)
card_layout = QVBoxLayout(self.card)
card_layout.setSizeConstraint(QLayout.SizeConstraint.SetDefaultConstraint)
card_layout.setContentsMargins(47, 42, 47, 26)
@@ -673,13 +512,13 @@ class LoginWindow(QMainWindow):
title = QLabel("欢迎回来")
title.setObjectName("LoginTitle")
- title.setStyleSheet("color:#1A1C1F; font-size:30px; font-weight:500;")
+ title.setStyleSheet("color:#1A1C1F; font-size:26px; font-weight:600;")
title.setContentsMargins(1, -3, 0, 3)
title.setFixedHeight(46)
card_layout.addWidget(title)
subtitle = QLabel("使用医生账号登录工作站")
subtitle.setProperty("role", "muted")
- subtitle.setStyleSheet("color:#606163; font-size:18px;")
+ subtitle.setStyleSheet("color:#606163; font-size:15px;")
subtitle.setContentsMargins(1, 8, 0, 0)
subtitle.setFixedHeight(27)
card_layout.addWidget(subtitle)
@@ -710,7 +549,7 @@ class LoginWindow(QMainWindow):
password_label.setFixedHeight(24)
card_layout.addWidget(password_label)
card_layout.addSpacing(11)
- password_field = QFrame()
+ password_field = _PasswordField()
password_field.setObjectName("PasswordField")
password_field.setFixedHeight(54)
password_row = QHBoxLayout(password_field)
@@ -721,6 +560,7 @@ class LoginWindow(QMainWindow):
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
self.password_edit.setPlaceholderText("请输入密码")
self.password_edit.setAccessibleName("登录密码")
+ self.password_edit.installEventFilter(password_field)
self.password_edit.setTextMargins(0, -2, 0, 2)
self.password_edit.returnPressed.connect(self.submit)
password_row.addWidget(self.password_edit, 1)
@@ -730,6 +570,7 @@ class LoginWindow(QMainWindow):
self.reveal_button.setCheckable(True)
self.reveal_button.setFixedSize(87, 52)
self.reveal_button.setToolTip("显示或隐藏密码")
+ self.reveal_button.installEventFilter(password_field)
self.reveal_button.toggled.connect(self._toggle_password)
password_row.addWidget(self.reveal_button)
card_layout.addWidget(password_field)
@@ -758,11 +599,6 @@ class LoginWindow(QMainWindow):
self.login_button = QPushButton("登录工作站")
self.login_button.setProperty("variant", "primary")
self.login_button.setFixedHeight(58)
- login_shadow = QGraphicsDropShadowEffect(self.login_button)
- login_shadow.setBlurRadius(20)
- login_shadow.setOffset(0, 7)
- login_shadow.setColor(QColor(82, 101, 246, 45))
- self.login_button.setGraphicsEffect(login_shadow)
self.login_button.clicked.connect(self.submit)
card_layout.addWidget(self.login_button)
self.debug_settings_section = QWidget()
diff --git a/app/src/doctor_workstation/ui/motion.py b/app/src/doctor_workstation/ui/motion.py
index 6236d8b14..9a4e41ce6 100755
--- a/app/src/doctor_workstation/ui/motion.py
+++ b/app/src/doctor_workstation/ui/motion.py
@@ -37,8 +37,10 @@ from PySide6.QtCore import (
QTimer,
)
from PySide6.QtWidgets import (
+ QAbstractItemView,
QAbstractScrollArea,
QGraphicsOpacityEffect,
+ QPlainTextEdit,
QStackedWidget,
QWidget,
)
@@ -75,15 +77,35 @@ def reduced_motion() -> bool:
return os.getenv("QT_QPA_PLATFORM", "").strip().lower() == "offscreen"
-def _own(target: QWidget, key: str, animation: QPropertyAnimation) -> QPropertyAnimation:
- """Park an animation on its target so Python does not collect it early."""
+def _stop(target: QObject, key: str) -> None:
+ """Retire a replaced animation without firing its completion callback."""
- running: dict[str, QPropertyAnimation] = getattr(target, "_doctor_motion", None) or {}
- previous = running.get(key)
+ running = getattr(target, "_doctor_motion", {})
+ previous = running.pop(key, None)
if previous is not None:
previous.stop()
+ previous.setParent(None)
+ previous.deleteLater()
+
+
+def _own(target: QObject, key: str, animation: QPropertyAnimation) -> QPropertyAnimation:
+ """Park an animation on its target so Python does not collect it early."""
+
+ _stop(target, key)
+ running: dict[str, QPropertyAnimation] = getattr(target, "_doctor_motion", {})
running[key] = animation
target._doctor_motion = running
+
+ def release() -> None:
+ if running.get(key) is animation:
+ running.pop(key)
+ # A callback can hold the last Python reference to the owner. Detach
+ # first so releasing that callback during deferred deletion cannot
+ # recursively delete this animation through its former parent.
+ animation.setParent(None)
+ animation.deleteLater()
+
+ animation.finished.connect(release)
return animation
@@ -107,7 +129,10 @@ def animate(
from inside its own ``finished`` emission.
"""
+ animation_owner = owner if owner is not None else target
+ animation_key = key or prop.decode()
if reduced_motion():
+ _stop(animation_owner, animation_key)
target.setProperty(prop.decode() if isinstance(prop, bytes) else prop, end)
if on_finished is not None:
on_finished()
@@ -117,18 +142,24 @@ def animate(
animation.setEasingCurve(easing)
animation.setStartValue(start)
animation.setEndValue(end)
+ _own(animation_owner, animation_key, animation)
if on_finished is not None:
animation.finished.connect(on_finished)
- _own(owner if owner is not None else target, key or prop.decode(), animation)
animation.start(QAbstractAnimation.DeletionPolicy.KeepWhenStopped)
return animation
-def _opacity_effect(widget: QWidget) -> QGraphicsOpacityEffect:
+def _opacity_effect(widget: QWidget) -> QGraphicsOpacityEffect | None:
effect = widget.graphicsEffect()
- if not isinstance(effect, QGraphicsOpacityEffect):
+ # Do not replace a caller's shadow or opacity effect: Qt deletes it when
+ # another effect is attached. Only effects created here belong to a fade.
+ if effect is not None and effect is not getattr(widget, "_doctor_opacity_effect", None):
+ return None
+ if effect is None:
effect = QGraphicsOpacityEffect(widget)
+ effect.setOpacity(1.0)
widget.setGraphicsEffect(effect)
+ widget._doctor_opacity_effect = effect
effect.setEnabled(True)
return effect
@@ -146,9 +177,17 @@ def _drop_effect(widget: QWidget) -> None:
signal that is still being delivered.
"""
+ effect = getattr(widget, "_doctor_opacity_effect", None)
+ revision = getattr(widget, "_doctor_fade_revision", 0)
+
def detach() -> None:
try:
- if isinstance(widget.graphicsEffect(), QGraphicsOpacityEffect):
+ if (
+ effect is not None
+ and widget.graphicsEffect() is effect
+ and getattr(widget, "_doctor_fade_revision", 0) == revision
+ ):
+ widget._doctor_opacity_effect = None
widget.setGraphicsEffect(None)
except RuntimeError: # the widget went away while the fade was running
pass
@@ -156,6 +195,13 @@ def _drop_effect(widget: QWidget) -> None:
QTimer.singleShot(0, detach)
+def _restart_fade(widget: QWidget) -> None:
+ _stop(widget, "fade")
+ # A completed fade may still have deferred cleanup waiting in the queue.
+ # It must not remove an effect now being used by a subsequent fade.
+ widget._doctor_fade_revision = getattr(widget, "_doctor_fade_revision", 0) + 1
+
+
def fade_in(
widget: QWidget,
*,
@@ -165,10 +211,20 @@ def fade_in(
) -> None:
"""Fade a widget up to full opacity, showing it first if needed."""
+ existing = widget.graphicsEffect()
+ if existing is not None and existing is getattr(widget, "_doctor_opacity_effect", None):
+ start = float(existing.opacity())
+ _restart_fade(widget)
if reduced_motion():
+ if existing is not None and existing is getattr(widget, "_doctor_opacity_effect", None):
+ existing.setOpacity(1.0)
+ _drop_effect(widget)
widget.show()
return
effect = _opacity_effect(widget)
+ if effect is None:
+ widget.show()
+ return
effect.setOpacity(start)
widget.show()
animate(
@@ -193,9 +249,11 @@ def fade_out(
) -> None:
"""Fade a widget down, optionally hiding it when the fade completes."""
+ _restart_fade(widget)
if reduced_motion():
if hide:
widget.hide()
+ _drop_effect(widget)
if on_finished is not None:
on_finished()
return
@@ -208,6 +266,9 @@ def fade_out(
if on_finished is not None:
on_finished()
+ if effect is None:
+ done()
+ return
animate(
effect,
b"opacity",
@@ -229,13 +290,17 @@ def enter(widget: QWidget, *, duration: int = BASE, rise: int = RISE) -> None:
the user has to wait out.
"""
+ previous = getattr(widget, "_doctor_motion", {}).get("enter")
+ origin = previous.endValue() if previous is not None else widget.pos()
if reduced_motion():
- widget.show()
+ _stop(widget, "enter")
+ widget.move(origin)
+ fade_in(widget, duration=duration)
return
fade_in(widget, duration=duration)
if rise:
- origin = widget.pos()
- widget.move(origin + QPoint(0, rise))
+ if previous is None:
+ widget.move(origin + QPoint(0, rise))
animate(
widget,
b"pos",
@@ -260,7 +325,7 @@ def switch_stack(stack: QStackedWidget, index: int, *, rise: int = RISE) -> None
return
stack.setCurrentIndex(index)
page = stack.currentWidget()
- if page is None or reduced_motion():
+ if page is None:
return
enter(page, rise=rise)
@@ -274,50 +339,121 @@ SCROLL_STEP = 120
SCROLL_MS = 190
+class _ScrollAnimation(QPropertyAnimation):
+ """Identify animation writes so direct scrollbar changes can interrupt us."""
+
+ writing = False
+
+ def updateCurrentValue(self, value: Any) -> None: # noqa: N802 - Qt API
+ self.writing = True
+ try:
+ super().updateCurrentValue(value)
+ finally:
+ self.writing = False
+
+
class _SmoothScroller(QObject):
"""Animate a scroll area's wheel movement instead of jumping to it."""
+ _INTERRUPT_EVENTS = frozenset(
+ {
+ QEvent.Type.KeyPress,
+ QEvent.Type.MouseButtonPress,
+ QEvent.Type.TouchBegin,
+ QEvent.Type.Hide,
+ }
+ )
+
def __init__(self, area: QAbstractScrollArea, *, orientation: Qt.Orientation) -> None:
super().__init__(area)
+ self._area = area
+ self._orientation = orientation
self._bar = (
area.verticalScrollBar()
if orientation is Qt.Orientation.Vertical
else area.horizontalScrollBar()
)
self._target = self._bar.value()
- self._animation = QPropertyAnimation(self._bar, b"value", self)
+ self._animation = _ScrollAnimation(self._bar, b"value", self)
self._animation.setEasingCurve(EASE_ENTER)
self._animation.setDuration(SCROLL_MS)
- # Keyboard, programmatic and drag movements must not be fought over: when
- # nothing is animating, the wheel target follows wherever the bar went.
self._bar.valueChanged.connect(self._sync_target)
+ self._bar.sliderPressed.connect(self._cancel)
+ self._bar.actionTriggered.connect(self._cancel)
+ self._bar.rangeChanged.connect(self._cancel)
+ self._bar.installEventFilter(self)
+ area.installEventFilter(self)
area.viewport().installEventFilter(self)
+ def _cancel(self, *_: Any) -> None:
+ self._animation.stop()
+ self._target = self._bar.value()
+
def _sync_target(self, value: int) -> None:
- if self._animation.state() != QAbstractAnimation.State.Running:
+ if not self._animation.writing:
+ self._animation.stop()
self._target = value
+ def _uses_pixels(self) -> bool:
+ if isinstance(self._area, QAbstractItemView):
+ mode = (
+ self._area.verticalScrollMode()
+ if self._orientation == Qt.Orientation.Vertical
+ else self._area.horizontalScrollMode()
+ )
+ return mode == QAbstractItemView.ScrollMode.ScrollPerPixel
+ # QPlainTextEdit's vertical scrollbar counts text blocks, not pixels.
+ return not (
+ isinstance(self._area, QPlainTextEdit) and self._orientation == Qt.Orientation.Vertical
+ )
+
def eventFilter(self, watched: QObject, event: QEvent) -> bool: # noqa: N802 - Qt API
- del watched
- if event.type() is not QEvent.Type.Wheel or reduced_motion():
+ event_type = event.type()
+ if event_type in self._INTERRUPT_EVENTS:
+ self._cancel()
return False
- delta = event.angleDelta().y() or event.angleDelta().x()
- if not delta or event.modifiers() & Qt.KeyboardModifier.ControlModifier:
+ if event_type != QEvent.Type.Wheel:
return False
+ horizontal = self._orientation == Qt.Orientation.Horizontal
+ shifted = bool(event.modifiers() & Qt.KeyboardModifier.ShiftModifier)
+ delta = event.angleDelta().x() if horizontal else event.angleDelta().y()
+ if horizontal and shifted and not delta:
+ delta = event.angleDelta().y()
+ if (
+ watched is not self._area.viewport()
+ or reduced_motion()
+ or not self._uses_pixels()
+ or not event.pixelDelta().isNull()
+ or event.phase() != Qt.ScrollPhase.NoScrollPhase
+ or event.modifiers()
+ & (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier)
+ or (shifted and not horizontal)
+ or not delta
+ ):
+ # Trackpads already provide continuous motion and native momentum.
+ # Mixing another easing curve into it adds lag and fights gestures.
+ self._cancel()
+ return False
+
lower, upper = self._bar.minimum(), self._bar.maximum()
# Re-clamp first: the range can shrink underneath a running animation
# when the content behind it reloads, which would otherwise leave the
# pending target past the end of the new content.
self._target = max(lower, min(upper, self._target))
- target = self._target - round(delta / 120.0 * SCROLL_STEP)
+ current = self._bar.value()
+ step = -round(delta / 120.0 * SCROLL_STEP)
+ # Reverse immediately from the visible position, not the end of a
+ # backlog of wheel notches still travelling in the opposite direction.
+ origin = current if (self._target - current) * step < 0 else self._target
+ target = origin + step
target = max(lower, min(upper, target))
# At either end, hand the wheel back so an enclosing scroll area still
# gets it - swallowing it there is what makes nested panes feel stuck.
if target == self._target:
- return False
+ return target != current
self._target = target
self._animation.stop()
- self._animation.setStartValue(self._bar.value())
+ self._animation.setStartValue(current)
self._animation.setEndValue(target)
self._animation.start()
return True
@@ -328,7 +464,7 @@ def install_smooth_scroll(
*,
orientation: Qt.Orientation = Qt.Orientation.Vertical,
) -> None:
- """Give a scroll area eased wheel scrolling."""
+ """Ease discrete wheels on pixel-based areas; preserve native gestures."""
if getattr(area, "_doctor_smooth_scroll", None) is not None:
return
diff --git a/app/src/doctor_workstation/ui/pages/patients.py b/app/src/doctor_workstation/ui/pages/patients.py
index a83e2893f..d56f34338 100755
--- a/app/src/doctor_workstation/ui/pages/patients.py
+++ b/app/src/doctor_workstation/ui/pages/patients.py
@@ -50,6 +50,7 @@ from ...core.appointment_modes import (
)
from .. import icons
from ..appointment_drawer import AppointmentDrawer
+from ..design_system import PALETTE, clinical_stylesheet
from ..dialogs import DiagnosisDialog, present_ai_consult, present_order_detail
from ..dialogs.ai_consult import can_open_ai_consult
from ..dialogs.prescription import PrescriptionOrderListDialog
@@ -110,97 +111,97 @@ FULFILLMENT_TEXT = {
}
_SEMANTIC_COLORS = {
- "primary": "#4F63D9",
- "success": "#287B65",
- "warning": "#A9691D",
- "danger": "#BE4B58",
- "info": "#4F63D9",
- "muted": "#606163",
+ "primary": PALETTE["accent"],
+ "success": PALETTE["success"],
+ "warning": PALETTE["warning"],
+ "danger": PALETTE["danger"],
+ "info": PALETTE["accent"],
+ "muted": PALETTE["muted"],
}
-PATIENTS_LIGHT_QSS = """
+PATIENTS_LIGHT_QSS = clinical_stylesheet("""
#PatientsPage QWidget#PageHeader QLabel[role="pageTitle"] {
- color: #1A1C1F;
+ color: $ds_heading;
font-size: 20px;
font-weight: 600;
}
#PatientsPage QWidget#PageHeader QLabel[role="muted"] {
- color: #606163;
+ color: $ds_muted;
font-size: 13px;
}
#PatientsPage QPushButton[patientSearchAction="true"] {
min-height: 32px;
max-height: 32px;
- color: #FFFFFF;
- background-color: #4F63D9;
- border: 1px solid #4F63D9;
+ color: $ds_surface;
+ background-color: $ds_accent;
+ border: 1px solid $ds_accent;
border-radius: 7px;
font-weight: 500;
}
#PatientsPage QPushButton[patientSearchAction="true"]:hover {
- background-color: #4156C4;
- border-color: #4156C4;
+ background-color: $ds_accent_hover;
+ border-color: $ds_accent_hover;
}
#PatientsPage QFrame[patientListFilter="true"] {
min-height: 88px;
max-height: 88px;
- background-color: #FFFFFF;
- border: 1px solid #EDEDEE;
+ background-color: $ds_surface;
+ border: 1px solid $ds_line;
border-radius: 12px;
}
#PatientsPage QFrame[patientListFilter="true"] QLineEdit,
#PatientsPage QFrame[patientListFilter="true"] QDateEdit {
min-height: 32px;
max-height: 32px;
- background-color: #FFFFFF;
- border: 1px solid #EDEDEE;
+ background-color: $ds_surface;
+ border: 1px solid $ds_line;
border-radius: 7px; font-size: 14px;
}
#PatientsPage QFrame[patientListFilter="true"] QPushButton {
min-height: 32px; max-height: 32px;
}
#PatientsPage QFrame[patientListFilter="true"] QDateEdit:disabled {
- color: #8E8F90; background-color: #F7F7F7;
+ color: $ds_disabled; background-color: $ds_surface_alt;
}
#PatientsPage QPushButton[patientStatusChip="true"] {
min-height: 32px;
max-height: 32px;
padding: 0 10px;
- color: #606163;
- background-color: #F7F7F7;
+ color: $ds_muted;
+ background-color: $ds_surface_alt;
border: 1px solid transparent;
border-radius: 5px;
}
#PatientsPage QPushButton[patientStatusChip="true"]:hover {
- color: #4F63D9;
- background-color: #EEF1FA;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
}
#PatientsPage QPushButton[patientStatusChip="true"]:checked {
- color: #4F63D9;
- background-color: #EEF1FA;
- border: 1px solid #8B9AD9;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
+ border: 1px solid $ds_focus;
}
#PatientsPage QPushButton[patientQuickDate="true"] {
min-height: 32px;
max-height: 32px;
padding: 0 9px;
- color: #1A1C1F;
+ color: $ds_heading;
background-color: transparent;
border: 1px solid transparent;
border-radius: 7px;
}
#PatientsPage QPushButton[patientQuickDate="true"]:hover {
- color: #4F63D9;
- background-color: #EEF1FA;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
}
#PatientsPage QPushButton[patientQuickDate="true"]:checked {
- color: #4F63D9;
- background-color: #EEF1FA;
- border-color: #8B9AD9;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
+ border-color: $ds_focus;
}
#PatientsPage QTabWidget#PatientWorkspaceTabs::pane {
border: 0;
- border-top: 1px solid #EDEDEE;
+ border-top: 1px solid $ds_line;
background-color: transparent;
}
#PatientsPage QTabWidget#PatientWorkspaceTabs QTabBar::tab {
@@ -208,124 +209,124 @@ PATIENTS_LIGHT_QSS = """
min-height: 34px;
padding: 0 6px;
margin-right: 8px;
- color: #606163;
+ color: $ds_muted;
background: transparent;
border: 0;
border-bottom: 2px solid transparent;
font-weight: 400;
}
#PatientsPage QTabWidget#PatientWorkspaceTabs QTabBar::tab:selected {
- color: #4F63D9;
- border-bottom-color: #4F63D9;
+ color: $ds_accent;
+ border-bottom-color: $ds_accent;
font-weight: 500;
}
#PatientsPage QPushButton[summaryCard="true"] {
min-height: 42px;
max-height: 42px;
padding: 0 11px;
- color: #1A1C1F;
- background-color: #F7F7F7;
- border: 1px solid #EDEDEE;
+ color: $ds_heading;
+ background-color: $ds_surface_alt;
+ border: 1px solid $ds_line;
border-radius: 9px;
text-align: left;
font-weight: 500;
}
#PatientsPage QPushButton[summaryCard="true"]:hover {
- color: #4F63D9;
- background-color: #EEF1FA;
- border-color: #8B9AD9;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
+ border-color: $ds_focus;
}
#PatientsPage QPushButton[rowAction="true"] {
min-height: 26px;
max-height: 26px;
padding: 0 7px;
- color: #4F63D9;
- background-color: #FFFFFF;
- border: 1px solid #EDEDEE;
+ color: $ds_accent;
+ background-color: $ds_surface;
+ border: 1px solid $ds_line;
border-radius: 6px;
font-size: 13px;
font-weight: 400;
}
#PatientsPage QPushButton[rowAction="true"]:hover {
- background-color: #EEF1FA;
- border-color: #8B9AD9;
+ background-color: $ds_accent_soft;
+ border-color: $ds_focus;
}
#PatientsPage QPushButton[rowAction="true"][variant="danger"] {
- color: #BE4B58;
- background-color: #FFF7F8;
- border-color: #F4C4CC;
+ color: $ds_danger;
+ background-color: $ds_danger_soft;
+ border-color: $ds_danger_soft;
}
#PatientsPage QTableWidget#PatientTable QHeaderView::section {
min-height: 34px;
- background-color: #F7F7F7; font-size: 13px;
+ background-color: $ds_surface_alt; font-size: 13px;
}
#PatientsPage QTableWidget#PatientTable::item { padding: 5px 7px; }
#PatientsPage QTableWidget#PatientTable {
- gridline-color: #EDEDEE;
- selection-background-color: #EEF1FA;
- selection-color: #1A1C1F; font-size: 14px;
+ gridline-color: $ds_line;
+ selection-background-color: $ds_accent_soft;
+ selection-color: $ds_heading; font-size: 14px;
}
#PatientsPage QCheckBox[patientSelector="true"]::indicator {
width: 13px;
height: 13px;
- background-color: #FFFFFF;
- border: 1px solid #EDEDEE;
+ background-color: $ds_surface;
+ border: 1px solid $ds_line;
border-radius: 2px;
}
#PatientsPage QCheckBox[patientSelector="true"]::indicator:checked {
- background-color: #4F63D9;
- border-color: #4F63D9;
+ background-color: $ds_accent;
+ border-color: $ds_accent;
}
#PatientsPage QPushButton[variant="ghost"]:checked {
- color: #4F63D9;
- background-color: #EEF1FA;
- border: 1px solid #4F63D9;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
+ border: 1px solid $ds_accent;
}
-#PatientsPage QPushButton[variant="ghost"]:checked:hover { background-color: #EEF1FA; }
+#PatientsPage QPushButton[variant="ghost"]:checked:hover { background-color: $ds_accent_soft; }
#PatientsPage QPushButton[statusKind="info"]:checked {
- color: #4F63D9;
- border-color: #4F63D9;
+ color: $ds_accent;
+ border-color: $ds_accent;
}
#PatientsPage QPushButton[statusKind="warning"]:checked {
- color: #A9691D;
- border-color: #A9691D;
+ color: $ds_warning;
+ border-color: $ds_warning;
}
#PatientsPage QPushButton[statusKind="success"]:checked {
- color: #287B65;
- border-color: #287B65;
+ color: $ds_success;
+ border-color: $ds_success;
}
#PatientsPage QPushButton[statusKind="danger"]:checked {
- color: #BE4B58;
- border-color: #BE4B58;
+ color: $ds_danger;
+ border-color: $ds_danger;
}
-#PatientsPage QLabel[metricKind="primary"] { color: #4F63D9; }
-#PatientsPage QLabel[metricKind="info"] { color: #4F63D9; }
-#PatientsPage QLabel[metricKind="success"] { color: #287B65; }
-#PatientsPage QLabel[metricKind="warning"] { color: #A9691D; }
-#PatientsPage QLabel[metricKind="danger"] { color: #BE4B58; }
+#PatientsPage QLabel[metricKind="primary"] { color: $ds_accent; }
+#PatientsPage QLabel[metricKind="info"] { color: $ds_accent; }
+#PatientsPage QLabel[metricKind="success"] { color: $ds_success; }
+#PatientsPage QLabel[metricKind="warning"] { color: $ds_warning; }
+#PatientsPage QLabel[metricKind="danger"] { color: $ds_danger; }
#PatientsPage QTabWidget#PatientWorkspaceTabs::pane {
background-color: transparent;
border: 0;
top: -1px;
}
#PatientsPage QTabWidget#PatientWorkspaceTabs QTabBar::tab {
- color: #606163;
+ color: $ds_muted;
background-color: transparent;
border: 0;
border-bottom: 2px solid transparent;
font-weight: 400;
}
#PatientsPage QTabWidget#PatientWorkspaceTabs QTabBar::tab:hover {
- color: #4F63D9;
- background-color: #EEF1FA;
+ color: $ds_accent;
+ background-color: $ds_accent_soft;
}
#PatientsPage QTabWidget#PatientWorkspaceTabs QTabBar::tab:selected {
- color: #4F63D9;
+ color: $ds_accent;
background-color: transparent;
- border-bottom-color: #4F63D9;
+ border-bottom-color: $ds_accent;
font-weight: 500;
}
-"""
+""")
def _style_table_cell(table: SortableTable, row: int, column: int, kind: str) -> None:
@@ -1282,7 +1283,7 @@ class _PatientDateEdit(QDateEdit):
def paintEvent(self, event: Any) -> None:
super().paintEvent(event)
painter = QPainter(self)
- glyph = icons.pixmap("calendar", "#5D6B80" if self.isEnabled() else "#8A97A9", 15)
+ glyph = icons.pixmap("calendar", PALETTE["muted"] if self.isEnabled() else PALETTE["disabled"], 15)
painter.drawPixmap(QRectF(self.width() - 24, (self.height() - 15) / 2, 15, 15), glyph, QRectF(glyph.rect()))
painter.end()
@@ -1300,18 +1301,18 @@ class _PatientSummaryButton(QPushButton):
label, _, count = self.text().partition("\n")
left = max(18, (self.width() - 204) // 2)
icon_rect = QRectF(left, (self.height() - 36) / 2, 36, 36)
- glyph = icons.pixmap("calendar", "#1769E8", 36)
+ glyph = icons.pixmap("calendar", PALETTE["accent"], 36)
painter.drawPixmap(icon_rect, glyph, QRectF(glyph.rect()))
font = QFont(body_family())
font.setPixelSize(13)
painter.setFont(font)
- painter.setPen(QColor("#5D6B80"))
+ painter.setPen(QColor(PALETTE["muted"]))
text_rect = self.rect().adjusted(left + 46, 10, -12, -32)
painter.drawText(text_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
painter.fontMetrics().elidedText(label, Qt.TextElideMode.ElideRight, text_rect.width()))
font.setPixelSize(16)
painter.setFont(font)
- painter.setPen(QColor("#273244"))
+ painter.setPen(QColor(PALETTE["text"]))
painter.drawText(self.rect().adjusted(left + 46, 31, -12, -9),
Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, count)
painter.end()
@@ -1324,11 +1325,11 @@ class _PatientInfoDelegate(QStyledItemDelegate):
painter.save()
selected = bool(option.state & QStyle.StateFlag.State_Selected)
hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
- painter.fillRect(option.rect, QColor("#EAF2FF" if selected else "#F6F9FE" if hovered else "#FFFFFF"))
- painter.setPen(QColor("#E6EDF6"))
+ painter.fillRect(option.rect, QColor(PALETTE["accent_soft"] if selected else PALETTE["surface_alt"] if hovered else PALETTE["surface"]))
+ painter.setPen(QColor(PALETTE["line"]))
painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
if selected and index.column() == 0:
- painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor("#1769E8"))
+ painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor(PALETTE["accent"]))
if index.column() in (0, 9):
painter.restore()
return
@@ -1337,9 +1338,9 @@ class _PatientInfoDelegate(QStyledItemDelegate):
font = QFont(body_family())
font.setPixelSize(14)
painter.setFont(font)
- painter.setPen(QColor("#273244"))
+ painter.setPen(QColor(PALETTE["text"]))
- def draw(text: str, target: Any, color: str = "#273244", centered: bool = False) -> None:
+ def draw(text: str, target: Any, color: str = PALETTE["text"], centered: bool = False) -> None:
painter.setPen(QColor(color))
text = painter.fontMetrics().elidedText(text, Qt.TextElideMode.ElideRight, target.width())
alignment = Qt.AlignmentFlag.AlignVCenter | (Qt.AlignmentFlag.AlignHCenter if centered else Qt.AlignmentFlag.AlignLeft)
@@ -1359,17 +1360,17 @@ class _PatientInfoDelegate(QStyledItemDelegate):
doctor = display_text(first_value(row, "appointment_doctor_name"), "")
status, _kind = _patient_status(row)
if not doctor:
- draw(status, rect, "#5D6B80")
+ draw(status, rect, PALETTE["muted"])
else:
draw(doctor, top)
font.setPixelSize(13)
painter.setFont(font)
- color, fill = ("#A9691D", "#FFF7EA") if status == "已过号" else ("#1769E8", "#F0F6FF")
+ color, fill = (PALETTE["warning"], PALETTE["warning_soft"]) if status == "已过号" else (PALETTE["accent"], PALETTE["accent_soft"])
if status == "已取消":
- color, fill = "#5D6B80", "#F5F7FA"
+ color, fill = PALETTE["muted"], PALETTE["canvas"]
badge = QRectF(bottom.x(), bottom.y() + 1, min(bottom.width(), painter.fontMetrics().horizontalAdvance(status) + 10), 20)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- painter.setPen(QColor("#E7CDA8" if status == "已过号" else "#C7DAF7"))
+ painter.setPen(QColor(PALETTE["warning_soft"] if status == "已过号" else PALETTE["line_strong"]))
painter.setBrush(QColor(fill))
painter.drawRoundedRect(badge, 3, 3)
draw(status, badge.toRect(), color, True)
@@ -1385,7 +1386,7 @@ class _PatientInfoDelegate(QStyledItemDelegate):
draw(value, rect)
else:
text = str(index.data(Qt.ItemDataRole.DisplayRole) or "")
- draw(text, rect, "#A9691D" if index.column() == 6 and text == "待确认" else "#273244", index.column() == 5)
+ draw(text, rect, PALETTE["warning"] if index.column() == 6 and text == "待确认" else PALETTE["text"], index.column() == 5)
painter.restore()
@@ -1493,7 +1494,7 @@ class PatientListWorkspace(QWidget):
self.keyword_edit.setMaximumWidth(360)
self.keyword_edit.setPlaceholderText("患者姓名 / 手机号 / 助理 / 医生")
self.keyword_edit.setClearButtonEnabled(True)
- self.keyword_edit.addAction(icons.icon("search", "#5D6B80", 16), QLineEdit.ActionPosition.LeadingPosition)
+ self.keyword_edit.addAction(icons.icon("search", PALETTE["muted"], 16), QLineEdit.ActionPosition.LeadingPosition)
self.keyword_edit.returnPressed.connect(self.search)
search_row.addWidget(self.keyword_edit, 1)
self.status_label = QLabel("患者状态:")
@@ -1846,7 +1847,7 @@ class PatientListWorkspace(QWidget):
)
host = RowActions(row_actions, self.table)
if host.more_button is not None:
- host.more_button.setIcon(icons.icon("chevron_down", "#5D6B80", 12))
+ host.more_button.setIcon(icons.icon("chevron_down", PALETTE["muted"], 12))
host.more_button.setIconSize(QSize(12, 12))
host.more_button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
host.more_button.setLayoutDirection(Qt.LayoutDirection.RightToLeft)
@@ -2079,7 +2080,7 @@ class _OrderComboBox(QComboBox):
def paintEvent(self, event: Any) -> None:
super().paintEvent(event)
painter = QPainter(self)
- glyph = icons.pixmap("chevron_down", "#5D6B80", 14)
+ glyph = icons.pixmap("chevron_down", PALETTE["muted"], 14)
painter.drawPixmap(QRectF(self.width() - 24, (self.height() - 14) / 2, 14, 14), glyph, QRectF(glyph.rect()))
painter.end()
@@ -2088,7 +2089,7 @@ class _OrderActionButton(QToolButton):
def paintEvent(self, event: Any) -> None:
super().paintEvent(event)
painter = QPainter(self)
- glyph = icons.pixmap("chevron_down", "#5D6B80" if self.isEnabled() else "#97A4B6", 14)
+ glyph = icons.pixmap("chevron_down", PALETTE["muted"] if self.isEnabled() else PALETTE["disabled"], 14)
painter.drawPixmap(QRectF(self.width() - 23, (self.height() - 14) / 2, 14, 14), glyph, QRectF(glyph.rect()))
painter.end()
@@ -2107,18 +2108,18 @@ class _OrderInfoDelegate(QStyledItemDelegate):
painter.setClipRect(option.rect)
selected = bool(option.state & QStyle.StateFlag.State_Selected)
hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
- painter.fillRect(option.rect, QColor("#F5F8FF" if selected else "#F8FAFE" if hovered else "#FFFFFF"))
- painter.setPen(QColor("#E6EDF6"))
+ painter.fillRect(option.rect, QColor(PALETTE["accent_soft"] if selected else PALETTE["surface_alt"] if hovered else PALETTE["surface"]))
+ painter.setPen(QColor(PALETTE["line"]))
painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
if selected and index.column() == 0:
- painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor("#1769E8"))
+ painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor(PALETTE["accent"]))
rect = option.rect.adjusted(16, 0, -12, -1)
font = QFont(body_family())
font.setPixelSize(14)
painter.setFont(font)
text = str(index.data(Qt.ItemDataRole.DisplayRole) or "—")
- def draw(value: str, target: Any, color: str = "#273244", right: bool = False) -> None:
+ def draw(value: str, target: Any, color: str = PALETTE["text"], right: bool = False) -> None:
painter.setPen(QColor(color))
value = painter.fontMetrics().elidedText(value, Qt.TextElideMode.ElideRight, target.width())
painter.drawText(target, Qt.AlignmentFlag.AlignVCenter | (Qt.AlignmentFlag.AlignRight if right else Qt.AlignmentFlag.AlignLeft), value)
@@ -2138,7 +2139,7 @@ class _OrderInfoDelegate(QStyledItemDelegate):
font.setWeight(QFont.Weight.Normal)
font.setPixelSize(13)
painter.setFont(font)
- draw(secondary, bottom, "#5D6B80")
+ draw(secondary, bottom, PALETTE["muted"])
else:
draw(text, rect)
elif column in (9, 11):
@@ -2147,7 +2148,7 @@ class _OrderInfoDelegate(QStyledItemDelegate):
draw(primary, top)
font.setPixelSize(13)
painter.setFont(font)
- draw(("(" if column == 9 else "") + secondary, bottom, "#5D6B80")
+ draw(("(" if column == 9 else "") + secondary, bottom, PALETTE["muted"])
else:
draw(text, rect)
elif column in (4, 5, 6):
@@ -2158,10 +2159,10 @@ class _OrderInfoDelegate(QStyledItemDelegate):
else:
kind = "blue" if raw in {3, 5, 6, 7, 8, 11} else "danger" if raw in {4, 9, 10} else "warning" if raw in {1, 2, 12} else "neutral"
foreground, background, border = {
- "blue": ("#1769E8", "#F2F7FF", "#CEE0FA"),
- "warning": ("#AD640C", "#FFFAF2", "#F2DABD"),
- "danger": ("#BE4657", "#FFF5F6", "#F0D0D7"),
- "neutral": ("#5D6B80", "#F6F8FC", "#E2E9F2"),
+ "blue": (PALETTE["accent"], PALETTE["accent_soft"], PALETTE["line_strong"]),
+ "warning": (PALETTE["warning"], PALETTE["warning_soft"], PALETTE["warning_soft"]),
+ "danger": (PALETTE["danger"], PALETTE["danger_soft"], PALETTE["danger_soft"]),
+ "neutral": (PALETTE["muted"], PALETTE["disabled_surface"], PALETTE["line"]),
}[kind]
font.setPixelSize(13)
painter.setFont(font)
@@ -2275,7 +2276,7 @@ class PatientOrdersWorkspace(QWidget):
self.keyword_edit.setMinimumWidth(240)
self.keyword_edit.setPlaceholderText("订单号 / 患者 / 手机号 / 处方ID / 诊单ID")
self.keyword_edit.setClearButtonEnabled(True)
- self.keyword_edit.addAction(icons.icon("search", "#5D6B80", 16), QLineEdit.ActionPosition.LeadingPosition)
+ self.keyword_edit.addAction(icons.icon("search", PALETTE["muted"], 16), QLineEdit.ActionPosition.LeadingPosition)
self.keyword_edit.returnPressed.connect(self.search)
self.filter_top_row.addWidget(self.keyword_edit, 1)
self.audit_host = QWidget()
@@ -2747,11 +2748,11 @@ class _ProgressInfoDelegate(QStyledItemDelegate):
painter.setClipRect(option.rect)
selected = bool(option.state & QStyle.StateFlag.State_Selected)
hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
- painter.fillRect(option.rect, QColor("#F2F7FF" if selected else "#F8FAFE" if hovered else "#FFFFFF"))
- painter.setPen(QColor("#E6EDF6"))
+ painter.fillRect(option.rect, QColor(PALETTE["accent_soft"] if selected else PALETTE["surface_alt"] if hovered else PALETTE["surface"]))
+ painter.setPen(QColor(PALETTE["line"]))
painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
if selected and index.column() == 0:
- painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor("#1769E8"))
+ painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor(PALETTE["accent"]))
rect = option.rect.adjusted(16, 0, -16, -1)
font = QFont(body_family())
font.setPixelSize(14)
@@ -2762,20 +2763,20 @@ class _ProgressInfoDelegate(QStyledItemDelegate):
painter.setFont(font)
raw_text = index.data(Qt.ItemDataRole.DisplayRole)
text = "" if raw_text is None else str(raw_text)
- color = "#273244"
+ color = PALETTE["text"]
if not self.schedule and index.column() == 5 and text and text != "—":
row = index.data(Qt.ItemDataRole.UserRole)
status = str(first_value(row, "queue_status", default="") or "").lower()
color = {
- "consulting": "#1769E8", "next": "#1555B6",
- "waiting": "#AD640C", "missed": "#BE4657",
- }.get(status, "#5D6B80")
+ "consulting": PALETTE["accent"], "next": PALETTE["accent_hover"],
+ "waiting": PALETTE["warning"], "missed": PALETTE["danger"],
+ }.get(status, PALETTE["muted"])
painter.setPen(QColor(color))
alignment = Qt.AlignmentFlag.AlignVCenter
alignment |= Qt.AlignmentFlag.AlignHCenter if self.schedule and 1 <= index.column() <= 5 else Qt.AlignmentFlag.AlignLeft
painter.drawText(rect, alignment, painter.fontMetrics().elidedText(text, Qt.TextElideMode.ElideRight, rect.width()))
if option.state & QStyle.StateFlag.State_HasFocus:
- painter.setPen(QColor("#75A5F0"))
+ painter.setPen(QColor(PALETTE["focus"]))
painter.setBrush(Qt.BrushStyle.NoBrush)
painter.drawRect(option.rect.adjusted(1, 1, -2, -2))
painter.restore()
@@ -2875,7 +2876,7 @@ class PatientProgressWorkspace(QWidget):
row = QHBoxLayout(frame)
row.setContentsMargins(0, 0, 0, 0)
row.setSpacing(0)
- divider = QFrame()
+ divider = QFrame(frame)
divider.setObjectName("ProgressMetricDivider")
divider.setFixedSize(1, 60)
divider.setVisible(key != "total")
diff --git a/app/src/doctor_workstation/ui/pages/prescription_library.py b/app/src/doctor_workstation/ui/pages/prescription_library.py
index e555800ab..3a6480cdb 100755
--- a/app/src/doctor_workstation/ui/pages/prescription_library.py
+++ b/app/src/doctor_workstation/ui/pages/prescription_library.py
@@ -24,6 +24,7 @@ from PySide6.QtWidgets import (
)
from .. import motion
+from ..design_system import PALETTE
from ..dialogs.prescription import PrescriptionTemplateDialog
from ..dialogs.prescription_ai import PrescriptionAiReportDialog, can_open_ai_explain
from ..filter_disclosure import FilterDisclosure
@@ -119,7 +120,7 @@ def _metric_card(title: str, kind: str = "accent", glyph: str = "layers") -> Met
icon.setProperty("metricIcon", True)
icon.setAlignment(Qt.AlignmentFlag.AlignCenter)
icon.setFixedSize(32, 32)
- color = "#1769E8" if kind == "accent" else "#60789F"
+ color = PALETTE["accent"] if kind == "accent" else PALETTE["muted"]
icon.setPixmap(_painted_icon(glyph, color, 25).pixmap(25, 25))
card.layout().addWidget(icon)
return card
@@ -543,7 +544,7 @@ class PrescriptionLibraryPage(QWidget):
name_item = self.table.item(row_index, 1)
if name_item is not None:
- name_item.setForeground(QColor("#1A1C1F"))
+ name_item.setForeground(QColor(PALETTE["heading"]))
font = name_item.font()
font.setWeight(QFont.Weight.Medium)
name_item.setFont(font)
diff --git a/app/src/doctor_workstation/ui/pages/prescriptions.py b/app/src/doctor_workstation/ui/pages/prescriptions.py
index 4bf9ba9dd..5a0a65f83 100755
--- a/app/src/doctor_workstation/ui/pages/prescriptions.py
+++ b/app/src/doctor_workstation/ui/pages/prescriptions.py
@@ -50,6 +50,7 @@ from PySide6.QtWidgets import (
)
from .. import icons, motion
+from ..design_system import PALETTE, clinical_stylesheet
from ..dialogs.issued_prescription_ai import (
PrescriptionAiStatisticsDialog,
agreement_safe_batch,
@@ -229,11 +230,11 @@ _ROLE_AVATAR = Qt.ItemDataRole.UserRole + 11
_ROLE_LEAD_ICON = Qt.ItemDataRole.UserRole + 12
_TAG_PALETTE = {
- "accent": ("#4F63D9", "#EEF1FA"),
- "success": ("#287B65", "#E7F8F1"),
- "warning": ("#A9691D", "#FFF5DF"),
- "danger": ("#BE4B58", "#FFF0F2"),
- "neutral": ("#606163", "#F7F7F7"),
+ "accent": (PALETTE["accent"], PALETTE["accent_soft"]),
+ "success": (PALETTE["success"], PALETTE["success_soft"]),
+ "warning": (PALETTE["warning"], PALETTE["warning_soft"]),
+ "danger": (PALETTE["danger"], PALETTE["danger_soft"]),
+ "neutral": (PALETTE["muted"], PALETTE["surface_alt"]),
}
@@ -293,7 +294,7 @@ class _RowDecorationDelegate(QStyledItemDelegate):
glyph,
QRectF(glyph.rect()),
)
- painter.setPen(QColor("#1A1C1F"))
+ painter.setPen(QColor(PALETTE["heading"]))
painter.setFont(style_option.font)
text_rect = rect.adjusted(28, 0, -8, 0)
painter.drawText(
@@ -306,17 +307,17 @@ class _RowDecorationDelegate(QStyledItemDelegate):
else:
initial = str(avatar)[:1] or "医"
circle = QRectF(rect.left() + 8, rect.center().y() - 10, 20, 20)
- painter.setPen(QPen(QColor("#EDEDEE"), 1.0))
- painter.setBrush(QColor("#F7F7F7"))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1.0))
+ painter.setBrush(QColor(PALETTE["surface_alt"]))
painter.drawEllipse(circle.adjusted(0.5, 0.5, -0.5, -0.5))
initial_font = QFont(style_option.font)
initial_font.setPixelSize(10)
initial_font.setWeight(QFont.Weight.Medium)
painter.setFont(initial_font)
- painter.setPen(QColor("#6A6B6D"))
+ painter.setPen(QColor(PALETTE["muted"]))
painter.drawText(circle, Qt.AlignmentFlag.AlignCenter, initial)
painter.setFont(style_option.font)
- painter.setPen(QColor("#1A1C1F"))
+ painter.setPen(QColor(PALETTE["heading"]))
name_rect = rect.adjusted(35, 0, -8, 0)
painter.drawText(
name_rect,
@@ -509,11 +510,11 @@ class _PrescriptionNumberDelegate(QStyledItemDelegate):
text_option.setWrapMode(QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere)
document.setDefaultTextOption(text_option)
paragraphs = [
- f'{escape(number)}
',
- f'ID: {escape(record_id)}
',
+ f'{escape(number)}
',
+ f'ID: {escape(record_id)}
',
]
paragraphs.extend(
- ''
+ f'
'
+ escape(warning)
+ "
"
for warning in _order_warnings(row)
@@ -603,14 +604,14 @@ class _DoctorOptionDelegate(QStyledItemDelegate):
rect = option.rect.adjusted(2, 1, -2, -1)
hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#EAF2FF" if checked else "#F3F7FD" if hovered else "#FFFFFF"))
+ painter.setBrush(QColor(PALETTE["accent_soft"] if checked else PALETTE["canvas"] if hovered else PALETTE["surface"]))
painter.drawRoundedRect(rect, 5, 5)
box = QRectF(rect.left() + 10, rect.center().y() - 8, 16, 16)
- painter.setPen(QPen(QColor("#1769E8" if checked else "#B8C7DA"), 1))
- painter.setBrush(QColor("#1769E8" if checked else "#FFFFFF"))
+ painter.setPen(QPen(QColor(PALETTE["accent"] if checked else PALETTE["line_strong"]), 1))
+ painter.setBrush(QColor(PALETTE["accent"] if checked else PALETTE["surface"]))
painter.drawRoundedRect(box, 3, 3)
if checked:
- pen = QPen(QColor("#FFFFFF"), 2)
+ pen = QPen(QColor(PALETTE["surface"]), 2)
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
painter.setPen(pen)
x, y = int(box.x()), int(box.y())
@@ -619,16 +620,16 @@ class _DoctorOptionDelegate(QStyledItemDelegate):
font = QFont(body_family())
font.setPixelSize(13)
painter.setFont(font)
- painter.setPen(QColor("#273244"))
+ painter.setPen(QColor(PALETTE["text"]))
text_rect = rect.adjusted(38, 0, -54, 0)
label = painter.fontMetrics().elidedText(str(index.data() or ""), Qt.TextElideMode.ElideRight, text_rect.width())
painter.drawText(text_rect, Qt.AlignmentFlag.AlignVCenter, label)
if checked:
- painter.setPen(QColor("#1769E8"))
+ painter.setPen(QColor(PALETTE["accent"]))
painter.drawText(rect.adjusted(0, 0, -12, 0), Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter, "已选")
if option.state & QStyle.StateFlag.State_HasFocus:
painter.setBrush(Qt.BrushStyle.NoBrush)
- painter.setPen(QPen(QColor("#ADC8F2"), 1))
+ painter.setPen(QPen(QColor(PALETTE["line_strong"]), 1))
painter.drawRoundedRect(rect, 5, 5)
painter.restore()
@@ -674,18 +675,18 @@ class _DoctorSelectionDialog(QDialog):
self.setObjectName("DoctorSelectionDialog")
self.setWindowTitle("选择医生")
self.resize(420, 500)
- self.setStyleSheet("""
- QDialog#DoctorSelectionDialog { background: #FFFFFF; color: #273244; }
- QListWidget#DoctorOptionsList { background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 6px; padding: 3px; }
- QLabel#DoctorSelectionCount { color: #1769E8; font-size: 13px; }
- QDialog#DoctorSelectionDialog QLineEdit { border: 1px solid #DBE5F2; border-radius: 6px; }
- QDialog#DoctorSelectionDialog QLineEdit:focus { border-color: #1769E8; }
- QDialog#DoctorSelectionDialog QPushButton { background: #FFFFFF; color: #273244; border: 1px solid #DBE5F2; border-radius: 6px; }
- QDialog#DoctorSelectionDialog QPushButton:hover { background: #F3F7FD; border-color: #ADC8F2; }
- QDialog#DoctorSelectionDialog QPushButton:disabled { color: #8A97A9; }
- QDialog#DoctorSelectionDialog QPushButton#ConfirmDoctorSelection { background: #1769E8; color: #FFFFFF; border-color: #1769E8; }
- QDialog#DoctorSelectionDialog QPushButton#ConfirmDoctorSelection:hover { background: #125DCE; border-color: #125DCE; }
- """)
+ self.setStyleSheet(clinical_stylesheet("""
+ QDialog#DoctorSelectionDialog { background: $ds_surface; color: $ds_text; }
+ QListWidget#DoctorOptionsList { background: $ds_surface; border: 1px solid $ds_line; border-radius: 6px; padding: 3px; }
+ QLabel#DoctorSelectionCount { color: $ds_accent; font-size: 13px; }
+ QDialog#DoctorSelectionDialog QLineEdit { border: 1px solid $ds_line; border-radius: 6px; }
+ QDialog#DoctorSelectionDialog QLineEdit:focus { border-color: $ds_accent; }
+ QDialog#DoctorSelectionDialog QPushButton { background: $ds_surface; color: $ds_text; border: 1px solid $ds_line; border-radius: 6px; }
+ QDialog#DoctorSelectionDialog QPushButton:hover { background: $ds_canvas; border-color: $ds_line_strong; }
+ QDialog#DoctorSelectionDialog QPushButton:disabled { color: $ds_disabled; }
+ QDialog#DoctorSelectionDialog QPushButton#ConfirmDoctorSelection { background: $ds_accent; color: $ds_surface; border-color: $ds_accent; }
+ QDialog#DoctorSelectionDialog QPushButton#ConfirmDoctorSelection:hover { background: $ds_accent_hover; border-color: $ds_accent_hover; }
+ """))
layout = QVBoxLayout(self)
layout.setContentsMargins(16, 16, 16, 16)
layout.setSpacing(10)
@@ -793,9 +794,9 @@ class DoctorMultiSelect(QWidget):
self.button.setText("、".join(names[:2]) + (f" 等{len(names)}人" if len(names) > 2 else ""))
-def _blue_prescription_icon(kind: str, color: str = "#1769E8", size: int = 15) -> QIcon:
+def _blue_prescription_icon(kind: str, color: str = PALETTE["accent"], size: int = 15) -> QIcon:
result = QIcon(icons.icon(kind, color, size))
- result.addPixmap(icons.pixmap(kind, "#A4ADBA", size), QIcon.Mode.Disabled)
+ result.addPixmap(icons.pixmap(kind, PALETTE["disabled"], size), QIcon.Mode.Disabled)
return result
@@ -803,7 +804,7 @@ class _PrescriptionCombo(QComboBox):
def paintEvent(self, event: Any) -> None:
super().paintEvent(event)
painter = QPainter(self)
- glyph = icons.pixmap("chevron_down", "#5D6B80", 14)
+ glyph = icons.pixmap("chevron_down", PALETTE["muted"], 14)
painter.drawPixmap(QRectF(self.width() - 25, (self.height() - 14) / 2, 14, 14), glyph, QRectF(glyph.rect()))
painter.end()
@@ -812,7 +813,7 @@ class _PrescriptionDateTime(QDateTimeEdit):
def paintEvent(self, event: Any) -> None:
super().paintEvent(event)
painter = QPainter(self)
- glyph = icons.pixmap("calendar", "#5D6B80" if self.isEnabled() else "#8A97A9", 14)
+ glyph = icons.pixmap("calendar", PALETTE["muted"] if self.isEnabled() else PALETTE["disabled"], 14)
painter.drawPixmap(QRectF(self.width() - 25, (self.height() - 14) / 2, 14, 14), glyph, QRectF(glyph.rect()))
painter.end()
@@ -825,7 +826,7 @@ class _PrescriptionDoctorButton(QPushButton):
option.text = self.fontMetrics().elidedText(self.text(), Qt.TextElideMode.ElideRight, max(1, self.width() - 48))
painter = QPainter(self)
self.style().drawControl(QStyle.ControlElement.CE_PushButton, option, painter, self)
- glyph = icons.pixmap("chevron_down", "#5D6B80", 14)
+ glyph = icons.pixmap("chevron_down", PALETTE["muted"], 14)
painter.drawPixmap(QRectF(self.width() - 25, (self.height() - 14) / 2, 14, 14), glyph, QRectF(glyph.rect()))
painter.end()
@@ -837,13 +838,13 @@ class _PrescriptionDoctorButton(QPushButton):
def _prescription_cell_background(painter: QPainter, option: Any, index: QModelIndex) -> None:
selected = bool(option.state & QStyle.StateFlag.State_Selected)
hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
- painter.fillRect(option.rect, QColor("#F2F7FF" if selected else "#F8FAFE" if hovered else "#FFFFFF"))
- painter.setPen(QColor("#E6EDF6"))
+ painter.fillRect(option.rect, QColor(PALETTE["accent_soft"] if selected else PALETTE["surface_alt"] if hovered else PALETTE["surface"]))
+ painter.setPen(QColor(PALETTE["line"]))
painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
if selected and index.column() == 0:
- painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor("#1769E8"))
+ painter.fillRect(option.rect.adjusted(0, 0, -option.rect.width() + 3, 0), QColor(PALETTE["accent"]))
if option.state & QStyle.StateFlag.State_HasFocus:
- painter.setPen(QColor("#75A5F0"))
+ painter.setPen(QColor(PALETTE["focus"]))
painter.setBrush(Qt.BrushStyle.NoBrush)
painter.drawRect(option.rect.adjusted(1, 1, -2, -2))
@@ -875,7 +876,7 @@ class _PrescriptionInfoDelegate(QStyledItemDelegate):
font = QFont(body_family())
font.setPixelSize(14)
painter.setFont(font)
- painter.setPen(QColor("#273244"))
+ painter.setPen(QColor(PALETTE["text"]))
text = str(index.data(Qt.ItemDataRole.DisplayRole) or "")
column = index.column()
if column == 0:
@@ -888,9 +889,9 @@ class _PrescriptionInfoDelegate(QStyledItemDelegate):
elif column in (3, 6):
kind = index.data(_ROLE_TAG_KIND)
foreground, background = {
- "accent": ("#1769E8", "#EDF4FF"), "success": ("#1769E8", "#EDF4FF"),
- "warning": ("#AD640C", "#FFF5E5"), "danger": ("#BE4657", "#FFF0F2"),
- }.get(kind, ("#5D6B80", "#F5F8FD"))
+ "accent": (PALETTE["accent"], PALETTE["accent_soft"]), "success": (PALETTE["accent"], PALETTE["accent_soft"]),
+ "warning": (PALETTE["warning"], PALETTE["warning_soft"]), "danger": (PALETTE["danger"], PALETTE["danger_soft"]),
+ }.get(kind, (PALETTE["muted"], PALETTE["surface_alt"]))
font.setPixelSize(13)
painter.setFont(font)
label = painter.fontMetrics().elidedText(text, Qt.TextElideMode.ElideRight, max(1, rect.width() - 12))
@@ -918,7 +919,7 @@ class _PrescriptionInfoDelegate(QStyledItemDelegate):
font = QFont(body_family())
font.setPixelSize(13)
painter.setFont(font)
- painter.setPen(QColor("#5D6B80"))
+ painter.setPen(QColor(PALETTE["muted"]))
second_rect = first_rect.translated(0, 26)
painter.drawText(second_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, painter.fontMetrics().elidedText(secondary, Qt.TextElideMode.ElideRight, rect.width()))
else:
@@ -942,11 +943,11 @@ class _PrescriptionNumberBlueDelegate(_PrescriptionNumberDelegate):
text_option.setWrapMode(QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere)
document.setDefaultTextOption(text_option)
paragraphs = [
- f'{escape(number)}
',
- f'ID: {escape(record_id)}
',
+ f'{escape(number)}
',
+ f'ID: {escape(record_id)}
',
]
paragraphs.extend(
- '' + escape(warning) + "
"
+ f'' + escape(warning) + "
"
for warning in _order_warnings(row)
)
document.setHtml("".join(paragraphs))
@@ -976,7 +977,7 @@ class _PrescriptionBlueTable(SortableTable):
for button in widget.findChildren(QPushButton):
kind = {"查看处方": "eye", "编辑处方": "pencil", "删除处方": "trash"}.get(button.accessibleName())
if kind:
- button.setIcon(_blue_prescription_icon(kind, "#BE4657" if kind == "trash" else "#1769E8"))
+ button.setIcon(_blue_prescription_icon(kind, PALETTE["danger"] if kind == "trash" else PALETTE["accent"]))
class PrescriptionsPage(QWidget):
@@ -1060,7 +1061,7 @@ class PrescriptionsPage(QWidget):
self.add_button.setObjectName("PrescriptionAddButton")
self.add_button.setMinimumWidth(122)
self.add_button.setProperty("variant", "primary")
- self.add_button.setIcon(_blue_prescription_icon("plus", "#FFFFFF"))
+ self.add_button.setIcon(_blue_prescription_icon("plus", PALETTE["surface"]))
self.add_button.setIconSize(QSize(15, 15))
self.add_button.setCursor(Qt.CursorShape.PointingHandCursor)
self.add_button.setVisible(has_permission(permissions, "cf.prescription/add"))
@@ -1079,7 +1080,7 @@ class PrescriptionsPage(QWidget):
self.table_card = table_card
root.addWidget(table_card, 1)
for button, kind in ((self.view_button, "eye"), (self.edit_button, "pencil"), (self.delete_button, "trash")):
- button.setIcon(_blue_prescription_icon(kind, "#BE4657" if kind == "trash" else "#1769E8"))
+ button.setIcon(_blue_prescription_icon(kind, PALETTE["danger"] if kind == "trash" else PALETTE["accent"]))
self._load_doctor_options()
def _build_filters(self) -> QWidget:
@@ -1226,7 +1227,7 @@ class PrescriptionsPage(QWidget):
refresh = QPushButton("刷新")
refresh.setProperty("variant", "ghost")
refresh.setCursor(Qt.CursorShape.PointingHandCursor)
- refresh.setIcon(_blue_prescription_icon("refresh", "#5D6B80"))
+ refresh.setIcon(_blue_prescription_icon("refresh", PALETTE["muted"]))
refresh.setIconSize(QSize(15, 15))
refresh.clicked.connect(self.refresh)
toolbar.addWidget(refresh)
@@ -1287,7 +1288,7 @@ class PrescriptionsPage(QWidget):
self.table.setItemDelegate(_PrescriptionInfoDelegate(self.table))
self.table.setItemDelegateForColumn(1, _PrescriptionNumberBlueDelegate(self.table))
self.table.horizontalHeader().sectionResized.connect(self._number_column_resized)
- self.table.horizontalHeaderItem(0).setIcon(_blue_prescription_icon("checkbox", "#8A97A9", 14))
+ self.table.horizontalHeaderItem(0).setIcon(_blue_prescription_icon("checkbox", PALETTE["disabled"], 14))
self.table.horizontalHeaderItem(0).setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.table.itemSelectionChanged.connect(self._selection_changed)
self.table.itemDoubleClicked.connect(lambda _item: self._view_selected())
@@ -1537,7 +1538,7 @@ class PrescriptionsPage(QWidget):
sn_item = self.table.item(row_index, 1)
if sn_item is not None:
- sn_item.setForeground(QColor("#1A1C1F"))
+ sn_item.setForeground(QColor(PALETTE["heading"]))
font = sn_item.font()
font.setWeight(QFont.Weight.Normal)
sn_item.setFont(font)
diff --git a/app/src/doctor_workstation/ui/pages/reception.py b/app/src/doctor_workstation/ui/pages/reception.py
index cb13eaae5..ea58bc6c2 100755
--- a/app/src/doctor_workstation/ui/pages/reception.py
+++ b/app/src/doctor_workstation/ui/pages/reception.py
@@ -75,6 +75,7 @@ from PySide6.QtWidgets import (
from ...core.appointment_modes import appointment_type_description, appointment_type_value
from .. import icons
+from ..design_system import PALETTE, clinical_stylesheet
from ..diagnosis_drawer import DailyRecordPanel
from ..diagnosis_editors import FlowLayout
from ..dialogs import DiagnosisDialog
@@ -2020,7 +2021,7 @@ def _painted_reception_tab_icon(kind: str, size: int = 16) -> QIcon:
outline (bubble / chart page / capsule / clipboard / calendar-clock).
"""
- return icons.icon(kind, "#5D6B80", size)
+ return icons.icon(kind, PALETTE["muted"], size)
def _painted_reception_action_icon(kind: str, color: str, size: int = 14) -> QIcon:
@@ -2882,7 +2883,7 @@ class _ReceptionSparkIcon(QWidget):
del event
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- glyph = icons.pixmap("ai", "#1769E8", 18)
+ glyph = icons.pixmap("ai", PALETTE["accent"], 18)
painter.drawPixmap(QRectF(0, 0, 18, 18), glyph, QRectF(glyph.rect()))
painter.end()
@@ -2896,9 +2897,9 @@ class _ReceptionAiSectionIcon(QWidget):
#: Section tone -> (plate, glyph tint, shared glyph name).
_TONES = {
- "diagnosis": ("#EAF2FF", "#1769E8", "report"),
- "risk": ("#EAF2FF", "#1769E8", "alert"),
- "treatment": ("#EAF2FF", "#1769E8", "meds"),
+ "diagnosis": (PALETTE["accent_soft"], PALETTE["accent"], "report"),
+ "risk": (PALETTE["accent_soft"], PALETTE["accent"], "alert"),
+ "treatment": (PALETTE["accent_soft"], PALETTE["accent"], "meds"),
}
def __init__(self, tone: str, parent: QWidget | None = None) -> None:
@@ -2949,9 +2950,9 @@ class _ReceptionAssistantIcon(QWidget):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#1769E8"))
+ painter.setBrush(QColor(PALETTE["accent"]))
painter.drawRoundedRect(QRectF(1, 1, 22, 22), 4, 4)
- painter.setPen(QColor("#FFFFFF"))
+ painter.setPen(QColor(PALETTE["surface"]))
font = painter.font()
font.setPixelSize(11)
font.setBold(True)
@@ -2975,7 +2976,7 @@ class _ReceptionSendButton(QPushButton):
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(
QPen(
- QColor("#FFFFFF"),
+ QColor(PALETTE["surface"]),
1.8,
Qt.PenStyle.SolidLine,
Qt.PenCapStyle.RoundCap,
@@ -3053,7 +3054,7 @@ class _ReceptionDateButton(QPushButton):
super().paintEvent(event)
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- color = QColor("#5D6B80")
+ color = QColor(PALETTE["muted"])
painter.setPen(
QPen(
color,
@@ -3087,7 +3088,7 @@ class _ReceptionAiExpandButton(QPushButton):
del event
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- color = QColor("#1769E8" if self.isEnabled() else "#8E8F90")
+ color = QColor(PALETTE["accent"] if self.isEnabled() else PALETTE["disabled"])
painter.setPen(
QPen(
color,
@@ -3120,7 +3121,7 @@ class _ReceptionAiModelCombo(QComboBox):
super().paintEvent(event)
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- color = QColor("#273244" if self.isEnabled() else "#8E8F90")
+ color = QColor(PALETTE["text"] if self.isEnabled() else PALETTE["disabled"])
painter.setPen(
QPen(
color,
@@ -3162,7 +3163,7 @@ class _ReceptionAiAnalysisDialog(QDialog):
self.resize(920, 760)
self.setMinimumSize(720, 560)
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
- self.setStyleSheet(RECEPTION_AI_DIALOG_QSS)
+ self.setStyleSheet(clinical_stylesheet(RECEPTION_AI_DIALOG_QSS))
root = QVBoxLayout(self)
root.setContentsMargins(18, 18, 18, 18)
@@ -3365,7 +3366,11 @@ class _ReceptionAiAnalysisDialog(QDialog):
source_label.setTextFormat(Qt.TextFormat.PlainText)
source_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
source_label.setWordWrap(True)
- source_label.setStyleSheet("color: #555B68; font-size: 12px; padding: 10px 14px; background: #F7F8FC; border: 1px solid #E4E8F2; border-radius: 8px;")
+ source_label.setStyleSheet(clinical_stylesheet(
+ "color: $ds_muted; font-size: 12px; padding: 10px 14px; "
+ "background: $ds_surface_alt; border: 1px solid $ds_line; "
+ "border-radius: $ds_radius_control;"
+ ))
body_layout.addWidget(source_label)
self.source_label = source_label
body_layout.addStretch(1)
@@ -3614,9 +3619,9 @@ class _VitalMetricIcon(QWidget):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#EAF2FF"))
+ painter.setBrush(QColor(PALETTE["accent_soft"]))
painter.drawRoundedRect(QRectF(0, 0, 22, 22), 6, 6)
- glyph = icons.pixmap(self._GLYPHS.get(self._kind, "pulse"), "#1769E8", 15)
+ glyph = icons.pixmap(self._GLYPHS.get(self._kind, "pulse"), PALETTE["accent"], 15)
painter.drawPixmap(QRectF(3.5, 3.5, 15, 15), glyph, QRectF(glyph.rect()))
painter.end()
@@ -3636,7 +3641,7 @@ class _LifestyleIcon(QWidget):
del event
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- glyph = icons.pixmap(self._GLYPHS.get(self._kind, "exercise"), "#5D6B80", 16)
+ glyph = icons.pixmap(self._GLYPHS.get(self._kind, "exercise"), PALETTE["muted"], 16)
painter.drawPixmap(QRectF(0, 0, 16, 16), glyph, QRectF(glyph.rect()))
painter.end()
@@ -3672,7 +3677,7 @@ class _GenderMark(QWidget):
return
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- pen = QPen(QColor("#5D6B80"), 1.35)
+ pen = QPen(QColor(PALETTE["muted"]), 1.35)
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)
painter.setPen(pen)
@@ -3737,7 +3742,7 @@ class _ReceptionQueueSpinner(QWidget):
del event
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
- pen = QPen(QColor("#1769E8"), 2.2)
+ pen = QPen(QColor(PALETTE["accent"]), 2.2)
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
painter.setPen(pen)
painter.drawArc(QRectF(2, 2, 14, 14), self._angle * 16, 250 * 16)
@@ -3873,15 +3878,15 @@ class QueueRow(QWidget):
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
rect = QRectF(self.rect()).adjusted(0.5, 0.5, -0.5, -0.5)
if self._selected:
- painter.setBrush(QColor("#EAF2FF"))
- painter.setPen(QPen(QColor("#E5ECF6"), 1))
+ painter.setBrush(QColor(PALETTE["accent_soft"]))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1))
else:
- painter.setBrush(QColor("#FFFFFF"))
- painter.setPen(QPen(QColor("#E5ECF6"), 1))
- painter.drawRoundedRect(rect, 6, 6)
+ painter.setBrush(QColor(PALETTE["surface"]))
+ painter.setPen(QPen(QColor(PALETTE["line"]), 1))
+ painter.drawRoundedRect(rect, 10, 10)
if self._selected:
painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#1769E8"))
+ painter.setBrush(QColor(PALETTE["accent"]))
painter.drawRoundedRect(QRectF(1.2, 1, 3.2, self.height() - 2), 1.6, 1.6)
@@ -4074,7 +4079,7 @@ class ReceptionDailyRecordsPanel(DailyRecordPanel):
font = item.font()
font.setWeight(QFont.Weight.DemiBold if high else QFont.Weight.Normal)
item.setFont(font)
- item.setForeground(QBrush(QColor("#BE4B58" if high else "#273244")))
+ item.setForeground(QBrush(QColor(PALETTE["danger"] if high else PALETTE["text"])))
item.setBackground(
QBrush(
QColor(
@@ -4103,9 +4108,11 @@ class ReceptionPage(QWidget):
super().__init__(parent)
self.setObjectName("ReceptionPage")
self.setStyleSheet(
- (RECEPTION_QSS + RECEPTION_WORKSPACE_QSS).replace("$body_family", body_family())
- .replace("$heading_family", heading_family())
- .replace("$number_family", number_family())
+ clinical_stylesheet(
+ (RECEPTION_QSS + RECEPTION_WORKSPACE_QSS).replace("$body_family", body_family())
+ .replace("$heading_family", heading_family())
+ .replace("$number_family", number_family())
+ )
)
self.repository = repository
self.permissions = permissions
@@ -4262,7 +4269,7 @@ class ReceptionPage(QWidget):
header_layout.addWidget(title)
header_layout.addStretch(1)
self.refresh_button = QPushButton("", header)
- self.refresh_button.setIcon(icons.icon("refresh", "#5D6B80", 18))
+ self.refresh_button.setIcon(icons.icon("refresh", PALETTE["muted"], 18))
self.refresh_button.setObjectName("ReceptionRefreshButton")
self.refresh_button.setFixedSize(34, 32)
self.refresh_button.setAccessibleName("刷新接诊台")
@@ -4454,7 +4461,7 @@ class ReceptionPage(QWidget):
self.video_button.clicked.connect(self._request_video)
actions.addWidget(self.video_button)
self.more_button = QPushButton(hero)
- self.more_button.setIcon(icons.icon("more", "#5D6B80", 16))
+ self.more_button.setIcon(icons.icon("more", PALETTE["muted"], 16))
self.more_button.setIconSize(QSize(16, 16))
self.more_button.setToolTip("更多操作")
self.more_button.setAccessibleName("更多操作")
@@ -5286,7 +5293,9 @@ class ReceptionPage(QWidget):
self.ai_source_label.setTextFormat(Qt.TextFormat.PlainText)
self.ai_source_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
self.ai_source_label.setWordWrap(True)
- self.ai_source_label.setStyleSheet("color: #5B6474; font-size: 11px;")
+ self.ai_source_label.setStyleSheet(clinical_stylesheet(
+ "color: $ds_muted; font-size: 12px;"
+ ))
analysis_layout.addWidget(self.ai_source_label)
self.ai_detail_actions_host = QWidget(analysis_card)
diff --git a/app/src/doctor_workstation/ui/patient_orders_style.py b/app/src/doctor_workstation/ui/patient_orders_style.py
index 925e55d43..89d11ce25 100755
--- a/app/src/doctor_workstation/ui/patient_orders_style.py
+++ b/app/src/doctor_workstation/ui/patient_orders_style.py
@@ -1,119 +1,126 @@
-"""Scoped surfaces for the approved patient order-management workspace."""
-
-from string import Template
-
-from .reception_style import body_family
-
-
-def patient_orders_stylesheet() -> str:
- return Template(_ORDERS).substitute(body=body_family())
-
-
-_ORDERS = """
-#PatientOrdersWorkspace { background: transparent; color: #273244; }
-#OrderWorkspaceContent, #OrderWorkspaceScroll { background: transparent; border: 0; }
-#PatientOrdersWorkspace QLabel, #PatientOrdersWorkspace QPushButton,
-#PatientOrdersWorkspace QToolButton, #PatientOrdersWorkspace QLineEdit,
-#PatientOrdersWorkspace QComboBox, #PatientOrdersWorkspace QDateEdit,
-#PatientOrdersWorkspace QCheckBox, #PatientOrdersWorkspace QTableWidget {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
-}
-#PatientOrdersWorkspace QLabel[role="muted"] { font-size: 13px; color: #5D6B80; }
-#PatientOrdersWorkspace QFrame#OrderFilterCard,
-#PatientOrdersWorkspace QFrame#OrderSummaryStrip,
-#PatientOrdersWorkspace QFrame#OrderTableCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
-}
-#PatientOrdersWorkspace QPushButton, #PatientOrdersWorkspace QToolButton {
- min-height: 38px; max-height: 38px; padding: 0 16px; border: 1px solid #DBE5F2;
- border-radius: 5px; background: #FFFFFF; color: #273244;
-}
-#PatientOrdersWorkspace QPushButton:hover, #PatientOrdersWorkspace QToolButton:hover {
- background: #F2F7FF; border-color: #B6CDEE; color: #1555B6;
-}
-#PatientOrdersWorkspace QPushButton:pressed, #PatientOrdersWorkspace QToolButton:pressed { background: #DCEAFF; }
-#PatientOrdersWorkspace QPushButton:focus, #PatientOrdersWorkspace QToolButton:focus { border-color: #75A5F0; }
-#PatientOrdersWorkspace QPushButton#OrderSearchButton,
-#PatientOrdersWorkspace QPushButton#OrderDetailButton {
- color: #FFFFFF; background: #1769E8; border-color: #1769E8;
-}
-#PatientOrdersWorkspace QPushButton#OrderSearchButton:hover,
-#PatientOrdersWorkspace QPushButton#OrderDetailButton:hover { background: #155BCC; border-color: #155BCC; }
-#PatientOrdersWorkspace QPushButton:disabled, #PatientOrdersWorkspace QToolButton:disabled {
- color: #97A4B6; background: #F6F8FC; border-color: #E2E9F2;
-}
-#PatientOrdersWorkspace QLineEdit, #PatientOrdersWorkspace QComboBox,
-#PatientOrdersWorkspace QDateEdit {
- min-height: 38px; max-height: 38px; padding: 0 10px; font-size: 13px;
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 5px;
- selection-background-color: #DCEAFF; selection-color: #273244;
-}
-#PatientOrdersWorkspace QLineEdit:focus, #PatientOrdersWorkspace QComboBox:focus,
-#PatientOrdersWorkspace QDateEdit:focus { border-color: #75A5F0; }
-#PatientOrdersWorkspace QLineEdit QToolButton {
- min-height: 0; max-height: 24px; min-width: 0; border: 0; padding: 0; background: transparent;
-}
-#PatientOrdersWorkspace QComboBox { padding-right: 30px; }
-#PatientOrdersWorkspace QComboBox::drop-down { border: 0; width: 28px; background: transparent; }
-#PatientOrdersWorkspace QComboBox::down-arrow { image: none; width: 0; height: 0; }
-#PatientOrdersWorkspace QComboBox QAbstractItemView {
- font-family: "$body"; font-size: 13px; color: #273244; background: #FFFFFF;
- border: 1px solid #DBE5F2; outline: 0; selection-background-color: #EAF2FF; selection-color: #1555B6;
-}
-#PatientOrdersWorkspace QComboBox QAbstractItemView::item { min-height: 30px; padding: 3px 10px; }
-#PatientOrdersWorkspace QDateEdit { padding-right: 26px; }
-#PatientOrdersWorkspace QDateEdit::drop-down { border: 0; width: 24px; background: transparent; }
-#PatientOrdersWorkspace QDateEdit::down-arrow { image: none; width: 0; height: 0; }
-#PatientOrdersWorkspace QDateEdit:disabled { color: #8A97A9; background: #F6F8FC; border-color: #E2E9F2; }
-#PatientOrdersWorkspace QCalendarWidget {
- font-family: "$body"; font-size: 13px; background: #FFFFFF; color: #273244;
-}
-#PatientOrdersWorkspace QCalendarWidget QWidget#qt_calendar_navigationbar { background: #F5F8FD; }
-#PatientOrdersWorkspace QCalendarWidget QToolButton {
- min-height: 28px; max-height: 28px; padding: 0 8px; border: 0; background: transparent;
- font-family: "$body"; font-size: 13px; color: #273244;
-}
-#PatientOrdersWorkspace QCalendarWidget QToolButton:hover { background: #EAF2FF; }
-#PatientOrdersWorkspace QCalendarWidget QAbstractItemView {
- font-family: "$body"; font-size: 13px; background: #FFFFFF; alternate-background-color: #FFFFFF;
- color: #273244; selection-background-color: #1769E8; selection-color: #FFFFFF; outline: 0;
-}
-#PatientOrdersWorkspace QCheckBox { spacing: 9px; font-size: 13px; }
-#PatientOrdersWorkspace QCheckBox::indicator {
- width: 15px; height: 15px; border: 1px solid #C5D5EB; border-radius: 3px; background: #FFFFFF;
-}
-#PatientOrdersWorkspace QCheckBox::indicator:checked { background: #1769E8; border-color: #1769E8; }
-#PatientOrdersWorkspace QCheckBox::indicator:hover { border-color: #75A5F0; }
-#PatientOrdersWorkspace QCheckBox:focus { color: #1555B6; }
-#PatientOrdersWorkspace QFrame#OrderMetricCell { background: transparent; border: 0; }
-#PatientOrdersWorkspace QFrame#OrderMetricDivider { border: 0; background: #DBE5F2; }
-#PatientOrdersWorkspace QLabel[orderMetricCaption="true"] { color: #5D6B80; font-size: 13px; }
-#PatientOrdersWorkspace QLabel[orderMetricValue="true"] { color: #273244; font-size: 18px; font-weight: 500; }
-#PatientOrdersWorkspace QLabel#OrderAmountMetric { color: #1769E8; }
-#PatientOrdersWorkspace QLabel[role="sectionTitle"] { font-size: 14px; font-weight: 600; }
-#PatientOrdersWorkspace QTableWidget#OrderTable {
- border: 1px solid #E6EDF6; border-radius: 0; background: #FFFFFF; alternate-background-color: #FFFFFF;
- selection-background-color: #F5F8FF; selection-color: #273244; gridline-color: #E6EDF6;
-}
-#PatientOrdersWorkspace QTableWidget#OrderTable::item { padding: 0; border: 0; }
-#PatientOrdersWorkspace QTableWidget#OrderTable QHeaderView::section {
- min-height: 44px; padding: 0 16px; background: #F8FAFD; color: #5D6B80;
- border: 0; border-bottom: 1px solid #E1E9F4;
- font-family: "$body"; font-size: 13px; font-weight: 400;
-}
-#PatientOrdersWorkspace QWidget#OrderActionBar { background: #FFFFFF; }
-#PatientOrdersWorkspace QToolButton#OrderActionButton { padding-right: 28px; }
-#PatientOrdersWorkspace QToolButton#OrderActionButton::menu-indicator { image: none; width: 0; height: 0; }
-#PatientOrdersWorkspace QWidget#InfiniteList { background: #FFFFFF; border-top: 1px solid #E6EDF6; }
-#PatientOrdersWorkspace QMenu, QMenu#OrderActionMenu {
- font-family: "$body"; font-size: 13px; color: #273244; background: #FFFFFF;
- border: 1px solid #DBE5F2; padding: 5px;
-}
-#PatientOrdersWorkspace QMenu::item, QMenu#OrderActionMenu::item { padding: 8px 24px; }
-#PatientOrdersWorkspace QMenu::item:selected, QMenu#OrderActionMenu::item:selected { color: #1555B6; background: #EAF2FF; }
-#PatientOrdersWorkspace QScrollBar:vertical { background: #F4F7FC; width: 7px; margin: 0; }
-#PatientOrdersWorkspace QScrollBar:horizontal { background: #F4F7FC; height: 7px; margin: 0; }
-#PatientOrdersWorkspace QScrollBar::handle { background: #C8D5E6; border-radius: 3px; min-width: 24px; min-height: 24px; }
-#PatientOrdersWorkspace QScrollBar::add-line, #PatientOrdersWorkspace QScrollBar::sub-line { width: 0; height: 0; }
-#PatientOrdersWorkspace QScrollBar::add-page, #PatientOrdersWorkspace QScrollBar::sub-page { background: transparent; }
-"""
+"""Scoped surfaces for the approved patient order-management workspace."""
+
+from string import Template
+
+from .design_system import clinical_stylesheet
+from .reception_style import body_family
+
+
+def patient_orders_stylesheet() -> str:
+ return clinical_stylesheet(Template(_ORDERS).safe_substitute(body=body_family()))
+
+
+_ORDERS = """
+#PatientOrdersWorkspace { background: transparent; color: $ds_text; }
+#OrderWorkspaceContent, #OrderWorkspaceScroll { background: transparent; border: 0; }
+#PatientOrdersWorkspace QLabel, #PatientOrdersWorkspace QPushButton,
+#PatientOrdersWorkspace QToolButton, #PatientOrdersWorkspace QLineEdit,
+#PatientOrdersWorkspace QComboBox, #PatientOrdersWorkspace QDateEdit,
+#PatientOrdersWorkspace QCheckBox, #PatientOrdersWorkspace QTableWidget {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+}
+#PatientOrdersWorkspace QLabel[role="muted"] { font-size: 13px; color: $ds_muted; }
+#PatientOrdersWorkspace QFrame#OrderFilterCard,
+#PatientOrdersWorkspace QFrame#OrderTableCard {
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PatientOrdersWorkspace QFrame#OrderSummaryStrip { background: transparent; border: 0; }
+#PatientOrdersWorkspace QPushButton, #PatientOrdersWorkspace QToolButton {
+ min-height: 38px; max-height: 38px; padding: 0 16px; border: 1px solid transparent;
+ border-radius: $ds_radius_control; background: $ds_surface_alt; color: $ds_text;
+}
+#PatientOrdersWorkspace QPushButton:hover, #PatientOrdersWorkspace QToolButton:hover {
+ background: $ds_surface_alt; border-color: $ds_line_strong; color: $ds_accent;
+}
+#PatientOrdersWorkspace QPushButton:pressed, #PatientOrdersWorkspace QToolButton:pressed { background: $ds_accent_soft; }
+#PatientOrdersWorkspace QPushButton:focus, #PatientOrdersWorkspace QToolButton:focus { border-color: $ds_focus; }
+#PatientOrdersWorkspace QPushButton#OrderSearchButton,
+#PatientOrdersWorkspace QPushButton#OrderDetailButton {
+ color: $ds_surface; background: $ds_accent; border-color: $ds_accent;
+}
+#PatientOrdersWorkspace QPushButton#OrderSearchButton:hover,
+#PatientOrdersWorkspace QPushButton#OrderDetailButton:hover { background: $ds_accent_hover; border-color: $ds_accent_hover; }
+#PatientOrdersWorkspace QPushButton#OrderSearchButton:pressed,
+#PatientOrdersWorkspace QPushButton#OrderDetailButton:pressed { background: $ds_accent_pressed; border-color: $ds_accent_pressed; }
+#PatientOrdersWorkspace QPushButton#OrderSearchButton:focus,
+#PatientOrdersWorkspace QPushButton#OrderDetailButton:focus { border-color: $ds_focus; }
+#PatientOrdersWorkspace QPushButton:disabled, #PatientOrdersWorkspace QToolButton:disabled,
+#PatientOrdersWorkspace QPushButton#OrderSearchButton:disabled,
+#PatientOrdersWorkspace QPushButton#OrderDetailButton:disabled {
+ color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line;
+}
+#PatientOrdersWorkspace QLineEdit, #PatientOrdersWorkspace QComboBox,
+#PatientOrdersWorkspace QDateEdit {
+ min-height: 38px; max-height: 38px; padding: 0 10px; font-size: 13px;
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_control;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text;
+}
+#PatientOrdersWorkspace QLineEdit:focus, #PatientOrdersWorkspace QComboBox:focus,
+#PatientOrdersWorkspace QDateEdit:focus { border-color: $ds_focus; }
+#PatientOrdersWorkspace QLineEdit QToolButton {
+ min-height: 0; max-height: 24px; min-width: 0; border: 0; padding: 0; background: transparent;
+}
+#PatientOrdersWorkspace QComboBox { padding-right: 30px; }
+#PatientOrdersWorkspace QComboBox::drop-down { border: 0; width: 28px; background: transparent; }
+#PatientOrdersWorkspace QComboBox::down-arrow { image: none; width: 0; height: 0; }
+#PatientOrdersWorkspace QComboBox QAbstractItemView {
+ font-family: "$body"; font-size: 13px; color: $ds_text; background: $ds_surface;
+ border: 1px solid $ds_line; outline: 0; selection-background-color: $ds_accent_soft; selection-color: $ds_accent;
+}
+#PatientOrdersWorkspace QComboBox QAbstractItemView::item { min-height: 30px; padding: 3px 10px; }
+#PatientOrdersWorkspace QDateEdit { padding-right: 26px; }
+#PatientOrdersWorkspace QDateEdit::drop-down { border: 0; width: 24px; background: transparent; }
+#PatientOrdersWorkspace QDateEdit::down-arrow { image: none; width: 0; height: 0; }
+#PatientOrdersWorkspace QDateEdit:disabled { color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line; }
+#PatientOrdersWorkspace QCalendarWidget {
+ font-family: "$body"; font-size: 13px; background: $ds_surface; color: $ds_text;
+}
+#PatientOrdersWorkspace QCalendarWidget QWidget#qt_calendar_navigationbar { background: $ds_surface_alt; }
+#PatientOrdersWorkspace QCalendarWidget QToolButton {
+ min-height: 28px; max-height: 28px; padding: 0 8px; border: 0; background: transparent;
+ font-family: "$body"; font-size: 13px; color: $ds_text;
+}
+#PatientOrdersWorkspace QCalendarWidget QToolButton:hover { background: $ds_accent_soft; }
+#PatientOrdersWorkspace QCalendarWidget QAbstractItemView {
+ font-family: "$body"; font-size: 13px; background: $ds_surface; alternate-background-color: $ds_surface;
+ color: $ds_text; selection-background-color: $ds_accent; selection-color: $ds_surface; outline: 0;
+}
+#PatientOrdersWorkspace QCheckBox { spacing: 9px; font-size: 13px; }
+#PatientOrdersWorkspace QCheckBox::indicator {
+ width: 15px; height: 15px; border: 1px solid $ds_line_strong; border-radius: 3px; background: $ds_surface;
+}
+#PatientOrdersWorkspace QCheckBox::indicator:checked { background: $ds_accent; border-color: $ds_accent; }
+#PatientOrdersWorkspace QCheckBox::indicator:hover { border-color: $ds_focus; }
+#PatientOrdersWorkspace QCheckBox:focus { color: $ds_accent; }
+#PatientOrdersWorkspace QFrame#OrderMetricCell { background: transparent; border: 0; }
+#PatientOrdersWorkspace QFrame#OrderMetricDivider { border: 0; background: $ds_line; }
+#PatientOrdersWorkspace QLabel[orderMetricCaption="true"] { color: $ds_muted; font-size: 13px; }
+#PatientOrdersWorkspace QLabel[orderMetricValue="true"] { color: $ds_text; font-size: 18px; font-weight: 500; }
+#PatientOrdersWorkspace QLabel#OrderAmountMetric { color: $ds_accent; }
+#PatientOrdersWorkspace QLabel[role="sectionTitle"] { font-size: 14px; font-weight: 600; }
+#PatientOrdersWorkspace QTableWidget#OrderTable {
+ border: 0; border-radius: 0; background: $ds_surface; alternate-background-color: $ds_surface;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text; gridline-color: $ds_line;
+}
+#PatientOrdersWorkspace QTableWidget#OrderTable::item { padding: 0; border: 0; }
+#PatientOrdersWorkspace QTableWidget#OrderTable QHeaderView::section {
+ min-height: 44px; padding: 0 16px; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-bottom: 1px solid $ds_line;
+ font-family: "$body"; font-size: 13px; font-weight: 400;
+}
+#PatientOrdersWorkspace QWidget#OrderActionBar { background: $ds_surface; }
+#PatientOrdersWorkspace QToolButton#OrderActionButton { padding-right: 28px; }
+#PatientOrdersWorkspace QToolButton#OrderActionButton::menu-indicator { image: none; width: 0; height: 0; }
+#PatientOrdersWorkspace QWidget#InfiniteList { background: $ds_surface; border-top: 1px solid $ds_line; }
+#PatientOrdersWorkspace QMenu, QMenu#OrderActionMenu {
+ font-family: "$body"; font-size: 13px; color: $ds_text; background: $ds_surface;
+ border: 1px solid $ds_line; padding: 5px;
+}
+#PatientOrdersWorkspace QMenu::item, QMenu#OrderActionMenu::item { padding: 8px 24px; }
+#PatientOrdersWorkspace QMenu::item:selected, QMenu#OrderActionMenu::item:selected { color: $ds_accent; background: $ds_accent_soft; }
+#PatientOrdersWorkspace QScrollBar:vertical { background: $ds_canvas; width: 7px; margin: 0; }
+#PatientOrdersWorkspace QScrollBar:horizontal { background: $ds_canvas; height: 7px; margin: 0; }
+#PatientOrdersWorkspace QScrollBar::handle { background: $ds_line_strong; border-radius: 3px; min-width: 24px; min-height: 24px; }
+#PatientOrdersWorkspace QScrollBar::add-line, #PatientOrdersWorkspace QScrollBar::sub-line { width: 0; height: 0; }
+#PatientOrdersWorkspace QScrollBar::add-page, #PatientOrdersWorkspace QScrollBar::sub-page { background: transparent; }
+"""
diff --git a/app/src/doctor_workstation/ui/patient_progress_style.py b/app/src/doctor_workstation/ui/patient_progress_style.py
index b9ba83397..906f34f9d 100755
--- a/app/src/doctor_workstation/ui/patient_progress_style.py
+++ b/app/src/doctor_workstation/ui/patient_progress_style.py
@@ -1,54 +1,55 @@
-"""Local typography and surfaces for the approved consultation-progress page."""
-
-from string import Template
-
-from .reception_style import body_family
-
-
-def patient_progress_stylesheet() -> str:
- return Template(_PROGRESS).substitute(body=body_family())
-
-
-_PROGRESS = """
-#PatientProgressWorkspace { background: transparent; color: #273244; }
-#ProgressWorkspaceContent, #ProgressWorkspaceScroll { background: transparent; border: 0; }
-#PatientProgressWorkspace QLabel, #PatientProgressWorkspace QPushButton,
-#PatientProgressWorkspace QTableWidget {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
-}
-#PatientProgressWorkspace QLabel[role="muted"] { font-size: 13px; color: #5D6B80; }
-#PatientProgressWorkspace QLabel[role="sectionTitle"] { font-size: 14px; font-weight: 600; }
-#PatientProgressWorkspace QLabel#EmptyStateGlyph {
- font-size: 24px; color: #1769E8; background: #F2F7FF;
- border: 1px solid #DBE5F2; border-radius: 22px;
-}
-#PatientProgressWorkspace QFrame#ProgressOverviewCard,
-#PatientProgressWorkspace QFrame#ProgressScheduleCard,
-#PatientProgressWorkspace QFrame#ProgressQueueCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
-}
-#PatientProgressWorkspace QFrame#ProgressMetricCell { background: transparent; border: 0; }
-#PatientProgressWorkspace QFrame#ProgressMetricDivider { background: #DBE5F2; border: 0; }
-#PatientProgressWorkspace QLabel[progressMetricValue="true"] { font-size: 18px; font-weight: 500; color: #273244; }
-#PatientProgressWorkspace QLabel#ProgressTotalMetric { color: #1769E8; }
-#PatientProgressWorkspace QSplitter#ProgressSplitter { background: transparent; }
-#PatientProgressWorkspace QSplitter#ProgressSplitter::handle { background: transparent; }
-#PatientProgressWorkspace QSplitter#ProgressSplitter::handle:hover { background: #EAF2FF; }
-#PatientProgressWorkspace QTableWidget#ProgressScheduleTable,
-#PatientProgressWorkspace QTableWidget#ProgressQueueTable {
- border: 0; border-radius: 0; background: #FFFFFF; alternate-background-color: #FFFFFF;
- selection-background-color: #F2F7FF; selection-color: #273244; gridline-color: #E6EDF6;
-}
-#PatientProgressWorkspace QTableWidget::item { border: 0; padding: 0; }
-#PatientProgressWorkspace QHeaderView::section {
- min-height: 0; padding: 0 16px; background: #F5F8FD; color: #5D6B80;
- border: 0; border-bottom: 1px solid #E1E9F4;
- font-family: "$body"; font-size: 13px; font-weight: 400;
-}
-#PatientProgressWorkspace QWidget#InfiniteList { background: #FFFFFF; border-top: 1px solid #E6EDF6; }
-#PatientProgressWorkspace QScrollBar:vertical { background: #F4F7FC; width: 7px; margin: 0; }
-#PatientProgressWorkspace QScrollBar:horizontal { background: #F4F7FC; height: 7px; margin: 0; }
-#PatientProgressWorkspace QScrollBar::handle { background: #C8D5E6; border-radius: 3px; min-width: 24px; min-height: 24px; }
-#PatientProgressWorkspace QScrollBar::add-line, #PatientProgressWorkspace QScrollBar::sub-line { width: 0; height: 0; }
-#PatientProgressWorkspace QScrollBar::add-page, #PatientProgressWorkspace QScrollBar::sub-page { background: transparent; }
-"""
+"""Local typography and surfaces for the approved consultation-progress page."""
+
+from string import Template
+
+from .design_system import clinical_stylesheet
+from .reception_style import body_family
+
+
+def patient_progress_stylesheet() -> str:
+ return clinical_stylesheet(Template(_PROGRESS).safe_substitute(body=body_family()))
+
+
+_PROGRESS = """
+#PatientProgressWorkspace { background: transparent; color: $ds_text; }
+#ProgressWorkspaceContent, #ProgressWorkspaceScroll { background: transparent; border: 0; }
+#PatientProgressWorkspace QLabel, #PatientProgressWorkspace QPushButton,
+#PatientProgressWorkspace QTableWidget {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+}
+#PatientProgressWorkspace QLabel[role="muted"] { font-size: 13px; color: $ds_muted; }
+#PatientProgressWorkspace QLabel[role="sectionTitle"] { font-size: 14px; font-weight: 600; }
+#PatientProgressWorkspace QLabel#EmptyStateGlyph {
+ font-size: 24px; color: $ds_accent; background: $ds_surface_alt;
+ border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PatientProgressWorkspace QFrame#ProgressScheduleCard,
+#PatientProgressWorkspace QFrame#ProgressQueueCard {
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PatientProgressWorkspace QFrame#ProgressOverviewCard { background: transparent; border: 0; }
+#PatientProgressWorkspace QFrame#ProgressMetricCell { background: transparent; border: 0; }
+#PatientProgressWorkspace QFrame#ProgressMetricDivider { background: $ds_line; border: 0; }
+#PatientProgressWorkspace QLabel[progressMetricValue="true"] { font-size: 18px; font-weight: 500; color: $ds_text; }
+#PatientProgressWorkspace QLabel#ProgressTotalMetric { color: $ds_accent; }
+#PatientProgressWorkspace QSplitter#ProgressSplitter { background: transparent; }
+#PatientProgressWorkspace QSplitter#ProgressSplitter::handle { background: transparent; }
+#PatientProgressWorkspace QSplitter#ProgressSplitter::handle:hover { background: $ds_accent_soft; }
+#PatientProgressWorkspace QTableWidget#ProgressScheduleTable,
+#PatientProgressWorkspace QTableWidget#ProgressQueueTable {
+ border: 0; border-radius: 0; background: $ds_surface; alternate-background-color: $ds_surface;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text; gridline-color: $ds_line;
+}
+#PatientProgressWorkspace QTableWidget::item { border: 0; padding: 0; }
+#PatientProgressWorkspace QHeaderView::section {
+ min-height: 0; padding: 0 16px; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-bottom: 1px solid $ds_line;
+ font-family: "$body"; font-size: 13px; font-weight: 400;
+}
+#PatientProgressWorkspace QWidget#InfiniteList { background: $ds_surface; border-top: 1px solid $ds_line; }
+#PatientProgressWorkspace QScrollBar:vertical { background: $ds_canvas; width: 7px; margin: 0; }
+#PatientProgressWorkspace QScrollBar:horizontal { background: $ds_canvas; height: 7px; margin: 0; }
+#PatientProgressWorkspace QScrollBar::handle { background: $ds_line_strong; border-radius: 3px; min-width: 24px; min-height: 24px; }
+#PatientProgressWorkspace QScrollBar::add-line, #PatientProgressWorkspace QScrollBar::sub-line { width: 0; height: 0; }
+#PatientProgressWorkspace QScrollBar::add-page, #PatientProgressWorkspace QScrollBar::sub-page { background: transparent; }
+"""
diff --git a/app/src/doctor_workstation/ui/patients_style.py b/app/src/doctor_workstation/ui/patients_style.py
index 8273fb598..545c4e680 100755
--- a/app/src/doctor_workstation/ui/patients_style.py
+++ b/app/src/doctor_workstation/ui/patients_style.py
@@ -1,141 +1,154 @@
-"""Scoped technology-blue surfaces for the approved patient-list workspace."""
-
-from string import Template
-
-from .reception_style import body_family, heading_family
-
-
-def patients_chrome_stylesheet() -> str:
- return Template(_CHROME).substitute(body=body_family(), heading=heading_family())
-
-
-def patient_list_stylesheet() -> str:
- return Template(_LIST).substitute(body=body_family())
-
-
-_CHROME = """
-#PatientsPage { background: #F3F7FD; }
-#PatientsPage QWidget#PageHeader QLabel {
- font-family: "$body"; font-size: 13px; font-weight: 400; color: #5D6B80;
-}
-#PatientsPage QWidget#PageHeader QLabel[role="pageTitle"] {
- font-family: "$heading"; font-size: 20px; font-weight: 600; color: #202C3F;
-}
-#PatientsPage QPushButton#PatientRefreshButton {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
- min-height: 38px; max-height: 38px; padding: 0 20px;
- border: 1px solid #DBE5F2; border-radius: 5px; background: #FFFFFF;
-}
-#PatientsPage QPushButton#PatientRefreshButton:hover { background: #F2F7FF; border-color: #B6CDEE; }
-#PatientsPage QTabWidget#PatientWorkspaceTabs::pane { border: 0; background: transparent; top: 0; }
-#PatientsPage QTabWidget#PatientWorkspaceTabs > QTabBar::tab {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
- min-width: 84px; min-height: 42px; padding: 0 10px; margin-right: 22px;
- border: 0; border-bottom: 2px solid transparent; border-radius: 0; background: transparent;
-}
-#PatientsPage QTabWidget#PatientWorkspaceTabs > QTabBar::tab:selected {
- color: #1769E8; border-bottom-color: #1769E8; background: transparent;
-}
-#PatientsPage QTabWidget#PatientWorkspaceTabs > QTabBar::tab:hover { color: #1769E8; background: #EAF2FF; }
-"""
-
-_LIST = """
-#PatientListWorkspace { background: transparent; color: #273244; }
-#PatientWorkspaceContent, #PatientWorkspaceScroll { background: transparent; border: 0; }
-#PatientListWorkspace QLabel, #PatientListWorkspace QPushButton,
-#PatientListWorkspace QToolButton, #PatientListWorkspace QDateEdit,
-#PatientListWorkspace QTableWidget, #PatientSearchToolbar QLineEdit,
-#PatientSearchToolbar QPushButton {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
-}
-#PatientListWorkspace QLabel[role="muted"], #PatientListWorkspace QLabel[filterLabel="true"] {
- color: #5D6B80; font-size: 13px;
-}
-#PatientListWorkspace QFrame#PatientFilterCard,
-#PatientListWorkspace QFrame#PatientSummaryStrip,
-#PatientListWorkspace QFrame#PatientListCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
-}
-#PatientListWorkspace QPushButton, #PatientSearchToolbar QPushButton {
- min-height: 38px; max-height: 38px; padding: 0 16px;
- border: 1px solid #DBE5F2; border-radius: 5px; background: #FFFFFF;
-}
-#PatientListWorkspace QPushButton:hover, #PatientSearchToolbar QPushButton:hover {
- color: #1555B6; background: #F2F7FF; border-color: #B6CDEE;
-}
-#PatientListWorkspace QPushButton:pressed, #PatientSearchToolbar QPushButton:pressed { background: #DCEAFF; }
-#PatientListWorkspace QPushButton:focus, #PatientSearchToolbar QPushButton:focus { border-color: #75A5F0; }
-#PatientSearchToolbar QPushButton#PatientSearchButton {
- min-height: 38px; max-height: 38px; color: #FFFFFF; background: #1769E8; border-color: #1769E8;
-}
-#PatientSearchToolbar QPushButton#PatientSearchButton:hover { background: #155BCC; }
-#PatientSearchToolbar QLineEdit {
- min-height: 38px; max-height: 38px; padding: 0 8px; background: #FFFFFF;
- border: 1px solid #DBE5F2; border-radius: 5px; selection-background-color: #DCEAFF;
-}
-#PatientSearchToolbar QLineEdit:focus { border-color: #75A5F0; }
-#PatientSearchToolbar QLineEdit QToolButton { border: 0; padding: 0; background: transparent; }
-#PatientListWorkspace QPushButton[patientStatusChip="true"] {
- min-height: 44px; max-height: 44px; padding: 0 16px; font-size: 13px;
- color: #273244; border: 0; border-bottom: 2px solid transparent; border-radius: 0; background: transparent;
-}
-#PatientListWorkspace QPushButton[patientStatusChip="true"]:checked {
- color: #1769E8; border-bottom-color: #1769E8; background: transparent;
-}
-#PatientListWorkspace QPushButton[patientStatusChip="true"]:hover { color: #1769E8; background: #F2F7FF; }
-#PatientListWorkspace QPushButton[patientQuickDate="true"] { padding: 0 12px; font-size: 13px; }
-#PatientListWorkspace QPushButton[patientQuickDate="true"]:checked,
-#PatientListWorkspace QPushButton#PatientCustomDateButton:checked {
- color: #FFFFFF; background: #1769E8; border: 1px solid #1769E8;
-}
-#PatientListWorkspace QDateEdit {
- min-height: 38px; max-height: 38px; padding: 0 8px; font-size: 13px;
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 5px;
- selection-background-color: #DCEAFF;
-}
-#PatientListWorkspace QDateEdit:focus { border-color: #75A5F0; }
-#PatientListWorkspace QDateEdit:disabled {
- color: #8A97A9; background: #F6F8FC; border-color: #E2E9F2;
-}
-#PatientListWorkspace QDateEdit::drop-down { border: 0; width: 20px; background: transparent; }
-#PatientListWorkspace QDateEdit::down-arrow { image: none; width: 0; height: 0; }
-#PatientListWorkspace QPushButton[summaryCard="true"] {
- min-height: 64px; max-height: 64px; padding: 0; background: transparent; border: 0; border-radius: 5px;
-}
-#PatientListWorkspace QPushButton[summaryCard="true"]:hover { background: #F2F7FF; }
-#PatientListWorkspace QFrame#PatientSummaryDivider { border: 0; background: #E1E9F4; }
-#PatientListWorkspace QWidget#PatientListHeading { background: transparent; }
-#PatientListWorkspace QLabel[role="sectionTitle"] { font-size: 14px; font-weight: 600; color: #273244; }
-#PatientListWorkspace QTableWidget#PatientTable {
- background: #FFFFFF; alternate-background-color: #FFFFFF; border: 0; border-radius: 0;
- selection-background-color: #EAF2FF; selection-color: #273244; gridline-color: #E6EDF6;
-}
-#PatientListWorkspace QTableWidget#PatientTable::item { padding: 0; border: 0; }
-#PatientListWorkspace QTableWidget#PatientTable QHeaderView::section {
- min-height: 41px; padding: 0 10px; background: #F5F8FD; color: #5D6B80;
- border: 0; border-top: 1px solid #E6EDF6; border-bottom: 1px solid #E1E9F4;
- font-family: "$body"; font-size: 13px; font-weight: 400;
-}
-#PatientListWorkspace QWidget#RowActions, #PatientListWorkspace QWidget#PatientSelectorHost { background: transparent; }
-#PatientListWorkspace QPushButton[rowAction="true"],
-#PatientListWorkspace QToolButton#RowActionsMore {
- min-height: 28px; max-height: 28px; padding: 0 5px; border: 0;
- border-radius: 4px; background: transparent; color: #1769E8; font-size: 13px;
-}
-#PatientListWorkspace QToolButton#RowActionsMore { color: #273244; padding-right: 16px; }
-#PatientListWorkspace QPushButton[rowAction="true"]:hover,
-#PatientListWorkspace QToolButton#RowActionsMore:hover { background: #DCEAFF; }
-#PatientListWorkspace QMenu { background: #FFFFFF; color: #273244; border: 1px solid #DBE5F2; padding: 4px; }
-#PatientListWorkspace QMenu::item { padding: 7px 22px; font-size: 13px; }
-#PatientListWorkspace QMenu::item:selected { background: #EAF2FF; color: #1555B6; }
-#PatientListWorkspace QCheckBox[patientSelector="true"]::indicator {
- width: 13px; height: 13px; background: #FFFFFF; border: 1px solid #CBDAED; border-radius: 3px;
-}
-#PatientListWorkspace QCheckBox[patientSelector="true"]::indicator:checked { background: #1769E8; border-color: #1769E8; }
-#PatientListWorkspace QWidget#InfiniteList { background: #FFFFFF; border-top: 1px solid #E6EDF6; }
-#PatientListWorkspace QScrollBar:vertical { background: #F4F7FC; width: 7px; margin: 0; }
-#PatientListWorkspace QScrollBar:horizontal { background: #F4F7FC; height: 7px; margin: 0; }
-#PatientListWorkspace QScrollBar::handle { background: #C8D5E6; border-radius: 3px; min-width: 24px; min-height: 24px; }
-#PatientListWorkspace QScrollBar::add-line, #PatientListWorkspace QScrollBar::sub-line { width: 0; height: 0; }
-#PatientListWorkspace QScrollBar::add-page, #PatientListWorkspace QScrollBar::sub-page { background: transparent; }
-"""
+"""Quiet clinical surfaces for the patient-list workspace."""
+
+from string import Template
+
+from .design_system import clinical_stylesheet
+from .reception_style import body_family, heading_family
+
+
+def patients_chrome_stylesheet() -> str:
+ return clinical_stylesheet(Template(_CHROME).safe_substitute(body=body_family(), heading=heading_family()))
+
+
+def patient_list_stylesheet() -> str:
+ return clinical_stylesheet(Template(_LIST).safe_substitute(body=body_family()))
+
+
+_CHROME = """
+#PatientsPage { background: $ds_canvas; }
+#PatientsPage QWidget#PageHeader QLabel {
+ font-family: "$body"; font-size: 13px; font-weight: 400; color: $ds_muted;
+}
+#PatientsPage QWidget#PageHeader QLabel[role="pageTitle"] {
+ font-family: "$heading"; font-size: 20px; font-weight: 600; color: $ds_heading;
+}
+#PatientsPage QPushButton#PatientRefreshButton {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+ min-height: 38px; max-height: 38px; padding: 0 20px;
+ border: 1px solid transparent; border-radius: $ds_radius_control; background: $ds_surface_alt;
+}
+#PatientsPage QPushButton#PatientRefreshButton:hover { background: $ds_surface_alt; border-color: $ds_line_strong; }
+#PatientsPage QPushButton#PatientRefreshButton:pressed { background: $ds_accent_soft; }
+#PatientsPage QPushButton#PatientRefreshButton:focus { border-color: $ds_focus; }
+#PatientsPage QPushButton#PatientRefreshButton:disabled { color: $ds_disabled; background: $ds_disabled_surface; }
+#PatientsPage QTabWidget#PatientWorkspaceTabs::pane { border: 0; background: transparent; top: 0; }
+#PatientsPage QTabWidget#PatientWorkspaceTabs > QTabBar::tab {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+ min-width: 84px; min-height: 42px; padding: 0 10px; margin-right: 22px;
+ border: 0; border-bottom: 2px solid transparent; border-radius: 0; background: transparent;
+}
+#PatientsPage QTabWidget#PatientWorkspaceTabs > QTabBar::tab:selected {
+ color: $ds_accent; border-bottom-color: $ds_accent; background: transparent;
+}
+#PatientsPage QTabWidget#PatientWorkspaceTabs > QTabBar::tab:hover { color: $ds_accent; background: $ds_accent_soft; }
+"""
+
+_LIST = """
+#PatientListWorkspace { background: transparent; color: $ds_text; }
+#PatientWorkspaceContent, #PatientWorkspaceScroll { background: transparent; border: 0; }
+#PatientListWorkspace QLabel, #PatientListWorkspace QPushButton,
+#PatientListWorkspace QToolButton, #PatientListWorkspace QDateEdit,
+#PatientListWorkspace QTableWidget, #PatientSearchToolbar QLineEdit,
+#PatientSearchToolbar QPushButton {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+}
+#PatientListWorkspace QLabel[role="muted"], #PatientListWorkspace QLabel[filterLabel="true"] {
+ color: $ds_muted; font-size: 13px;
+}
+#PatientListWorkspace QFrame#PatientFilterCard,
+#PatientListWorkspace QFrame#PatientListCard {
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PatientListWorkspace QFrame#PatientSummaryStrip { background: transparent; border: 0; }
+#PatientListWorkspace QPushButton, #PatientSearchToolbar QPushButton {
+ min-height: 38px; max-height: 38px; padding: 0 16px;
+ border: 1px solid transparent; border-radius: $ds_radius_control; background: $ds_surface_alt;
+}
+#PatientListWorkspace QPushButton:hover, #PatientSearchToolbar QPushButton:hover {
+ color: $ds_accent; background: $ds_surface_alt; border-color: $ds_line_strong;
+}
+#PatientListWorkspace QPushButton:pressed, #PatientSearchToolbar QPushButton:pressed { background: $ds_accent_soft; }
+#PatientListWorkspace QPushButton:focus, #PatientSearchToolbar QPushButton:focus { border-color: $ds_focus; }
+#PatientSearchToolbar QPushButton#PatientSearchButton {
+ min-height: 38px; max-height: 38px; color: $ds_surface; background: $ds_accent; border-color: $ds_accent;
+}
+#PatientSearchToolbar QPushButton#PatientSearchButton:hover { background: $ds_accent_hover; }
+#PatientSearchToolbar QPushButton#PatientSearchButton:pressed { background: $ds_accent_pressed; }
+#PatientSearchToolbar QPushButton#PatientSearchButton:focus { border-color: $ds_focus; }
+#PatientSearchToolbar QLineEdit {
+ min-height: 38px; max-height: 38px; padding: 0 8px; background: $ds_surface;
+ border: 1px solid $ds_line; border-radius: $ds_radius_control; selection-background-color: $ds_accent_soft;
+}
+#PatientSearchToolbar QLineEdit:focus { border-color: $ds_focus; }
+#PatientSearchToolbar QLineEdit QToolButton { border: 0; padding: 0; background: transparent; }
+#PatientListWorkspace QPushButton[patientStatusChip="true"] {
+ min-height: 44px; max-height: 44px; padding: 0 16px; font-size: 13px;
+ color: $ds_text; border: 0; border-bottom: 2px solid transparent; border-radius: 0; background: transparent;
+}
+#PatientListWorkspace QPushButton[patientStatusChip="true"]:checked {
+ color: $ds_accent; border-bottom-color: $ds_accent; background: transparent;
+}
+#PatientListWorkspace QPushButton[patientStatusChip="true"]:hover { color: $ds_accent; background: $ds_surface_alt; }
+#PatientListWorkspace QPushButton[patientStatusChip="true"]:focus { background: $ds_accent_soft; }
+#PatientListWorkspace QPushButton[patientQuickDate="true"] { padding: 0 12px; font-size: 13px; }
+#PatientListWorkspace QPushButton[patientQuickDate="true"]:checked,
+#PatientListWorkspace QPushButton#PatientCustomDateButton:checked {
+ color: $ds_accent; background: $ds_accent_soft; border: 1px solid transparent; font-weight: 600;
+}
+#PatientListWorkspace QPushButton[patientQuickDate="true"]:focus,
+#PatientListWorkspace QPushButton#PatientCustomDateButton:focus { border-color: $ds_focus; }
+#PatientListWorkspace QDateEdit {
+ min-height: 38px; max-height: 38px; padding: 0 8px; font-size: 13px;
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_control;
+ selection-background-color: $ds_accent_soft;
+}
+#PatientListWorkspace QDateEdit:focus { border-color: $ds_focus; }
+#PatientListWorkspace QDateEdit:disabled {
+ color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line;
+}
+#PatientListWorkspace QDateEdit::drop-down { border: 0; width: 20px; background: transparent; }
+#PatientListWorkspace QDateEdit::down-arrow { image: none; width: 0; height: 0; }
+#PatientListWorkspace QPushButton[summaryCard="true"] {
+ min-height: 64px; max-height: 64px; padding: 0; background: transparent;
+ border: 1px solid transparent; border-radius: $ds_radius_control;
+}
+#PatientListWorkspace QPushButton[summaryCard="true"]:hover { background: $ds_surface_alt; }
+#PatientListWorkspace QPushButton[summaryCard="true"]:focus { border-color: $ds_focus; }
+#PatientListWorkspace QFrame#PatientSummaryDivider { border: 0; background: $ds_line; }
+#PatientListWorkspace QWidget#PatientListHeading { background: transparent; }
+#PatientListWorkspace QLabel[role="sectionTitle"] { font-size: 14px; font-weight: 600; color: $ds_text; }
+#PatientListWorkspace QTableWidget#PatientTable {
+ background: $ds_surface; alternate-background-color: $ds_surface; border: 0; border-radius: 0;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text; gridline-color: $ds_line;
+}
+#PatientListWorkspace QTableWidget#PatientTable::item { padding: 0; border: 0; }
+#PatientListWorkspace QTableWidget#PatientTable QHeaderView::section {
+ min-height: 41px; padding: 0 10px; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-top: 1px solid $ds_line; border-bottom: 1px solid $ds_line;
+ font-family: "$body"; font-size: 13px; font-weight: 400;
+}
+#PatientListWorkspace QWidget#RowActions, #PatientListWorkspace QWidget#PatientSelectorHost { background: transparent; }
+#PatientListWorkspace QPushButton[rowAction="true"],
+#PatientListWorkspace QToolButton#RowActionsMore {
+ min-height: 28px; max-height: 28px; padding: 0 5px; border: 1px solid transparent;
+ border-radius: $ds_radius_small; background: transparent; color: $ds_accent; font-size: 13px;
+}
+#PatientListWorkspace QToolButton#RowActionsMore { color: $ds_text; padding-right: 16px; }
+#PatientListWorkspace QPushButton[rowAction="true"]:hover,
+#PatientListWorkspace QToolButton#RowActionsMore:hover { background: $ds_accent_soft; }
+#PatientListWorkspace QPushButton[rowAction="true"]:focus,
+#PatientListWorkspace QToolButton#RowActionsMore:focus { border-color: $ds_focus; }
+#PatientListWorkspace QMenu { background: $ds_surface; color: $ds_text; border: 1px solid $ds_line; padding: 4px; }
+#PatientListWorkspace QMenu::item { padding: 7px 22px; font-size: 13px; }
+#PatientListWorkspace QMenu::item:selected { background: $ds_accent_soft; color: $ds_accent; }
+#PatientListWorkspace QCheckBox[patientSelector="true"]::indicator {
+ width: 13px; height: 13px; background: $ds_surface; border: 1px solid $ds_line_strong; border-radius: 3px;
+}
+#PatientListWorkspace QCheckBox[patientSelector="true"]::indicator:checked { background: $ds_accent; border-color: $ds_accent; }
+#PatientListWorkspace QWidget#InfiniteList { background: $ds_surface; border-top: 1px solid $ds_line; }
+#PatientListWorkspace QScrollBar:vertical { background: $ds_canvas; width: 7px; margin: 0; }
+#PatientListWorkspace QScrollBar:horizontal { background: $ds_canvas; height: 7px; margin: 0; }
+#PatientListWorkspace QScrollBar::handle { background: $ds_line_strong; border-radius: 3px; min-width: 24px; min-height: 24px; }
+#PatientListWorkspace QScrollBar::add-line, #PatientListWorkspace QScrollBar::sub-line { width: 0; height: 0; }
+#PatientListWorkspace QScrollBar::add-page, #PatientListWorkspace QScrollBar::sub-page { background: transparent; }
+"""
diff --git a/app/src/doctor_workstation/ui/prescription_library_style.py b/app/src/doctor_workstation/ui/prescription_library_style.py
index 33255224b..3d018330e 100755
--- a/app/src/doctor_workstation/ui/prescription_library_style.py
+++ b/app/src/doctor_workstation/ui/prescription_library_style.py
@@ -1,410 +1,419 @@
-"""Local technology-blue rendering for the approved prescription library."""
-
-from __future__ import annotations
-
-from collections.abc import Iterable, Sequence
-from string import Template
-from typing import Any
-
-from PySide6.QtCore import QEvent, QModelIndex, QRectF, QSize, Qt, QTimer
-from PySide6.QtGui import QColor, QFont, QFontMetrics, QIcon, QPainter
-from PySide6.QtWidgets import (
- QComboBox,
- QPushButton,
- QStyle,
- QStyledItemDelegate,
- QToolTip,
- QWidget,
-)
-
-from .reception_style import body_family, heading_family
-from .widgets import SortableTable, TableColumn, first_value
-
-
-def library_stylesheet() -> str:
- return Template(_LIBRARY).substitute(body=body_family(), heading=heading_family())
-
-
-def _library_icon(kind: str, color: str = "#1769E8", size: int = 15) -> QIcon:
- # Defer the page helper lookup so importing this module alone does not
- # recurse through pages.__init__ and the library page's own style import.
- from .pages.prescriptions import _painted_icon
-
- result = QIcon()
- for mode, tint in (
- (QIcon.Mode.Normal, color),
- (QIcon.Mode.Active, color),
- (QIcon.Mode.Selected, color),
- (QIcon.Mode.Disabled, "#A4ADBA"),
- ):
- pixmap = _painted_icon(kind, tint, size).pixmap(QSize(size, size))
- for state in (QIcon.State.Off, QIcon.State.On):
- result.addPixmap(pixmap, mode, state)
- return result
-
-
-class LibraryComboBox(QComboBox):
- """Keep native combo interaction while painting the local caret."""
-
- def paintEvent(self, event: Any) -> None: # noqa: N802 - Qt virtual
- super().paintEvent(event)
- painter = QPainter(self)
- try:
- rect = QRectF(self.width() - 25, (self.height() - 14) / 2, 14, 14)
- mode = QIcon.Mode.Normal if self.isEnabled() else QIcon.Mode.Disabled
- _library_icon("chevron_down", "#5D6B80", 14).paint(painter, rect.toRect(), mode=mode)
- finally:
- painter.end()
-
-
-class LibraryTable(SortableTable):
- """Fit readable columns while preserving actions and selected template IDs."""
-
- _FLEX_COLUMNS = ((1, 2), (4, 5), (5, 2))
-
- def __init__(self, columns: Sequence[TableColumn], parent: QWidget | None = None) -> None:
- super().__init__(columns, parent)
- self.horizontalHeader().setStretchLastSection(False)
- self._minimum_widths = tuple(column.width for column in self.columns)
- self._manual_widths: dict[int, int] = {}
- self._fitting_columns = False
- self._fit_timer = QTimer(self)
- self._fit_timer.setSingleShot(True)
- self._fit_timer.timeout.connect(self._fit_columns)
- self.horizontalHeader().sectionResized.connect(self._column_resized)
- self.viewport().installEventFilter(self)
-
- def eventFilter(self, watched: Any, event: QEvent) -> bool: # noqa: N802
- if watched is self.viewport() and event.type() in {QEvent.Type.Resize, QEvent.Type.Show}:
- self._schedule_column_fit()
- return super().eventFilter(watched, event)
-
- def _schedule_column_fit(self) -> None:
- if not self._fit_timer.isActive():
- self._fit_timer.start(0)
-
- def _column_resized(self, column: int, _old_size: int, size: int) -> None:
- if self._fitting_columns:
- return
- self._manual_widths[column] = max(self._minimum_widths[column], size)
- self._schedule_column_fit()
-
- def _fit_columns(self) -> None:
- widths = [self._manual_widths.get(column, minimum)
- for column, minimum in enumerate(self._minimum_widths)]
- extra = max(0, self.viewport().width() - sum(widths))
- flexible = [(column, weight) for column, weight in self._FLEX_COLUMNS
- if column not in self._manual_widths]
- # If every text column was manually sized, keep those preferences as
- # minimums and let the herb preview absorb any remaining wide-screen space.
- flexible = flexible or [(4, 1)]
- total_weight = sum(weight for _column, weight in flexible)
- for column, weight in flexible:
- widths[column] += extra * weight // total_weight
- widths[flexible[0][0]] += max(0, self.viewport().width() - sum(widths))
- if widths == [self.columnWidth(column) for column in range(self.columnCount())]:
- return
- self._fitting_columns = True
- try:
- for column, width in enumerate(widths):
- self.setColumnWidth(column, width)
- finally:
- self._fitting_columns = False
-
- def set_rows(self, rows: Iterable[Any]) -> None:
- selected_id = first_value(self.current_data(), "id", "template_id", default=None)
- super().set_rows(rows)
- # The shared table restores an unsorted row index after enabling sort.
- # Locate the same source object in the finished visual order instead.
- if selected_id is not None:
- for row_index in range(self.rowCount()):
- item = self.item(row_index, 0)
- row = item.data(Qt.ItemDataRole.UserRole) if item is not None else None
- row_id = first_value(row, "id", "template_id", default=None)
- if row_id is not None and str(row_id) == str(selected_id):
- self.selectRow(row_index)
- return
- self.clearSelection()
- self.setCurrentCell(-1, -1)
-
- def setCellWidget(self, row: int, column: int, widget: QWidget | None) -> None: # noqa: N802
- super().setCellWidget(row, column, widget)
- if widget is None or column != 9:
- return
- widget.setObjectName("PrescriptionLibraryTableCellHost")
- widget.setAutoFillBackground(False)
- glyphs = {
- "查看处方模板": "eye",
- "AI 解释": "spark",
- "编辑处方模板": "pencil",
- "删除处方模板": "trash",
- }
- for button in widget.findChildren(QPushButton):
- if not button.property("rowAction"):
- continue
- glyph = glyphs.get(button.accessibleName()) or glyphs.get(button.toolTip())
- if glyph is not None:
- color = "#BE4657" if button.property("danger") else "#1769E8"
- button.setIcon(_library_icon(glyph, color, button.iconSize().width()))
-
-
-def _library_font(size: int = 14, *, medium: bool = False) -> QFont:
- font = QFont(heading_family() if medium else body_family())
- font.setPixelSize(size)
- font.setWeight(QFont.Weight.Medium if medium else QFont.Weight.Normal)
- return font
-
-
-def _elide(text: str, metrics: QFontMetrics, width: int) -> str:
- return metrics.elidedText(text, Qt.TextElideMode.ElideRight, max(1, width))
-
-
-def _herb_lines(text: str, metrics: QFontMetrics, width: int) -> list[str]:
- """Wrap between complete herb entries; elide only the displayed lines."""
- entries = text.split("、")
- first = entries[0]
- next_index = 1
- while next_index < min(2, len(entries)):
- candidate = first + "、" + entries[next_index]
- if metrics.horizontalAdvance(candidate) > width:
- break
- first = candidate
- next_index += 1
- lines = [_elide(first, metrics, width)]
- if next_index < len(entries):
- lines.append(_elide("、".join(entries[next_index:]), metrics, width))
- return lines
-
-
-def _name_lines(text: str, metrics: QFontMetrics, width: int) -> list[str]:
- if metrics.horizontalAdvance(text) <= width:
- return [text]
- split = 1
- while split < len(text) and metrics.horizontalAdvance(text[: split + 1]) <= width:
- split += 1
- return [_elide(text[:split], metrics, width), _elide(text[split:], metrics, width)]
-
-
-class LibraryItemDelegate(QStyledItemDelegate):
- """Paint the ten existing columns without changing display or source roles."""
-
- def sizeHint(self, option: Any, index: QModelIndex) -> QSize: # noqa: N802
- size = super().sizeHint(option, index)
- size.setHeight(78)
- return size
-
- def helpEvent(self, event: Any, view: Any, option: Any, index: QModelIndex) -> bool: # noqa: N802
- if event is not None and index.isValid() and index.column() != 9:
- text = index.data(Qt.ItemDataRole.ToolTipRole) or index.data(Qt.ItemDataRole.DisplayRole)
- if text:
- QToolTip.showText(event.globalPos(), str(text), view)
- return True
- return super().helpEvent(event, view, option, index)
-
- @staticmethod
- def _paint_lines(
- painter: QPainter,
- rect: QRectF,
- lines: list[str],
- *,
- secondary_muted: bool = False,
- ) -> None:
- line_height = 26
- top = rect.center().y() - len(lines) * line_height / 2
- for line_index, line in enumerate(lines):
- if secondary_muted and line_index:
- painter.setFont(_library_font(13))
- painter.setPen(QColor("#5D6B80"))
- line_rect = QRectF(rect.left(), top + line_index * line_height, rect.width(), line_height)
- painter.drawText(line_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, line)
-
- def paint(self, painter: QPainter, option: Any, index: QModelIndex) -> None:
- painter.save()
- try:
- painter.setClipRect(option.rect)
- selected = bool(option.state & QStyle.StateFlag.State_Selected)
- hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
- background = "#F2F7FF" if selected else "#F8FAFE" if hovered else "#FFFFFF"
- painter.fillRect(option.rect, QColor(background))
- painter.setPen(QColor("#E6EDF6"))
- painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
- if selected and index.column() == 0:
- stripe = QRectF(option.rect.left(), option.rect.top(), 3, option.rect.height() - 1)
- painter.fillRect(stripe, QColor("#1769E8"))
- if option.state & QStyle.StateFlag.State_HasFocus:
- painter.setPen(QColor("#75A5F0"))
- painter.setBrush(Qt.BrushStyle.NoBrush)
- painter.drawRect(option.rect.adjusted(1, 1, -2, -2))
-
- column = index.column()
- if column == 9:
- return
- rect = QRectF(option.rect.adjusted(12, 0, -12, -1))
- if rect.width() <= 0:
- return
- value = index.data(Qt.ItemDataRole.DisplayRole)
- text = "" if value is None else str(value)
- font = _library_font(medium=column == 1)
- painter.setFont(font)
- painter.setPen(QColor("#273244"))
- metrics = QFontMetrics(font)
- width = int(rect.width())
-
- if column == 2:
- painter.setFont(_library_font(13))
- metrics = painter.fontMetrics()
- label = _elide(text, metrics, width - 12)
- pill_width = min(rect.width(), metrics.horizontalAdvance(label) + 14)
- pill = QRectF(rect.center().x() - pill_width / 2, rect.center().y() - 12, pill_width, 24)
- painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
- painter.setPen(Qt.PenStyle.NoPen)
- painter.setBrush(QColor("#EAF2FF"))
- painter.drawRoundedRect(pill, 4, 4)
- painter.setPen(QColor("#1769E8"))
- painter.drawText(pill, Qt.AlignmentFlag.AlignCenter, label)
- elif column == 6:
- glyph = "users" if text == "所有人可见" else "lock"
- icon_rect = QRectF(rect.left(), rect.center().y() - 7, 14, 14)
- _library_icon(glyph, "#5D6B80", 14).paint(painter, icon_rect.toRect())
- label_rect = rect.adjusted(22, 0, 0, 0)
- painter.drawText(
- label_rect,
- Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
- _elide(text, metrics, int(label_rect.width())),
- )
- elif column == 4:
- self._paint_lines(painter, rect, _herb_lines(text, metrics, width))
- elif column == 8:
- parts = text.splitlines() if "\n" in text else text.rsplit(" ", 1)
- lines = [_elide(parts[0], metrics, width)]
- if len(parts) > 1:
- lines.append(_elide(" ".join(parts[1:]), QFontMetrics(_library_font(13)), width))
- self._paint_lines(painter, rect, lines, secondary_muted=True)
- elif column == 1:
- self._paint_lines(painter, rect, _name_lines(text, metrics, width))
- else:
- alignment = Qt.AlignmentFlag.AlignCenter if column in (0, 3, 5) else (
- Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter
- )
- painter.drawText(rect, alignment, _elide(text, metrics, width))
- finally:
- painter.restore()
-
-
-_LIBRARY = """
-#PrescriptionLibraryPage { background: #F3F7FD; color: #273244; }
-#PrescriptionLibraryPage QWidget#PrescriptionLibraryContent,
-#PrescriptionLibraryPage QScrollArea#PrescriptionLibraryScroll,
-#PrescriptionLibraryPage QScrollArea#PrescriptionLibraryToolbarScroll {
- background: transparent; border: 0;
-}
-#PrescriptionLibraryPage QLabel, #PrescriptionLibraryPage QPushButton,
-#PrescriptionLibraryPage QLineEdit, #PrescriptionLibraryPage QComboBox,
-#PrescriptionLibraryPage QTableWidget {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
-}
-#PrescriptionLibraryPage QLabel[role="pageTitle"] {
- font-family: "$heading"; font-size: 20px; font-weight: 600; color: #202C3F;
-}
-#PrescriptionLibraryPage QLabel[role="muted"] { color: #5D6B80; font-size: 13px; }
-#PrescriptionLibraryPage QFrame#MetricCard,
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryFilterBar,
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryTableCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
-}
-#PrescriptionLibraryPage QFrame#MetricCard QLabel[role="metricTitle"] {
- font-family: "$body"; color: #5D6B80; font-size: 13px; font-weight: 400;
-}
-#PrescriptionLibraryPage QFrame#MetricCard QLabel[role="metricValue"] {
- font-family: "$heading"; color: #273244; font-size: 18px; font-weight: 600;
-}
-#PrescriptionLibraryPage QFrame#MetricCard QLabel[metricIcon="true"] {
- border: 0; border-radius: 0; background: transparent;
-}
-#PrescriptionLibraryPage QPushButton {
- min-height: 38px; max-height: 38px; padding: 0 16px; border-radius: 5px;
- border: 1px solid #DBE5F2; background: #FFFFFF; color: #273244;
-}
-#PrescriptionLibraryPage QPushButton:hover { background: #F2F7FF; border-color: #B6CDEE; color: #1555B6; }
-#PrescriptionLibraryPage QPushButton:pressed { background: #DCEAFF; }
-#PrescriptionLibraryPage QPushButton:focus { border-color: #75A5F0; }
-#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton,
-#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton {
- background: #1769E8; border-color: #1769E8; color: #FFFFFF;
-}
-#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton:hover,
-#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton:hover {
- background: #155BCC; border-color: #155BCC;
-}
-#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton:pressed,
-#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton:pressed {
- background: #124EA9; border-color: #124EA9;
-}
-#PrescriptionLibraryPage QPushButton[variant="danger"] { color: #BE4657; border-color: #E9D8DE; }
-#PrescriptionLibraryPage QPushButton:disabled,
-#PrescriptionLibraryPage QPushButton[variant="danger"]:disabled {
- color: #97A4B6; background: #F6F8FC; border-color: #E2E9F2;
-}
-#PrescriptionLibraryPage QLineEdit, #PrescriptionLibraryPage QComboBox {
- min-height: 38px; max-height: 38px; padding: 0 12px; border: 1px solid #DBE5F2;
- border-radius: 5px; background: #FFFFFF; color: #273244;
- selection-background-color: #DCEAFF; selection-color: #273244;
-}
-#PrescriptionLibraryPage QLineEdit:focus, #PrescriptionLibraryPage QComboBox:focus { border-color: #75A5F0; }
-#PrescriptionLibraryPage QLineEdit QToolButton { border: 0; background: transparent; padding: 0; }
-#PrescriptionLibraryPage QComboBox { padding-right: 30px; font-size: 13px; }
-#PrescriptionLibraryPage QComboBox::drop-down { width: 28px; border: 0; background: transparent; }
-#PrescriptionLibraryPage QComboBox::down-arrow { image: none; width: 0; height: 0; }
-#PrescriptionLibraryPage QComboBox:disabled { color: #97A4B6; background: #F6F8FC; }
-#PrescriptionLibraryPage QComboBox QAbstractItemView {
- font-family: "$body"; font-size: 13px; color: #273244; background: #FFFFFF;
- border: 1px solid #DBE5F2; outline: 0; selection-background-color: #EAF2FF; selection-color: #1555B6;
-}
-#PrescriptionLibraryPage QComboBox QAbstractItemView::item { min-height: 30px; padding: 3px 10px; }
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar { background: transparent; border: 0; }
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton { padding: 0 12px; font-size: 13px; }
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"] {
- min-width: 80px; min-height: 40px; max-height: 40px; padding: 0 10px; margin-right: 8px;
- background: transparent; border: 0; border-bottom: 2px solid transparent;
- border-radius: 0; color: #273244; font-size: 14px;
-}
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"]:checked {
- color: #1769E8; border-bottom-color: #1769E8;
-}
-#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"]:hover {
- color: #1555B6; background: #F2F7FF;
-}
-#PrescriptionLibraryPage QTableWidget {
- border: 0; background: #FFFFFF; alternate-background-color: #FFFFFF;
- selection-background-color: #F2F7FF; selection-color: #273244; gridline-color: #E6EDF6;
-}
-#PrescriptionLibraryPage QTableWidget::item { padding: 0; border: 0; }
-#PrescriptionLibraryPage QHeaderView::section {
- min-height: 0; padding: 0 12px; background: #F5F8FD; color: #5D6B80;
- border: 0; border-bottom: 1px solid #DBE5F2;
- font-family: "$body"; font-size: 13px; font-weight: 400;
-}
-#PrescriptionLibraryPage QWidget#PrescriptionLibraryTableCellHost { background: transparent; border: 0; }
-#PrescriptionLibraryPage QPushButton[rowAction="true"] {
- min-width: 28px; max-width: 28px; min-height: 28px; max-height: 28px;
- padding: 0; border: 1px solid transparent; border-radius: 4px; background: transparent;
-}
-#PrescriptionLibraryPage QPushButton[rowAction="true"]:hover { background: #EAF2FF; border-color: #B6CDEE; }
-#PrescriptionLibraryPage QPushButton[rowAction="true"]:focus { border-color: #75A5F0; }
-#PrescriptionLibraryPage QPushButton[rowAction="true"][danger="true"]:hover { background: #FFF0F2; border-color: #EAC8D0; }
-#PrescriptionLibraryPage QPushButton[rowAction="true"]:disabled { background: transparent; border-color: transparent; color: #A4ADBA; }
-#PrescriptionLibraryPage QWidget#InfiniteList { background: #FFFFFF; border-top: 1px solid #E6EDF6; }
-#PrescriptionLibraryPage QLabel#EmptyStateGlyph {
- font-size: 24px; color: #1769E8; background: #F2F7FF;
- border: 1px solid #DBE5F2; border-radius: 22px;
-}
-#PrescriptionLibraryPage QWidget#EmptyState QLabel[role="muted"] { min-width: 300px; }
-#PrescriptionLibraryPage QScrollBar:vertical { background: #F4F7FC; width: 7px; margin: 0; }
-#PrescriptionLibraryPage QScrollBar:horizontal { background: #F4F7FC; height: 7px; margin: 0; }
-#PrescriptionLibraryPage QScrollBar::handle { background: #C8D5E6; border-radius: 3px; min-width: 24px; min-height: 24px; }
-#PrescriptionLibraryPage QScrollBar::add-line, #PrescriptionLibraryPage QScrollBar::sub-line { width: 0; height: 0; }
-#PrescriptionLibraryPage QScrollBar::add-page, #PrescriptionLibraryPage QScrollBar::sub-page { background: transparent; }
-"""
-
-
-__all__ = ["library_stylesheet", "LibraryComboBox", "LibraryTable", "LibraryItemDelegate"]
+"""Shared clinical tokens for the prescription library and its native delegates."""
+
+from __future__ import annotations
+
+from collections.abc import Iterable, Sequence
+from string import Template
+from typing import Any
+
+from PySide6.QtCore import QEvent, QModelIndex, QRectF, QSize, Qt, QTimer
+from PySide6.QtGui import QColor, QFont, QFontMetrics, QIcon, QPainter
+from PySide6.QtWidgets import (
+ QComboBox,
+ QPushButton,
+ QStyle,
+ QStyledItemDelegate,
+ QToolTip,
+ QWidget,
+)
+
+from .design_system import PALETTE, RADII, clinical_stylesheet
+from .reception_style import body_family, heading_family
+from .widgets import SortableTable, TableColumn, first_value
+
+
+def library_stylesheet() -> str:
+ return clinical_stylesheet(Template(_LIBRARY).safe_substitute(body=body_family(), heading=heading_family()))
+
+
+def _library_icon(kind: str, color: str = PALETTE["accent"], size: int = 15) -> QIcon:
+ # Defer the page helper lookup so importing this module alone does not
+ # recurse through pages.__init__ and the library page's own style import.
+ from .pages.prescriptions import _painted_icon
+
+ result = QIcon()
+ for mode, tint in (
+ (QIcon.Mode.Normal, color),
+ (QIcon.Mode.Active, color),
+ (QIcon.Mode.Selected, color),
+ (QIcon.Mode.Disabled, PALETTE["disabled"]),
+ ):
+ pixmap = _painted_icon(kind, tint, size).pixmap(QSize(size, size))
+ for state in (QIcon.State.Off, QIcon.State.On):
+ result.addPixmap(pixmap, mode, state)
+ return result
+
+
+class LibraryComboBox(QComboBox):
+ """Keep native combo interaction while painting the local caret."""
+
+ def paintEvent(self, event: Any) -> None: # noqa: N802 - Qt virtual
+ super().paintEvent(event)
+ painter = QPainter(self)
+ try:
+ rect = QRectF(self.width() - 25, (self.height() - 14) / 2, 14, 14)
+ mode = QIcon.Mode.Normal if self.isEnabled() else QIcon.Mode.Disabled
+ _library_icon("chevron_down", PALETTE["muted"], 14).paint(painter, rect.toRect(), mode=mode)
+ finally:
+ painter.end()
+
+
+class LibraryTable(SortableTable):
+ """Fit readable columns while preserving actions and selected template IDs."""
+
+ _FLEX_COLUMNS = ((1, 2), (4, 5), (5, 2))
+
+ def __init__(self, columns: Sequence[TableColumn], parent: QWidget | None = None) -> None:
+ super().__init__(columns, parent)
+ self.horizontalHeader().setStretchLastSection(False)
+ self._minimum_widths = tuple(column.width for column in self.columns)
+ self._manual_widths: dict[int, int] = {}
+ self._fitting_columns = False
+ self._fit_timer = QTimer(self)
+ self._fit_timer.setSingleShot(True)
+ self._fit_timer.timeout.connect(self._fit_columns)
+ self.horizontalHeader().sectionResized.connect(self._column_resized)
+ self.viewport().installEventFilter(self)
+
+ def eventFilter(self, watched: Any, event: QEvent) -> bool: # noqa: N802
+ if watched is self.viewport() and event.type() in {QEvent.Type.Resize, QEvent.Type.Show}:
+ self._schedule_column_fit()
+ return super().eventFilter(watched, event)
+
+ def _schedule_column_fit(self) -> None:
+ if not self._fit_timer.isActive():
+ self._fit_timer.start(0)
+
+ def _column_resized(self, column: int, _old_size: int, size: int) -> None:
+ if self._fitting_columns:
+ return
+ self._manual_widths[column] = max(self._minimum_widths[column], size)
+ self._schedule_column_fit()
+
+ def _fit_columns(self) -> None:
+ widths = [self._manual_widths.get(column, minimum)
+ for column, minimum in enumerate(self._minimum_widths)]
+ extra = max(0, self.viewport().width() - sum(widths))
+ flexible = [(column, weight) for column, weight in self._FLEX_COLUMNS
+ if column not in self._manual_widths]
+ # If every text column was manually sized, keep those preferences as
+ # minimums and let the herb preview absorb any remaining wide-screen space.
+ flexible = flexible or [(4, 1)]
+ total_weight = sum(weight for _column, weight in flexible)
+ for column, weight in flexible:
+ widths[column] += extra * weight // total_weight
+ widths[flexible[0][0]] += max(0, self.viewport().width() - sum(widths))
+ if widths == [self.columnWidth(column) for column in range(self.columnCount())]:
+ return
+ self._fitting_columns = True
+ try:
+ for column, width in enumerate(widths):
+ self.setColumnWidth(column, width)
+ finally:
+ self._fitting_columns = False
+
+ def set_rows(self, rows: Iterable[Any]) -> None:
+ selected_id = first_value(self.current_data(), "id", "template_id", default=None)
+ super().set_rows(rows)
+ # The shared table restores an unsorted row index after enabling sort.
+ # Locate the same source object in the finished visual order instead.
+ if selected_id is not None:
+ for row_index in range(self.rowCount()):
+ item = self.item(row_index, 0)
+ row = item.data(Qt.ItemDataRole.UserRole) if item is not None else None
+ row_id = first_value(row, "id", "template_id", default=None)
+ if row_id is not None and str(row_id) == str(selected_id):
+ self.selectRow(row_index)
+ return
+ self.clearSelection()
+ self.setCurrentCell(-1, -1)
+
+ def setCellWidget(self, row: int, column: int, widget: QWidget | None) -> None: # noqa: N802
+ super().setCellWidget(row, column, widget)
+ if widget is None or column != 9:
+ return
+ widget.setObjectName("PrescriptionLibraryTableCellHost")
+ widget.setAutoFillBackground(False)
+ glyphs = {
+ "查看处方模板": "eye",
+ "AI 解释": "spark",
+ "编辑处方模板": "pencil",
+ "删除处方模板": "trash",
+ }
+ for button in widget.findChildren(QPushButton):
+ if not button.property("rowAction"):
+ continue
+ glyph = glyphs.get(button.accessibleName()) or glyphs.get(button.toolTip())
+ if glyph is not None:
+ color = PALETTE["danger"] if button.property("danger") else PALETTE["accent"]
+ button.setIcon(_library_icon(glyph, color, button.iconSize().width()))
+
+
+def _library_font(size: int = 14, *, medium: bool = False) -> QFont:
+ font = QFont(heading_family() if medium else body_family())
+ font.setPixelSize(size)
+ font.setWeight(QFont.Weight.Medium if medium else QFont.Weight.Normal)
+ return font
+
+
+def _elide(text: str, metrics: QFontMetrics, width: int) -> str:
+ return metrics.elidedText(text, Qt.TextElideMode.ElideRight, max(1, width))
+
+
+def _herb_lines(text: str, metrics: QFontMetrics, width: int) -> list[str]:
+ """Wrap between complete herb entries; elide only the displayed lines."""
+ entries = text.split("、")
+ first = entries[0]
+ next_index = 1
+ while next_index < min(2, len(entries)):
+ candidate = first + "、" + entries[next_index]
+ if metrics.horizontalAdvance(candidate) > width:
+ break
+ first = candidate
+ next_index += 1
+ lines = [_elide(first, metrics, width)]
+ if next_index < len(entries):
+ lines.append(_elide("、".join(entries[next_index:]), metrics, width))
+ return lines
+
+
+def _name_lines(text: str, metrics: QFontMetrics, width: int) -> list[str]:
+ if metrics.horizontalAdvance(text) <= width:
+ return [text]
+ split = 1
+ while split < len(text) and metrics.horizontalAdvance(text[: split + 1]) <= width:
+ split += 1
+ return [_elide(text[:split], metrics, width), _elide(text[split:], metrics, width)]
+
+
+class LibraryItemDelegate(QStyledItemDelegate):
+ """Paint the ten existing columns without changing display or source roles."""
+
+ def sizeHint(self, option: Any, index: QModelIndex) -> QSize: # noqa: N802
+ size = super().sizeHint(option, index)
+ size.setHeight(78)
+ return size
+
+ def helpEvent(self, event: Any, view: Any, option: Any, index: QModelIndex) -> bool: # noqa: N802
+ if event is not None and index.isValid() and index.column() != 9:
+ text = index.data(Qt.ItemDataRole.ToolTipRole) or index.data(Qt.ItemDataRole.DisplayRole)
+ if text:
+ QToolTip.showText(event.globalPos(), str(text), view)
+ return True
+ return super().helpEvent(event, view, option, index)
+
+ @staticmethod
+ def _paint_lines(
+ painter: QPainter,
+ rect: QRectF,
+ lines: list[str],
+ *,
+ secondary_muted: bool = False,
+ ) -> None:
+ line_height = 26
+ top = rect.center().y() - len(lines) * line_height / 2
+ for line_index, line in enumerate(lines):
+ if secondary_muted and line_index:
+ painter.setFont(_library_font(13))
+ painter.setPen(QColor(PALETTE["muted"]))
+ line_rect = QRectF(rect.left(), top + line_index * line_height, rect.width(), line_height)
+ painter.drawText(line_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, line)
+
+ def paint(self, painter: QPainter, option: Any, index: QModelIndex) -> None:
+ painter.save()
+ try:
+ painter.setClipRect(option.rect)
+ selected = bool(option.state & QStyle.StateFlag.State_Selected)
+ hovered = bool(option.state & QStyle.StateFlag.State_MouseOver)
+ background = PALETTE["accent_soft"] if selected else PALETTE["surface_alt"] if hovered else PALETTE["surface"]
+ painter.fillRect(option.rect, QColor(background))
+ painter.setPen(QColor(PALETTE["line"]))
+ painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
+ if selected and index.column() == 0:
+ stripe = QRectF(option.rect.left(), option.rect.top(), 3, option.rect.height() - 1)
+ painter.fillRect(stripe, QColor(PALETTE["accent"]))
+ if option.state & QStyle.StateFlag.State_HasFocus:
+ painter.setPen(QColor(PALETTE["focus"]))
+ painter.setBrush(Qt.BrushStyle.NoBrush)
+ painter.drawRect(option.rect.adjusted(1, 1, -2, -2))
+
+ column = index.column()
+ if column == 9:
+ return
+ rect = QRectF(option.rect.adjusted(12, 0, -12, -1))
+ if rect.width() <= 0:
+ return
+ value = index.data(Qt.ItemDataRole.DisplayRole)
+ text = "" if value is None else str(value)
+ font = _library_font(medium=column == 1)
+ painter.setFont(font)
+ painter.setPen(QColor(PALETTE["text"]))
+ metrics = QFontMetrics(font)
+ width = int(rect.width())
+
+ if column == 2:
+ painter.setFont(_library_font(13))
+ metrics = painter.fontMetrics()
+ label = _elide(text, metrics, width - 12)
+ pill_width = min(rect.width(), metrics.horizontalAdvance(label) + 14)
+ pill = QRectF(rect.center().x() - pill_width / 2, rect.center().y() - 12, pill_width, 24)
+ painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
+ painter.setPen(Qt.PenStyle.NoPen)
+ painter.setBrush(QColor(PALETTE["accent_soft"]))
+ painter.drawRoundedRect(pill, RADII["small"], RADII["small"])
+ painter.setPen(QColor(PALETTE["accent"]))
+ painter.drawText(pill, Qt.AlignmentFlag.AlignCenter, label)
+ elif column == 6:
+ glyph = "users" if text == "所有人可见" else "lock"
+ icon_rect = QRectF(rect.left(), rect.center().y() - 7, 14, 14)
+ _library_icon(glyph, PALETTE["muted"], 14).paint(painter, icon_rect.toRect())
+ label_rect = rect.adjusted(22, 0, 0, 0)
+ painter.drawText(
+ label_rect,
+ Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
+ _elide(text, metrics, int(label_rect.width())),
+ )
+ elif column == 4:
+ self._paint_lines(painter, rect, _herb_lines(text, metrics, width))
+ elif column == 8:
+ parts = text.splitlines() if "\n" in text else text.rsplit(" ", 1)
+ lines = [_elide(parts[0], metrics, width)]
+ if len(parts) > 1:
+ lines.append(_elide(" ".join(parts[1:]), QFontMetrics(_library_font(13)), width))
+ self._paint_lines(painter, rect, lines, secondary_muted=True)
+ elif column == 1:
+ self._paint_lines(painter, rect, _name_lines(text, metrics, width))
+ else:
+ alignment = Qt.AlignmentFlag.AlignCenter if column in (0, 3, 5) else (
+ Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter
+ )
+ painter.drawText(rect, alignment, _elide(text, metrics, width))
+ finally:
+ painter.restore()
+
+
+_LIBRARY = """
+#PrescriptionLibraryPage { background: $ds_canvas; color: $ds_text; }
+#PrescriptionLibraryPage QWidget#PrescriptionLibraryContent,
+#PrescriptionLibraryPage QScrollArea#PrescriptionLibraryScroll,
+#PrescriptionLibraryPage QScrollArea#PrescriptionLibraryToolbarScroll {
+ background: transparent; border: 0;
+}
+#PrescriptionLibraryPage QLabel, #PrescriptionLibraryPage QPushButton,
+#PrescriptionLibraryPage QLineEdit, #PrescriptionLibraryPage QComboBox,
+#PrescriptionLibraryPage QTableWidget {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+}
+#PrescriptionLibraryPage QLabel[role="pageTitle"] {
+ font-family: "$heading"; font-size: 20px; font-weight: 600; color: $ds_heading;
+}
+#PrescriptionLibraryPage QLabel[role="muted"] { color: $ds_muted; font-size: 13px; }
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryFilterBar,
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryTableCard {
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PrescriptionLibraryPage QFrame#MetricCard { background: $ds_surface; border: 0; border-radius: $ds_radius_panel; }
+#PrescriptionLibraryPage QFrame#MetricCard QLabel[role="metricTitle"] {
+ font-family: "$body"; color: $ds_muted; font-size: 13px; font-weight: 400;
+}
+#PrescriptionLibraryPage QFrame#MetricCard QLabel[role="metricValue"] {
+ font-family: "$heading"; color: $ds_text; font-size: 18px; font-weight: 600;
+}
+#PrescriptionLibraryPage QFrame#MetricCard QLabel[metricIcon="true"] {
+ border: 0; border-radius: 0; background: transparent;
+}
+#PrescriptionLibraryPage QPushButton {
+ min-height: 38px; max-height: 38px; padding: 0 16px; border-radius: $ds_radius_control;
+ border: 1px solid transparent; background: $ds_surface_alt; color: $ds_text;
+}
+#PrescriptionLibraryPage QPushButton:hover { background: $ds_surface_alt; border-color: $ds_line_strong; color: $ds_accent; }
+#PrescriptionLibraryPage QPushButton:pressed { background: $ds_accent_soft; }
+#PrescriptionLibraryPage QPushButton:focus { border-color: $ds_focus; }
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton,
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton {
+ background: $ds_accent; border-color: $ds_accent; color: $ds_surface;
+}
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton:hover,
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton:hover {
+ background: $ds_accent_hover; border-color: $ds_accent_hover;
+}
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton:pressed,
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton:pressed {
+ background: $ds_accent_pressed; border-color: $ds_accent_pressed;
+}
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton:focus,
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton:focus { border-color: $ds_focus; }
+#PrescriptionLibraryPage QPushButton[variant="danger"] { color: $ds_danger; background: $ds_danger_soft; border-color: transparent; }
+#PrescriptionLibraryPage QPushButton[variant="danger"]:hover { border-color: $ds_danger; }
+#PrescriptionLibraryPage QPushButton[variant="danger"]:focus { border-color: $ds_focus; }
+#PrescriptionLibraryPage QPushButton:disabled,
+#PrescriptionLibraryPage QPushButton[variant="danger"]:disabled,
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryAddButton:disabled,
+#PrescriptionLibraryPage QPushButton#PrescriptionLibraryQueryButton:disabled {
+ color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line;
+}
+#PrescriptionLibraryPage QLineEdit, #PrescriptionLibraryPage QComboBox {
+ min-height: 38px; max-height: 38px; padding: 0 12px; border: 1px solid $ds_line;
+ border-radius: $ds_radius_control; background: $ds_surface; color: $ds_text;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text;
+}
+#PrescriptionLibraryPage QLineEdit:focus, #PrescriptionLibraryPage QComboBox:focus { border-color: $ds_focus; }
+#PrescriptionLibraryPage QLineEdit QToolButton { border: 0; background: transparent; padding: 0; }
+#PrescriptionLibraryPage QComboBox { padding-right: 30px; font-size: 13px; }
+#PrescriptionLibraryPage QComboBox::drop-down { width: 28px; border: 0; background: transparent; }
+#PrescriptionLibraryPage QComboBox::down-arrow { image: none; width: 0; height: 0; }
+#PrescriptionLibraryPage QComboBox:disabled { color: $ds_disabled; background: $ds_disabled_surface; }
+#PrescriptionLibraryPage QComboBox QAbstractItemView {
+ font-family: "$body"; font-size: 13px; color: $ds_text; background: $ds_surface;
+ border: 1px solid $ds_line; outline: 0; selection-background-color: $ds_accent_soft; selection-color: $ds_accent;
+}
+#PrescriptionLibraryPage QComboBox QAbstractItemView::item { min-height: 30px; padding: 3px 10px; }
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar { background: transparent; border: 0; }
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton { padding: 0 12px; font-size: 13px; }
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"] {
+ min-width: 80px; min-height: 40px; max-height: 40px; padding: 0 10px; margin-right: 8px;
+ background: transparent; border: 0; border-bottom: 2px solid transparent;
+ border-radius: 0; color: $ds_text; font-size: 14px;
+}
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"]:checked {
+ color: $ds_accent; border-bottom-color: $ds_accent;
+}
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"]:hover {
+ color: $ds_accent; background: $ds_surface_alt;
+}
+#PrescriptionLibraryPage QFrame#PrescriptionLibraryToolbar QPushButton[toolbarTab="true"]:focus { background: $ds_accent_soft; }
+#PrescriptionLibraryPage QTableWidget {
+ border: 0; background: $ds_surface; alternate-background-color: $ds_surface;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text; gridline-color: $ds_line;
+}
+#PrescriptionLibraryPage QTableWidget::item { padding: 0; border: 0; }
+#PrescriptionLibraryPage QHeaderView::section {
+ min-height: 0; padding: 0 12px; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-bottom: 1px solid $ds_line;
+ font-family: "$body"; font-size: 13px; font-weight: 400;
+}
+#PrescriptionLibraryPage QWidget#PrescriptionLibraryTableCellHost { background: transparent; border: 0; }
+#PrescriptionLibraryPage QPushButton[rowAction="true"] {
+ min-width: 28px; max-width: 28px; min-height: 28px; max-height: 28px;
+ padding: 0; border: 1px solid transparent; border-radius: $ds_radius_small; background: transparent;
+}
+#PrescriptionLibraryPage QPushButton[rowAction="true"]:hover { background: $ds_accent_soft; border-color: $ds_line_strong; }
+#PrescriptionLibraryPage QPushButton[rowAction="true"]:focus { border-color: $ds_focus; }
+#PrescriptionLibraryPage QPushButton[rowAction="true"][danger="true"]:hover { background: $ds_danger_soft; border-color: $ds_danger_soft; }
+#PrescriptionLibraryPage QPushButton[rowAction="true"][danger="true"]:focus { border-color: $ds_focus; }
+#PrescriptionLibraryPage QPushButton[rowAction="true"]:disabled { background: transparent; border-color: transparent; color: $ds_disabled; }
+#PrescriptionLibraryPage QWidget#InfiniteList { background: $ds_surface; border-top: 1px solid $ds_line; }
+#PrescriptionLibraryPage QLabel#EmptyStateGlyph {
+ font-size: 24px; color: $ds_accent; background: $ds_surface_alt;
+ border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PrescriptionLibraryPage QWidget#EmptyState QLabel[role="muted"] { min-width: 300px; }
+#PrescriptionLibraryPage QScrollBar:vertical { background: $ds_canvas; width: 7px; margin: 0; }
+#PrescriptionLibraryPage QScrollBar:horizontal { background: $ds_canvas; height: 7px; margin: 0; }
+#PrescriptionLibraryPage QScrollBar::handle { background: $ds_line_strong; border-radius: 3px; min-width: 24px; min-height: 24px; }
+#PrescriptionLibraryPage QScrollBar::add-line, #PrescriptionLibraryPage QScrollBar::sub-line { width: 0; height: 0; }
+#PrescriptionLibraryPage QScrollBar::add-page, #PrescriptionLibraryPage QScrollBar::sub-page { background: transparent; }
+"""
+
+
+__all__ = ["library_stylesheet", "LibraryComboBox", "LibraryTable", "LibraryItemDelegate"]
diff --git a/app/src/doctor_workstation/ui/prescriptions_style.py b/app/src/doctor_workstation/ui/prescriptions_style.py
index bf1554418..9d452dfcf 100755
--- a/app/src/doctor_workstation/ui/prescriptions_style.py
+++ b/app/src/doctor_workstation/ui/prescriptions_style.py
@@ -1,107 +1,115 @@
-"""Scoped surfaces and real fonts for the approved issued-prescription page."""
-
-from string import Template
-
-from .reception_style import body_family, heading_family
-
-
-def prescriptions_stylesheet() -> str:
- return Template(_PRESCRIPTIONS).substitute(body=body_family(), heading=heading_family())
-
-
-_PRESCRIPTIONS = """
-#PrescriptionsPage { background: #F3F7FD; color: #273244; }
-#PrescriptionWorkspaceContent, #PrescriptionWorkspaceScroll { background: transparent; border: 0; }
-#PrescriptionsPage QLabel, #PrescriptionsPage QPushButton, #PrescriptionsPage QLineEdit,
-#PrescriptionsPage QComboBox, #PrescriptionsPage QDateTimeEdit, #PrescriptionsPage QTableWidget {
- font-family: "$body"; font-size: 14px; font-weight: 400; color: #273244;
-}
-#PrescriptionsPage QLabel[role="pageTitle"] {
- font-family: "$heading"; font-size: 20px; font-weight: 600; color: #202C3F;
-}
-#PrescriptionsPage QLabel[role="sectionTitle"] {
- font-family: "$heading"; font-size: 14px; font-weight: 600;
-}
-#PrescriptionsPage QLabel[role="muted"], #PrescriptionsPage QLabel#PrescriptionCountBadge {
- color: #5D6B80; font-size: 13px; background: transparent; border: 0; padding: 0;
-}
-#PrescriptionsPage QFrame#PrescriptionFilterBar, #PrescriptionsPage QFrame#PrescriptionTableCard {
- background: #FFFFFF; border: 1px solid #DBE5F2; border-radius: 8px;
-}
-#PrescriptionsPage QFrame#PrescriptionToolbar { background: transparent; border: 0; }
-#PrescriptionsPage QPushButton {
- min-height: 38px; max-height: 38px; padding: 0 16px; border-radius: 5px;
- border: 1px solid #DBE5F2; background: #FFFFFF; color: #273244;
-}
-#PrescriptionsPage QPushButton:hover { background: #F2F7FF; border-color: #B6CDEE; color: #1555B6; }
-#PrescriptionsPage QPushButton:pressed { background: #DCEAFF; }
-#PrescriptionsPage QPushButton:focus { border-color: #75A5F0; }
-#PrescriptionsPage QPushButton#PrescriptionAddButton, #PrescriptionsPage QPushButton#PrescriptionQueryButton {
- background: #1769E8; color: #FFFFFF; border-color: #1769E8;
-}
-#PrescriptionsPage QPushButton#PrescriptionAddButton:hover, #PrescriptionsPage QPushButton#PrescriptionQueryButton:hover {
- background: #155BCC; border-color: #155BCC;
-}
-#PrescriptionsPage QPushButton#PrescriptionAddButton:pressed, #PrescriptionsPage QPushButton#PrescriptionQueryButton:pressed {
- background: #124EA9; border-color: #124EA9;
-}
-#PrescriptionsPage QPushButton[variant="danger"] { color: #BE4657; background: #FFFFFF; border-color: #E9D8DE; }
-#PrescriptionsPage QPushButton:disabled, #PrescriptionsPage QPushButton[variant="danger"]:disabled {
- color: #97A4B6; background: #F6F8FC; border-color: #E2E9F2;
-}
-#PrescriptionsPage QLineEdit, #PrescriptionsPage QComboBox, #PrescriptionsPage QDateTimeEdit {
- min-height: 38px; max-height: 38px; padding: 0 12px; border: 1px solid #DBE5F2;
- border-radius: 5px; background: #FFFFFF; color: #273244;
- selection-background-color: #DCEAFF; selection-color: #273244;
-}
-#PrescriptionsPage QLineEdit:focus, #PrescriptionsPage QComboBox:focus, #PrescriptionsPage QDateTimeEdit:focus { border-color: #75A5F0; }
-#PrescriptionsPage QLineEdit QToolButton { min-width: 0; min-height: 0; border: 0; background: transparent; padding: 0; }
-#PrescriptionsPage QComboBox, #PrescriptionsPage QDateTimeEdit { padding-right: 30px; font-size: 13px; }
-#PrescriptionsPage QComboBox::drop-down, #PrescriptionsPage QDateTimeEdit::drop-down { width: 28px; border: 0; background: transparent; }
-#PrescriptionsPage QComboBox::down-arrow, #PrescriptionsPage QDateTimeEdit::down-arrow { image: none; width: 0; height: 0; }
-#PrescriptionsPage QDateTimeEdit:disabled { color: #8A97A9; background: #F6F8FC; border-color: #E2E9F2; }
-#PrescriptionsPage QPushButton#PrescriptionDoctorButton { text-align: left; padding-right: 30px; font-size: 13px; }
-#PrescriptionsPage QComboBox QAbstractItemView {
- font-family: "$body"; font-size: 13px; color: #273244; background: #FFFFFF;
- border: 1px solid #DBE5F2; outline: 0; selection-background-color: #EAF2FF; selection-color: #1555B6;
-}
-#PrescriptionsPage QComboBox QAbstractItemView::item { min-height: 30px; padding: 3px 10px; }
-#PrescriptionsPage QCalendarWidget { font-family: "$body"; font-size: 13px; background: #FFFFFF; color: #273244; }
-#PrescriptionsPage QCalendarWidget QWidget#qt_calendar_navigationbar { background: #F5F8FD; }
-#PrescriptionsPage QCalendarWidget QToolButton { min-height: 28px; border: 0; padding: 0 8px; color: #273244; background: transparent; }
-#PrescriptionsPage QCalendarWidget QAbstractItemView { color: #273244; background: #FFFFFF; selection-background-color: #1769E8; selection-color: #FFFFFF; outline: 0; }
-#PrescriptionsPage QFrame#PrescriptionToolbar QPushButton { padding: 0 12px; font-size: 13px; }
-#PrescriptionsPage QTableWidget#PrescriptionTable {
- border: 0; background: #FFFFFF; alternate-background-color: #FFFFFF;
- selection-background-color: #F2F7FF; selection-color: #273244; gridline-color: #E6EDF6;
-}
-#PrescriptionsPage QTableWidget#PrescriptionTable::item { border: 0; padding: 0; }
-#PrescriptionsPage QHeaderView::section {
- min-height: 0; padding: 0 12px; background: #F5F8FD; color: #5D6B80;
- border: 0; border-bottom: 1px solid #DBE5F2;
- font-family: "$body"; font-size: 13px; font-weight: 400;
-}
-#PrescriptionsPage QWidget#PrescriptionTableCellHost { border: 0; background: transparent; }
-#PrescriptionsPage QPushButton[rowAction="true"] {
- min-width: 28px; max-width: 28px; min-height: 28px; max-height: 28px;
- padding: 0; border: 1px solid transparent; border-radius: 4px; background: transparent;
-}
-#PrescriptionsPage QPushButton[rowAction="true"][labeled="true"] {
- min-width: 64px; max-width: 64px; color: #1769E8; font-size: 13px; padding: 0;
-}
-#PrescriptionsPage QPushButton[rowAction="true"]:hover { background: #EAF2FF; border-color: #B6CDEE; }
-#PrescriptionsPage QPushButton[rowAction="true"]:focus { border-color: #75A5F0; }
-#PrescriptionsPage QPushButton[rowAction="true"][danger="true"]:hover { background: #FFF0F2; border-color: #EAC8D0; }
-#PrescriptionsPage QPushButton[rowAction="true"]:disabled,
-#PrescriptionsPage QPushButton[rowAction="true"][labeled="true"]:disabled {
- background: transparent; border-color: transparent; color: #A4ADBA;
-}
-#PrescriptionsPage QWidget#InfiniteList { background: #FFFFFF; border-top: 1px solid #E6EDF6; }
-#PrescriptionsPage QLabel#EmptyStateGlyph { font-size: 24px; color: #1769E8; background: #F2F7FF; border: 1px solid #DBE5F2; border-radius: 22px; }
-#PrescriptionsPage QWidget#EmptyState QLabel[role="muted"] { min-width: 300px; }
-#PrescriptionsPage QScrollBar:vertical { background: #F4F7FC; width: 7px; margin: 0; }
-#PrescriptionsPage QScrollBar:horizontal { background: #F4F7FC; height: 7px; margin: 0; }
-#PrescriptionsPage QScrollBar::handle { background: #C8D5E6; border-radius: 3px; min-width: 24px; min-height: 24px; }
-#PrescriptionsPage QScrollBar::add-line, #PrescriptionsPage QScrollBar::sub-line { width: 0; height: 0; }
-#PrescriptionsPage QScrollBar::add-page, #PrescriptionsPage QScrollBar::sub-page { background: transparent; }
-"""
+"""Scoped surfaces and real fonts for the approved issued-prescription page."""
+
+from string import Template
+
+from .design_system import clinical_stylesheet
+from .reception_style import body_family, heading_family
+
+
+def prescriptions_stylesheet() -> str:
+ return clinical_stylesheet(Template(_PRESCRIPTIONS).safe_substitute(body=body_family(), heading=heading_family()))
+
+
+_PRESCRIPTIONS = """
+#PrescriptionsPage { background: $ds_canvas; color: $ds_text; }
+#PrescriptionWorkspaceContent, #PrescriptionWorkspaceScroll { background: transparent; border: 0; }
+#PrescriptionsPage QLabel, #PrescriptionsPage QPushButton, #PrescriptionsPage QLineEdit,
+#PrescriptionsPage QComboBox, #PrescriptionsPage QDateTimeEdit, #PrescriptionsPage QTableWidget {
+ font-family: "$body"; font-size: 14px; font-weight: 400; color: $ds_text;
+}
+#PrescriptionsPage QLabel[role="pageTitle"] {
+ font-family: "$heading"; font-size: 20px; font-weight: 600; color: $ds_heading;
+}
+#PrescriptionsPage QLabel[role="sectionTitle"] {
+ font-family: "$heading"; font-size: 14px; font-weight: 600;
+}
+#PrescriptionsPage QLabel[role="muted"], #PrescriptionsPage QLabel#PrescriptionCountBadge {
+ color: $ds_muted; font-size: 13px; background: transparent; border: 0; padding: 0;
+}
+#PrescriptionsPage QFrame#PrescriptionFilterBar, #PrescriptionsPage QFrame#PrescriptionTableCard {
+ background: $ds_surface; border: 1px solid $ds_line; border-radius: $ds_radius_panel;
+}
+#PrescriptionsPage QFrame#PrescriptionToolbar { background: transparent; border: 0; }
+#PrescriptionsPage QPushButton {
+ min-height: 38px; max-height: 38px; padding: 0 16px; border-radius: $ds_radius_control;
+ border: 1px solid transparent; background: $ds_surface_alt; color: $ds_text;
+}
+#PrescriptionsPage QPushButton:hover { background: $ds_surface_alt; border-color: $ds_line_strong; color: $ds_accent; }
+#PrescriptionsPage QPushButton:pressed { background: $ds_accent_soft; }
+#PrescriptionsPage QPushButton:focus { border-color: $ds_focus; }
+#PrescriptionsPage QPushButton#PrescriptionAddButton, #PrescriptionsPage QPushButton#PrescriptionQueryButton {
+ background: $ds_accent; color: $ds_surface; border-color: $ds_accent;
+}
+#PrescriptionsPage QPushButton#PrescriptionAddButton:hover, #PrescriptionsPage QPushButton#PrescriptionQueryButton:hover {
+ background: $ds_accent_hover; border-color: $ds_accent_hover;
+}
+#PrescriptionsPage QPushButton#PrescriptionAddButton:pressed, #PrescriptionsPage QPushButton#PrescriptionQueryButton:pressed {
+ background: $ds_accent_pressed; border-color: $ds_accent_pressed;
+}
+#PrescriptionsPage QPushButton#PrescriptionAddButton:focus,
+#PrescriptionsPage QPushButton#PrescriptionQueryButton:focus { border-color: $ds_focus; }
+#PrescriptionsPage QPushButton[variant="danger"] { color: $ds_danger; background: $ds_danger_soft; border-color: transparent; }
+#PrescriptionsPage QPushButton[variant="danger"]:hover { border-color: $ds_danger; }
+#PrescriptionsPage QPushButton[variant="danger"]:focus { border-color: $ds_focus; }
+#PrescriptionsPage QPushButton:disabled, #PrescriptionsPage QPushButton[variant="danger"]:disabled,
+#PrescriptionsPage QPushButton#PrescriptionAddButton:disabled,
+#PrescriptionsPage QPushButton#PrescriptionQueryButton:disabled {
+ color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line;
+}
+#PrescriptionsPage QLineEdit, #PrescriptionsPage QComboBox, #PrescriptionsPage QDateTimeEdit {
+ min-height: 38px; max-height: 38px; padding: 0 12px; border: 1px solid $ds_line;
+ border-radius: $ds_radius_control; background: $ds_surface; color: $ds_text;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text;
+}
+#PrescriptionsPage QLineEdit:focus, #PrescriptionsPage QComboBox:focus, #PrescriptionsPage QDateTimeEdit:focus { border-color: $ds_focus; }
+#PrescriptionsPage QLineEdit QToolButton { min-width: 0; min-height: 0; border: 0; background: transparent; padding: 0; }
+#PrescriptionsPage QComboBox, #PrescriptionsPage QDateTimeEdit { padding-right: 30px; font-size: 13px; }
+#PrescriptionsPage QComboBox::drop-down, #PrescriptionsPage QDateTimeEdit::drop-down { width: 28px; border: 0; background: transparent; }
+#PrescriptionsPage QComboBox::down-arrow, #PrescriptionsPage QDateTimeEdit::down-arrow { image: none; width: 0; height: 0; }
+#PrescriptionsPage QDateTimeEdit:disabled { color: $ds_disabled; background: $ds_disabled_surface; border-color: $ds_line; }
+#PrescriptionsPage QPushButton#PrescriptionDoctorButton { text-align: left; padding-right: 30px; font-size: 13px; }
+#PrescriptionsPage QComboBox QAbstractItemView {
+ font-family: "$body"; font-size: 13px; color: $ds_text; background: $ds_surface;
+ border: 1px solid $ds_line; outline: 0; selection-background-color: $ds_accent_soft; selection-color: $ds_accent;
+}
+#PrescriptionsPage QComboBox QAbstractItemView::item { min-height: 30px; padding: 3px 10px; }
+#PrescriptionsPage QCalendarWidget { font-family: "$body"; font-size: 13px; background: $ds_surface; color: $ds_text; }
+#PrescriptionsPage QCalendarWidget QWidget#qt_calendar_navigationbar { background: $ds_surface_alt; }
+#PrescriptionsPage QCalendarWidget QToolButton { min-height: 28px; border: 0; padding: 0 8px; color: $ds_text; background: transparent; }
+#PrescriptionsPage QCalendarWidget QAbstractItemView { color: $ds_text; background: $ds_surface; selection-background-color: $ds_accent; selection-color: $ds_surface; outline: 0; }
+#PrescriptionsPage QFrame#PrescriptionToolbar QPushButton { padding: 0 12px; font-size: 13px; }
+#PrescriptionsPage QTableWidget#PrescriptionTable {
+ border: 0; background: $ds_surface; alternate-background-color: $ds_surface;
+ selection-background-color: $ds_accent_soft; selection-color: $ds_text; gridline-color: $ds_line;
+}
+#PrescriptionsPage QTableWidget#PrescriptionTable::item { border: 0; padding: 0; }
+#PrescriptionsPage QHeaderView::section {
+ min-height: 0; padding: 0 12px; background: $ds_surface_alt; color: $ds_muted;
+ border: 0; border-bottom: 1px solid $ds_line;
+ font-family: "$body"; font-size: 13px; font-weight: 400;
+}
+#PrescriptionsPage QWidget#PrescriptionTableCellHost { border: 0; background: transparent; }
+#PrescriptionsPage QPushButton[rowAction="true"] {
+ min-width: 28px; max-width: 28px; min-height: 28px; max-height: 28px;
+ padding: 0; border: 1px solid transparent; border-radius: $ds_radius_small; background: transparent;
+}
+#PrescriptionsPage QPushButton[rowAction="true"][labeled="true"] {
+ min-width: 64px; max-width: 64px; color: $ds_accent; font-size: 13px; padding: 0;
+}
+#PrescriptionsPage QPushButton[rowAction="true"]:hover { background: $ds_accent_soft; border-color: $ds_line_strong; }
+#PrescriptionsPage QPushButton[rowAction="true"]:focus { border-color: $ds_focus; }
+#PrescriptionsPage QPushButton[rowAction="true"][danger="true"]:hover { background: $ds_danger_soft; border-color: $ds_danger_soft; }
+#PrescriptionsPage QPushButton[rowAction="true"][danger="true"]:focus { border-color: $ds_focus; }
+#PrescriptionsPage QPushButton[rowAction="true"]:disabled,
+#PrescriptionsPage QPushButton[rowAction="true"][labeled="true"]:disabled {
+ background: transparent; border-color: transparent; color: $ds_disabled;
+}
+#PrescriptionsPage QWidget#InfiniteList { background: $ds_surface; border-top: 1px solid $ds_line; }
+#PrescriptionsPage QLabel#EmptyStateGlyph { font-size: 24px; color: $ds_accent; background: $ds_surface_alt; border: 1px solid $ds_line; border-radius: $ds_radius_panel; }
+#PrescriptionsPage QWidget#EmptyState QLabel[role="muted"] { min-width: 300px; }
+#PrescriptionsPage QScrollBar:vertical { background: $ds_canvas; width: 7px; margin: 0; }
+#PrescriptionsPage QScrollBar:horizontal { background: $ds_canvas; height: 7px; margin: 0; }
+#PrescriptionsPage QScrollBar::handle { background: $ds_line_strong; border-radius: 3px; min-width: 24px; min-height: 24px; }
+#PrescriptionsPage QScrollBar::add-line, #PrescriptionsPage QScrollBar::sub-line { width: 0; height: 0; }
+#PrescriptionsPage QScrollBar::add-page, #PrescriptionsPage QScrollBar::sub-page { background: transparent; }
+"""
diff --git a/app/src/doctor_workstation/ui/reception_style.py b/app/src/doctor_workstation/ui/reception_style.py
index 23524d058..c19e1b737 100755
--- a/app/src/doctor_workstation/ui/reception_style.py
+++ b/app/src/doctor_workstation/ui/reception_style.py
@@ -4,23 +4,24 @@ from __future__ import annotations
from PySide6.QtWidgets import QApplication
+from .design_system import PALETTE
from .theme import _register_preferred_cjk_fonts
TECH_BLUE = {
- "accent": "#1769E8",
- "accent_hover": "#155BCC",
- "accent_pressed": "#124EA9",
- "selection": "#EAF2FF",
- "selected_text": "#1555B6",
- "canvas": "#F3F7FD",
- "sidebar": "#EDF4FF",
- "surface": "#FFFFFF",
- "raised": "#F7FAFE",
- "line": "#DBE5F2",
- "text": "#273244",
- "heading": "#202C3F",
- "muted": "#5D6B80",
- "focus": "#75A5F0",
+ "accent": PALETTE["accent"],
+ "accent_hover": PALETTE["accent_hover"],
+ "accent_pressed": PALETTE["accent_pressed"],
+ "selection": PALETTE["accent_soft"],
+ "selected_text": PALETTE["accent_hover"],
+ "canvas": PALETTE["canvas"],
+ "sidebar": PALETTE["sidebar"],
+ "surface": PALETTE["surface"],
+ "raised": PALETTE["surface_alt"],
+ "line": PALETTE["line"],
+ "text": PALETTE["text"],
+ "heading": PALETTE["heading"],
+ "muted": PALETTE["muted"],
+ "focus": PALETTE["focus"],
}
diff --git a/app/src/doctor_workstation/ui/reception_workspace.py b/app/src/doctor_workstation/ui/reception_workspace.py
index 0cb853d7f..6357fd1d3 100644
--- a/app/src/doctor_workstation/ui/reception_workspace.py
+++ b/app/src/doctor_workstation/ui/reception_workspace.py
@@ -170,8 +170,8 @@ QWidget#ReceptionPage QStackedWidget#ReceptionNarrowWorkspace {
}
QWidget#ReceptionPage QFrame#ReceptionQueuePanel {
background-color: #FFFFFF;
- border: 1px solid #E5ECF6;
- border-radius: 8px;
+ border: 1px solid #EDF0F5;
+ border-radius: 16px;
}
QWidget#ReceptionPage QLabel#ReceptionQueueTitle {
font-size: 18px;
@@ -200,8 +200,8 @@ QWidget#ReceptionPage QFrame#ReceptionHero,
QWidget#ReceptionPage QFrame#ReceptionClinicalCard {
min-height: 0;
background-color: #FFFFFF;
- border: 1px solid #E5ECF6;
- border-radius: 8px;
+ border: 1px solid #EDF0F5;
+ border-radius: 16px;
}
QWidget#ReceptionPage QLabel#ReceptionPatientName {
font-size: 20px;
@@ -223,8 +223,8 @@ QWidget#ReceptionPage QTabBar#ReceptionWorkspaceTabs {
background-color: #FFFFFF;
border: 0;
border-bottom: 1px solid #E5ECF6;
- border-top-left-radius: 8px;
- border-top-right-radius: 8px;
+ border-top-left-radius: 16px;
+ border-top-right-radius: 16px;
}
QWidget#ReceptionPage QTabBar#ReceptionDetailTabs::tab,
QWidget#ReceptionPage QTabBar#ReceptionWorkspaceTabs::tab {
@@ -295,8 +295,8 @@ QWidget#ReceptionPage QFrame#ReceptionPatientSummaryCard,
QWidget#ReceptionPage QFrame#ReceptionVitalsCard,
QWidget#ReceptionPage QFrame#ReceptionLabsCard {
background-color: #FFFFFF;
- border: 1px solid #E5ECF6;
- border-radius: 8px;
+ border: 1px solid #EDF0F5;
+ border-radius: 16px;
}
QWidget#ReceptionPage QLabel#ReceptionPatientSummaryValue {
color: #24334A;
@@ -367,8 +367,8 @@ QWidget#ReceptionPage QLabel[receptionMetricState="true"][alert="true"][warning=
QWidget#ReceptionPage QFrame#ReceptionAiAnalysisCard,
QWidget#ReceptionPage QFrame#ReceptionAiAssistantCard {
background-color: #FFFFFF;
- border: 1px solid #DCE5F0;
- border-radius: 8px;
+ border: 1px solid $ds_line;
+ border-radius: $ds_radius_panel;
}
QWidget#ReceptionPage QLabel#ReceptionAiTitle,
QWidget#ReceptionPage QPushButton#ReceptionAiTitle {
@@ -405,4 +405,37 @@ QWidget#ReceptionPage QScrollArea#ReceptionInsightsScroll QScrollBar::add-line:v
QWidget#ReceptionPage QScrollArea#ReceptionInsightsScroll QScrollBar::sub-line:vertical {
height: 0;
}
+QWidget#ReceptionPage QLineEdit#ReceptionQueueSearch,
+QWidget#ReceptionPage QPushButton#ReceptionDateButton,
+QWidget#ReceptionPage QPushButton#ReceptionQueueFilterToggle,
+QWidget#ReceptionPage QPushButton#ReceptionVideoButton,
+QWidget#ReceptionPage QPushButton#ReceptionNotifyButton,
+QWidget#ReceptionPage QPushButton#ReceptionHistoryButton,
+QWidget#ReceptionPage QPushButton#ReceptionImButton,
+QWidget#ReceptionPage QPushButton#ReceptionMoreButton,
+QWidget#ReceptionPage QPushButton#ReceptionCompleteButton,
+QWidget#ReceptionPage QPushButton[receptionAiPrompt="true"] {
+ border-radius: $ds_radius_control;
+}
+QWidget#ReceptionPage QPushButton:focus,
+QWidget#ReceptionPage QLineEdit:focus,
+QWidget#ReceptionPage QComboBox:focus,
+QWidget#ReceptionPage QTextEdit:focus {
+ border-color: $ds_focus;
+}
+QWidget#ReceptionPage QPushButton#ReceptionVideoButton:pressed {
+ color: $ds_surface;
+ background-color: $ds_accent_pressed;
+ border-color: $ds_accent_pressed;
+}
+QWidget#ReceptionPage QLabel[receptionMetricState="true"] {
+ border-radius: $ds_radius_small;
+}
+QWidget#ReceptionPage QFrame#ReceptionLabCell,
+QWidget#ReceptionPage QWidget#ReceptionCaseField {
+ border-bottom-color: $ds_line;
+}
+QWidget#ReceptionPage QLabel#ReceptionPatientSummaryValue[missing="true"] {
+ color: $ds_muted;
+}
"""
diff --git a/app/src/doctor_workstation/ui/shell.py b/app/src/doctor_workstation/ui/shell.py
index 5abad6e8a..628f6573e 100755
--- a/app/src/doctor_workstation/ui/shell.py
+++ b/app/src/doctor_workstation/ui/shell.py
@@ -59,6 +59,7 @@ from .chat_notifications import (
ChatNotification,
ChatNotificationCenter,
)
+from .design_system import PALETTE, clinical_stylesheet
from .dialogs.ai_consult import can_open_ai_consult
from .dialogs.ai_consult_picker import select_and_present_ai_consult
from .dialogs.diagnosis import DiagnosisDialog
@@ -72,7 +73,7 @@ from .pages import (
ReceptionPage,
)
from .reception_style import TECH_BLUE, body_family, heading_family, number_family
-from .theme import COLORS, TYPE, crisp_pixmap
+from .theme import COLORS, METRICS, TYPE, crisp_pixmap
from .widgets import (
EmptyState,
StatusBadge,
@@ -93,8 +94,8 @@ _SHELL_DESIGN_SIZE = QSize(1710, 920)
_SHELL_MINIMUM_SIZE = QSize(1024, 640)
_RECEPTION_SIDEBAR_WIDTH = 208
_RECEPTION_TOPBAR_HEIGHT = 76
-_RECEPTION_SIDEBAR_COLOR = "#F3F7FD"
-_RECEPTION_CHROME_LINE = "#E7EDF7"
+_RECEPTION_SIDEBAR_COLOR = PALETTE["sidebar"]
+_RECEPTION_CHROME_LINE = PALETTE["line"]
# Approved pages share one chrome state, so navigation among them keeps it intact.
_TECH_BLUE_PAGES = frozenset({"appointments", "consultations", "patients", "prescriptions", "prescription_library", "reception"})
@@ -1005,7 +1006,7 @@ class ShellWindow(QMainWindow):
chrome_widgets.extend(self.topbar.findChildren(_PaintedIconButton))
chrome_widgets.append(self.tabs_menu_button)
self._legacy_chrome_styles = {
- widget: widget.styleSheet() for widget in chrome_widgets
+ widget: clinical_stylesheet(widget.styleSheet()) for widget in chrome_widgets
}
self._register_pages()
self.search_shortcut = QShortcut(QKeySequence("Ctrl+K"), self)
@@ -1268,7 +1269,7 @@ class ShellWindow(QMainWindow):
color: #606163;
background-color: #FFFFFF;
border: 1px solid #EDEDEE;
- border-radius: 999px;
+ border-radius: 10px;
padding: 4px 10px;
font-size: 13px;
font-weight: 500;
@@ -1693,7 +1694,7 @@ class ShellWindow(QMainWindow):
font-family: "{body_family()}"; font-weight: 400;
min-height: 44px; max-height: 44px;
border: 0; border-left: 5px solid transparent;
- border-radius: 6px;
+ border-radius: {METRICS["r_md"]};
padding: 0 16px; font-size: {TYPE['fs_body']};
color: {TECH_BLUE['text']};
}}
@@ -1711,7 +1712,7 @@ class ShellWindow(QMainWindow):
}}
QPushButton#ShellNavButton[collapsed="true"] {{ padding: 0; }}
QFrame#ShellAssistantCard {{
- background-color: {TECH_BLUE['surface']}; border-radius: 8px;
+ background-color: {TECH_BLUE['surface']}; border-radius: {METRICS["r_lg"]};
border: 1px solid {_RECEPTION_CHROME_LINE};
}}
QLabel#ShellAssistantName {{
@@ -1723,7 +1724,7 @@ class ShellWindow(QMainWindow):
QPushButton#ShellAssistantButton, QPushButton#ShellSettingsButton {{
font-family: "{body_family()}"; font-weight: 400; font-size: {TYPE['fs_body']};
}}
- QPushButton#ShellAssistantButton {{ border-radius: 6px; }}
+ QPushButton#ShellAssistantButton {{ border-radius: {METRICS["r_md"]}; }}
QPushButton#ShellSettingsButton {{
min-height: 50px; max-height: 50px;
text-align: left; padding: 0 32px;
@@ -1738,7 +1739,7 @@ class ShellWindow(QMainWindow):
border-radius: 0;
border-bottom: 1px solid {_RECEPTION_CHROME_LINE};
}}
- QFrame#ShellGlobalSearch {{ border: 1px solid {_RECEPTION_CHROME_LINE}; border-radius: 5px; }}
+ QFrame#ShellGlobalSearch {{ background-color: {PALETTE["surface_alt"]}; border: 1px solid transparent; border-radius: {METRICS["r_md"]}; }}
QFrame#ShellUserSeparator {{ background: {_RECEPTION_CHROME_LINE}; border: 0; }}
QLabel#ShellShortcutHint {{
font-family: "{number_family()}"; font-size: {TYPE['fs_small']};
@@ -1767,7 +1768,7 @@ class ShellWindow(QMainWindow):
if isinstance(widget, _PaintedIconButton):
side = 50 if widget in (self.refresh_button, self.notification_button, self.settings_button) else 34
stylesheet += f"QToolButton#ShellPaintedIconButton {{ min-width: {side - 2}px; max-width: {side - 2}px; min-height: {side - 2}px; max-height: {side - 2}px; }}"
- widget.setStyleSheet(stylesheet)
+ widget.setStyleSheet(clinical_stylesheet(stylesheet))
self._set_reception_geometry(active)
for widget in (
diff --git a/app/src/doctor_workstation/ui/theme.py b/app/src/doctor_workstation/ui/theme.py
index c8b4e9d41..e62654238 100755
--- a/app/src/doctor_workstation/ui/theme.py
+++ b/app/src/doctor_workstation/ui/theme.py
@@ -41,46 +41,46 @@ from doctor_workstation.resources import resource_path
# ``motion`` deliberately imports nothing from this module, so this stays a
# one-way dependency: tokens here, animation there.
from . import motion
+from .design_system import PALETTE, RADII, SPACING, clinical_stylesheet
-# Neutral reading colors follow the installed Codex light chrome defaults.
+# Shared reading colors keep native pages and dialog chrome consistent.
# Brand accents are independent of reading ink; use opaque text for stable contrast.
# The legacy teal/ink aliases remain for existing callers.
COLORS = {
- "canvas": "#F4F6FA",
- "canvas_mid": "#FFFFFF",
- "canvas_glow": "#EEF1FA",
- "surface": "#FFFFFF",
- "surface_alt": "#F7F7F7",
- "raised": "#F7F7F7",
- "glass": "#FFFFFF",
- "glass_alt": "#F7F7F7",
- "line": "#EDEDEE",
- "line_soft": "#E4E4E5",
- "text": "#1A1C1F",
- "text_soft": "#606163",
- "muted": "#6A6B6D",
- "disabled_surface": "#F2F2F2",
- "disabled_text": "#8E8F90",
- "indigo": "#4F63D9",
- "indigo_hover": "#4156C4",
- "indigo_pressed": "#354BB4",
- "indigo_pale": "#EEF1FA",
- "focus": "#8B9AD9",
- "selection": "#EEF1FA",
- "success": "#287B65",
- "success_pale": "#EEF7F3",
- "warning": "#A9691D",
- "warning_pale": "#FCF5E9",
- "danger": "#BE4B58",
- "danger_pale": "#FCF0F2",
- "info": "#4F63D9",
- "info_pale": "#EEF1FA",
- # Backward-compatible names used by older UI code and integrations.
- "ink": "#1A1C1F",
- "ink_soft": "#606163",
- "teal": "#4F63D9",
- "teal_dark": "#354BB4",
- "teal_pale": "#EEF1FA",
+ "canvas": PALETTE["canvas"],
+ "canvas_mid": PALETTE["surface"],
+ "canvas_glow": PALETTE["accent_soft"],
+ "surface": PALETTE["surface"],
+ "surface_alt": PALETTE["surface_alt"],
+ "raised": PALETTE["surface_alt"],
+ "glass": PALETTE["surface"],
+ "glass_alt": PALETTE["surface_alt"],
+ "line": PALETTE["line"],
+ "line_soft": PALETTE["line_strong"],
+ "text": PALETTE["heading"],
+ "text_soft": PALETTE["text"],
+ "muted": PALETTE["muted"],
+ "disabled_surface": PALETTE["disabled_surface"],
+ "disabled_text": PALETTE["disabled"],
+ "indigo": PALETTE["accent"],
+ "indigo_hover": PALETTE["accent_hover"],
+ "indigo_pressed": PALETTE["accent_pressed"],
+ "indigo_pale": PALETTE["accent_soft"],
+ "focus": PALETTE["focus"],
+ "selection": PALETTE["accent_soft"],
+ "success": PALETTE["success"],
+ "success_pale": PALETTE["success_soft"],
+ "warning": PALETTE["warning"],
+ "warning_pale": PALETTE["warning_soft"],
+ "danger": PALETTE["danger"],
+ "danger_pale": PALETTE["danger_soft"],
+ "info": PALETTE["accent"],
+ "info_pale": PALETTE["accent_soft"],
+ "ink": PALETTE["heading"],
+ "ink_soft": PALETTE["text"],
+ "teal": PALETTE["accent"],
+ "teal_dark": PALETTE["accent_pressed"],
+ "teal_pale": PALETTE["accent_soft"],
}
@@ -122,11 +122,11 @@ METRICS = {
# ``outer - gap``. Where the gap is bigger than the outer radius the inner
# element is far enough from the corner that its own radius is free.
"r_xs": "4px", # chips, badges, tiny status pills
- "r_sm": "6px", # inline row actions, tags
- "r_md": "8px", # buttons, inputs, combo boxes
- "r_lg": "12px", # cards, filter bars, panels
- "r_xl": "16px", # the shell surfaces the cards sit on
- "pad_control": "12px", # horizontal padding inside default controls
+ "r_sm": f"{RADII['small']}px", # inline row actions, tags
+ "r_md": f"{RADII['control']}px", # buttons, inputs, combo boxes
+ "r_lg": f"{RADII['panel']}px", # cards, filter bars, panels
+ "r_xl": f"{RADII['window']}px", # the shell surfaces the cards sit on
+ "pad_control": f"{SPACING['control']}px", # horizontal padding inside default controls
"pad_compact": "9px",
}
@@ -176,7 +176,7 @@ QDialog[businessDialog="true"] QFrame#DialogSurface,
QDialog[businessDialog="true"] QFrame[dialogSurface="true"] {
background-color: $surface;
border: 1px solid $line;
- border-radius: 14px;
+ border-radius: $r_lg;
}
QDialog[businessDialog="true"] QFrame#DialogHeader,
QDialog[businessDialog="true"] QFrame[dialogRole="header"] {
@@ -275,18 +275,18 @@ QFrame#Card, QFrame#Panel, QFrame#FilterBar, QFrame#DetailPanel,
QFrame[glass="true"] {
background-color: $glass;
border: 1px solid $line;
- border-radius: 12px;
+ border-radius: $r_lg;
}
QFrame#FilterBar { background-color: $surface; }
QFrame#SubtleCard {
background-color: $glass_alt;
border: 1px solid $line;
- border-radius: 12px;
+ border-radius: $r_lg;
}
QFrame#MetricCard {
background-color: $surface;
border: 1px solid $line;
- border-radius: 11px;
+ border-radius: $r_md;
}
QFrame#MetricCard:hover { border-color: $line_soft; background-color: $surface_alt; }
QFrame#MetricCard QLabel[role="metricTitle"] { color: $muted; font-size: $fs_caption; }
@@ -297,7 +297,7 @@ QFrame#ReceptionAiCard {
min-height: 132px;
background-color: #FFFFFF;
border: 1px solid $line_soft;
- border-radius: 13px;
+ border-radius: $r_lg;
}
QLabel#ReceptionAiTitle {
color: $indigo_pressed;
@@ -313,7 +313,7 @@ QLabel#MetricGlyph {
color: $indigo;
background-color: $indigo_pale;
border: 1px solid $line_soft;
- border-radius: 11px;
+ border-radius: $r_md;
font-size: $fs_section;
font-weight: $fw_heading;
}
@@ -329,7 +329,7 @@ QGroupBox {
margin-top: 12px;
padding-top: 12px;
border: 1px solid $line;
- border-radius: 12px;
+ border-radius: $r_lg;
background-color: $glass;
font-weight: $fw_control;
}
@@ -351,7 +351,7 @@ QPushButton {
}
QPushButton:hover {
background-color: $raised;
- border-color: $indigo_hover;
+ border-color: $line_soft;
}
QPushButton:pressed {
background-color: $indigo_pale;
@@ -401,7 +401,7 @@ QPushButton[variant="primary"]:disabled {
QPushButton[variant="secondary"] {
color: $indigo_hover;
background-color: $indigo_pale;
- border-color: $line_soft;
+ border-color: $indigo_pale;
}
QPushButton[variant="secondary"]:hover {
color: $indigo_pressed;
@@ -462,7 +462,7 @@ QToolButton#RowActionsMore::menu-indicator { width: 0; height: 0; image: none; }
QFrame#NoteAttachmentTile {
background-color: $surface;
border: 1px solid $line;
- border-radius: 10px;
+ border-radius: $r_md;
}
QPushButton#NoteAttachmentPreview {
min-height: 132px;
@@ -470,7 +470,7 @@ QPushButton#NoteAttachmentPreview {
color: $muted;
background-color: $surface_alt;
border: 1px solid $line;
- border-radius: 8px;
+ border-radius: $r_md;
font-weight: $fw_control;
}
QPushButton#NoteAttachmentPreview:hover {
@@ -558,7 +558,7 @@ QPushButton[variant="chip"] {
color: $text_soft;
background-color: $surface_alt;
border-color: $line;
- border-radius: 8px;
+ border-radius: $r_md;
}
QPushButton[variant="chip"]:hover {
color: $text;
@@ -653,7 +653,7 @@ QComboBox QAbstractItemView {
background-color: $raised;
alternate-background-color: $surface_alt;
border: 1px solid $line;
- border-radius: 10px;
+ border-radius: $r_md;
padding: 5px;
outline: 0;
selection-background-color: $indigo_pressed;
@@ -692,7 +692,7 @@ QAbstractItemView, QTableWidget, QTableView, QListWidget, QListView, QTreeWidget
background-color: $surface;
alternate-background-color: $surface_alt;
border: 0;
- border-radius: 12px;
+ border-radius: $r_lg;
gridline-color: $line;
selection-background-color: $selection;
selection-color: $text;
@@ -729,17 +729,17 @@ QListWidget::item:selected, QListView::item:selected,
QTreeWidget::item:selected, QTreeView::item:selected {
background-color: $indigo_pale;
color: $indigo_pressed;
- border-radius: 8px;
+ border-radius: $r_md;
}
QListWidget::item:hover, QListView::item:hover,
QTreeWidget::item:hover, QTreeView::item:hover {
background-color: $surface_alt;
- border-radius: 8px;
+ border-radius: $r_md;
}
QTabWidget::pane {
border: 1px solid $line;
- border-radius: 12px;
+ border-radius: $r_lg;
background-color: $glass;
}
QTabBar::tab {
@@ -749,7 +749,7 @@ QTabBar::tab {
color: $muted;
background-color: transparent;
border: 1px solid transparent;
- border-radius: 9px;
+ border-radius: $r_md;
font-weight: $fw_control;
}
QTabBar::tab:hover { color: $text; background-color: $surface_alt; }
@@ -792,7 +792,7 @@ QMenu {
color: $text;
background-color: $raised;
border: 1px solid $line_soft;
- border-radius: 10px;
+ border-radius: $r_md;
padding: 6px;
}
QMenu::item {
@@ -815,7 +815,7 @@ QCalendarWidget {
color: $text;
background-color: $surface;
border: 1px solid $line;
- border-radius: 12px;
+ border-radius: $r_lg;
}
QCalendarWidget QWidget#qt_calendar_navigationbar {
background-color: $raised;
@@ -914,7 +914,7 @@ QWidget#Pager QLabel#PagerActive {
color: #FFFFFF;
background-color: $indigo;
border: 1px solid $indigo;
- border-radius: 8px;
+ border-radius: $r_md;
font-size: $fs_caption;
font-weight: $fw_control;
}
@@ -937,7 +937,7 @@ QLabel#EmptyStateGlyph {
QFrame#MessageBanner {
border: 1px solid $line;
- border-radius: 10px;
+ border-radius: $r_md;
color: $text_soft;
}
QFrame#MessageBanner QLabel { background-color: transparent; }
@@ -955,7 +955,7 @@ QLabel#Toast {
color: $text;
background-color: $raised;
border: 1px solid $line_soft;
- border-radius: 11px;
+ border-radius: $r_md;
padding: 11px 16px;
font-weight: $fw_control;
}
@@ -995,13 +995,9 @@ QLabel#UserAvatar {
font-weight: $fw_heading;
}
QWidget#LoginBrandPanel {
- background-color: qlineargradient(
- x1: 0, y1: 0, x2: 1, y2: 1,
- stop: 0 $surface,
- stop: 1 $canvas_glow
- );
+ background-color: $surface_alt;
border: 1px solid $line_soft;
- border-radius: 22px;
+ border-radius: $r_lg;
}
QFrame#LoginCard {
background-color: $glass;
@@ -1043,6 +1039,7 @@ QToolTip {
}
"""
).substitute(_QSS_TOKENS)
+GLOBAL_QSS = clinical_stylesheet(GLOBAL_QSS)
#: Per-block reading rhythm, in device pixels. ``(top, bottom, line%)``.
diff --git a/app/src/doctor_workstation/ui/widgets.py b/app/src/doctor_workstation/ui/widgets.py
index 60efcbfca..2c0b43167 100755
--- a/app/src/doctor_workstation/ui/widgets.py
+++ b/app/src/doctor_workstation/ui/widgets.py
@@ -44,6 +44,7 @@ from doctor_workstation.core.errors import (
)
from . import icons, motion
+from .design_system import PALETTE
AuthenticationExpiredHandler = Callable[[AuthenticationExpiredError], bool]
_AUTHENTICATION_EXPIRED_HANDLER: AuthenticationExpiredHandler | None = None
@@ -798,7 +799,7 @@ class _BusyTrack(QWidget):
chunk_width = max(36, int(rect.width() * 0.32))
span = rect.width() + chunk_width
x = int(self._phase * span) - chunk_width
- painter.setBrush(QColor("#4F63D9"))
+ painter.setBrush(QColor(PALETTE["accent"]))
painter.drawRoundedRect(x, 0, chunk_width, rect.height(), 3, 3)
diff --git a/app/src/doctor_workstation/video/im_ai.py b/app/src/doctor_workstation/video/im_ai.py
new file mode 100644
index 000000000..a184cb34a
--- /dev/null
+++ b/app/src/doctor_workstation/video/im_ai.py
@@ -0,0 +1,387 @@
+"""Bounded, Qt-independent AI requests for one authenticated IM window.
+
+Only server-archived clinical context is submitted. This module never sends IM
+messages and never shares the ordered call/recording lifecycle worker.
+"""
+
+from __future__ import annotations
+
+import re
+from collections import deque
+from collections.abc import Callable, Mapping
+from dataclasses import dataclass, field
+from threading import BoundedSemaphore, Event, RLock, Thread
+from time import monotonic
+from typing import Any
+from uuid import UUID, uuid4
+
+MAX_RESULT_CHARS = 65_536
+MAX_SYNC_STEPS = 24
+SYNC_TIMEOUT_SECONDS = 45.0
+_WORKER_SLOTS = BoundedSemaphore(4)
+_CANCEL_SLOTS = BoundedSemaphore(4)
+_ACTIONS = frozenset({"summary", "followup", "reply"})
+
+
+def _integer(value: Any, *, minimum: int) -> int | None:
+ if isinstance(value, bool) or not isinstance(value, (int, str)):
+ return None
+ if isinstance(value, str) and re.fullmatch(r"0|[1-9][0-9]{0,18}", value) is None:
+ return None
+ number = int(value)
+ return number if minimum <= number < 2**63 else None
+
+
+def _request_uuid(value: Any) -> bool:
+ if not isinstance(value, str) or len(value) != 36:
+ return False
+ try:
+ return str(UUID(value)) == value.lower()
+ except (ValueError, AttributeError):
+ return False
+
+
+def task_prompt(action: str, doctor_account: str) -> tuple[str, str]:
+ """Keep instructions separate from clinical source text and under API limits."""
+
+ if action not in _ACTIONS or not re.fullmatch(r"doctor_[1-9][0-9]{0,18}", doctor_account):
+ raise ValueError("AI 操作或当前医生账号无效")
+ shared = (
+ f"这是 IM 问诊辅助,本次医生 IM 账号为 {doctor_account}。"
+ "优先依据该医生与本患者最近已归档对话,结合服务端授权病历;"
+ "其他医生及历史记录仅作背景,不能当成本次已确认事实。"
+ "若未找到本次对话请明确说明,不猜测最新诉求。"
+ "区分已知、明确否认与未知,保留日期及不确定性;"
+ "不补问脉象,不编造事实、不自动确诊、不新增或更改药物剂量。"
+ )
+ instructions = {
+ "summary": "请用简短条目总结本次病情、病程、现用治疗与待核实事项,供医生交接复核。",
+ "followup": (
+ "请建议最多5条优先追问,直接给出可向患者询问的自然短句,"
+ "每条可附简短目的;避免重复已回答的问题,不做通用问卷。"
+ ),
+ "reply": (
+ "请起草一段医生可审阅后发给患者的简短自然回复,围绕该对话最近的患者问题。"
+ "不冒称已检查、已预约或已开处方,不承诺疗效,不让患者自行停换药。"
+ "只给回复草稿,不写分析过程;任何缺失资料通过必要的问题核实。"
+ ),
+ }
+ prompt = shared + instructions[action] + "此内容须由医生复核,不能自动发送。"
+ if len(prompt) > 500:
+ raise ValueError("AI 提示词超过接口长度限制")
+ return ("summary" if action == "summary" else "custom"), prompt
+
+
+def _warnings(value: Any) -> list[str]:
+ if not isinstance(value, (list, tuple)):
+ return []
+ warnings = []
+ for row in value[:20]:
+ if isinstance(row, str):
+ text = row
+ elif isinstance(row, Mapping):
+ text = row.get("message") or row.get("label")
+ if not text and row.get("code"):
+ text = (
+ "请复核回答中的脉象判断;本流程不采集脉象。"
+ if row["code"] == "PULSE_EXCLUDED_FROM_ASSESSMENT"
+ else "请对照原始记录复核,回答中的事实、否认或未知状态可能不一致。"
+ )
+ else:
+ continue
+ if isinstance(text, str) and text.strip():
+ rendered = text.strip()[:400]
+ if rendered not in warnings:
+ warnings.append(rendered)
+ return warnings
+
+
+class _RequestError(Exception):
+ """A deliberately safe, user-facing failure message."""
+
+
+@dataclass
+class _Job:
+ identity: dict[str, Any]
+ action: str
+ cancelled: Event = field(default_factory=Event)
+ completed: bool = False
+ succeeded: bool = False
+ stream_started: bool = False
+ cancel_sent: bool = False
+
+
+class ImAiController:
+ """One live request, a coalesced mailbox, and bounded daemon workers.
+
+ Qt polls ``take_result`` every 60 ms. Worker threads only mutate plain data;
+ they never touch a QObject. A cancelled worker must retire before a retry
+ starts, so rapid clicks cannot create an unbounded collection of requests.
+ """
+
+ def __init__(
+ self,
+ repository: Any,
+ *,
+ diagnosis_id: Any,
+ appointment_id: Any,
+ doctor_account: str,
+ enabled: bool = False,
+ clock: Callable[[], float] = monotonic,
+ max_sync_steps: int = MAX_SYNC_STEPS,
+ sync_timeout: float = SYNC_TIMEOUT_SECONDS,
+ ) -> None:
+ self.repository = repository
+ self.diagnosis_id = _integer(diagnosis_id, minimum=1)
+ self.appointment_id = _integer(appointment_id, minimum=0)
+ self.doctor_account = str(doctor_account)
+ self.enabled = (
+ enabled is True
+ and repository is not None
+ and self.diagnosis_id is not None
+ and self.appointment_id is not None
+ and re.fullmatch(r"doctor_[1-9][0-9]{0,18}", self.doctor_account) is not None
+ )
+ self.session_id = str(uuid4())
+ self._clock = clock
+ self._max_sync_steps = max(1, min(MAX_SYNC_STEPS, max_sync_steps))
+ self._sync_timeout = max(0.01, min(SYNC_TIMEOUT_SECONDS, sync_timeout))
+ self._lock = RLock()
+ self._closed = False
+ self._current: _Job | None = None
+ self._running: _Job | None = None
+ self._worker: Thread | None = None
+ self._mailbox: dict[str, Any] | None = None
+ self._seen: deque[str] = deque(maxlen=256)
+
+ @property
+ def config(self) -> dict[str, Any]:
+ return {
+ "version": 1,
+ "enabled": self.enabled and not self._closed,
+ "sessionId": self.session_id,
+ **({} if self.enabled else {"reason": "当前账号或问诊暂不能使用 AI 辅助。"}),
+ }
+
+ def _valid_identity(self, message: Mapping[str, Any]) -> bool:
+ return (
+ self.enabled
+ and not self._closed
+ and message.get("source") == "doctor-call"
+ and message.get("sessionId") == self.session_id
+ and _request_uuid(message.get("requestId"))
+ and isinstance(message.get("contextKey"), str)
+ and 0 < len(message["contextKey"]) <= 128
+ and _integer(message.get("diagnosisId"), minimum=1) == self.diagnosis_id
+ and _integer(message.get("appointmentId"), minimum=0) == self.appointment_id
+ and isinstance(message.get("action"), str)
+ and message["action"] in _ACTIONS
+ )
+
+ def handle(self, message: Mapping[str, Any]) -> bool:
+ with self._lock:
+ if not self._valid_identity(message):
+ return False
+ event = message.get("event")
+ identity = {key: message[key] for key in (
+ "sessionId", "requestId", "contextKey", "diagnosisId", "appointmentId", "action"
+ )}
+ if event == "im-ai-cancel":
+ if self._current is None or self._current.identity != identity:
+ return False
+ self._cancel(self._current)
+ return True
+ if event != "im-ai-request" or message["requestId"] in self._seen:
+ return False
+ self._seen.append(message["requestId"])
+ job = _Job(identity, message["action"])
+ if self._running is not None:
+ self._cancel(self._running)
+ self._current = job
+ self._publish(job, "error", message="上次请求正在结束,请稍后重试。", terminal=True)
+ return True
+ self._current = job
+ if not _WORKER_SLOTS.acquire(blocking=False):
+ self._publish(job, "error", message="AI 正在处理其他请求,请稍后重试。", terminal=True)
+ return True
+ self._running = job
+ self._publish(job, "loading", message="正在同步当前聊天记录…")
+ self._worker = Thread(target=self._run, args=(job,), name="im-ai", daemon=True)
+ try:
+ self._worker.start()
+ except RuntimeError:
+ self._running = None
+ _WORKER_SLOTS.release()
+ self._publish(job, "error", message="AI 请求暂时无法启动,请稍后重试。", terminal=True)
+ return True
+
+ def _publish(self, job: _Job, status: str, *, terminal: bool = False, **fields: Any) -> None:
+ with self._lock:
+ if self._closed or self._current is not job or job.cancelled.is_set() or job.completed:
+ return
+ if terminal:
+ job.completed = True
+ job.succeeded = status == "success"
+ self._mailbox = {**job.identity, "status": status, **fields}
+
+ def take_result(self) -> dict[str, Any] | None:
+ with self._lock:
+ result, self._mailbox = self._mailbox, None
+ return None if self._closed else result
+
+ def _sync(self, job: _Job) -> bool:
+ deadline = self._clock() + self._sync_timeout
+ token = ""
+ for _ in range(self._max_sync_steps):
+ if job.cancelled.is_set():
+ return False
+ if self._clock() >= deadline:
+ raise _RequestError("聊天同步超时,尚未生成,请稍后重试。")
+ result = self.repository.sync_im_chat_messages(
+ self.diagnosis_id, scope="current", sync_token=token
+ )
+ if job.cancelled.is_set():
+ return False
+ if self._clock() >= deadline:
+ raise _RequestError("聊天同步超时,尚未生成,请稍后重试。")
+ if not isinstance(result, Mapping) or result.get("errors"):
+ raise _RequestError("当前聊天记录未能完整同步,尚未生成,请稍后重试。")
+ if result.get("completed") is True:
+ return True
+ token = result.get("sync_token", "")
+ if not isinstance(token, str) or re.fullmatch(r"[a-f0-9]{48}", token) is None:
+ raise _RequestError("聊天同步进度无效,请更新客户端或稍后重试。")
+ raise _RequestError("聊天记录仍在同步,尚未生成,请稍后重试。")
+
+ def _run(self, job: _Job) -> None:
+ try:
+ if not self._sync(job):
+ return
+ task, prompt = task_prompt(job.action, self.doctor_account)
+ with self._lock:
+ if job.cancelled.is_set() or self._closed:
+ return
+ job.stream_started = True
+ self._publish(job, "loading", message="聊天已同步,正在整理病历资料…")
+ if job.cancelled.is_set():
+ return
+ text = ""
+ events = self.repository.stream_diagnosis_ai(
+ self.diagnosis_id, prompt, task=task,
+ request_id=job.identity["requestId"], cancelled=job.cancelled.is_set,
+ )
+ try:
+ for event in events:
+ if job.cancelled.is_set():
+ return
+ if not isinstance(event, Mapping):
+ continue
+ kind = event.get("event")
+ if kind == "delta":
+ delta = event.get("text", "")
+ if not isinstance(delta, str) or len(text) + len(delta) > MAX_RESULT_CHARS:
+ raise _RequestError("AI 内容超过显示上限,已停止接收,请缩小问题后重试。")
+ text += delta
+ self._publish(job, "streaming", text=text, message="正在生成,内容尚未完成。")
+ elif kind in {"start", "progress"}:
+ message = str(event.get("message") or "正在整理资料并生成…")[:240]
+ self._publish(job, "streaming" if text else "loading", text=text, message=message)
+ elif kind == "done":
+ result_id = event.get("diagnosis_id")
+ if result_id is not None and _integer(result_id, minimum=1) != self.diagnosis_id:
+ raise _RequestError("AI 返回的问诊上下文不匹配,结果未采用。")
+ answer = event.get("answer", event.get("content", text))
+ if not isinstance(answer, str) or not answer.strip():
+ raise _RequestError("AI 未返回完整内容,请重试。")
+ if len(answer) > MAX_RESULT_CHARS:
+ raise _RequestError("AI 内容超过显示上限,结果未采用,请缩小问题后重试。")
+ self._publish(
+ job, "success", terminal=True, text=answer,
+ message="已生成,请由医生复核后使用。",
+ modelLabel=str(event.get("model_label") or "")[:100],
+ warnings=_warnings(event.get("clinical_review_warnings")),
+ )
+ return
+ elif kind == "error":
+ raise _RequestError("AI 请求未完成,请检查权限或稍后重试。")
+ if not job.cancelled.is_set():
+ raise _RequestError("AI 连接提前结束,内容未完成,请重试。")
+ finally:
+ close = getattr(events, "close", None)
+ if callable(close):
+ close()
+ except Exception as error:
+ message = str(error) if isinstance(error, _RequestError) else (
+ "AI 请求失败,请检查权限或稍后重试。" if job.stream_started
+ else "当前聊天同步失败,尚未生成,请检查权限或稍后重试。"
+ )
+ self._publish(job, "error", message=message, terminal=True)
+ if job.stream_started and not job.cancelled.is_set() and not job.succeeded:
+ self._request_cancel(job)
+ finally:
+ with self._lock:
+ if self._running is job:
+ self._running = None
+ _WORKER_SLOTS.release()
+
+ def _cancel(self, job: _Job) -> None:
+ if job.completed or job.cancelled.is_set():
+ return
+ job.cancelled.set()
+ if self._current is job and not self._closed:
+ self._mailbox = {
+ **job.identity, "status": "cancelled",
+ "message": ("已停止本次接收,上游是否结束尚未确认。" if job.stream_started
+ else "已取消,尚未向 AI 提交请求。"),
+ }
+ if job.stream_started:
+ self._request_cancel(job)
+
+ def _request_cancel(self, job: _Job) -> None:
+ with self._lock:
+ if job.cancel_sent:
+ return
+ job.cancel_sent = True
+ if not _CANCEL_SLOTS.acquire(blocking=False):
+ return
+
+ def send() -> None:
+ try:
+ result = self.repository.cancel_diagnosis_ai(self.diagnosis_id, job.identity["requestId"])
+ if not isinstance(result, Mapping):
+ return
+ message = "已发送取消请求,上游是否结束尚未确认。"
+ terminal = result.get("upstream_terminal_status")
+ if result.get("upstream_terminal_confirmed") is True and terminal in {"stopped", "succeeded", "failed"}:
+ message = "本次接收已停止,上游工作流已结束。"
+ elif result.get("upstream_stop_confirmed") is True:
+ message = "上游已接受停止请求,是否结束尚未确认。"
+ with self._lock:
+ if not self._closed and self._current is job and job.cancelled.is_set():
+ self._mailbox = {**job.identity, "status": "cancelled", "message": message}
+ except Exception:
+ pass # Keep the visible unconfirmed cancellation; never expose transport details.
+ finally:
+ _CANCEL_SLOTS.release()
+
+ try:
+ Thread(target=send, name="im-ai-cancel", daemon=True).start()
+ except RuntimeError:
+ _CANCEL_SLOTS.release()
+
+ def close(self) -> None:
+ with self._lock:
+ if self._closed:
+ return
+ self._closed = True
+ self._mailbox = None
+ if self._running is not None:
+ self._cancel(self._running)
+
+ def wait(self, timeout: float = 1.0) -> bool:
+ """Bounded diagnostic/test helper; never called by the Qt GUI."""
+
+ worker = self._worker
+ if worker is not None:
+ worker.join(max(0.0, min(timeout, 5.0)))
+ return worker is None or not worker.is_alive()
diff --git a/app/src/doctor_workstation/video/launcher.py b/app/src/doctor_workstation/video/launcher.py
index f4efccbe9..45051df94 100755
--- a/app/src/doctor_workstation/video/launcher.py
+++ b/app/src/doctor_workstation/video/launcher.py
@@ -413,6 +413,7 @@ class VideoCallLauncher:
patient_name: str = "患者",
patient_case: Mapping[str, Any] | None = None,
on_open_diagnosis: Callable[[], None] | None = None,
+ can_ai_assistant: bool = False,
) -> Any:
request = self.prepare(
ticket,
@@ -432,6 +433,7 @@ class VideoCallLauncher:
patient_name=patient_name,
patient_case=patient_case,
on_open_diagnosis=on_open_diagnosis,
+ can_ai_assistant=can_ai_assistant is True,
)
@@ -450,6 +452,7 @@ def launch_video_call(
patient_name: str = "患者",
patient_case: Mapping[str, Any] | None = None,
on_open_diagnosis: Callable[[], None] | None = None,
+ can_ai_assistant: bool = False,
) -> Any:
"""Normalize a ticket and open a call with the requested backend."""
@@ -468,4 +471,5 @@ def launch_video_call(
patient_name=patient_name,
patient_case=patient_case,
on_open_diagnosis=on_open_diagnosis,
+ can_ai_assistant=can_ai_assistant is True,
)
diff --git a/app/src/doctor_workstation/video/lifecycle.py b/app/src/doctor_workstation/video/lifecycle.py
index b43f7b4c5..be11dbfd8 100755
--- a/app/src/doctor_workstation/video/lifecycle.py
+++ b/app/src/doctor_workstation/video/lifecycle.py
@@ -18,6 +18,7 @@ from dataclasses import dataclass
from pathlib import Path
from typing import Any, TypeVar
+from ..core.transcript_text import simplified_transcript
from .launcher import VideoCallRequest, normalize_backend_ticket
ResultT = TypeVar("ResultT")
@@ -134,7 +135,7 @@ def _extract_cloud_recording_outcome(result: Any) -> tuple[bool, str] | None:
return None
-def _clean_transcript_segment(segment: Mapping[str, Any], session_id: str) -> dict[str, Any]:
+def normalize_transcript_segment(segment: Mapping[str, Any], session_id: str) -> dict[str, Any]:
segment_id = str(segment.get("segment_id", segment.get("segmentId", ""))).strip()
text = str(segment.get("text", segment.get("sourceText", ""))).strip()
speaker_user_id = str(
@@ -145,13 +146,14 @@ def _clean_transcript_segment(segment: Mapping[str, Any], session_id: str) -> di
raise ValueError("transcript segment_id must contain 1 to 160 characters")
if not text or len(text) > 4_000:
raise ValueError("transcript text must contain 1 to 4000 characters")
+ text = simplified_transcript(text)
if len(speaker_user_id) > 160:
raise ValueError("transcript speaker_user_id is too long")
if speaker_role not in {"doctor", "patient", "unknown"}:
speaker_role = "unknown"
try:
timestamp = int(segment.get("timestamp") or 0)
- except (TypeError, ValueError):
+ except (TypeError, ValueError, OverflowError):
timestamp = 0
return {
"segment_id": segment_id,
@@ -543,10 +545,25 @@ class OrderedCallLifecycle:
with self._lock:
if self._end_future is not None:
raise RuntimeError("video call has already ended")
- if self._transcription_start_future is not None:
- if self._transcription_session_id != clean_session:
- raise RuntimeError("another transcription session already exists")
- return self._transcription_start_future
+ if self._transcription_finish_future is not None:
+ raise RuntimeError("call transcription has already stopped")
+ if (
+ self._transcription_session_id is not None
+ and self._transcription_session_id != clean_session
+ ):
+ raise RuntimeError("another transcription session already exists")
+ previous = self._transcription_start_future
+ if previous is not None:
+ if not previous.done() or (
+ not previous.cancelled()
+ and previous.exception() is None
+ and previous.result() is True
+ ):
+ return previous
+ # A completed failure must not poison this call's retry button.
+ # Keep the exact session identity: the server may have accepted
+ # an earlier request whose response never reached this client.
+ self._transcription_active = False
if self._start_future is None:
self.start()
method = getattr(self.repository, "start_call_transcription", None)
@@ -593,7 +610,7 @@ class OrderedCallLifecycle:
raise RuntimeError("call transcription has not started")
if self._transcription_finish_future is not None:
raise RuntimeError("call transcription has already stopped")
- cleaned = _clean_transcript_segment(segment, session_id)
+ cleaned = normalize_transcript_segment(segment, session_id)
segment_id = cleaned["segment_id"]
existing = self._segment_futures.get(segment_id)
if existing is not None:
@@ -738,4 +755,4 @@ class OrderedCallLifecycle:
return self._worker.wait(timeout)
-__all__ = ["OrderedCallLifecycle"]
+__all__ = ["OrderedCallLifecycle", "normalize_transcript_segment"]
diff --git a/app/src/doctor_workstation/video/live_ai.py b/app/src/doctor_workstation/video/live_ai.py
new file mode 100644
index 000000000..6cb373c94
--- /dev/null
+++ b/app/src/doctor_workstation/video/live_ai.py
@@ -0,0 +1,414 @@
+"""Incremental video assistance; never runs on the call persistence FIFO or Qt.
+
+Only persisted segment notifications trigger work. One in-flight request and
+one coalesced latest revision are retained, with explicit patient/call/session
+correlation. Clinical content is never written or sent to the patient here.
+"""
+from __future__ import annotations
+
+import copy
+import logging
+import math
+import re
+from collections.abc import Callable, Mapping
+from contextlib import suppress
+from dataclasses import dataclass, field
+from threading import BoundedSemaphore, Event, RLock, Thread
+from time import monotonic
+from typing import Any
+from uuid import uuid4
+
+from ..core.errors import (
+ ApiBusinessError,
+ ApiHttpError,
+ ApiProtocolError,
+ ApiTimeoutError,
+ ApiTransportError,
+ AuthenticationExpiredError,
+)
+
+_LOGGER = logging.getLogger(__name__)
+_SLOTS = BoundedSemaphore(2)
+_CANCEL_SLOTS = BoundedSemaphore(4)
+
+
+def _failure_details(error: Exception) -> tuple[str, str]:
+ """Translate stable error codes, never echo an upstream exception/response."""
+ if isinstance(error, ApiTimeoutError):
+ code = "UPSTREAM_TIMEOUT"
+ elif isinstance(error, AuthenticationExpiredError):
+ code = "AUTH_REQUIRED"
+ elif isinstance(error, ApiHttpError):
+ code = ({401: "AUTH_REQUIRED", 403: "PERMISSION_DENIED", 404: "SERVICE_UPDATE_REQUIRED",
+ 405: "SERVICE_UPDATE_REQUIRED", 429: "RATE_LIMITED"}.get(error.status_code)
+ or "UPSTREAM_UNAVAILABLE")
+ elif isinstance(error, ApiBusinessError) and isinstance(error.data, Mapping):
+ code = error.data.get("error_code") or error.data.get("code")
+ elif isinstance(error, ApiProtocolError):
+ code = "STREAM_INCOMPLETE"
+ elif isinstance(error, ApiTransportError):
+ code = "NETWORK_ERROR"
+ elif isinstance(error, ValueError):
+ code = "LIVE_RESULT_INVALID"
+ else:
+ code = "UPSTREAM_UNAVAILABLE"
+ messages = {
+ "UPSTREAM_TIMEOUT": "分析服务响应超时,可点击重新生成。",
+ "AUTH_REQUIRED": "登录状态已失效,请重新登录后使用 AI 辅助。",
+ "PERMISSION_DENIED": "当前账号没有 AI 辅助权限,请联系管理员开通。",
+ "SERVICE_UPDATE_REQUIRED": "服务端尚不支持实时 AI,请更新服务端后重试。",
+ "RATE_LIMITED": "分析请求较多,请稍后重新生成。",
+ "LIVE_RESULT_INVALID": "本次建议未通过格式或引用校验,可点击重新生成。",
+ "LIVE_CONTEXT_UNAVAILABLE": "本次通话的分析资料尚未就绪,请等待转写保存后重试。",
+ "STREAM_INCOMPLETE": "分析连接提前结束,可点击重新生成。",
+ "NETWORK_ERROR": "分析服务连接中断,请检查网络后重试。",
+ "UPSTREAM_UNAVAILABLE": "分析服务暂时不可用,请稍后重新生成。",
+ }
+ if not isinstance(code, str) or code not in messages:
+ code = "UPSTREAM_UNAVAILABLE"
+ if code == "LIVE_RESULT_INVALID" and isinstance(getattr(error, "data", None), Mapping):
+ reason = error.data.get("live_validation_reason")
+ details = {
+ "JSON_INVALID": "分析服务返回的格式不完整,可点击重新生成。",
+ "SCHEMA_INVALID": "分析服务返回的格式不符合要求,可点击重新生成。",
+ "CITATION_INVALID": "部分建议的原文引用无法核对,可点击重新生成。",
+ "SOURCE_QUOTE_MISMATCH": "部分建议与引用原文不一致,可点击重新生成。",
+ "SAFETY_REJECTED": "本次建议包含超出辅助范围的内容,未通过校验,可重新生成。",
+ }
+ if isinstance(reason, str) and reason in details:
+ return code, details[reason]
+ return code, messages[code]
+
+
+def empty_video_ai_state(available: bool) -> dict[str, Any]:
+ return {
+ "enabled": available, "available": available, "busy": False,
+ "phase": "waiting", "message": ("接通并产生转写文字后,自动整理本次对话。" if available
+ else "当前账号或服务暂不能使用 AI 辅助;语音转写可独立运行。"),
+ "error": "", "revision": "", "throughTimestampMs": 0, "segmentCount": 0,
+ "transcriptionStatus": "idle", "summary": [], "questions": [],
+ "checks": [], "review": [], "sources": [],
+ "elapsedMs": 0, "lastDurationMs": 0, "firstResultMs": None,
+ "pendingSegments": 0, "errorCode": "", "analysisScope": "",
+ }
+
+
+@dataclass
+class _Job:
+ generation: int
+ call_id: int
+ session_id: str
+ dirty: int
+ task: str
+ started_at: float = 0.0
+ first_result_ms: int | None = None
+ revision: str = ""
+ analysis_scope: str | None = None
+ request_id: str = field(default_factory=lambda: str(uuid4()))
+ cancelled: Event = field(default_factory=Event)
+ cancel_sent: bool = False
+
+
+class LiveAiController:
+ def __init__(self, repository: Any, *, diagnosis_id: int, enabled: bool,
+ clock: Callable[[], float] = monotonic, interval: float = 2.0) -> None:
+ self.repository = repository
+ self.diagnosis_id = diagnosis_id
+ self.available = enabled is True and callable(getattr(repository, "stream_video_ai", None))
+ self._clock = clock
+ self._interval = max(0, interval)
+ self._lock = RLock()
+ self._state = empty_video_ai_state(self.available)
+ self._mailbox: dict[str, Any] | None = copy.deepcopy(self._state)
+ self._closed = False
+ self._generation = 0
+ self._call_id = 0
+ self._session_id = ""
+ self._dirty = 0
+ self._attempted = 0
+ self._displayed_dirty = 0
+ self._due = 0.0
+ self._forced_task = ""
+ self._running: _Job | None = None
+ self._worker: Thread | None = None
+
+ def _publish(self, **changes: Any) -> None:
+ self._state.update(changes)
+ self._state["pendingSegments"] = max(0, self._dirty - self._displayed_dirty)
+ self._mailbox = copy.deepcopy(self._state)
+
+ def take_state(self) -> dict[str, Any] | None:
+ with self._lock:
+ result, self._mailbox = self._mailbox, None
+ return None if self._closed else result
+
+ def bind(self, call_id: int, session_id: str) -> None:
+ with self._lock:
+ if self._closed or (self._call_id == call_id and self._session_id == session_id):
+ return
+ self._cancel()
+ enabled = self._state["enabled"]
+ self._generation += 1
+ self._call_id, self._session_id = call_id, session_id
+ self._dirty = self._attempted = 0
+ self._displayed_dirty = 0
+ self._forced_task = ""
+ self._state = empty_video_ai_state(self.available)
+ self._publish(enabled=enabled, transcriptionStatus="running" if session_id else "idle")
+
+ def reset(self) -> None:
+ """Clear the previous call before a new call's model/storage is ready."""
+ self.bind(0, "")
+
+ def changed(self, session_id: str) -> None:
+ with self._lock:
+ if self._closed or session_id != self._session_id:
+ return
+ was_clean = self._dirty == self._attempted
+ self._dirty += 1
+ if was_clean:
+ # Coalesce a short speech burst without repeatedly moving the deadline.
+ self._due = self._clock() + (0.8 if not self._state["revision"] else self._interval)
+ self._publish()
+
+ def transcription_error(self, message: str, *, status: str = "partial") -> None:
+ with self._lock:
+ if not self._closed:
+ self._publish(transcriptionStatus=status, error=message[:240])
+
+ def transcription_starting(self) -> None:
+ with self._lock:
+ if not self._closed:
+ self._publish(transcriptionStatus="starting", error="")
+
+ def transcription_running(self, session_id: str) -> None:
+ """A retried cloud recognizer is ready without resetting saved evidence."""
+ with self._lock:
+ if not self._closed and session_id == self._session_id:
+ self._publish(transcriptionStatus="running", error="")
+
+ def finish(self, session_id: str, status: str) -> None:
+ with self._lock:
+ if not self._closed and session_id == self._session_id:
+ self._publish(transcriptionStatus=status)
+
+ def handle(self, action: str, enabled: Any = None) -> None:
+ with self._lock:
+ if self._closed or not self.available:
+ return
+ if action == "toggle" and isinstance(enabled, bool):
+ if not enabled:
+ self._cancel()
+ self._publish(enabled=enabled, busy=False if not enabled else self._state["busy"],
+ message="已暂停自动分析。" if not enabled else "有新增对话后自动更新。")
+ return
+ if action not in {"refresh", "review"} or not self._dirty or self._running is not None:
+ return
+ if action == "review" and self._state["transcriptionStatus"] not in {"completed", "partial"}:
+ return
+ self._forced_task = "live_review" if action == "review" else "live_consultation"
+ self._due = self._clock()
+
+ def tick(self) -> None:
+ with self._lock:
+ if self._running is not None and self._current(self._running):
+ elapsed = self._elapsed(self._running)
+ if elapsed // 1000 != self._state["elapsedMs"] // 1000:
+ self._publish(elapsedMs=elapsed)
+ if (self._closed or not self.available or not self._call_id or not self._session_id
+ or self._running is not None or not self._dirty
+ or (not self._forced_task and (not self._state["enabled"] or self._dirty <= self._attempted))
+ or self._clock() < self._due):
+ return
+ if not _SLOTS.acquire(blocking=False):
+ return
+ job = _Job(self._generation, self._call_id, self._session_id, self._dirty,
+ self._forced_task or "live_consultation", started_at=self._clock())
+ self._forced_task = ""
+ self._attempted = self._dirty
+ self._running = job
+ self._publish(busy=True, phase="analyzing", error="", errorCode="", elapsedMs=0, firstResultMs=None,
+ message="正在分析最新对话,优先整理下一步追问…")
+ self._worker = Thread(target=self._run, args=(job,), name="video-ai", daemon=True)
+ try:
+ self._worker.start()
+ except RuntimeError:
+ self._running = None
+ _SLOTS.release()
+ self._publish(busy=False, phase="error", error="分析任务无法启动,请重试。")
+
+ def _elapsed(self, job: _Job) -> int:
+ return max(0, int((self._clock() - job.started_at) * 1000))
+
+ def _current(self, job: _Job) -> bool:
+ return not self._closed and job.generation == self._generation and not job.cancelled.is_set()
+
+ def _validated_result(self, job: _Job, event: Mapping[str, Any]) -> dict[str, Any]:
+ context = event.get("live_context")
+ result = event.get("live_assistance")
+ # Only label the scope of validated displayed content. Older servers do
+ # not report it; never infer dialogue-only behavior from the task name.
+ scope = event.get("analysis_scope", "")
+ if not isinstance(scope, str) or scope not in {"", "current_call_only", "authorized_case"}:
+ raise ValueError("invalid analysis scope")
+ if (not isinstance(context, Mapping) or not isinstance(result, Mapping)
+ or event.get("diagnosis_id") != self.diagnosis_id
+ or context.get("call_record_id") != job.call_id
+ or context.get("transcription_session_id") != job.session_id
+ or not isinstance(context.get("revision"), str)
+ or not re.fullmatch(r"[a-f0-9]{64}", context["revision"])):
+ raise ValueError("context mismatch")
+ sources = context.get("sources")
+ if not isinstance(sources, list) or len(sources) > 1000:
+ raise ValueError("invalid evidence")
+ known: set[str] = set()
+ clean_sources = []
+ for source in sources:
+ if (not isinstance(source, Mapping) or not isinstance(source.get("id"), str)
+ or not source["id"] or source["id"] in known
+ or not isinstance(source.get("text"), str) or not source["text"].strip()
+ or len(source["text"]) > 4000
+ or source.get("role") not in {"doctor", "patient", "unknown"}
+ or isinstance(source.get("timestamp_ms"), bool)
+ or not isinstance(source.get("timestamp_ms"), int) or source["timestamp_ms"] < 0):
+ raise ValueError("invalid source")
+ known.add(source["id"])
+ clean_sources.append({key: source.get(key) for key in ("id", "text", "role", "timestamp_ms")})
+ cleaned: dict[str, Any] = {}
+ for key in ("summary", "questions", "checks", "review"):
+ items = result.get(key, [])
+ if not isinstance(items, list) or len(items) > 6:
+ raise ValueError("invalid items")
+ cleaned[key] = []
+ for item in items:
+ if (not isinstance(item, Mapping) or not isinstance(item.get("text"), str)
+ or not item["text"].strip() or len(item["text"]) > (4020 if key == "summary" else 600)
+ or not isinstance(item.get("evidence_ids"), list)
+ or not 1 <= len(item["evidence_ids"]) <= 8
+ or any(not isinstance(s, str) or s not in known for s in item["evidence_ids"])
+ or len(set(item["evidence_ids"])) != len(item["evidence_ids"])):
+ raise ValueError("invalid cited item")
+ reason = item.get("reason", "")
+ if not isinstance(reason, str) or len(reason) > 600:
+ raise ValueError("invalid reason")
+ cleaned[key].append({"text": item["text"], "reason": reason,
+ "evidence_ids": list(item["evidence_ids"])})
+ count = context.get("segment_count")
+ through = context.get("through_timestamp_ms")
+ if (isinstance(count, bool) or not isinstance(count, int) or count < 1
+ or isinstance(through, bool) or not isinstance(through, (int, float))
+ or not math.isfinite(through) or through < 0
+ or context.get("transcription_status") not in {"running", "completed", "partial"}):
+ raise ValueError("invalid revision metadata")
+ return {**cleaned, "sources": clean_sources, "revision": context["revision"], "analysisScope": scope,
+ "segmentCount": count, "throughTimestampMs": through,
+ "transcriptionStatus": context.get("transcription_status", "partial")}
+
+ def _run(self, job: _Job) -> None:
+ events = None
+ success = False
+ try:
+ if job.cancelled.is_set():
+ return
+ events = self.repository.stream_video_ai(
+ self.diagnosis_id, call_record_id=job.call_id, transcription_session_id=job.session_id,
+ task=job.task, request_id=job.request_id, cancelled=job.cancelled.is_set,
+ )
+ for event in events:
+ with self._lock:
+ if not self._current(job):
+ return
+ if event.get("event") in {"start", "progress"}:
+ self._publish(message=str(event.get("message") or "正在分析本次对话…")[:200])
+ elif event.get("event") in {"live_update", "done"}:
+ result = self._validated_result(job, event)
+ if job.revision and job.revision != result["revision"]:
+ raise ValueError("revision changed inside a single snapshot")
+ if job.analysis_scope is not None and job.analysis_scope != result["analysisScope"]:
+ raise ValueError("analysis scope changed inside a single snapshot")
+ job.revision = result["revision"]
+ job.analysis_scope = result["analysisScope"]
+ # Preserve a newer native completion status while an older
+ # in-flight snapshot still reports running.
+ if self._state["transcriptionStatus"] in {"completed", "partial", "failed"}:
+ result["transcriptionStatus"] = self._state["transcriptionStatus"]
+ complete = event.get("event") == "done"
+ duration = self._elapsed(job)
+ if job.first_result_ms is None and any(
+ result[key] for key in ("summary", "questions", "checks", "review")
+ ):
+ job.first_result_ms = duration
+ self._displayed_dirty = job.dirty
+ self._publish(**result, busy=not complete,
+ phase="ready" if complete else "analyzing", error="", errorCode="",
+ elapsedMs=duration,
+ firstResultMs=job.first_result_ms,
+ lastDurationMs=duration if complete else self._state["lastDurationMs"],
+ message="已更新,请对照原话复核。" if complete
+ else "已显示可核对的建议,其余内容仍在整理。")
+ if complete:
+ success = True
+ return
+ if not job.cancelled.is_set():
+ raise ApiProtocolError("incomplete stream")
+ except Exception as error:
+ with self._lock:
+ if self._current(job):
+ code, message = _failure_details(error)
+ self._publish(busy=False, phase="error", error=message, errorCode=code,
+ elapsedMs=self._elapsed(job), lastDurationMs=self._elapsed(job),
+ message=("已显示的建议仍可核对,本次分析尚未全部完成。"
+ if job.first_result_ms is not None else
+ "保留上次结果;新内容尚未分析完成。" if any(
+ self._state[key] for key in ("summary", "questions", "checks", "review")
+ ) else
+ "本次暂未生成可用建议,可点击重新生成。"))
+ # Log categories/timing only, never response text or patient details.
+ _LOGGER.warning("video_ai_failed code=%s type=%s duration_ms=%d",
+ code, type(error).__name__, self._elapsed(job))
+ finally:
+ if events is not None and callable(getattr(events, "close", None)):
+ with suppress(Exception):
+ events.close()
+ with self._lock:
+ if not success:
+ self._send_cancel(job)
+ if self._running is job:
+ self._running = None
+ _SLOTS.release()
+ if success:
+ _LOGGER.info("video_ai_completed duration_ms=%d first_result_ms=%s",
+ self._elapsed(job), job.first_result_ms)
+
+ def _cancel(self) -> None:
+ if self._running is not None:
+ self._running.cancelled.set()
+ self._send_cancel(self._running)
+
+ def _send_cancel(self, job: _Job) -> None:
+ if job.cancel_sent or not _CANCEL_SLOTS.acquire(blocking=False):
+ return
+ job.cancel_sent = True
+
+ def cancel() -> None:
+ try:
+ self.repository.cancel_diagnosis_ai(self.diagnosis_id, job.request_id)
+ except Exception:
+ pass
+ finally:
+ _CANCEL_SLOTS.release()
+ try:
+ Thread(target=cancel, name="video-ai-cancel", daemon=True).start()
+ except RuntimeError:
+ _CANCEL_SLOTS.release()
+
+ def close(self) -> None:
+ with self._lock:
+ self._closed = True
+ self._cancel()
+ self._mailbox = None
+
+ def wait(self, timeout: float = 1.0) -> bool:
+ if self._worker is not None:
+ self._worker.join(max(0, min(timeout, 5)))
+ return self._worker is None or not self._worker.is_alive()
diff --git a/app/src/doctor_workstation/video/local_transcription.py b/app/src/doctor_workstation/video/local_transcription.py
new file mode 100644
index 000000000..bc65aeed8
--- /dev/null
+++ b/app/src/doctor_workstation/video/local_transcription.py
@@ -0,0 +1,446 @@
+"""Bounded, in-memory speech recognition using an explicitly installed local model.
+
+This module has no dependency on Qt, the recording queue, or the call lifecycle.
+Callbacks run on one daemon worker and must only enqueue work (for example, emit
+a Qt signal). Runtime code never downloads a model or sends audio to a service.
+"""
+
+from __future__ import annotations
+
+import base64
+import binascii
+import importlib.util
+import os
+import re
+import sys
+import threading
+from collections import deque
+from collections.abc import Callable
+from contextlib import suppress
+from dataclasses import dataclass, field
+from pathlib import Path
+from typing import Any, Protocol
+
+from platformdirs import user_data_path
+
+from ..core.transcript_text import simplified_transcript
+
+SAMPLE_RATE = 16_000
+MAX_CHUNK_SECONDS = 12
+MAX_PCM_BYTES = SAMPLE_RATE * 2 * MAX_CHUNK_SECONDS
+MAX_BASE64_CHARS = ((MAX_PCM_BYTES + 2) // 3) * 4
+MAX_SEQUENCE = 2_147_483_647
+MAX_TIMESTAMP_MS = 253_402_300_799_999
+MAX_TRANSCRIPT_CHARS = 4_000
+_SESSION_ID = re.compile(r"[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}\Z")
+_REQUIRED_FILES = ("model.bin", "config.json", "tokenizer.json")
+_DEPENDENCIES = ("faster_whisper", "numpy", "ctranslate2", "onnxruntime", "opencc")
+_MESSAGES = {
+ "model_missing": "本地语音模型未安装或文件不完整,请先运行本地转写安装工具。",
+ "dependency_missing": "本地转写运行库未安装,请先安装本地转写依赖。",
+ "dependency_unavailable": "本地转写运行库无法加载,请检查安装包及系统运行库。",
+ "model_load_failed": "本地语音模型加载失败,请检查模型文件和本机运行环境。",
+ "conversion_unavailable": "简体转换字典无法加载,请修复本地转写安装。",
+ "invalid_audio": "本地转写音频格式无效,需要最长 12 秒的单声道 16 kHz PCM16 音频。",
+ "invalid_metadata": "本地转写音频的角色、序号或时间戳无效。",
+ "sequence_out_of_order": "本地转写音频序号重复或倒序,该片段未被接受。",
+ "sequence_gap": "本地转写检测到音频片段缺失,转写结果可能不完整。",
+ "overloaded": "本地转写处理速度不足,部分音频片段未转写;通话和录音继续。",
+ "transcription_failed": "本地音频片段转写失败,结果可能不完整;通话和录音继续。",
+}
+
+
+def default_model_path() -> Path:
+ """Return the model directory without creating it or accessing the network."""
+ override = os.getenv("DOCTOR_ASR_MODEL_PATH", "").strip()
+ if override:
+ return Path(override).expanduser().resolve()
+ bundle = Path(getattr(sys, "_MEIPASS", Path(__file__).resolve().parents[3]))
+ bundled_model = bundle / "resources" / "local-asr" / "model"
+ if bundled_model.is_dir():
+ return bundled_model
+ return (
+ user_data_path("ZhenyangDoctorWorkstation", appauthor="ZhenYangTang")
+ / "local-asr"
+ / "model"
+ )
+
+
+def _missing_model_files(path: Path) -> list[str]:
+ def exists(name: str) -> bool:
+ try:
+ file = path / name
+ return file.is_file() and file.stat().st_size > 0
+ except OSError:
+ return False
+
+ missing = [name for name in _REQUIRED_FILES if not exists(name)]
+ if not any(exists(name) for name in ("vocabulary.txt", "vocabulary.json")):
+ missing.append("vocabulary.txt or vocabulary.json")
+ return missing
+
+
+def local_transcription_readiness(model_path: Path | str | None = None) -> dict[str, Any]:
+ """Cheap installation preflight; ``available`` does not claim a model has loaded."""
+ path = Path(model_path).expanduser().resolve() if model_path else default_model_path()
+ missing_dependencies = []
+ for name in _DEPENDENCIES:
+ try:
+ available = importlib.util.find_spec(name) is not None
+ except (ImportError, ValueError):
+ available = False
+ if not available:
+ missing_dependencies.append(name)
+ missing_files = _missing_model_files(path)
+ code = (
+ "model_missing" if missing_files else "dependency_missing" if missing_dependencies else ""
+ )
+ return {
+ "available": not (missing_files or missing_dependencies),
+ "modelPath": str(path),
+ "missingDependencies": missing_dependencies,
+ "missingFiles": missing_files,
+ "code": code,
+ "message": _MESSAGES.get(code, "本地转写文件检查通过,启动后将加载模型。"),
+ }
+
+
+class LocalTranscriptionError(RuntimeError):
+ """A fixed, patient-data-free error suitable for displaying in the UI."""
+
+ def __init__(self, code: str) -> None:
+ self.code = code if code in _MESSAGES else "transcription_failed"
+ super().__init__(_MESSAGES[self.code])
+
+
+class SpeechEngine(Protocol):
+ def transcribe(self, pcm: bytes) -> str:
+ """Return verbatim recognized text for mono, little-endian PCM16 at 16 kHz."""
+
+
+class FasterWhisperEngine:
+ """CPU/int8 recognition. Construct only on a background worker or setup CLI."""
+
+ def __init__(self, model_path: Path | str | None = None) -> None:
+ path = Path(model_path).expanduser().resolve() if model_path else default_model_path()
+ # In particular, require tokenizer.json: upstream may otherwise fetch a
+ # tokenizer even when WhisperModel(local_files_only=True) is requested.
+ if _missing_model_files(path):
+ raise LocalTranscriptionError("model_missing")
+ try:
+ import numpy as np
+ from faster_whisper import WhisperModel
+ from faster_whisper.vad import get_vad_model
+ except ModuleNotFoundError:
+ raise LocalTranscriptionError("dependency_missing") from None
+ except (ImportError, OSError):
+ raise LocalTranscriptionError("dependency_unavailable") from None
+ self._np = np
+ try:
+ # Load local dictionaries before ready, so a broken/frozen install
+ # cannot claim successful ASR and then fail on its first sentence.
+ simplified_transcript("")
+ except ImportError:
+ raise LocalTranscriptionError("dependency_missing") from None
+ except Exception:
+ raise LocalTranscriptionError("conversion_unavailable") from None
+ try:
+ self._model = WhisperModel(
+ str(path),
+ device="cpu",
+ compute_type="int8",
+ cpu_threads=min(4, max(1, (os.cpu_count() or 2) // 2)),
+ num_workers=1,
+ local_files_only=True,
+ )
+ # Silero's ONNX asset ships inside faster-whisper; preflight it so
+ # a packaged application cannot report ready with a missing VAD.
+ get_vad_model()
+ except Exception:
+ raise LocalTranscriptionError("model_load_failed") from None
+
+ def transcribe(self, pcm: bytes) -> str:
+ if not pcm or len(pcm) % 2 or len(pcm) > MAX_PCM_BYTES:
+ raise LocalTranscriptionError("invalid_audio")
+ if not any(pcm):
+ return ""
+ audio = self._np.frombuffer(pcm, dtype=" None:
+ if type(max_pending_chunks) is not int or not 1 <= max_pending_chunks <= 64:
+ raise ValueError("max_pending_chunks must be an integer between 1 and 64")
+ self._on_event = on_event
+ self._engine_factory = engine_factory or FasterWhisperEngine
+ self._max_pending_chunks = max_pending_chunks
+ self._condition = threading.Condition(threading.RLock())
+ self._session: _Session | None = None
+ self._engine: SpeechEngine | None = None
+ self._closed = False
+ self._worker: threading.Thread | None = None
+
+ def start(self, session_id: str) -> bool:
+ if not isinstance(session_id, str) or not _SESSION_ID.fullmatch(session_id):
+ return False
+ with self._condition:
+ if self._closed:
+ return False
+ if self._session and self._session.id == session_id:
+ return not (self._session.stopping or self._session.stopped)
+ if self._session:
+ self._session.chunks.clear()
+ self._session.errors.clear()
+ self._session = _Session(session_id)
+ if self._worker is None:
+ self._worker = threading.Thread(
+ target=self._run, name="doctor-local-asr", daemon=True
+ )
+ self._worker.start()
+ self._condition.notify_all()
+ return True
+
+ def submit(
+ self,
+ session_id: str,
+ role: str,
+ sequence: int,
+ timestamp_ms: int,
+ pcm_base64: str,
+ ) -> bool:
+ with self._condition:
+ session = self._session
+ if (
+ self._closed
+ or session is None
+ or session.id != session_id
+ or session.stopping
+ or session.stopped
+ ):
+ return False
+ if (
+ role not in ("doctor", "patient")
+ or type(sequence) is not int
+ or not 0 <= sequence <= MAX_SEQUENCE
+ or type(timestamp_ms) is not int
+ or not 0 < timestamp_ms <= MAX_TIMESTAMP_MS
+ ):
+ self._error_locked(session, "invalid_metadata")
+ return False
+ if (
+ not isinstance(pcm_base64, str)
+ or not pcm_base64
+ or len(pcm_base64) > MAX_BASE64_CHARS
+ ):
+ self._error_locked(session, "invalid_audio")
+ return False
+ try:
+ pcm = base64.b64decode(pcm_base64, validate=True)
+ except (ValueError, binascii.Error):
+ self._error_locked(session, "invalid_audio")
+ return False
+ if not pcm or len(pcm) % 2 or len(pcm) > MAX_PCM_BYTES:
+ self._error_locked(session, "invalid_audio")
+ return False
+ previous = session.last_sequence.get(role)
+ if previous is not None and sequence <= previous:
+ self._error_locked(session, "sequence_out_of_order")
+ return False
+ if previous is not None and sequence != previous + 1:
+ self._error_locked(session, "sequence_gap")
+ session.last_sequence[role] = sequence
+ if len(session.chunks) >= self._max_pending_chunks:
+ self._error_locked(session, "overloaded")
+ return False
+ session.chunks.append(_Chunk(role, sequence, timestamp_ms, pcm))
+ self._condition.notify_all()
+ return True
+
+ def stop(self, session_id: str) -> bool:
+ with self._condition:
+ session = self._session
+ if self._closed or session is None or session.id != session_id:
+ return False
+ session.stopping = True
+ self._condition.notify_all()
+ return True
+
+ def close(self) -> None:
+ with self._condition:
+ self._closed = True
+ if self._session:
+ self._session.chunks.clear()
+ self._session.errors.clear()
+ self._session = None
+ self._condition.notify_all()
+
+ def _error_locked(self, session: _Session, code: str) -> None:
+ session.partial = True
+ # At most one pending/report per fixed error code, even when the browser
+ # continues submitting into an overloaded queue. No unbounded UI queue.
+ if code not in session.reported_errors:
+ session.reported_errors.add(code)
+ session.errors.append(code)
+ self._condition.notify_all()
+
+ def _emit(self, session: _Session, event: dict[str, Any]) -> None:
+ with self._condition:
+ if self._closed or self._session is not session:
+ return
+ # A detached UI must not kill the worker or expose transcript
+ # contents through exception logging.
+ with suppress(Exception):
+ self._on_event({"sessionId": session.id, **event})
+
+ def _initialize(self, session: _Session) -> None:
+ try:
+ if self._engine is None:
+ self._engine = self._engine_factory()
+ except Exception as error:
+ code = error.code if isinstance(error, LocalTranscriptionError) else "model_load_failed"
+ with self._condition:
+ if self._closed or self._session is not session:
+ return
+ session.initialized = True
+ session.stopping = True
+ session.chunks.clear()
+ self._error_locked(session, code)
+ return
+ with self._condition:
+ if self._closed or self._session is not session:
+ return
+ session.initialized = True
+ if not session.stopping:
+ self._emit(session, {"type": "ready"})
+
+ def _transcribe(self, session: _Session, chunk: _Chunk) -> None:
+ try:
+ # Reject only exact digital silence here. VAD in the real engine
+ # handles room noise without an amplitude cutoff that loses quiet
+ # numerals or one-word negations.
+ if not any(chunk.pcm):
+ return
+ assert self._engine is not None
+ text = self._engine.transcribe(chunk.pcm)
+ if not isinstance(text, str) or len(text) > MAX_TRANSCRIPT_CHARS:
+ raise LocalTranscriptionError("transcription_failed")
+ # Normalize before persistence and captions, so AI evidence and the
+ # doctor's visible transcript refer to the exact same text.
+ text = simplified_transcript(text.strip())
+ if text:
+ self._emit(
+ session,
+ {
+ "type": "segment",
+ "segmentId": f"{session.id}:{chunk.role}:{chunk.sequence}",
+ "role": chunk.role,
+ "text": text,
+ "timestamp": chunk.timestamp_ms,
+ "isCompleted": True,
+ },
+ )
+ except Exception:
+ with self._condition:
+ if not self._closed and self._session is session:
+ self._error_locked(session, "transcription_failed")
+
+ def _run(self) -> None:
+ try:
+ while True:
+ with self._condition:
+ while True:
+ if self._closed:
+ return
+ session = self._session
+ if session is not None and not session.stopped:
+ if session.errors:
+ action, payload = "error", session.errors.popleft()
+ break
+ if not session.initialized:
+ action, payload = "initialize", None
+ break
+ if session.chunks:
+ action, payload = "chunk", session.chunks.popleft()
+ break
+ if session.stopping:
+ session.stopped = True
+ action, payload = "stopped", None
+ break
+ self._condition.wait()
+ if action == "initialize":
+ self._initialize(session)
+ elif action == "chunk":
+ self._transcribe(session, payload)
+ payload = None # Release raw PCM before waiting for work.
+ elif action == "error":
+ self._emit(
+ session,
+ {"type": "error", "code": payload, "message": _MESSAGES[payload]},
+ )
+ else:
+ self._emit(
+ session,
+ {
+ "type": "stopped",
+ "status": "partial" if session.partial else "completed",
+ },
+ )
+ finally:
+ self._engine = None
diff --git a/app/src/doctor_workstation/video/screenshot.py b/app/src/doctor_workstation/video/screenshot.py
new file mode 100644
index 000000000..a364767bb
--- /dev/null
+++ b/app/src/doctor_workstation/video/screenshot.py
@@ -0,0 +1,124 @@
+"""Capture the rendered call region without accessing the rest of the desktop."""
+
+from __future__ import annotations
+
+import base64
+import math
+from collections.abc import Mapping
+from typing import Any
+
+
+class ScreenshotPreviewSize:
+ """Temporarily give a compact call the same space as a normal preview."""
+
+ def __init__(self) -> None:
+ self._state: tuple[Any, Any, Any] | None = None
+
+ def open(self, window: Any, target: Any = None) -> None:
+ from PySide6.QtCore import QRect
+
+ if self._state is not None or window.isMaximized() or window.isFullScreen():
+ return
+ screen = window.screen()
+ if screen is None:
+ return
+ available = screen.availableGeometry().adjusted(24, 24, -24, -24)
+ if available.isEmpty():
+ return
+ original = window.geometry()
+ width = min(available.width(), max(original.width(), target.width() if target else 1120))
+ height = min(available.height(), max(original.height(), target.height() if target else 760))
+ if original.width() >= width and original.height() >= height:
+ return
+ expanded = QRect(
+ available.x() + (available.width() - width) // 2,
+ available.y() + (available.height() - height) // 2,
+ width,
+ height,
+ )
+ window.setGeometry(expanded)
+ self._state = (original, window.geometry(), window.property("doctorSkipOpenGeometry"))
+
+ def restore(self, window: Any) -> None:
+ state, self._state = self._state, None
+ if state is None:
+ return
+ original, expanded, compact_flag = state
+ # A diagnosis closing or a manual resize takes priority over this temporary size.
+ if (
+ window.isMaximized()
+ or window.isFullScreen()
+ or window.geometry() != expanded
+ or window.property("doctorSkipOpenGeometry") != compact_flag
+ ):
+ return
+ window.setGeometry(original)
+
+
+def capture_view_region(web_view: Any, region: Mapping[str, Any]) -> str:
+ """Map CSS viewport coordinates to Qt logical pixels; retain composited video."""
+
+ from PySide6.QtCore import QBuffer, QByteArray, QIODevice, QRect, Qt
+
+ values: dict[str, float] = {}
+ for key in ("x", "y", "width", "height", "viewportWidth", "viewportHeight"):
+ value = region.get(key)
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
+ raise ValueError("截屏区域无效,请重试。")
+ try:
+ value = float(value)
+ except OverflowError as error:
+ raise ValueError("截屏区域无效,请重试。") from error
+ if not math.isfinite(value):
+ raise ValueError("截屏区域无效,请重试。")
+ values[key] = value
+
+ viewport_width = values["viewportWidth"]
+ viewport_height = values["viewportHeight"]
+ if min(viewport_width, viewport_height, values["width"], values["height"]) <= 0:
+ raise ValueError("视频区域尚未显示,请稍后重试。")
+ left = max(0.0, values["x"])
+ top = max(0.0, values["y"])
+ right = min(viewport_width, values["x"] + values["width"])
+ bottom = min(viewport_height, values["y"] + values["height"])
+ if right <= left or bottom <= top:
+ raise ValueError("视频区域尚未显示,请稍后重试。")
+
+ zoom = web_view.zoomFactor()
+ tolerance = max(2.0, 2 * zoom)
+ if (
+ abs(viewport_width * zoom - web_view.width()) > tolerance
+ or abs(viewport_height * zoom - web_view.height()) > tolerance
+ ):
+ raise ValueError("视频窗口尺寸已变化,请重新截屏。")
+
+ # QWebEngine's zoom and Windows display scaling are independent. grab() takes
+ # widget logical coordinates and returns an image at the widget's pixel ratio.
+ scale_x = web_view.width() / viewport_width
+ scale_y = web_view.height() / viewport_height
+ x = math.ceil(left * scale_x)
+ y = math.ceil(top * scale_y)
+ width = math.floor(right * scale_x) - x
+ height = math.floor(bottom * scale_y) - y
+ if width <= 0 or height <= 0:
+ raise ValueError("视频区域尚未显示,请稍后重试。")
+ rect = QRect(x, y, width, height).intersected(web_view.rect())
+ if rect.isEmpty():
+ raise ValueError("视频区域尚未显示,请稍后重试。")
+
+ image = web_view.grab(rect).toImage()
+ if image.isNull():
+ raise ValueError("截屏失败,请稍后重试。")
+ if max(image.width(), image.height()) > 1920:
+ image = image.scaled(
+ 1920, 1920,
+ Qt.AspectRatioMode.KeepAspectRatio,
+ Qt.TransformationMode.SmoothTransformation,
+ )
+ data = QByteArray()
+ buffer = QBuffer(data)
+ buffer.open(QIODevice.OpenModeFlag.WriteOnly)
+ if not image.save(buffer, "JPEG", 90):
+ raise ValueError("截屏图片生成失败,请重试。")
+ buffer.close()
+ return "data:image/jpeg;base64," + base64.b64encode(bytes(data)).decode("ascii")
diff --git a/app/src/doctor_workstation/video/window.py b/app/src/doctor_workstation/video/window.py
index 9730506f5..4af441911 100755
--- a/app/src/doctor_workstation/video/window.py
+++ b/app/src/doctor_workstation/video/window.py
@@ -11,6 +11,7 @@ import base64
import binascii
import json
import logging
+import math
import os
import re
import sqlite3
@@ -28,12 +29,15 @@ from ..services.local_audio_queue import (
LocalAudioUploadManager,
get_local_audio_upload_manager,
)
+from .im_ai import ImAiController
from .launcher import (
VideoCallRequest,
VideoTicketError,
require_supported_backend,
)
-from .lifecycle import OrderedCallLifecycle
+from .lifecycle import OrderedCallLifecycle, normalize_transcript_segment
+from .live_ai import LiveAiController
+from .screenshot import ScreenshotPreviewSize, capture_view_region
from .security import TrustedDocumentError, TrustedDocumentPolicy
try: # Optional by design: core-only builds must still import this module.
@@ -188,9 +192,29 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
return None
class _QtVideoBridge(QObject): # type: ignore[misc, valid-type]
- def __init__(self, callback: Callable[[Mapping[str, Any]], None]) -> None:
+ def __init__(
+ self,
+ callback: Callable[[Mapping[str, Any]], None],
+ capture_screenshot: Callable[[Mapping[str, Any]], str],
+ ) -> None:
super().__init__()
self._callback = callback
+ self._capture_screenshot = capture_screenshot
+
+ @Slot(str, result=str) # type: ignore[misc]
+ def captureScreenshot(self, payload: str) -> str: # noqa: N802 - Qt bridge API
+ """Return a local preview only; persistence still needs saveScreenshot."""
+
+ try:
+ if not isinstance(payload, str) or len(payload) > 2048:
+ raise ValueError("截屏区域无效,请重试。")
+ region = json.loads(payload)
+ if not isinstance(region, Mapping):
+ raise ValueError("截屏区域无效,请重试。")
+ result = {"dataUrl": self._capture_screenshot(region)}
+ except (ValueError, TypeError, RuntimeError):
+ result = {"error": "无法截取当前视频画面,请稍后重试。"}
+ return json.dumps(result, ensure_ascii=False)
@Slot(str) # type: ignore[misc]
def notify(self, payload: str) -> None:
@@ -274,6 +298,16 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
}
)
+ @Slot(str, str, int, float, str) # type: ignore[misc]
+ def appendLocalTranscriptionChunk( # noqa: N802
+ self, session_id: str, role: str, sequence: int, timestamp: float, encoded: str
+ ) -> None:
+ if len(encoded) > 512_000:
+ return
+ self._callback({"source": "doctor-call", "event": "local-transcription-chunk",
+ "sessionId": session_id, "role": role, "sequence": sequence,
+ "timestamp": timestamp, "data": encoded})
+
class _EmbeddedVideoWindow(QMainWindow): # type: ignore[misc, valid-type]
status_changed = Signal(str) # type: ignore[misc]
call_ended = Signal(str) # type: ignore[misc]
@@ -282,7 +316,8 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
_policy_completed = Signal(str, object) # type: ignore[misc]
_room_completed = Signal(str, bool, str) # type: ignore[misc]
_screenshot_completed = Signal(bool, str) # type: ignore[misc]
- _transcription_completed = Signal(str, str, str, bool, str) # type: ignore[misc]
+ _transcription_completed = Signal(str, str, str, bool, str, str) # type: ignore[misc]
+ _local_transcription_event = Signal(object) # type: ignore[misc]
_local_recording_completed = Signal( # type: ignore[misc]
str, str, int, bool, str
)
@@ -299,6 +334,8 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
patient_name: str = "患者",
patient_case: Mapping[str, Any] | None = None,
on_open_diagnosis: Callable[[], None] | None = None,
+ can_ai_assistant: bool = False,
+ repository: Any = None,
) -> None:
super().__init__()
self.request = request
@@ -311,6 +348,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
self.patient_name = str(patient_name or "患者").strip() or "患者"
self.patient_case = dict(patient_case or {})
self._on_open_diagnosis = on_open_diagnosis
+ self._on_compact_close: Callable[[], None] | None = None
try:
self._policy = TrustedDocumentPolicy.from_url(
location.url,
@@ -327,6 +365,33 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
self._call_cycle_closed = False
self._start_requested = False
self._shutdown_requested = False
+ self._im_ai = ImAiController(
+ repository,
+ diagnosis_id=request.diagnosis_id,
+ appointment_id=request.appointment_id,
+ doctor_account=request.user_id,
+ enabled=can_ai_assistant is True and self.open_im,
+ )
+ self._im_ai_timer = QTimer(self)
+ self._im_ai_timer.setInterval(60)
+ self._im_ai_timer.timeout.connect(self._flush_im_ai)
+ if self._im_ai.enabled:
+ self._im_ai_timer.start()
+ self._live_ai = LiveAiController(
+ repository, diagnosis_id=request.diagnosis_id, enabled=can_ai_assistant is True,
+ )
+ # The default recognizer is Tencent's existing call transcriber.
+ # Keep local audio recording independent; no local model is loaded.
+ self._local_transcription = None
+ self._asr_session_id = ""
+ self._asr_ready = False
+ self._asr_partial = False
+ self._transcription_final_status = "idle"
+ self._video_ai_timer = QTimer(self)
+ self._video_ai_timer.setInterval(100)
+ self._video_ai_timer.timeout.connect(self._flush_video_ai)
+ self._video_ai_timer.start()
+ self._screenshot_preview_size = ScreenshotPreviewSize()
self._local_audio_capture: _LocalAudioCapture | None = None
self._local_audio_store: LocalAudioQueueStore | None = None
self._local_audio_uploads: LocalAudioUploadManager | None = None
@@ -363,7 +428,9 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
self.setCentralWidget(self.web_view)
self._configure_settings(self._page.settings())
- self._bridge = _QtVideoBridge(self._handle_bridge_message)
+ self._bridge = _QtVideoBridge(
+ self._handle_bridge_message, self._capture_screenshot_preview
+ )
self._channel = QWebChannel(self._page)
self._channel.registerObject("qtVideoBridge", self._bridge)
self._page.setWebChannel(self._channel)
@@ -374,6 +441,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
self._room_completed.connect(self._on_room_completed)
self._screenshot_completed.connect(self._on_screenshot_completed)
self._transcription_completed.connect(self._on_transcription_completed)
+ self._local_transcription_event.connect(self._on_local_transcription)
self._local_recording_completed.connect(self._on_local_recording_completed)
self.web_view.loadFinished.connect(self._on_load_finished)
self.web_view.setUrl(QUrl(self.location.url))
@@ -449,8 +517,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
"embedded video companion failed to load",
extra={"video_call": self.request.safe_log_context()},
)
- self._close_reason = "page-load-failed"
- self.close()
+ self._request_companion_shutdown("page-load-failed")
return
self._media_active = True
@@ -459,6 +526,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
"patientName": self.patient_name,
"patientCase": self.patient_case,
"mode": "chat" if self.open_im else "video",
+ "imAi": self._im_ai.config,
}
config_json = json.dumps(config, ensure_ascii=True, separators=(",", ":"))
script = f"""
@@ -499,13 +567,37 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
def _after_injection(self, result: Any) -> None:
self._injected = result is not False
if not self._injected:
- self._close_reason = "bridge-api-missing"
- self.close()
+ self._request_companion_shutdown("bridge-api-missing")
+ return
+ if not self._im_ai_context_is_trusted():
+ return
+ # open() may finish IM login before runJavaScript returns. Only
+ # acknowledge readiness after the native request gate is open.
+ session_id = json.dumps(self._im_ai.session_id, ensure_ascii=True)
+ self._page.runJavaScript(
+ f"window.doctorConsultation?.imAiReady?.({session_id});"
+ )
def _handle_bridge_message(self, message: Mapping[str, Any]) -> None:
if self._closing:
return
event = str(message.get("event", ""))
+ if event.startswith("local-transcription-"):
+ # An old companion must not start a second recognizer.
+ return
+ if event == "video-ai-action":
+ self._handle_video_assistance_message(message)
+ return
+ if event.startswith("transcription-") and not self._local_transcription_context_is_trusted():
+ return
+ if event in {"im-ai-request", "im-ai-cancel"}:
+ self._handle_im_ai_message(message)
+ return
+ if event == "screenshot-preview":
+ visible = message.get("visible")
+ if isinstance(visible, bool):
+ self._set_screenshot_preview_visible(visible)
+ return
if event == "open-diagnosis-request":
if self._on_open_diagnosis is not None:
QTimer.singleShot(0, self._open_diagnosis_safely)
@@ -548,6 +640,9 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
self._abort_local_audio_recording(str(message.get("sessionId") or ""))
return
if event == "transcription-start-request":
+ if (self._shutdown_requested or not self._start_requested
+ or self._call_cycle_closed or not self.lifecycle.call_record_id):
+ return
self._start_transcription(
str(message.get("sessionId") or ""),
str(message.get("language") or "zh-CN"),
@@ -556,6 +651,22 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
if event == "transcription-segment":
self._save_transcript_segment(message)
return
+ if event == "transcription-ready":
+ session_id = str(message.get("sessionId") or "")
+ if (not self._shutdown_requested and session_id
+ and session_id == str(self.lifecycle.transcription_session_id or "")):
+ self._live_ai.transcription_running(session_id)
+ return
+ if event == "transcription-error":
+ if (str(message.get("sessionId") or "")
+ == str(self.lifecycle.transcription_session_id or "")
+ and self.lifecycle.transcription_session_id):
+ self._asr_partial = True
+ self._live_ai.transcription_error(
+ str(message.get("message") or "腾讯云实时转写未完成,请重试。")[:240],
+ status="failed",
+ )
+ return
if event == "transcription-stop":
self._finish_transcription(
str(message.get("sessionId") or ""),
@@ -594,6 +705,139 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
if not self.open_im or self._shutdown_requested:
self._close_from_companion("companion-error")
+ def _im_ai_context_is_trusted(self) -> bool:
+ return (
+ not self._closing
+ and not self._released
+ and not self._shutdown_requested
+ and self._injected
+ and self._policy.allows_main_document(self._page.url().toString())
+ )
+
+ def _handle_im_ai_message(self, message: Mapping[str, Any]) -> None:
+ if self._im_ai_context_is_trusted():
+ self._im_ai.handle(message)
+
+ def _flush_im_ai(self) -> None:
+ if not self._im_ai_context_is_trusted():
+ return
+ result = self._im_ai.take_result()
+ if result is not None:
+ payload = json.dumps(result, ensure_ascii=True, separators=(",", ":"))
+ self._page.runJavaScript(f"window.doctorConsultation?.imAiResult?.({payload});")
+
+ def _close_im_ai(self) -> None:
+ controller = getattr(self, "_im_ai", None)
+ if controller is not None:
+ controller.close()
+ timer = getattr(self, "_im_ai_timer", None)
+ if timer is not None:
+ timer.stop()
+
+ def _local_transcription_context_is_trusted(self) -> bool:
+ return (not self._closing and not self._released and self._injected
+ and self._policy.allows_main_document(self._page.url().toString()))
+
+ def _handle_video_assistance_message(self, message: Mapping[str, Any]) -> None:
+ if not self._local_transcription_context_is_trusted():
+ return
+ event = message.get("event")
+ if event == "video-ai-action":
+ if not self._shutdown_requested:
+ self._live_ai.handle(str(message.get("action") or ""), message.get("enabled"))
+ return
+ session_id = str(message.get("sessionId") or "")
+ if event == "local-transcription-start":
+ if (self._shutdown_requested or not self._start_requested or self._call_cycle_closed
+ or not self.lifecycle.call_record_id
+ or re.fullmatch(r"[A-Za-z0-9_-]{1,128}", session_id) is None):
+ return
+ existing = str(self.lifecycle.transcription_session_id or "")
+ if existing and existing != session_id:
+ return
+ was_ready = self._asr_session_id == session_id and self._asr_ready
+ if self._asr_session_id != session_id:
+ self._asr_partial = False
+ self._asr_ready = False
+ self._asr_session_id = session_id
+ self._live_ai.transcription_starting()
+ accepted = self._local_transcription.start(session_id)
+ if accepted and was_ready:
+ self._on_local_transcription({"type": "ready", "sessionId": session_id})
+ elif not accepted:
+ self._on_local_transcription({"type": "error", "sessionId": session_id,
+ "message": "本次转写已结束,请重新发起通话。"})
+ elif session_id and session_id == self._asr_session_id:
+ if event == "local-transcription-chunk":
+ if session_id != str(self.lifecycle.transcription_session_id or ""):
+ return
+ timestamp = message.get("timestamp")
+ if (isinstance(timestamp, bool) or not isinstance(timestamp, (int, float))
+ or not math.isfinite(timestamp) or not 0 < timestamp < 2**53):
+ return
+ self._local_transcription.submit(
+ session_id, str(message.get("role") or ""), message.get("sequence"),
+ int(timestamp), str(message.get("data") or ""),
+ )
+ elif event == "local-transcription-stop":
+ self._local_transcription.stop(session_id)
+
+ def _emit_local_transcription(self, event: dict[str, Any]) -> None:
+ with suppress(RuntimeError):
+ self._local_transcription_event.emit(event)
+
+ def _on_local_transcription(self, event: Mapping[str, Any]) -> None:
+ if (not self._local_transcription_context_is_trusted()
+ or event.get("sessionId") != self._asr_session_id):
+ return
+ kind = event.get("type")
+ if kind == "ready":
+ self._asr_ready = True
+ elif kind == "stopped":
+ self._asr_ready = False
+ elif kind == "segment":
+ role = event.get("role")
+ if role not in {"doctor", "patient"}:
+ return
+ self._save_transcript_segment({
+ "sessionId": self._asr_session_id,
+ "segment": {
+ "segment_id": event.get("segmentId"),
+ "speaker_role": role,
+ "speaker_user_id": (self.request.user_id if role == "doctor"
+ else self.request.target_user_id),
+ "timestamp": event.get("timestamp"), "text": event.get("text"),
+ },
+ })
+ elif kind == "error":
+ self._asr_partial = True
+ self._live_ai.transcription_error(
+ str(event.get("message") or "本地转写未完成"),
+ status="partial" if self._asr_ready else "failed",
+ )
+ payload = json.dumps(dict(event), ensure_ascii=True, separators=(",", ":"))
+ self._page.runJavaScript(f"window.doctorConsultation?.localTranscriptionEvent?.({payload});")
+
+ def _flush_video_ai(self) -> None:
+ if not self._local_transcription_context_is_trusted() or self._shutdown_requested:
+ return
+ self._live_ai.tick()
+ state = self._live_ai.take_state()
+ if state is not None:
+ payload = json.dumps(state, ensure_ascii=True, separators=(",", ":"))
+ self._page.runJavaScript(f"window.doctorConsultation?.videoAiState?.({payload});")
+
+ def _close_video_assistance(self, *, close_asr: bool = True) -> None:
+ controller = getattr(self, "_live_ai", None)
+ if controller is not None:
+ controller.close()
+ timer = getattr(self, "_video_ai_timer", None)
+ if timer is not None:
+ timer.stop()
+ controller = getattr(self, "_local_transcription", None)
+ if close_asr and controller is not None:
+ controller.close()
+
def _open_diagnosis_safely(self) -> None:
if self._closing or self._on_open_diagnosis is None:
return
@@ -978,6 +1222,12 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
if self._closing or self._shutdown_requested or self._start_requested:
return
self._prepare_call_cycle()
+ live_ai = getattr(self, "_live_ai", None)
+ if live_ai is not None:
+ live_ai.reset()
+ self._asr_session_id = ""
+ self._asr_ready = False
+ self._asr_partial = False
self._start_requested = True
try:
future = self.lifecycle.start(call_type=call_type)
@@ -987,6 +1237,30 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
return
future.add_done_callback(self._notify_start_completed)
+ def _set_screenshot_preview_visible(self, visible: bool) -> None:
+ if self._closing or self._released:
+ return
+ if not self._policy.allows_main_document(self._page.url().toString()):
+ return
+ if not visible:
+ self.restore_screenshot_preview()
+ return
+ if self._shutdown_requested or not self._media_active:
+ return
+ from ..ui.theme import main_window_target_rect
+
+ self._screenshot_preview_size.open(self, main_window_target_rect(self))
+
+ def restore_screenshot_preview(self) -> None:
+ self._screenshot_preview_size.restore(self)
+
+ def _capture_screenshot_preview(self, region: Mapping[str, Any]) -> str:
+ if self._closing or self._released or self._shutdown_requested or not self._media_active:
+ raise ValueError("视频窗口已关闭。")
+ if not self._policy.allows_main_document(self._page.url().toString()):
+ raise ValueError("视频页面不可用。")
+ return capture_view_region(self.web_view, region)
+
def _save_screenshot(self, data_url: str) -> None:
prefix = "data:image/jpeg;base64,"
if not data_url.startswith(prefix):
@@ -1032,6 +1306,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
session_id: str,
segment_id: str,
future: Future[bool],
+ normalized_segment: Mapping[str, Any] | None = None,
) -> None:
try:
succeeded = bool(future.result())
@@ -1046,7 +1321,8 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
}.get(operation, "")
with suppress(RuntimeError):
self._transcription_completed.emit(
- operation, session_id, segment_id, succeeded, message
+ operation, session_id, segment_id, succeeded, message,
+ json.dumps(normalized_segment if succeeded else None, ensure_ascii=True),
)
def _on_transcription_completed(
@@ -1056,16 +1332,47 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
segment_id: str,
succeeded: bool,
message: str,
+ normalized_segment: str | Mapping[str, Any] | None = None,
) -> None:
+ if not self._local_transcription_context_is_trusted():
+ return
+ live_ai = getattr(self, "_live_ai", None)
+ if (live_ai is not None
+ and session_id == str(self.lifecycle.transcription_session_id or "")):
+ if operation == "start" and succeeded:
+ live_ai.bind(int(self.lifecycle.call_record_id), session_id)
+ elif operation == "start":
+ live_ai.transcription_error(message or "转写文字存储未就绪,请重试。", status="failed")
+ elif operation == "segment":
+ if succeeded:
+ live_ai.changed(session_id)
+ else:
+ self._asr_partial = True
+ live_ai.transcription_error("部分对话文字保存失败,分析资料可能不完整。")
+ elif operation == "stop":
+ live_ai.finish(session_id, self._transcription_final_status if succeeded else "partial")
payload = json.dumps(str(message)[:200], ensure_ascii=True)
state = "true" if succeeded else "false"
+ if isinstance(normalized_segment, str):
+ try:
+ normalized_segment = json.loads(normalized_segment)
+ except (ValueError, TypeError):
+ normalized_segment = None
+ caption = json.dumps(
+ dict(normalized_segment)
+ if succeeded and operation == "segment" and isinstance(normalized_segment, Mapping)
+ else None,
+ ensure_ascii=True,
+ )
self._page.runJavaScript(
"window.doctorConsultation?.transcriptionResult?.("
f"{json.dumps(operation)}, {json.dumps(session_id)}, "
- f"{json.dumps(segment_id)}, {state}, {payload});"
+ f"{json.dumps(segment_id)}, {state}, {payload}, {caption});"
)
def _start_transcription(self, session_id: str, language: str) -> None:
+ if not self._local_transcription_context_is_trusted() or self._shutdown_requested:
+ return
try:
future = self.lifecycle.start_transcription(session_id, language=language)
except Exception as error:
@@ -1073,6 +1380,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
"start", session_id, "", False, str(error)[:200]
)
return
+ self._live_ai.transcription_starting()
future.add_done_callback(
lambda completed: self._notify_transcription_completed(
"start", session_id, "", completed
@@ -1080,6 +1388,8 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
)
def _save_transcript_segment(self, message: Mapping[str, Any]) -> None:
+ if not self._local_transcription_context_is_trusted():
+ return
session_id = str(message.get("sessionId") or "").strip()
segment = message.get("segment")
segment_id = (
@@ -1098,25 +1408,44 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
)
return
try:
- future = self.lifecycle.save_transcript_segment(segment)
+ normalized = normalize_transcript_segment(segment, session_id)
+ speaker = normalized["speaker_user_id"]
+ normalized["speaker_role"] = (
+ "doctor" if speaker == self.request.user_id
+ else "patient" if speaker == self.request.target_user_id
+ else "unknown"
+ )
+ future = self.lifecycle.save_transcript_segment(normalized)
except Exception as error:
self._on_transcription_completed(
"segment", session_id, segment_id, False, str(error)[:200]
)
return
+ caption = {
+ "segmentId": normalized["segment_id"],
+ "speakerUserId": normalized["speaker_user_id"],
+ "sourceText": normalized["text"],
+ "timestamp": normalized["timestamp"],
+ "isCompleted": True,
+ }
future.add_done_callback(
lambda completed: self._notify_transcription_completed(
- "segment", session_id, segment_id, completed
+ "segment", session_id, segment_id, completed, caption
)
)
def _finish_transcription(self, session_id: str, status: str) -> None:
+ if not self._local_transcription_context_is_trusted():
+ return
if session_id.strip() != str(self.lifecycle.transcription_session_id or ""):
self._on_transcription_completed(
"stop", session_id, "", False, "录音会话标识不匹配。"
)
return
try:
+ if getattr(self, "_asr_partial", False):
+ status = "partial"
+ self._transcription_final_status = status
future = self.lifecycle.finish_transcription(status=status)
except Exception as error:
self._on_transcription_completed(
@@ -1137,9 +1466,16 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
def hangup(self) -> None:
self._request_companion_shutdown("desktop-hangup")
+ def set_compact_close_handler(self, callback: Callable[[], None] | None) -> None:
+ """Let the compact title-bar close return to the same full call window."""
+
+ self._on_compact_close = callback
+
def _request_companion_shutdown(self, reason: str) -> None:
"""Let MediaRecorder finish and upload before WebEngine is destroyed."""
+ _EmbeddedVideoWindow._close_im_ai(self)
+ _EmbeddedVideoWindow._close_video_assistance(self, close_asr=False)
self._close_reason = reason
if self._closing or self._released:
return
@@ -1150,6 +1486,7 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
and not self._companion_ended
)
if not should_wait_for_companion:
+ self._shutdown_requested = True
self.close()
return
if self._shutdown_requested:
@@ -1183,6 +1520,9 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
def _begin_shutdown(self) -> None:
if self._closing:
return
+ _EmbeddedVideoWindow._close_im_ai(self)
+ _EmbeddedVideoWindow._close_video_assistance(self)
+ self._on_compact_close = None
self._closing = True
self._media_active = False
self._shutdown_timer.stop()
@@ -1240,6 +1580,16 @@ if WEBENGINE_AVAILABLE: # pragma: no cover - GUI behavior needs an integration
self._profile.deleteLater()
def closeEvent(self, event: Any) -> None:
+ if (
+ self._on_compact_close is not None
+ and not self._shutdown_requested
+ and not self._companion_ended
+ and not self._closing
+ and not self._released
+ ):
+ event.ignore()
+ self._on_compact_close()
+ return
if (
self._injected
and self._start_requested
@@ -1273,6 +1623,7 @@ class VideoCallWindow:
patient_name: str = "患者",
patient_case: Mapping[str, Any] | None = None,
on_open_diagnosis: Callable[[], None] | None = None,
+ can_ai_assistant: bool = False,
) -> None:
del browser_opener # Reserved for a future authenticated handoff implementation.
try:
@@ -1291,6 +1642,7 @@ class VideoCallWindow:
self.open_im = bool(open_im)
self.patient_name = str(patient_name or "患者").strip() or "患者"
self.patient_case = dict(patient_case or {})
+ self.can_ai_assistant = can_ai_assistant is True
self.on_open_diagnosis = on_open_diagnosis
self.logger = logger or _LOGGER
self.location = resolve_companion_location(
@@ -1322,6 +1674,8 @@ class VideoCallWindow:
patient_name=self.patient_name,
patient_case=self.patient_case,
on_open_diagnosis=self.on_open_diagnosis,
+ can_ai_assistant=self.can_ai_assistant,
+ repository=self.repository,
)
except Exception:
self.lifecycle.end("window-open-failed")
@@ -1341,7 +1695,7 @@ class VideoCallWindow:
def close(self) -> None:
if self._session is not None:
- self._session.close()
+ self._session._request_companion_shutdown("window-closed")
else:
self.lifecycle.end("unopened-session")
@@ -1367,6 +1721,7 @@ def open_video_call(
patient_name: str = "患者",
patient_case: Mapping[str, Any] | None = None,
on_open_diagnosis: Callable[[], None] | None = None,
+ can_ai_assistant: bool = False,
) -> VideoCallWindow:
"""Create and immediately open a trusted embedded video window."""
@@ -1383,6 +1738,7 @@ def open_video_call(
patient_name=patient_name,
patient_case=patient_case,
on_open_diagnosis=on_open_diagnosis,
+ can_ai_assistant=can_ai_assistant,
).open()
diff --git a/app/tests/test_ai_consult_ui.py b/app/tests/test_ai_consult_ui.py
index d68fc681c..1c886d97f 100755
--- a/app/tests/test_ai_consult_ui.py
+++ b/app/tests/test_ai_consult_ui.py
@@ -26,6 +26,7 @@ from PySide6.QtWidgets import (
from doctor_workstation.core import PermissionSet
from doctor_workstation.services import ApiClient, DemoDoctorRepository, RemoteDoctorRepository
+from doctor_workstation.ui.design_system import PALETTE
from doctor_workstation.ui.dialogs import ai_consult as ai_consult_module
from doctor_workstation.ui.dialogs.ai_consult import (
AiConsultDialog,
@@ -2306,14 +2307,14 @@ def test_risk_block_uses_the_red_alert_palette() -> None:
assert "#FEF3F2" in risk_card
assert "#F1B35C" not in risk_card # 旧的橙色描边
marker = qss.split("QLabel#AiConsultRiskMarker {", 1)[1].split("}", 1)[0]
- assert "#BE4B58" in marker
+ assert PALETTE["danger"] in marker
def test_clinical_bodies_are_no_longer_rendered_at_eleven_pixels() -> None:
qss = ai_consult_module.AI_CONSULT_QSS
body = qss.rsplit("QLabel#AiConsultRiskBody {", 1)[1].split("}", 1)[0]
- assert "color: #1a1c1f" in body.lower()
+ assert f'color: {PALETTE["text"]}' in body
assert "font-size: 14px" in body
block = qss.split("QLabel#AiConsultClinicalBody,", 1)[1].split("}", 1)[0]
assert "font-size: 14px" in block
diff --git a/app/tests/test_appointment_drawer_visual.py b/app/tests/test_appointment_drawer_visual.py
index c34129ae7..fe057392a 100755
--- a/app/tests/test_appointment_drawer_visual.py
+++ b/app/tests/test_appointment_drawer_visual.py
@@ -10,6 +10,7 @@ from PySide6.QtCore import QDate, QSize, Qt
from PySide6.QtWidgets import QApplication, QStyle, QStyleOptionButton, QWidget
from doctor_workstation.ui.appointment_drawer import APPOINTMENT_DRAWER_QSS, AppointmentDrawer
+from doctor_workstation.ui.design_system import PALETTE
@pytest.fixture(scope="module")
@@ -565,8 +566,39 @@ def test_keyboard_focus_has_a_visible_state(
assert focus_target.hasFocus()
assert application.focusWidget() is focus_target
assert 'QPushButton[appointmentDate="true"]:focus' in APPOINTMENT_DRAWER_QSS
- assert "border-color: #8B9AD9;" in APPOINTMENT_DRAWER_QSS
+ assert f"border-color: {PALETTE['focus']};" in APPOINTMENT_DRAWER_QSS
drawer.close()
host.close()
application.processEvents()
+
+
+@pytest.mark.parametrize("button_kind", ["date", "slot"])
+def test_appointment_hover_keeps_hit_target_stable_after_relayout(
+ application: QApplication, button_kind: str,
+) -> None:
+ """Hovering must not move a time choice or restore a stale layout position."""
+ from PySide6.QtCore import QEvent, QPoint, QPointF
+ from PySide6.QtGui import QEnterEvent
+
+ host, drawer = _show_drawer(
+ application, (1440, 900), repository=_VisualRepository(), autoload=True,
+ )
+ tomorrow = QDate.currentDate().addDays(1).toString("yyyy-MM-dd")
+ button = drawer.date_buttons[tomorrow] if button_kind == "date" else drawer.slot_buttons["09:30-10:00"]
+ original = button.geometry()
+ try:
+ for _ in range(3):
+ application.sendEvent(button, QEnterEvent(QPointF(10, 10), QPointF(30, 34), QPointF(30, 34)))
+ assert button.geometry() == original
+ assert button.graphicsEffect() is None
+ relocated = original.topLeft() + QPoint(12, 16)
+ button.move(relocated) # A resize/reflow while the pointer stays inside.
+ application.sendEvent(button, QEvent(QEvent.Type.Leave))
+ assert button.pos() == relocated
+ button.setGeometry(original)
+ button.click()
+ assert button.isChecked()
+ finally:
+ drawer.close()
+ host.close()
diff --git a/app/tests/test_cloud_transcription_bridge.py b/app/tests/test_cloud_transcription_bridge.py
new file mode 100644
index 000000000..c360ec6cc
--- /dev/null
+++ b/app/tests/test_cloud_transcription_bridge.py
@@ -0,0 +1,362 @@
+"""Cloud ASR reaches UI and live AI only after trusted, normalized persistence."""
+
+from __future__ import annotations
+
+import json
+from concurrent.futures import Future
+from types import MethodType, SimpleNamespace
+from unittest.mock import Mock
+
+import pytest
+
+from doctor_workstation.video import window
+from doctor_workstation.video.security import TrustedDocumentPolicy
+
+pytestmark = pytest.mark.skipif(not window.WEBENGINE_AVAILABLE, reason="optional QtWebEngine")
+TRUSTED = "https://video.example.test/call/index.html"
+SESSION = "tr-cloud-test"
+SOURCE = "沒有過敏,沒有吃藥。0.5 mg,不是 5 mg。血壓 120/80 mmHg。\n唔係,冇食藥。"
+SIMPLIFIED = "没有过敏,没有吃药。0.5 mg,不是 5 mg。血压 120/80 mmHg。\n唔系,冇食药。"
+TIMESTAMP = 1793332800000
+
+
+def host(**changes):
+ item = SimpleNamespace(
+ _closing=False, _released=False, _shutdown_requested=False, _injected=True,
+ _start_requested=True, _call_cycle_closed=False,
+ _policy=TrustedDocumentPolicy.from_url(TRUSTED, is_local=False),
+ _page=Mock(), _local_transcription=Mock(), _live_ai=Mock(),
+ _asr_session_id=SESSION, _asr_ready=False, _asr_partial=False,
+ _transcription_final_status="completed", _transcription_completed=Mock(),
+ request=SimpleNamespace(user_id="doctor_test", target_user_id="patient_test"),
+ lifecycle=SimpleNamespace(
+ call_record_id=71, transcription_session_id=SESSION,
+ start_transcription=Mock(return_value=Future()),
+ save_transcript_segment=Mock(return_value=Future()),
+ finish_transcription=Mock(return_value=Future()),
+ ),
+ _start_local_audio_recording=Mock(), _append_local_audio_chunk=Mock(),
+ _finish_local_audio_recording=Mock(), _abort_local_audio_recording=Mock(),
+ )
+ item._page.url.return_value.toString.return_value = TRUSTED
+ for name in (
+ "_handle_bridge_message", "_handle_video_assistance_message",
+ "_local_transcription_context_is_trusted", "_start_transcription",
+ "_save_transcript_segment", "_finish_transcription",
+ "_notify_transcription_completed", "_on_transcription_completed",
+ ):
+ setattr(item, name, MethodType(getattr(window._EmbeddedVideoWindow, name), item))
+ item._transcription_completed.emit.side_effect = item._on_transcription_completed
+ for name, value in changes.items():
+ setattr(item, name, value)
+ return item
+
+
+def segment_message(**changes):
+ return {
+ "source": "doctor-call", "event": "transcription-segment", "sessionId": SESSION,
+ "segment": {
+ "segment_id": "cloud-segment-1", "speaker_user_id": "patient_test",
+ "speaker_role": "doctor", "timestamp": TIMESTAMP, "text": SOURCE,
+ },
+ **changes,
+ }
+
+
+def transcription_result(item):
+ script = item._page.runJavaScript.call_args.args[0]
+ assert script.startswith("window.doctorConsultation?.transcriptionResult?.(")
+ assert script.endswith(");")
+ return json.loads("[" + script.split("?.(", 1)[1][:-2] + "]")
+
+
+@pytest.mark.parametrize(
+ ("speaker_id", "expected_role"),
+ [("doctor_test", "doctor"), ("patient_test", "patient"), ("other_test", "unknown")],
+)
+def test_trusted_cloud_segment_is_normalized_and_role_is_host_derived(speaker_id, expected_role):
+ item = host()
+ message = segment_message()
+ message["segment"]["speaker_user_id"] = speaker_id
+ item._handle_bridge_message(message)
+
+ item.lifecycle.save_transcript_segment.assert_called_once()
+ saved = item.lifecycle.save_transcript_segment.call_args.args[0]
+ assert saved["text"] == SIMPLIFIED
+ assert saved["speaker_role"] == expected_role
+ assert saved["speaker_user_id"] == speaker_id
+ assert saved["segment_id"] == "cloud-segment-1"
+ assert saved["timestamp"] == TIMESTAMP
+ assert message["segment"]["text"] == SOURCE
+ item._live_ai.changed.assert_not_called()
+ item._page.runJavaScript.assert_not_called()
+
+ item.lifecycle.save_transcript_segment.return_value.set_result(True)
+
+ result = transcription_result(item)
+ assert result == [
+ "segment", SESSION, "cloud-segment-1", True, "",
+ {"segmentId": "cloud-segment-1", "speakerUserId": speaker_id,
+ "sourceText": SIMPLIFIED, "timestamp": TIMESTAMP, "isCompleted": True},
+ ]
+ assert len(item._transcription_completed.emit.call_args.args) == 6
+ item._live_ai.changed.assert_called_once_with(SESSION)
+ item._local_transcription.start.assert_not_called()
+ item._local_transcription.submit.assert_not_called()
+
+
+@pytest.mark.parametrize("failure", [False, RuntimeError("storage unavailable")])
+def test_failed_storage_never_returns_normalized_text_or_dirties_ai(failure):
+ item = host()
+ item._handle_bridge_message(segment_message())
+ future = item.lifecycle.save_transcript_segment.return_value
+ if isinstance(failure, Exception):
+ future.set_exception(failure)
+ else:
+ future.set_result(failure)
+
+ result = transcription_result(item)
+ assert result[:4] == ["segment", SESSION, "cloud-segment-1", False]
+ assert len(result) == 6 and result[5] is None
+ assert item._asr_partial
+ item._live_ai.changed.assert_not_called()
+ item._live_ai.transcription_error.assert_called_once()
+
+
+def test_synchronous_storage_failure_has_no_normalized_ack():
+ item = host()
+ item.lifecycle.save_transcript_segment.side_effect = RuntimeError("storage unavailable")
+ item._handle_bridge_message(segment_message())
+ result = transcription_result(item)
+ assert result[:4] == ["segment", SESSION, "cloud-segment-1", False]
+ assert result[5] is None
+ item._live_ai.changed.assert_not_called()
+
+
+def test_camel_case_cloud_segment_uses_the_same_normalized_contract():
+ item = host()
+ item._handle_bridge_message(segment_message(segment={
+ "segmentId": "cloud-segment-2", "speakerUserId": " doctor_test ",
+ "speakerRole": "patient", "sourceText": SOURCE, "timestamp": TIMESTAMP,
+ }))
+ saved = item.lifecycle.save_transcript_segment.call_args.args[0]
+ assert saved["speaker_role"] == "doctor"
+ assert saved["speaker_user_id"] == "doctor_test"
+ assert saved["text"] == SIMPLIFIED
+ item.lifecycle.save_transcript_segment.return_value.set_result(True)
+ assert transcription_result(item)[5] == {
+ "segmentId": "cloud-segment-2", "speakerUserId": "doctor_test",
+ "sourceText": SIMPLIFIED, "timestamp": TIMESTAMP, "isCompleted": True,
+ }
+
+
+@pytest.mark.parametrize("segment", [
+ None, {}, {"segment_id": "s1", "text": " "},
+ {"segment_id": "s1", "text": "字" * 4001},
+])
+def test_malformed_segment_is_rejected_before_storage(segment):
+ item = host()
+ item._handle_bridge_message(segment_message(segment=segment))
+ item.lifecycle.save_transcript_segment.assert_not_called()
+ result = transcription_result(item)
+ assert result[0] == "segment" and result[3] is False and result[5] is None
+ item._live_ai.changed.assert_not_called()
+
+
+def test_conversion_failure_does_not_store_or_ack_unnormalized_text(monkeypatch):
+ def unavailable_dictionary(_text):
+ raise RuntimeError("conversion dictionary unavailable")
+
+ monkeypatch.setattr(
+ "doctor_workstation.video.lifecycle.simplified_transcript", unavailable_dictionary,
+ )
+ item = host()
+ item._handle_bridge_message(segment_message())
+ item.lifecycle.save_transcript_segment.assert_not_called()
+ result = transcription_result(item)
+ assert result[:4] == ["segment", SESSION, "cloud-segment-1", False]
+ assert result[5] is None
+ item._live_ai.changed.assert_not_called()
+
+
+def test_json_ack_preserves_text_without_inserting_executable_source():
+ item = host()
+ message = segment_message()
+ message["segment"]["text"] = '沒有;0.5 mg,不是 5 mg。"\\\u2028\u2029結尾'
+ item._handle_bridge_message(message)
+ item.lifecycle.save_transcript_segment.return_value.set_result(True)
+ result = transcription_result(item)
+ assert result[5]["sourceText"] == '没有;0.5 mg,不是 5 mg。"\\\u2028\u2029结尾'
+ script = item._page.runJavaScript.call_args.args[0]
+ assert "\u2028" not in script and "\u2029" not in script
+
+
+@pytest.mark.parametrize("session_id", ["tr-old-call", ""])
+def test_segment_for_another_or_empty_session_is_not_saved(session_id):
+ item = host()
+ item._handle_bridge_message(segment_message(sessionId=session_id))
+ item.lifecycle.save_transcript_segment.assert_not_called()
+ item._live_ai.changed.assert_not_called()
+
+
+def test_late_persistence_completion_does_not_dirty_new_call():
+ item = host()
+ item._handle_bridge_message(segment_message())
+ original_future = item.lifecycle.save_transcript_segment.return_value
+ item.lifecycle = SimpleNamespace(call_record_id=72, transcription_session_id="tr-new-call")
+ item._asr_session_id = "tr-new-call"
+ original_future.set_result(True)
+ item._live_ai.changed.assert_not_called()
+ item._live_ai.bind.assert_not_called()
+ item._live_ai.finish.assert_not_called()
+
+
+def test_navigation_before_persistence_ack_blocks_page_delivery_and_ai_change():
+ item = host()
+ item._handle_bridge_message(segment_message())
+ item._page.url.return_value.toString.return_value = "https://another.example.test/"
+ item.lifecycle.save_transcript_segment.return_value.set_result(True)
+ item._page.runJavaScript.assert_not_called()
+ item._live_ai.changed.assert_not_called()
+
+
+@pytest.mark.parametrize("succeeded", [True, False])
+def test_start_marks_starting_and_binds_only_after_successful_storage_ack(succeeded):
+ item = host()
+ item._handle_bridge_message({
+ "event": "transcription-start-request", "sessionId": SESSION, "language": "zh-CN",
+ })
+ item._live_ai.transcription_starting.assert_called_once()
+ item.lifecycle.start_transcription.assert_called_once_with(SESSION, language="zh-CN")
+ item._live_ai.bind.assert_not_called()
+ item._local_transcription.start.assert_not_called()
+
+ item.lifecycle.start_transcription.return_value.set_result(succeeded)
+ if succeeded:
+ item._live_ai.bind.assert_called_once_with(71, SESSION)
+ else:
+ item._live_ai.bind.assert_not_called()
+ assert transcription_result(item)[:4] == ["start", SESSION, "", succeeded]
+ item._live_ai.changed.assert_not_called()
+
+
+def test_cloud_error_marks_failed_and_stop_keeps_partial_storage_status():
+ item = host()
+ item._handle_bridge_message({
+ "event": "transcription-error", "sessionId": SESSION, "message": "云转写连接中断",
+ })
+ item._live_ai.transcription_error.assert_called_once_with("云转写连接中断", status="failed")
+ assert item._asr_partial
+
+ item._handle_bridge_message({
+ "event": "transcription-stop", "sessionId": SESSION, "status": "completed",
+ })
+ item.lifecycle.finish_transcription.assert_called_once_with(status="partial")
+ item._live_ai.finish.assert_not_called()
+ item.lifecycle.finish_transcription.return_value.set_result(True)
+ item._live_ai.finish.assert_called_once_with(SESSION, "partial")
+ item._live_ai.changed.assert_not_called()
+
+
+@pytest.mark.parametrize("session,shutdown,ready", [(SESSION, False, True), ("old", False, False), (SESSION, True, False), ("", False, False)])
+def test_cloud_ready_after_retry_is_scoped_to_active_call(session, shutdown, ready):
+ item = host(_shutdown_requested=shutdown)
+ item._handle_bridge_message({"event": "transcription-ready", "sessionId": session})
+ assert item._live_ai.transcription_running.called is ready
+ if ready:
+ item._live_ai.transcription_running.assert_called_once_with(SESSION)
+
+
+def test_error_or_stop_from_old_session_does_not_change_current_call():
+ item = host()
+ item._handle_bridge_message({
+ "event": "transcription-error", "sessionId": "tr-old-call", "message": "old failure",
+ })
+ item._handle_bridge_message({
+ "event": "transcription-stop", "sessionId": "tr-old-call", "status": "partial",
+ })
+ assert not item._asr_partial
+ item.lifecycle.finish_transcription.assert_not_called()
+ item._live_ai.transcription_error.assert_not_called()
+ item._live_ai.finish.assert_not_called()
+
+
+@pytest.mark.parametrize("event", [
+ "transcription-start-request", "transcription-segment", "transcription-stop", "transcription-error", "transcription-ready",
+])
+@pytest.mark.parametrize("untrusted", ["closing", "released", "uninjected", "navigated"])
+def test_cloud_commands_require_injected_trusted_live_document(event, untrusted):
+ item = host()
+ if untrusted == "navigated":
+ item._page.url.return_value.toString.return_value = "https://another.example.test/"
+ else:
+ setattr(item, {"closing": "_closing", "released": "_released", "uninjected": "_injected"}[untrusted],
+ untrusted != "uninjected")
+ message = segment_message(event=event, message="cloud failure", language="zh-CN", status="completed")
+ item._handle_bridge_message(message)
+ item.lifecycle.start_transcription.assert_not_called()
+ item.lifecycle.save_transcript_segment.assert_not_called()
+ item.lifecycle.finish_transcription.assert_not_called()
+ item._live_ai.transcription_starting.assert_not_called()
+ item._live_ai.transcription_error.assert_not_called()
+ item._live_ai.transcription_running.assert_not_called()
+ item._live_ai.changed.assert_not_called()
+
+
+@pytest.mark.parametrize("operation", ["start", "segment", "stop"])
+def test_direct_transcription_methods_also_require_a_trusted_document(operation):
+ item = host(_injected=False)
+ if operation == "start":
+ item._start_transcription(SESSION, "zh-CN")
+ elif operation == "segment":
+ item._save_transcript_segment(segment_message())
+ else:
+ item._finish_transcription(SESSION, "completed")
+ item.lifecycle.start_transcription.assert_not_called()
+ item.lifecycle.save_transcript_segment.assert_not_called()
+ item.lifecycle.finish_transcription.assert_not_called()
+
+
+@pytest.mark.parametrize("event", [
+ "local-transcription-start", "local-transcription-chunk", "local-transcription-stop",
+])
+def test_old_local_asr_dispatch_cannot_run_recognition(event):
+ item = host()
+ item._handle_bridge_message({
+ "event": event, "sessionId": SESSION, "role": "patient", "sequence": 0,
+ "timestamp": TIMESTAMP, "data": "AQACAA==",
+ })
+ item._local_transcription.start.assert_not_called()
+ item._local_transcription.submit.assert_not_called()
+ item._local_transcription.stop.assert_not_called()
+ item.lifecycle.start_transcription.assert_not_called()
+ item.lifecycle.save_transcript_segment.assert_not_called()
+
+
+@pytest.mark.parametrize(
+ ("event", "handler", "arguments"),
+ [
+ ("local-audio-start", "_start_local_audio_recording", (SESSION, "audio/webm")),
+ ("local-audio-chunk", "_append_local_audio_chunk", (SESSION, 0, "AQACAA==")),
+ ("local-audio-finish", "_finish_local_audio_recording", (SESSION, 4)),
+ ("local-audio-abort", "_abort_local_audio_recording", (SESSION,)),
+ ],
+)
+def test_local_audio_recording_dispatch_remains_available(event, handler, arguments):
+ item = host()
+ item._handle_bridge_message({
+ "event": event, "sessionId": SESSION, "mimeType": "audio/webm",
+ "sequence": 0, "data": "AQACAA==", "totalBytes": 4,
+ })
+ getattr(item, handler).assert_called_once_with(*arguments)
+
+
+def test_pending_shutdown_drains_cloud_segments_and_stop_without_new_start():
+ item = host(_shutdown_requested=True)
+ item._handle_bridge_message({"event": "transcription-start-request", "sessionId": "tr-next"})
+ item._handle_bridge_message(segment_message())
+ item._handle_bridge_message({"event": "transcription-stop", "sessionId": SESSION})
+ item.lifecycle.start_transcription.assert_not_called()
+ item.lifecycle.save_transcript_segment.assert_called_once()
+ item.lifecycle.finish_transcription.assert_called_once_with(status="completed")
+ item._local_transcription.start.assert_not_called()
diff --git a/app/tests/test_compact_video_close.py b/app/tests/test_compact_video_close.py
new file mode 100644
index 000000000..ad2d43f6c
--- /dev/null
+++ b/app/tests/test_compact_video_close.py
@@ -0,0 +1,343 @@
+from __future__ import annotations
+
+import os
+from collections.abc import Callable, Iterator
+from types import MethodType, SimpleNamespace
+from typing import Any
+from unittest.mock import Mock
+
+import pytest
+
+os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
+
+from PySide6.QtCore import QRect, QSize, Qt
+from PySide6.QtGui import QCloseEvent
+from PySide6.QtWidgets import QApplication, QDialog, QMainWindow
+
+from doctor_workstation.app import ApplicationController
+from doctor_workstation.video import window as video_window
+
+
+class _CallWindow(QMainWindow):
+ """Exercise production Qt close handling without starting WebEngine or media."""
+
+ closeEvent = video_window._EmbeddedVideoWindow.closeEvent
+ set_compact_close_handler = video_window._EmbeddedVideoWindow.set_compact_close_handler
+ hangup = video_window._EmbeddedVideoWindow.hangup
+ _request_companion_shutdown = video_window._EmbeddedVideoWindow._request_companion_shutdown
+ _close_from_companion = video_window._EmbeddedVideoWindow._close_from_companion
+ _force_requested_shutdown = video_window._EmbeddedVideoWindow._force_requested_shutdown
+ _begin_shutdown = video_window._EmbeddedVideoWindow._begin_shutdown
+ _handle_bridge_message = video_window._EmbeddedVideoWindow._handle_bridge_message
+ _on_load_finished = video_window._EmbeddedVideoWindow._on_load_finished
+ _after_injection = video_window._EmbeddedVideoWindow._after_injection
+
+ def __init__(self, **changes: Any) -> None:
+ super().__init__()
+ self._on_compact_close: Callable[[], None] | None = None
+ self._closing = False
+ self._released = False
+ self._shutdown_requested = False
+ self._companion_ended = False
+ self._injected = True
+ self._start_requested = True
+ self._call_cycle_closed = False
+ self._media_active = True
+ self._close_reason = "window-closed"
+ self.open_im = False
+ self.lifecycle = SimpleNamespace(end=Mock())
+ self._page = SimpleNamespace(runJavaScript=Mock())
+ self._shutdown_timer = SimpleNamespace(start=Mock(), stop=Mock())
+ self._abort_local_audio_recording = Mock()
+ self._append_local_audio_chunk = Mock()
+ self._release_webengine = Mock(side_effect=self._mark_released)
+ self.restore_screenshot_preview = Mock()
+ self.call_ended = SimpleNamespace(emit=Mock())
+ self.call_error = SimpleNamespace(emit=Mock())
+ self.logger = Mock()
+ self.request = SimpleNamespace(safe_log_context=lambda: {})
+ for key, value in changes.items():
+ setattr(self, key, value)
+ self.setProperty("doctorSkipOpenGeometry", True)
+ self.setMinimumSize(620, 420)
+ self.setGeometry(40, 50, 680, 480)
+
+ def _mark_released(self) -> None:
+ self._released = True
+
+
+@pytest.fixture
+def qapp() -> QApplication:
+ return QApplication.instance() or QApplication([])
+
+
+@pytest.fixture
+def make_window(qapp: QApplication) -> Iterator[Callable[..., _CallWindow]]:
+ windows: list[_CallWindow] = []
+
+ def create(**changes: Any) -> _CallWindow:
+ window = _CallWindow(**changes)
+ windows.append(window)
+ return window
+
+ yield create
+ for window in windows:
+ window.set_compact_close_handler(None)
+ window._companion_ended = True
+ window.close()
+ window.deleteLater()
+ qapp.processEvents()
+
+
+def _controller() -> SimpleNamespace:
+ controller = SimpleNamespace(_video_preview_state=None, _video_preview_generation=0)
+ controller._show_video_preview = MethodType(
+ ApplicationController._show_video_preview, controller
+ )
+ controller._restore_video_preview = MethodType(
+ ApplicationController._restore_video_preview, controller
+ )
+ return controller
+
+
+def test_native_compact_close_restores_visible_window_and_next_close_ends_call(
+ qapp: QApplication, make_window: Callable[..., _CallWindow]
+) -> None:
+ window = make_window()
+ window.show()
+ qapp.processEvents()
+ original_geometry = QRect(window.geometry())
+ original_minimum = QSize(window.minimumSize())
+ controller = _controller()
+ dialog = QDialog()
+
+ controller._show_video_preview(window, dialog)
+ qapp.processEvents()
+
+ assert window.isVisible()
+ assert window.minimumSize() == QSize(440, 300)
+ assert window.geometry() != original_geometry
+ assert window.windowFlags() & Qt.WindowType.WindowStaysOnTopHint
+ assert window._on_compact_close is not None
+
+ assert window.close() is False
+ qapp.processEvents()
+
+ assert window.isVisible()
+ assert window.geometry() == original_geometry
+ assert window.minimumSize() == original_minimum
+ assert not window.windowFlags() & Qt.WindowType.WindowStaysOnTopHint
+ assert window.property("doctorSkipOpenGeometry") is False
+ assert controller._video_preview_state is None
+ assert window._on_compact_close is None
+ assert window._shutdown_requested is False
+ window._page.runJavaScript.assert_not_called()
+ window.lifecycle.end.assert_not_called()
+ window._abort_local_audio_recording.assert_not_called()
+ window._release_webengine.assert_not_called()
+ window.restore_screenshot_preview.assert_called_once_with()
+
+ assert window.close() is False
+
+ assert window._shutdown_requested is True
+ assert window.isVisible()
+ assert window._closing is False
+ window._page.runJavaScript.assert_called_once()
+ window._release_webengine.assert_not_called()
+
+ window._handle_bridge_message({"event": "hangup", "status": "local-hangup"})
+ qapp.processEvents()
+
+ assert not window.isVisible()
+ assert window._closing is True
+ window._release_webengine.assert_called_once_with()
+
+
+@pytest.mark.parametrize("action", ["hangup", "facade-close"])
+@pytest.mark.parametrize("wait_for_recording", [False, True], ids=["idle", "recording"])
+def test_explicit_shutdown_bypasses_compact_restore_and_drains_recording(
+ make_window: Callable[..., _CallWindow], action: str, wait_for_recording: bool
+) -> None:
+ window = make_window(_start_requested=wait_for_recording)
+ restore = Mock()
+ window.set_compact_close_handler(restore)
+ window.show()
+
+ def end_call() -> None:
+ if action == "hangup":
+ window.hangup()
+ else:
+ video_window.VideoCallWindow.close(SimpleNamespace(_session=window))
+
+ end_call()
+
+ restore.assert_not_called()
+ assert window._shutdown_requested is True
+ if wait_for_recording:
+ assert window.isVisible()
+ assert window._closing is False
+ window.lifecycle.end.assert_not_called()
+ window._release_webengine.assert_not_called()
+ window._abort_local_audio_recording.assert_not_called()
+ window._shutdown_timer.start.assert_called_once_with(190_000)
+ window._page.runJavaScript.assert_called_once()
+ assert "doctorConsultation?.close?.()" in window._page.runJavaScript.call_args.args[0]
+
+ end_call()
+ window.close()
+ window._page.runJavaScript.assert_called_once()
+ window._handle_bridge_message(
+ {"event": "local-audio-chunk", "sessionId": "recording", "sequence": 7, "data": "YQ=="}
+ )
+ window._append_local_audio_chunk.assert_called_once_with("recording", 7, "YQ==")
+ window._release_webengine.assert_not_called()
+ window._handle_bridge_message({"event": "hangup", "status": "local-hangup"})
+ else:
+ window._page.runJavaScript.assert_not_called()
+ window._shutdown_timer.start.assert_not_called()
+ reason = "desktop-hangup" if action == "hangup" else "window-closed"
+ window.lifecycle.end.assert_called_once_with(reason)
+
+ restore.assert_not_called()
+ assert not window.isVisible()
+ assert window._on_compact_close is None
+ assert window._closing is True
+ assert window._released is True
+ assert window._media_active is False
+ window._shutdown_timer.stop.assert_called_once_with()
+ window._abort_local_audio_recording.assert_called_once_with("")
+ window._release_webengine.assert_called_once_with()
+ window._begin_shutdown()
+ window._release_webengine.assert_called_once_with()
+
+
+@pytest.mark.parametrize(
+ "trigger",
+ ["remote-hangup", "remote-error", "timeout", "load-failed", "load-failed-active", "bridge-missing"],
+)
+def test_terminal_paths_close_compact_window_without_restoring(
+ make_window: Callable[..., _CallWindow], trigger: str
+) -> None:
+ window = make_window()
+ restore = Mock()
+ window.set_compact_close_handler(restore)
+ window.show()
+
+ if trigger == "remote-hangup":
+ window._handle_bridge_message({"event": "hangup", "status": "remote-hangup"})
+ window.call_ended.emit.assert_called_once_with("remote-hangup")
+ elif trigger == "remote-error":
+ window._handle_bridge_message({"event": "error", "message": "connection lost"})
+ window.call_error.emit.assert_called_once_with("connection lost")
+ elif trigger == "timeout":
+ window.hangup()
+ window._force_requested_shutdown()
+ window.lifecycle.end.assert_any_call("desktop-hangup-timeout")
+ elif trigger.startswith("load-failed"):
+ if trigger == "load-failed":
+ window._injected = False
+ window._start_requested = False
+ window._on_load_finished(False)
+ assert window._close_reason == "page-load-failed"
+ if trigger == "load-failed-active":
+ assert window._closing is False
+ window._release_webengine.assert_not_called()
+ restore.assert_not_called()
+ window._force_requested_shutdown()
+ window.lifecycle.end.assert_any_call("page-load-failed-timeout")
+ else:
+ window._after_injection(False)
+ assert window._close_reason == "bridge-api-missing"
+
+ restore.assert_not_called()
+ assert not window.isVisible()
+ assert window._closing is True
+ assert window._released is True
+ assert window._on_compact_close is None
+ window._release_webengine.assert_called_once_with()
+ window._shutdown_timer.stop.assert_called_once_with()
+
+
+@pytest.mark.parametrize(
+ "state", ["_shutdown_requested", "_companion_ended", "_closing", "_released"]
+)
+def test_close_event_never_restores_a_stopping_or_released_call(
+ make_window: Callable[..., _CallWindow], state: str
+) -> None:
+ window = make_window(_start_requested=False, **{state: True})
+ restore = Mock()
+ window.set_compact_close_handler(restore)
+ event = QCloseEvent()
+
+ window.closeEvent(event)
+
+ restore.assert_not_called()
+ assert event.isAccepted()
+
+
+def test_repeated_preview_refreshes_handler_and_ignores_old_dialog_generation(
+ make_window: Callable[..., _CallWindow],
+) -> None:
+ window = make_window()
+ controller = _controller()
+ first_dialog, second_dialog, third_dialog = QDialog(), QDialog(), QDialog()
+ controller._show_video_preview(window, first_dialog)
+ first_handler = window._on_compact_close
+ original_state = controller._video_preview_state
+
+ controller._show_video_preview(window, second_dialog)
+ second_handler = window._on_compact_close
+ assert first_handler is not None
+ assert second_handler is not None
+ assert first_handler is not second_handler
+ assert controller._video_preview_state is original_state
+ first_dialog.finished.emit(0)
+ first_handler()
+ assert controller._video_preview_state is original_state
+ assert window._on_compact_close is second_handler
+
+ second_handler()
+ assert controller._video_preview_state is None
+ assert window._on_compact_close is None
+
+ controller._show_video_preview(window, third_dialog)
+ current_handler = window._on_compact_close
+ second_dialog.finished.emit(0)
+ second_handler()
+ assert controller._video_preview_state is not None
+ assert window._on_compact_close is current_handler
+
+ third_dialog.finished.emit(0)
+ assert controller._video_preview_state is None
+ assert window._on_compact_close is None
+ window.lifecycle.end.assert_not_called()
+ window._page.runJavaScript.assert_not_called()
+
+
+def test_switching_preview_restores_old_window_and_isolates_old_callbacks(
+ make_window: Callable[..., _CallWindow],
+) -> None:
+ first, second = make_window(), make_window()
+ controller = _controller()
+ first_dialog, second_dialog = QDialog(), QDialog()
+ first_geometry = QRect(first.geometry())
+ controller._show_video_preview(first, first_dialog)
+ old_handler = first._on_compact_close
+
+ controller._show_video_preview(second, second_dialog)
+ current_handler = second._on_compact_close
+
+ assert first._on_compact_close is None
+ assert first.geometry() == first_geometry
+ assert controller._video_preview_state["window"] is second
+ assert old_handler is not None
+ old_handler()
+ first_dialog.finished.emit(0)
+ assert controller._video_preview_state["window"] is second
+ assert second._on_compact_close is current_handler
+
+ second_dialog.finished.emit(0)
+ assert controller._video_preview_state is None
+ assert second._on_compact_close is None
+ first.lifecycle.end.assert_not_called()
+ second.lifecycle.end.assert_not_called()
diff --git a/app/tests/test_diagnosis_drawer_visual.py b/app/tests/test_diagnosis_drawer_visual.py
index 470facfa2..8d8693307 100755
--- a/app/tests/test_diagnosis_drawer_visual.py
+++ b/app/tests/test_diagnosis_drawer_visual.py
@@ -22,6 +22,7 @@ from PySide6.QtWidgets import (
)
from doctor_workstation.core import PermissionSet
+from doctor_workstation.ui.design_system import PALETTE
from doctor_workstation.ui.diagnosis_drawer import (
DiagnosisChoiceButtons,
DiagnosisComboBox,
@@ -1012,14 +1013,14 @@ def test_choice_chips_keep_visible_checked_style_when_readonly(
application.processEvents()
# Sample the pad (not glyph center) so white text does not hide the fill.
enabled_color = selected.grab().toImage().pixelColor(6, selected.height() // 2)
- assert enabled_color.name().lower() == "#eef1fa"
+ assert enabled_color.name().lower() == PALETTE["accent_soft"].lower()
diet.setReadOnly(True)
application.processEvents()
disabled_color = selected.grab().toImage().pixelColor(6, selected.height() // 2)
assert selected.isChecked()
assert selected.isEnabled()
assert diet.isReadOnly()
- assert disabled_color.name().lower() == "#eef1fa"
+ assert disabled_color.name().lower() == PALETTE["accent_soft"].lower()
dialog.close()
application.processEvents()
@@ -1039,7 +1040,7 @@ def test_view_only_drawer_shows_selected_choice_chips(
selected = next(button for button in diet._buttons if button.isChecked())
application.processEvents()
color = selected.grab().toImage().pixelColor(6, selected.height() // 2)
- assert color.name().lower() == "#eef1fa"
+ assert color.name().lower() == PALETTE["accent_soft"].lower()
assert diet.isReadOnly()
assert not dialog.save_button.isVisibleTo(dialog)
dialog.close()
diff --git a/app/tests/test_diagnosis_index_visual.py b/app/tests/test_diagnosis_index_visual.py
index 450def724..75050d297 100755
--- a/app/tests/test_diagnosis_index_visual.py
+++ b/app/tests/test_diagnosis_index_visual.py
@@ -23,6 +23,7 @@ from PySide6.QtWidgets import (
)
from doctor_workstation.core import PermissionSet
+from doctor_workstation.ui.design_system import PALETTE
from doctor_workstation.ui.diagnosis_index_widgets import (
DIAGNOSIS_INDEX_QSS,
DiagnosisItemDelegate,
@@ -424,8 +425,8 @@ def test_empty_loading_and_compact_footer_keep_the_table_shell(
@pytest.mark.parametrize(
("record", "stripe", "channel"),
[
- (_row(701, DiagnosisViewRecord=[{"is_confirmed": 0}]), "#a9691d", "warning"),
- (_row(702, has_appointment=0, appointments=[]), "#4f63d9", "info"),
+ (_row(701, DiagnosisViewRecord=[{"is_confirmed": 0}]), PALETTE["warning"].lower(), "warning"),
+ (_row(702, has_appointment=0, appointments=[]), PALETTE["accent"].lower(), "info"),
],
)
def test_semantic_hover_preserves_three_pixel_stripe_on_neutral_background(
@@ -452,9 +453,9 @@ def test_semantic_hover_preserves_three_pixel_stripe_on_neutral_background(
assert image.pixelColor(0, 20).name() == stripe
assert image.pixelColor(1, 20).name() == stripe
assert image.pixelColor(2, 20).name() == stripe
- assert image.pixelColor(3, 20).name() == "#f7f7f7", f"{channel} stripe widened"
- assert image.pixelColor(6, 20).name() == "#f7f7f7"
- assert image.pixelColor(40, 20).name() == "#f7f7f7"
+ assert image.pixelColor(3, 20).name() == PALETTE["surface_alt"].lower(), f"{channel} stripe widened"
+ assert image.pixelColor(6, 20).name() == PALETTE["surface_alt"].lower()
+ assert image.pixelColor(40, 20).name() == PALETTE["surface_alt"].lower()
def test_page_hides_fixed_shadow_and_preserves_admin_token_contract(
diff --git a/app/tests/test_diagnosis_table_blue.py b/app/tests/test_diagnosis_table_blue.py
index fd129b46e..f26add35a 100755
--- a/app/tests/test_diagnosis_table_blue.py
+++ b/app/tests/test_diagnosis_table_blue.py
@@ -9,10 +9,17 @@ from pathlib import Path
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import pytest
-from PySide6.QtCore import QPoint, Qt
-from PySide6.QtGui import QFont
+from PySide6.QtCore import QPoint, QRect, Qt
+from PySide6.QtGui import QFont, QImage, QPainter
from PySide6.QtTest import QTest
-from PySide6.QtWidgets import QApplication, QLabel, QToolButton, QVBoxLayout, QWidget
+from PySide6.QtWidgets import (
+ QApplication,
+ QLabel,
+ QStyleOptionViewItem,
+ QToolButton,
+ QVBoxLayout,
+ QWidget,
+)
from doctor_workstation.ui.diagnosis_index_widgets import (
DiagnosisTableHost,
@@ -115,6 +122,79 @@ def test_blue_metrics_are_opt_in_and_expand_for_complete_content(application: QA
legacy.close()
+@pytest.mark.parametrize(
+ "size,column_width,row_height",
+ [((1024, 640), 84, 75), ((1440, 900), 126, 72)],
+)
+def test_followup_paint_keeps_time_whole_and_preserves_density(
+ application: QApplication, size: tuple[int, int], column_width: int, row_height: int,
+) -> None:
+ class RecordingPainter(QPainter):
+ def __init__(self, image: QImage) -> None:
+ super().__init__(image)
+ self.lines: list[tuple[QRect, int, str]] = []
+
+ def drawText(self, rect: QRect, flags: int, text: str) -> None: # noqa: N802
+ self.lines.append((QRect(rect), flags, text))
+ super().drawText(rect, flags, text)
+
+ row = {
+ "id": 501, "has_prescription": 1,
+ "followup_time_text": "2026-08-17 09:00", "followup_doctor_name": "陈医生",
+ }
+ original = copy.deepcopy(row)
+ host = DiagnosisTableHost(tech_blue=True)
+ host.resize(*size)
+ host.set_rows([row])
+ host.show()
+ _settle(application)
+ try:
+ assert host.main.columnWidth(6) == column_width
+ assert host.main.rowHeight(0) == row_height
+ assert host.fixed.rowHeight(0) == row_height
+ index = host.model.index(0, 6)
+ full_text = "2026-08-17 09:00\n陈医生"
+ assert index.data() == full_text
+ assert index.data(Qt.ItemDataRole.ToolTipRole) == full_text
+ option = QStyleOptionViewItem()
+ option.rect = QRect(0, 0, column_width, row_height)
+ image = QImage(column_width, row_height, QImage.Format.Format_ARGB32)
+ painter = RecordingPainter(image)
+ host.main.itemDelegate().paint(painter, option, index)
+ painter.end()
+ expected = ["2026-08-17", "09:00", "陈医生"] if size[0] == 1024 else [
+ "2026-08-17 09:00", "陈医生",
+ ]
+ assert [line[2] for line in painter.lines] == expected
+ content = option.rect.adjusted(8, 8, -8, -8)
+ for rect, flags, _text in painter.lines:
+ assert content.contains(rect)
+ assert flags & Qt.TextFlag.TextSingleLine
+ assert not flags & Qt.TextFlag.TextWrapAnywhere
+ assert row == original
+ finally:
+ host.close()
+ _settle(application)
+
+
+def test_followup_long_metadata_has_complete_tooltip(application: QApplication) -> None:
+ host = DiagnosisTableHost(tech_blue=True)
+ row = {
+ "id": 502, "has_prescription": 1,
+ "followup_time_text": "2026-08-17 09:00-09:30",
+ "followup_doctor_name": "陈医生(内分泌科专家门诊)", "followup_rx_voided": True,
+ }
+ original = copy.deepcopy(row)
+ host.set_rows([row])
+ index = host.model.index(0, 6)
+ assert index.data(Qt.ItemDataRole.ToolTipRole) == (
+ "2026-08-17 09:00-09:30\n陈医生(内分泌科专家门诊)\n处方已作废"
+ )
+ assert index.data() == index.data(Qt.ItemDataRole.ToolTipRole)
+ assert row == original
+ host.close()
+
+
@pytest.mark.parametrize("tech_blue", [False, True])
def test_geometry_has_no_minimum_height_feedback_and_tracks_both_scroll_axes(
application: QApplication, tech_blue: bool,
diff --git a/app/tests/test_doctor_selection.py b/app/tests/test_doctor_selection.py
index c0729c7d4..342609447 100755
--- a/app/tests/test_doctor_selection.py
+++ b/app/tests/test_doctor_selection.py
@@ -8,6 +8,7 @@ from PySide6.QtCore import QPoint, Qt, QTimer
from PySide6.QtTest import QTest
from PySide6.QtWidgets import QApplication
+from doctor_workstation.ui.design_system import PALETTE
from doctor_workstation.ui.pages.prescriptions import DoctorMultiSelect, _DoctorSelectionDialog
from doctor_workstation.ui.theme import apply_theme
@@ -74,7 +75,7 @@ def test_checked_row_blue_and_unchecked_white(dialog, application):
rect = dialog.listing.visualItemRect(item_for(dialog, doctor_id))
colors.append(image.pixelColor(int((rect.right() - 70) * scale),
int(rect.center().y() * scale)).name())
- assert colors == ["#eaf2ff", "#ffffff"]
+ assert colors == [PALETTE["accent_soft"].lower(), PALETTE["surface"].lower()]
def test_accept_commits_cancel_preserves_and_reopen_restores(application):
diff --git a/app/tests/test_im_ai_repository.py b/app/tests/test_im_ai_repository.py
new file mode 100644
index 000000000..91e38d722
--- /dev/null
+++ b/app/tests/test_im_ai_repository.py
@@ -0,0 +1,42 @@
+"""Current-peer archive paging preserves old callers and request identities."""
+
+import pytest
+
+from doctor_workstation.services.mock_repository import DemoDoctorRepository
+from doctor_workstation.services.repository import RemoteDoctorRepository
+
+
+class Client:
+ def __init__(self):
+ self.calls = []
+
+ def post(self, endpoint, payload, *, timeout=None):
+ self.calls.append((endpoint, payload, timeout))
+ return {"completed": False, "sync_token": "a" * 48, "errors": []}
+
+
+def test_sync_optional_parameters_and_timeout_preserve_exact_legacy_payload():
+ client = Client()
+ repository = RemoteDoctorRepository(client)
+ repository.sync_im_chat_messages(501)
+ result = repository.sync_im_chat_messages(501, scope="current", sync_token="a" * 48)
+ assert client.calls == [
+ ("tcm.diagnosis/triggerImChatSync", {"diagnosis_id": 501}, 15.0),
+ ("tcm.diagnosis/triggerImChatSync",
+ {"diagnosis_id": 501, "scope": "current", "sync_token": "a" * 48}, 15.0),
+ ]
+ assert result["completed"] is False
+
+
+@pytest.mark.parametrize("kwargs", [{"scope": "other"}, {"sync_token": "bad"}, {"sync_token": None}])
+def test_sync_rejects_invalid_options_without_network(kwargs):
+ client = Client()
+ with pytest.raises(ValueError):
+ RemoteDoctorRepository(client).sync_im_chat_messages(501, **kwargs)
+ assert not client.calls
+
+
+def test_mock_sync_supports_paging_contract_and_legacy_receipt():
+ repository = DemoDoctorRepository()
+ assert repository.sync_im_chat_messages(501)["queued"] is True
+ assert repository.sync_im_chat_messages(501, scope="current")["completed"] is True
diff --git a/app/tests/test_im_ai_service.py b/app/tests/test_im_ai_service.py
new file mode 100644
index 000000000..99606401b
--- /dev/null
+++ b/app/tests/test_im_ai_service.py
@@ -0,0 +1,270 @@
+"""Offline tests for native IM AI authorization, synchronization and races."""
+
+from __future__ import annotations
+
+from collections import deque
+from threading import BoundedSemaphore, Event
+from uuid import uuid4
+
+import pytest
+
+from doctor_workstation.video import im_ai
+
+
+class Repository:
+ def __init__(self, pages=None, events=None):
+ self.pages = deque(pages or [{"completed": True, "errors": []}])
+ self.events = events or [{"event": "done", "diagnosis_id": 501, "answer": "合成回复"}]
+ self.sync_calls = []
+ self.stream_calls = []
+ self.cancel_calls = []
+ self.cancel_called = Event()
+
+ def sync_im_chat_messages(self, diagnosis_id, **kwargs):
+ self.sync_calls.append((diagnosis_id, kwargs))
+ return self.pages.popleft()
+
+ def stream_diagnosis_ai(self, diagnosis_id, prompt, **kwargs):
+ self.stream_calls.append((diagnosis_id, prompt, kwargs))
+ yield from self.events
+
+ def cancel_diagnosis_ai(self, diagnosis_id, request_id):
+ self.cancel_calls.append((diagnosis_id, request_id))
+ self.cancel_called.set()
+ return {"cancel_requested": True}
+
+
+def controller(repository=None, **kwargs):
+ return im_ai.ImAiController(
+ repository or Repository(), diagnosis_id=501, appointment_id=101,
+ doctor_account="doctor_7", enabled=True, **kwargs,
+ )
+
+
+def request(service, **changes):
+ return {
+ "source": "doctor-call", "event": "im-ai-request", "sessionId": service.session_id,
+ "requestId": str(uuid4()), "contextKey": "view-1", "diagnosisId": "501",
+ "appointmentId": 101, "action": "summary", **changes,
+ }
+
+
+@pytest.mark.parametrize("action,task", [("summary", "summary"), ("followup", "custom"), ("reply", "custom")])
+def test_current_peer_sync_completes_before_ai_and_keeps_identity(action, task):
+ token = "a" * 48
+ repository = Repository(pages=[
+ {"completed": False, "phase": "checking_accounts", "sync_token": token, "errors": []},
+ {"completed": False, "phase": "syncing", "sync_token": token, "errors": []},
+ {"completed": True, "errors": []},
+ ], events=[
+ {"event": "start"}, {"event": "delta", "text": "合成"},
+ {"event": "done", "diagnosis_id": 501, "answer": "合成完整回复", "model_label": "模型",
+ "clinical_review_warnings": [{"code": "PULSE_EXCLUDED_FROM_ASSESSMENT", "source_id": "report"}]},
+ ])
+ service = controller(repository)
+ message = request(service, action=action)
+ assert service.handle(message)
+ assert service.wait()
+ result = service.take_result()
+ assert result["status"] == "success"
+ assert result["text"] == "合成完整回复"
+ assert result["requestId"] == message["requestId"]
+ assert result["modelLabel"] == "模型"
+ assert "不采集脉象" in result["warnings"][0]
+ assert len(repository.sync_calls) == 3
+ assert repository.sync_calls[0] == (501, {"scope": "current", "sync_token": ""})
+ assert repository.sync_calls[1][1]["sync_token"] == token
+ assert len(repository.stream_calls) == 1
+ diagnosis_id, prompt, options = repository.stream_calls[0]
+ assert diagnosis_id == 501 and options["task"] == task
+ assert options["request_id"] == message["requestId"]
+ assert "doctor_7" in prompt and len(prompt) <= 500
+ assert "不补问脉象" in prompt and "不自动确诊" in prompt
+ assert not repository.cancel_calls
+ assert service.take_result() is None
+ assert not service.handle(message) # A replay cannot submit another billable request.
+
+
+@pytest.mark.parametrize("changes", [
+ {"sessionId": "other"}, {"diagnosisId": "502"}, {"diagnosisId": True},
+ {"diagnosisId": "0501"}, {"appointmentId": 102}, {"requestId": "invalid"},
+ {"contextKey": ""}, {"contextKey": "x" * 129}, {"action": "prescription"},
+ {"action": {}}, {"source": "another-page"}, {"event": "send-message"},
+])
+def test_invalid_identity_or_action_cannot_read_patient_context(changes):
+ repository = Repository()
+ service = controller(repository)
+ assert not service.handle(request(service, **changes))
+ assert not repository.sync_calls and not repository.stream_calls
+
+
+def test_permission_default_denied_and_each_host_has_unique_session():
+ repository = Repository()
+ disabled = im_ai.ImAiController(
+ repository, diagnosis_id=501, appointment_id=101, doctor_account="doctor_7"
+ )
+ assert disabled.config["enabled"] is False
+ assert not disabled.handle(request(disabled))
+ assert controller().session_id != controller().session_id
+
+
+@pytest.mark.parametrize("page", [
+ {"queued": True}, {"completed": "true"}, {"completed": True, "errors": ["private detail"]},
+ {"completed": False, "sync_token": "bad"}, None,
+])
+def test_incomplete_or_failed_sync_never_generates(page):
+ repository = Repository(pages=[page])
+ service = controller(repository)
+ assert service.handle(request(service))
+ assert service.wait()
+ result = service.take_result()
+ assert result["status"] == "error"
+ assert "private detail" not in str(result)
+ assert not repository.stream_calls and not repository.cancel_calls
+
+
+def test_sync_step_and_time_budget_are_bounded():
+ page = {"completed": False, "sync_token": "b" * 48, "errors": []}
+ repository = Repository(pages=[page] * 10)
+ service = controller(repository, max_sync_steps=2)
+ service.handle(request(service))
+ assert service.wait()
+ assert len(repository.sync_calls) == 2
+ assert service.take_result()["status"] == "error"
+ assert not repository.stream_calls
+
+ times = iter([0, 0, 46])
+ repository = Repository()
+ service = controller(repository, clock=lambda: next(times))
+ service.handle(request(service))
+ assert service.wait()
+ assert "超时" in service.take_result()["message"]
+ assert not repository.stream_calls
+
+
+def test_cancel_during_sync_stops_before_model_submission():
+ entered, release = Event(), Event()
+
+ class SlowSync(Repository):
+ def sync_im_chat_messages(self, diagnosis_id, **kwargs):
+ entered.set()
+ assert release.wait(2)
+ return super().sync_im_chat_messages(diagnosis_id, **kwargs)
+
+ repository = SlowSync()
+ service = controller(repository)
+ message = request(service)
+ service.handle(message)
+ try:
+ assert entered.wait(1)
+ assert service.handle({**message, "event": "im-ai-cancel"})
+ assert "尚未向 AI" in service.take_result()["message"]
+ finally:
+ release.set()
+ assert service.wait()
+ assert not repository.stream_calls and not repository.cancel_calls
+ assert service.take_result() is None
+
+
+def test_cancel_is_independent_and_late_response_cannot_overwrite_next_request():
+ entered, release, cancel_release = Event(), Event(), Event()
+
+ class SlowStream(Repository):
+ def stream_diagnosis_ai(self, *args, **kwargs):
+ self.stream_calls.append((args, kwargs))
+ yield {"event": "delta", "text": "尚未完成"}
+ entered.set()
+ assert release.wait(2)
+ yield {"event": "done", "answer": "迟到的旧结果"}
+
+ def cancel_diagnosis_ai(self, *args):
+ result = super().cancel_diagnosis_ai(*args)
+ assert cancel_release.wait(2)
+ return result
+
+ repository = SlowStream()
+ service = controller(repository)
+ first = request(service)
+ service.handle(first)
+ try:
+ assert entered.wait(1)
+ assert service.take_result()["text"] == "尚未完成"
+ service.handle({**first, "event": "im-ai-cancel"})
+ assert repository.cancel_called.wait(1) # Independent HTTP starts while stream is blocked.
+ assert service.take_result()["status"] == "cancelled"
+ second = request(service, contextKey="view-2")
+ assert service.handle(second)
+ result = service.take_result()
+ assert result["requestId"] == second["requestId"] and result["status"] == "error"
+ assert len(repository.stream_calls) == 1
+ finally:
+ release.set()
+ cancel_release.set()
+ assert service.wait()
+ assert service.take_result() is None
+
+
+def test_close_invalidates_mailbox_and_cancels_without_waiting():
+ entered, release = Event(), Event()
+
+ class SlowStream(Repository):
+ def stream_diagnosis_ai(self, *args, **kwargs):
+ entered.set()
+ assert release.wait(2)
+ yield {"event": "done", "answer": "旧患者回复"}
+
+ repository = SlowStream()
+ service = controller(repository)
+ message = request(service)
+ service.handle(message)
+ try:
+ assert entered.wait(1)
+ service.close()
+ assert repository.cancel_called.wait(1)
+ assert service.take_result() is None
+ assert not service.handle(request(service))
+ finally:
+ release.set()
+ assert service.wait()
+ assert service.take_result() is None
+
+
+@pytest.mark.parametrize("events", [
+ [{"event": "delta", "text": "不完整"}],
+ [{"event": "done", "answer": ""}],
+ [{"event": "done", "diagnosis_id": 502, "answer": "其他患者"}],
+ [{"event": "delta", "text": "x" * (im_ai.MAX_RESULT_CHARS + 1)}],
+ [{"event": "done", "answer": "x" * (im_ai.MAX_RESULT_CHARS + 1)}],
+])
+def test_incomplete_mismatched_and_oversized_results_are_not_usable(events):
+ repository = Repository(events=events)
+ service = controller(repository)
+ service.handle(request(service))
+ assert service.wait()
+ assert service.take_result()["status"] == "error"
+ assert repository.cancel_called.wait(1)
+ assert len(repository.stream_calls) == 1 # No transport/validation retry.
+
+
+def test_thousands_of_deltas_are_coalesced_into_one_mailbox_result():
+ events = [{"event": "delta", "text": "字"}] * 4000 + [{"event": "done"}]
+ service = controller(Repository(events=events))
+ service.handle(request(service))
+ assert service.wait()
+ result = service.take_result()
+ assert result["status"] == "success" and result["text"] == "字" * 4000
+ assert service.take_result() is None
+
+
+def test_capacity_rejection_does_not_spawn_or_sync(monkeypatch):
+ slots = BoundedSemaphore(1)
+ slots.acquire()
+ monkeypatch.setattr(im_ai, "_WORKER_SLOTS", slots)
+ repository = Repository()
+ service = controller(repository)
+ try:
+ service.handle(request(service))
+ assert service.take_result()["status"] == "error"
+ assert not repository.sync_calls
+ finally:
+ slots.release()
diff --git a/app/tests/test_im_ai_window.py b/app/tests/test_im_ai_window.py
new file mode 100644
index 000000000..c0107bc3d
--- /dev/null
+++ b/app/tests/test_im_ai_window.py
@@ -0,0 +1,157 @@
+"""Exercise bridge trust and JSON delivery without starting WebEngine or HTTP."""
+
+from __future__ import annotations
+
+import json
+import os
+import subprocess
+import sys
+from pathlib import Path
+from types import SimpleNamespace
+from unittest.mock import Mock
+
+import pytest
+
+from doctor_workstation.video import window
+from doctor_workstation.video.security import TrustedDocumentPolicy
+
+pytestmark = pytest.mark.skipif(not window.WEBENGINE_AVAILABLE, reason="optional QtWebEngine")
+TRUSTED = "https://video.example.test/im/index.html"
+
+
+def host(**changes):
+ item = SimpleNamespace(
+ _closing=False, _released=False, _shutdown_requested=False, _injected=True,
+ _policy=TrustedDocumentPolicy.from_url(TRUSTED, is_local=False),
+ _page=Mock(), _im_ai=Mock(), _im_ai_timer=Mock(),
+ )
+ item._page.url.return_value.toString.return_value = TRUSTED
+ item._im_ai_context_is_trusted = lambda: window._EmbeddedVideoWindow._im_ai_context_is_trusted(item)
+ for key, value in changes.items():
+ setattr(item, key, value)
+ return item
+
+
+@pytest.mark.parametrize("changes", [
+ {"_closing": True}, {"_released": True}, {"_shutdown_requested": True}, {"_injected": False},
+])
+def test_inactive_or_closing_page_cannot_submit_or_receive_ai(changes):
+ item = host(**changes)
+ window._EmbeddedVideoWindow._handle_im_ai_message(item, {"event": "im-ai-request"})
+ window._EmbeddedVideoWindow._flush_im_ai(item)
+ item._im_ai.handle.assert_not_called()
+ item._im_ai.take_result.assert_not_called()
+ item._page.runJavaScript.assert_not_called()
+
+
+@pytest.mark.parametrize("url", ["about:blank", "https://evil.example.test/im/index.html", TRUSTED + "?other=1"])
+def test_document_navigation_cannot_reuse_authenticated_ai_bridge(url):
+ item = host()
+ item._page.url.return_value.toString.return_value = url
+ window._EmbeddedVideoWindow._handle_im_ai_message(item, {"event": "im-ai-request"})
+ window._EmbeddedVideoWindow._flush_im_ai(item)
+ item._im_ai.handle.assert_not_called()
+ item._page.runJavaScript.assert_not_called()
+
+
+def test_trusted_bridge_routes_only_to_identity_checked_controller():
+ item = host()
+ message = {"source": "doctor-call", "event": "im-ai-request", "diagnosisId": 501}
+ window._EmbeddedVideoWindow._handle_im_ai_message(item, message)
+ item._im_ai.handle.assert_called_once_with(message)
+
+
+def test_result_content_is_json_encoded_and_no_javascript_is_executed():
+ item = host()
+ payload = {"status": "success", "text": '\");window.bad=true;//\n\u2028', "warnings": ["合成提示"]}
+ item._im_ai.take_result.return_value = payload
+ window._EmbeddedVideoWindow._flush_im_ai(item)
+ script = item._page.runJavaScript.call_args.args[0]
+ prefix, suffix = "window.doctorConsultation?.imAiResult?.(", ");"
+ assert script.startswith(prefix) and script.endswith(suffix)
+ assert json.loads(script[len(prefix):-len(suffix)]) == payload
+ assert "\\u2028" in script
+
+
+def test_host_acknowledges_initial_summary_only_after_request_gate_opens():
+ item = host(_injected=False)
+ item._im_ai.session_id = 'synthetic-session-\\"\u2028'
+
+ def verify_gate(script):
+ assert item._im_ai_context_is_trusted() is True
+ prefix, suffix = "window.doctorConsultation?.imAiReady?.(", ");"
+ assert script.startswith(prefix) and script.endswith(suffix)
+ assert json.loads(script[len(prefix):-len(suffix)]) == item._im_ai.session_id
+
+ item._page.runJavaScript.side_effect = verify_gate
+ window._EmbeddedVideoWindow._after_injection(item, True)
+ item._page.runJavaScript.assert_called_once()
+
+
+@pytest.mark.parametrize("changes", [
+ {"_closing": True}, {"_released": True}, {"_shutdown_requested": True},
+])
+def test_late_injection_cannot_acknowledge_a_closed_ai_context(changes):
+ item = host(_injected=False, **changes)
+ window._EmbeddedVideoWindow._after_injection(item, True)
+ item._page.runJavaScript.assert_not_called()
+
+
+def test_navigation_cannot_receive_ai_readiness_acknowledgement():
+ item = host(_injected=False)
+ item._page.url.return_value.toString.return_value = "https://evil.example.test/im/index.html"
+ window._EmbeddedVideoWindow._after_injection(item, True)
+ item._page.runJavaScript.assert_not_called()
+
+
+def test_failed_injection_closes_without_ai_readiness_acknowledgement():
+ item = host(_injected=False, _request_companion_shutdown=Mock())
+ window._EmbeddedVideoWindow._after_injection(item, False)
+ item._request_companion_shutdown.assert_called_once_with("bridge-api-missing")
+ item._page.runJavaScript.assert_not_called()
+
+
+def test_shutdown_cancels_ai_before_waiting_for_media_or_destroying_page():
+ item = host(
+ _start_requested=True, _call_cycle_closed=False, _companion_ended=False,
+ _shutdown_timer=Mock(), close=Mock(),
+ )
+ window._EmbeddedVideoWindow._request_companion_shutdown(item, "window-closed")
+ item._im_ai.close.assert_called_once()
+ item._im_ai_timer.stop.assert_called_once()
+ assert item._shutdown_requested is True
+ item.close.assert_not_called() # Recording shutdown still gets its existing grace period.
+ item._shutdown_timer.start.assert_called_once_with(190_000)
+
+
+def test_qt_notify_rejects_oversized_or_wrong_source_payloads():
+ callback = Mock()
+ bridge = window._QtVideoBridge(callback, Mock())
+ bridge.notify("x" * 16_385)
+ bridge.notify(json.dumps({"source": "evil", "event": "im-ai-request"}))
+ bridge.notify("[]")
+ callback.assert_not_called()
+ message = {"source": "doctor-call", "event": "im-ai-cancel"}
+ bridge.notify(json.dumps(message))
+ callback.assert_called_once_with(message)
+
+
+def test_video_module_remains_importable_without_optional_qt():
+ source = Path(__file__).resolve().parents[1] / "src"
+ script = """
+import builtins
+original_import = builtins.__import__
+def without_qt(name, *args, **kwargs):
+ if name == 'PySide6' or name.startswith('PySide6.'):
+ raise ImportError('synthetic core-only installation')
+ return original_import(name, *args, **kwargs)
+builtins.__import__ = without_qt
+from doctor_workstation.video.window import WEBENGINE_AVAILABLE, VideoCallWindow
+from doctor_workstation.video.im_ai import ImAiController
+assert WEBENGINE_AVAILABLE is False
+"""
+ result = subprocess.run(
+ [sys.executable, "-c", script], env={**os.environ, "PYTHONPATH": str(source)},
+ capture_output=True, text=True, timeout=10, check=False,
+ )
+ assert result.returncode == 0, result.stderr
diff --git a/app/tests/test_live_video_ai.py b/app/tests/test_live_video_ai.py
new file mode 100644
index 000000000..bc0c6c798
--- /dev/null
+++ b/app/tests/test_live_video_ai.py
@@ -0,0 +1,512 @@
+from __future__ import annotations
+
+from copy import deepcopy
+from threading import Event
+
+import pytest
+
+from doctor_workstation.core.errors import ApiBusinessError, ApiHttpError, ApiTimeoutError
+from doctor_workstation.video.live_ai import LiveAiController
+
+
+def result(call=71, session="tr-local", **changes):
+ value = {
+ "event": "done", "diagnosis_id": 9,
+ "live_context": {
+ "call_record_id": call, "transcription_session_id": session,
+ "revision": "a" * 64, "segment_count": 151,
+ "through_timestamp_ms": 1793332800000, "transcription_status": "running",
+ "sources": [{"id": "patient-1", "role": "patient", "timestamp_ms": 1793332800000,
+ "text": "这是用于软件测试的合成对话。"}],
+ },
+ "live_assistance": {
+ "summary": [{"text": "合成测试要点", "evidence_ids": ["patient-1"]}],
+ "questions": [], "checks": [], "review": [],
+ },
+ }
+ value.update(changes)
+ return value
+
+
+class Repo:
+ def __init__(self):
+ self.calls = []
+ self.cancels = []
+ self.response = result()
+ self.started = Event()
+ self.release = None
+ self.fail = False
+
+ def stream_video_ai(self, diagnosis_id, **kwargs):
+ self.calls.append((diagnosis_id, kwargs))
+ self.started.set()
+ if self.release is not None:
+ assert self.release.wait(3)
+ if self.fail:
+ raise RuntimeError("private connection details must not leak")
+ yield deepcopy(self.response)
+
+ def cancel_diagnosis_ai(self, diagnosis_id, request_id):
+ self.cancels.append((diagnosis_id, request_id))
+ return {"accepted": True}
+
+
+@pytest.fixture
+def configured():
+ repo = Repo()
+ clock = [100.0]
+ controller = LiveAiController(repo, diagnosis_id=9, enabled=True, clock=lambda: clock[0])
+ controller.bind(71, "tr-local")
+ yield controller, repo, clock
+ if repo.release is not None:
+ repo.release.set()
+ controller.close()
+ assert controller.wait(3)
+
+
+def run(controller, clock):
+ clock[0] += 10
+ controller.tick()
+ assert controller.wait(3)
+ return controller.take_state()
+
+
+def test_only_persisted_current_call_changes_trigger(configured):
+ controller, repo, clock = configured
+ controller.changed("another-call")
+ run(controller, clock)
+ assert not repo.calls
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["summary"][0]["evidence_ids"] == ["patient-1"]
+ assert state["segmentCount"] == 151
+ assert "transcript" not in repo.calls[0][1]
+ assert repo.calls[0][1]["call_record_id"] == 71
+ run(controller, clock)
+ assert len(repo.calls) == 1
+
+
+def test_cloud_retry_clears_failure_without_losing_saved_evidence(configured):
+ controller, repo, clock = configured
+ controller.changed("tr-local")
+ before = run(controller, clock)
+ controller.transcription_error("云转写中断", status="failed")
+ controller.transcription_running("stale-session")
+ assert controller.take_state()["transcriptionStatus"] == "failed"
+ controller.transcription_running("tr-local")
+ after = controller.take_state()
+ assert after["transcriptionStatus"] == "running"
+ assert after["error"] == ""
+ assert after["summary"] == before["summary"]
+ assert after["revision"] == before["revision"]
+ run(controller, clock)
+ assert len(repo.calls) == 1
+
+
+def test_one_inflight_and_many_changes_coalesce(configured):
+ controller, repo, clock = configured
+ repo.release = Event()
+ controller.changed("tr-local")
+ clock[0] += 2
+ controller.tick()
+ assert repo.started.wait(2)
+ for _ in range(50):
+ controller.changed("tr-local")
+ controller.tick()
+ assert len(repo.calls) == 1
+ repo.release.set()
+ assert controller.wait(3)
+ run(controller, clock)
+ assert len(repo.calls) == 2
+ run(controller, clock)
+ assert len(repo.calls) == 2
+
+
+def test_pause_stops_auto_but_explicit_refresh_works(configured):
+ controller, repo, clock = configured
+ controller.handle("toggle", False)
+ controller.changed("tr-local")
+ run(controller, clock)
+ assert not repo.calls
+ controller.handle("refresh")
+ state = run(controller, clock)
+ assert len(repo.calls) == 1
+ assert state["enabled"] is False
+
+
+def test_no_retry_loop_on_failure(configured):
+ controller, repo, clock = configured
+ repo.fail = True
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error"
+ assert "private" not in str(state)
+ for _ in range(5):
+ run(controller, clock)
+ assert len(repo.calls) == 1
+ repo.fail = False
+ controller.handle("refresh")
+ assert run(controller, clock)["phase"] == "ready"
+
+
+@pytest.mark.parametrize("mutation", [
+ lambda r: r.update(diagnosis_id=10),
+ lambda r: r["live_context"].update(call_record_id=72),
+ lambda r: r["live_context"].update(transcription_session_id="other"),
+ lambda r: r["live_context"].update(revision="invalid"),
+ lambda r: r["live_context"].update(segment_count=-1),
+ lambda r: r["live_context"].update(through_timestamp_ms=float("nan")),
+ lambda r: r["live_context"]["sources"][0].update(role="guessed"),
+ lambda r: r["live_context"]["sources"][0].update(timestamp_ms=True),
+ lambda r: r["live_assistance"]["summary"][0].update(evidence_ids=["made-up"]),
+ lambda r: r["live_assistance"]["summary"][0].update(evidence_ids=[]),
+])
+def test_invalid_identity_or_citations_never_published(configured, mutation):
+ controller, repo, clock = configured
+ mutation(repo.response)
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error"
+ assert state["summary"] == []
+
+
+def test_new_call_discards_late_result(configured):
+ controller, repo, clock = configured
+ repo.release = Event()
+ controller.changed("tr-local")
+ clock[0] += 2
+ controller.tick()
+ assert repo.started.wait(2)
+ controller.bind(72, "tr-next")
+ repo.release.set()
+ assert controller.wait(3)
+ state = controller.take_state()
+ assert state["summary"] == []
+ assert state["revision"] == ""
+
+
+def test_dialing_clears_previous_call_before_new_transcription_exists(configured):
+ controller, repo, clock = configured
+ controller.changed("tr-local")
+ assert run(controller, clock)["summary"]
+ controller.reset()
+ state = controller.take_state()
+ assert state["summary"] == [] and state["sources"] == []
+ assert state["transcriptionStatus"] == "idle"
+ controller.changed("tr-local")
+ controller.handle("review")
+ run(controller, clock)
+ assert len(repo.calls) == 1
+
+
+def test_complete_long_source_quote_is_not_truncated(configured):
+ controller, repo, clock = configured
+ source = "合成测试原文。" * 400
+ repo.response["live_context"]["sources"][0]["text"] = source
+ repo.response["live_assistance"]["summary"][0]["text"] = "患者原话:" + source
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["summary"][0]["text"] == "患者原话:" + source
+
+
+def test_previous_good_result_retained_during_update_and_failure(configured):
+ controller, repo, clock = configured
+ controller.changed("tr-local")
+ assert run(controller, clock)["summary"]
+ repo.release = Event()
+ repo.fail = True
+ controller.changed("tr-local")
+ clock[0] += 10
+ controller.tick()
+ state = controller.take_state()
+ assert state["busy"] and state["summary"]
+ repo.release.set()
+ assert controller.wait(3)
+ assert controller.take_state()["summary"]
+
+
+def test_review_only_after_transcript_finish(configured):
+ controller, repo, clock = configured
+ controller.changed("tr-local")
+ run(controller, clock)
+ controller.handle("review")
+ run(controller, clock)
+ assert len(repo.calls) == 1
+ controller.finish("tr-local", "partial")
+ controller.handle("review")
+ state = run(controller, clock)
+ assert repo.calls[-1][1]["task"] == "live_review"
+ assert state["transcriptionStatus"] == "partial"
+
+
+def test_no_permission_no_work(configured):
+ _, repo, clock = configured
+ disabled = LiveAiController(repo, diagnosis_id=9, enabled=False)
+ disabled.bind(71, "tr-local")
+ disabled.changed("tr-local")
+ disabled.handle("refresh")
+ disabled.tick()
+ assert not repo.calls
+ assert disabled.take_state()["available"] is False
+ disabled.close()
+
+
+def test_first_and_subsequent_updates_have_short_bounded_coalescing(configured):
+ controller, repo, clock = configured
+ controller.changed("tr-local")
+ clock[0] += 0.79
+ controller.tick()
+ assert not repo.calls
+ # More speech does not indefinitely postpone the first request.
+ controller.changed("tr-local")
+ clock[0] += 0.02
+ controller.tick()
+ assert controller.wait(3)
+ assert len(repo.calls) == 1
+ controller.changed("tr-local")
+ clock[0] += 1.99
+ controller.tick()
+ assert len(repo.calls) == 1
+ clock[0] += 0.02
+ controller.tick()
+ assert controller.wait(3)
+ assert len(repo.calls) == 2
+
+
+def test_validated_suggestions_are_visible_before_stream_finishes(configured):
+ controller, repo, clock = configured
+ delivered = Event()
+ repo.release = Event()
+
+ def stream(*args, **kwargs):
+ yield result(event="live_update")
+ delivered.set()
+ assert repo.release.wait(3)
+ yield result()
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ clock[0] += 1
+ controller.tick()
+ assert delivered.wait(2)
+ state = controller.take_state()
+ assert state["busy"] is True and state["phase"] == "analyzing"
+ assert state["firstResultMs"] == 0
+ assert state["summary"] and state["revision"] == "a" * 64
+ assert state["pendingSegments"] == 0
+ controller.changed("tr-local")
+ clock[0] += 3
+ controller.tick()
+ state = controller.take_state()
+ assert state["elapsedMs"] == 3000 and state["pendingSegments"] == 1
+ repo.release.set()
+ assert controller.wait(3)
+ state = controller.take_state()
+ assert state["busy"] is False and state["lastDurationMs"] == 3000
+ assert state["firstResultMs"] == 0
+ assert state["pendingSegments"] == 1
+
+
+def test_slow_request_does_not_add_another_wait_for_queued_speech(configured):
+ controller, repo, clock = configured
+ repo.release = Event()
+ controller.changed("tr-local")
+ clock[0] += 1
+ controller.tick()
+ assert repo.started.wait(2)
+ controller.changed("tr-local")
+ clock[0] += 20
+ controller.tick()
+ assert len(repo.calls) == 1
+ repo.release.set()
+ assert controller.wait(3)
+ # The queued snapshot is already due; no new sleep after the slow request ends.
+ controller.tick()
+ assert controller.wait(3)
+ assert len(repo.calls) == 2
+ assert controller.take_state()["pendingSegments"] == 0
+
+
+def test_failed_stream_keeps_only_validated_progress(configured):
+ controller, repo, clock = configured
+
+ def stream(*args, **kwargs):
+ yield result(event="live_update")
+ raise ApiTimeoutError("secret raw upstream content")
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error" and state["summary"]
+ assert state["errorCode"] == "UPSTREAM_TIMEOUT"
+ assert "尚未全部完成" in state["message"]
+ assert "secret" not in str(state)
+
+
+def test_progress_cannot_change_snapshot_mid_request(configured):
+ controller, repo, clock = configured
+
+ def stream(*args, **kwargs):
+ yield result(event="live_update")
+ different = result()
+ different["live_context"]["revision"] = "b" * 64
+ yield different
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error"
+ assert state["revision"] == "a" * 64
+
+
+@pytest.mark.parametrize("scope", ["current_call_only", "authorized_case"])
+def test_displayed_scope_comes_from_validated_server_result(configured, scope):
+ controller, repo, clock = configured
+ repo.response["analysis_scope"] = scope
+ controller.changed("tr-local")
+ assert run(controller, clock)["analysisScope"] == scope
+ controller.bind(72, "new-session")
+ assert controller.take_state()["analysisScope"] == ""
+
+
+def test_legacy_server_does_not_claim_dialogue_only(configured):
+ controller, repo, clock = configured
+ controller.changed("tr-local")
+ assert run(controller, clock)["analysisScope"] == ""
+
+
+@pytest.mark.parametrize("scope", [None, [], "invented"])
+def test_unrecognized_result_scope_is_rejected(configured, scope):
+ controller, repo, clock = configured
+ repo.response["analysis_scope"] = scope
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error" and not state["summary"]
+ assert state["analysisScope"] == ""
+
+
+def test_scope_cannot_change_within_one_stream(configured):
+ controller, repo, clock = configured
+
+ def stream(*args, **kwargs):
+ yield result(event="live_update", analysis_scope="current_call_only")
+ yield result(analysis_scope="authorized_case")
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error" and state["summary"]
+ assert state["analysisScope"] == "current_call_only"
+
+
+def test_scope_of_previous_results_survives_review_start_or_failure(configured):
+ controller, repo, clock = configured
+ repo.response["analysis_scope"] = "current_call_only"
+ controller.changed("tr-local")
+ assert run(controller, clock)["analysisScope"] == "current_call_only"
+ controller.finish("tr-local", "completed")
+ observed = []
+
+ def stream(*args, **kwargs):
+ assert kwargs["task"] == "live_review"
+ yield {"event": "start", "analysis_scope": "authorized_case"}
+ observed.append(controller.take_state())
+ raise ApiTimeoutError("synthetic timeout")
+
+ repo.stream_video_ai = stream
+ controller.handle("review")
+ state = run(controller, clock)
+ assert observed[0]["busy"] and observed[0]["analysisScope"] == "current_call_only"
+ assert state["phase"] == "error" and state["analysisScope"] == "current_call_only"
+
+
+def test_successful_review_and_refresh_replace_displayed_scope(configured):
+ controller, repo, clock = configured
+ repo.response["analysis_scope"] = "current_call_only"
+ controller.changed("tr-local")
+ assert run(controller, clock)["analysisScope"] == "current_call_only"
+ controller.finish("tr-local", "completed")
+ repo.response["analysis_scope"] = "authorized_case"
+ controller.handle("review")
+ assert run(controller, clock)["analysisScope"] == "authorized_case"
+ assert repo.calls[-1][1]["task"] == "live_review"
+ repo.response["analysis_scope"] = "current_call_only"
+ controller.handle("refresh")
+ assert run(controller, clock)["analysisScope"] == "current_call_only"
+ assert repo.calls[-1][1]["task"] == "live_consultation"
+
+
+def test_items_in_the_same_group_are_published_cumulatively(configured):
+ controller, repo, clock = configured
+ observed = []
+
+ def stream(*args, **kwargs):
+ response = result(event="live_update")
+ for index in range(3):
+ response["live_assistance"]["questions"].append({
+ "text": f"合成测试追问 {index + 1}?", "evidence_ids": ["patient-1"],
+ })
+ yield deepcopy(response)
+ observed.append(controller.take_state())
+ yield {**response, "event": "done"}
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert [len(item["questions"]) for item in observed] == [1, 2, 3]
+ assert all(item["busy"] and item["revision"] == "a" * 64 for item in observed)
+ assert len(state["questions"]) == 3 and not state["busy"]
+
+
+def test_invalid_progress_never_publishes_or_accepts_a_later_done(configured):
+ controller, repo, clock = configured
+
+ def stream(*args, **kwargs):
+ bad = result(event="live_update")
+ bad["live_assistance"]["summary"][0]["evidence_ids"] = ["invented"]
+ yield bad
+ yield result()
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["phase"] == "error" and not state["summary"]
+
+
+@pytest.mark.parametrize("error, expected", [
+ (ApiTimeoutError("private payload"), "UPSTREAM_TIMEOUT"),
+ (ApiHttpError("private payload", status_code=403), "PERMISSION_DENIED"),
+ (ApiHttpError("private payload", status_code=404), "SERVICE_UPDATE_REQUIRED"),
+ (ApiBusinessError("private payload", data={"error_code": "LIVE_RESULT_INVALID"}), "LIVE_RESULT_INVALID"),
+ (ApiBusinessError("private payload", data={"error_code": "UPSTREAM_TIMEOUT"}), "UPSTREAM_TIMEOUT"),
+ (ApiBusinessError("private payload", data={"error_code": {"secret": "payload"}}), "UPSTREAM_UNAVAILABLE"),
+])
+def test_failure_categories_do_not_leak_payloads(configured, error, expected, caplog):
+ controller, repo, clock = configured
+
+ def stream(*args, **kwargs):
+ raise error
+ yield
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert state["errorCode"] == expected
+ assert "private payload" not in str(state) + caplog.text
+ assert expected in caplog.text
+
+
+def test_validated_error_reason_distinguishes_citations_from_format(configured):
+ controller, repo, clock = configured
+
+ def stream(*args, **kwargs):
+ raise ApiBusinessError("private source text", data={
+ "error_code": "LIVE_RESULT_INVALID", "live_validation_reason": "CITATION_INVALID",
+ })
+ yield
+
+ repo.stream_video_ai = stream
+ controller.changed("tr-local")
+ state = run(controller, clock)
+ assert "引用无法核对" in state["error"]
+ assert "private" not in str(state)
diff --git a/app/tests/test_live_video_repository.py b/app/tests/test_live_video_repository.py
new file mode 100644
index 000000000..110b0e864
--- /dev/null
+++ b/app/tests/test_live_video_repository.py
@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+import pytest
+
+from doctor_workstation.core.errors import ApiProtocolError
+from doctor_workstation.services.repository import RemoteDoctorRepository
+
+
+class Client:
+ def __init__(self, events=None):
+ self.calls = []
+ self.events = events if events is not None else [{"event": "done", "data": {"diagnosis_id": 9, "live_context": {"revision": "a" * 64}}}]
+
+ def post_event_stream(self, endpoint, body, **kwargs):
+ self.calls.append((endpoint, body, kwargs))
+ yield from self.events
+
+
+def invoke(client, **changes):
+ args = {"call_record_id": 71, "transcription_session_id": "tr-local", "request_id": "a" * 36}
+ args.update(changes)
+ return list(RemoteDoctorRepository(client).stream_video_ai(9, **args))
+
+
+def test_scope_is_server_bound_and_structured_done_is_preserved():
+ client = Client()
+ result = invoke(client)
+ assert result[0]["live_context"]["revision"] == "a" * 64
+ endpoint, body, options = client.calls[0]
+ assert endpoint == "tcm.diagnosis/aiAssistantStream"
+ assert body["call_record_id"] == 71 and body["transcription_session_id"] == "tr-local"
+ assert body["task"] == "live_consultation"
+ assert "audio" not in body and "transcript" not in body
+ assert options["timeout"] == 105
+
+
+@pytest.mark.parametrize("changes", [{"call_record_id": True}, {"call_record_id": 0},
+ {"transcription_session_id": ""}, {"transcription_session_id": "../other"},
+ {"task": "prescription_generate"}])
+def test_bad_identity_or_task_never_sends(changes):
+ client = Client()
+ with pytest.raises(ValueError):
+ invoke(client, **changes)
+ assert client.calls == []
+
+
+def test_early_disconnect_does_not_fallback_to_unbound_general_assistant():
+ client = Client([])
+ with pytest.raises(ApiProtocolError):
+ invoke(client)
+ assert len(client.calls) == 1
+
+
+def test_cancelled_stream_does_not_publish_late_done():
+ client = Client()
+ assert invoke(client, cancelled=lambda: True) == []
+
+
+def test_validated_progress_is_forwarded_before_done_without_ending_stream():
+ client = Client([
+ {"event": "live_update", "data": {"diagnosis_id": 9, "live_assistance": {"questions": []}}},
+ {"event": "done", "data": {"diagnosis_id": 9, "live_context": {"revision": "a" * 64}}},
+ ])
+ events = invoke(client)
+ assert [event["event"] for event in events] == ["live_update", "done"]
+ assert events[0]["live_assistance"] == {"questions": []}
+
+
+def test_progress_does_not_substitute_for_final_done():
+ client = Client([{"event": "live_update", "data": {"diagnosis_id": 9}}])
+ with pytest.raises(ApiProtocolError):
+ invoke(client)
+
+
+def test_server_analysis_scope_is_preserved_in_stream_metadata():
+ client = Client([
+ {"event": kind, "data": {"analysis_scope": "current_call_only"}}
+ for kind in ("start", "live_update", "done")
+ ])
+ events = invoke(client)
+ assert [event["analysis_scope"] for event in events] == ["current_call_only"] * 3
+ assert "analysis_scope" not in client.calls[0][1]
diff --git a/app/tests/test_local_transcription.py b/app/tests/test_local_transcription.py
new file mode 100644
index 000000000..506c8861d
--- /dev/null
+++ b/app/tests/test_local_transcription.py
@@ -0,0 +1,571 @@
+from __future__ import annotations
+
+import base64
+import builtins
+import socket
+import struct
+import sys
+import threading
+from collections.abc import Callable
+from pathlib import Path
+from types import SimpleNamespace
+from typing import Any
+
+import pytest
+
+from doctor_workstation.video.local_transcription import (
+ MAX_BASE64_CHARS,
+ MAX_PCM_BYTES,
+ MAX_SEQUENCE,
+ FasterWhisperEngine,
+ LocalTranscriptionController,
+ LocalTranscriptionError,
+ default_model_path,
+ local_transcription_readiness,
+)
+
+TIMESTAMP = 1_795_000_000_000
+PCM = struct.pack(" None:
+ self.items: list[dict[str, Any]] = []
+ self.thread_ids: list[int] = []
+ self.condition = threading.Condition()
+
+ def __call__(self, event: dict[str, Any]) -> None:
+ with self.condition:
+ self.items.append(event)
+ self.thread_ids.append(threading.get_ident())
+ self.condition.notify_all()
+
+ def wait(self, kind: str, session: str = "call-1") -> dict[str, Any]:
+ with self.condition:
+
+ def match() -> dict[str, Any] | None:
+ return next(
+ (e for e in self.items if e["type"] == kind and e["sessionId"] == session),
+ None,
+ )
+
+ assert self.condition.wait_for(lambda: match() is not None, timeout=3)
+ event = match()
+ assert event is not None
+ return event
+
+
+class Engine:
+ def __init__(self, text: str = "无过敏史,服用 0.5 mg,不是 5 mg。") -> None:
+ self.text = text
+ self.inputs: list[bytes] = []
+
+ def transcribe(self, pcm: bytes) -> str:
+ self.inputs.append(pcm)
+ return self.text
+
+
+@pytest.fixture
+def make_controller():
+ controllers = []
+
+ def make(events: Events, factory: Callable | None = None, **kwargs):
+ controller = LocalTranscriptionController(events, factory or Engine, **kwargs)
+ controllers.append(controller)
+ return controller
+
+ yield make
+ for controller in controllers:
+ controller.close()
+ if controller._worker:
+ controller._worker.join(3)
+ assert not controller._worker.is_alive()
+
+
+def test_lazy_daemon_load_async_events_and_exact_numeric_negation_text(make_controller) -> None:
+ events = Events()
+ engine = Engine()
+ factory_threads = []
+
+ def factory():
+ factory_threads.append(threading.get_ident())
+ return engine
+
+ controller = make_controller(events, factory)
+ assert not factory_threads
+ assert controller.start("call-1")
+ assert events.wait("ready") == {"sessionId": "call-1", "type": "ready"}
+ assert controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ assert controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "completed"
+ assert events.wait("segment") == {
+ "sessionId": "call-1",
+ "type": "segment",
+ "segmentId": "call-1:patient:0",
+ "role": "patient",
+ "text": engine.text,
+ "timestamp": TIMESTAMP,
+ "isCompleted": True,
+ }
+ assert engine.inputs == [PCM]
+ assert controller._worker.daemon
+ assert factory_threads == [events.thread_ids[0]]
+ assert all(i != threading.get_ident() for i in events.thread_ids)
+
+
+def test_controller_converts_before_caption_and_persistence_events(make_controller) -> None:
+ events = Events()
+ controller = make_controller(events, lambda: Engine("沒有吃藥,0.5 mg,不是 5 mg。"))
+ controller.start("call-1")
+ controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert events.wait("segment")["text"] == "没有吃药,0.5 mg,不是 5 mg。"
+ assert events.wait("stopped")["status"] == "completed"
+
+
+def test_conversion_failure_does_not_emit_unconverted_text(make_controller, monkeypatch) -> None:
+ def broken(text):
+ raise OSError("private dictionary path")
+
+ monkeypatch.setattr("doctor_workstation.video.local_transcription.simplified_transcript", broken)
+ events = Events()
+ controller = make_controller(events, lambda: Engine("沒有吃藥"))
+ controller.start("call-1")
+ controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert events.wait("error")["code"] == "transcription_failed"
+ assert events.wait("stopped")["status"] == "partial"
+ assert not any(e["type"] == "segment" for e in events.items)
+
+
+def test_roles_have_independent_monotonic_sequences_and_drain_is_ordered(make_controller) -> None:
+ events = Events()
+ entered, release = threading.Event(), threading.Event()
+ engine = Engine()
+
+ def transcribe(pcm):
+ entered.set()
+ assert release.wait(3)
+ return engine.text
+
+ engine.transcribe = transcribe
+ controller = make_controller(events, lambda: engine)
+ assert controller.start("call-1")
+ events.wait("ready")
+ try:
+ assert controller.submit("call-1", "doctor", 0, TIMESTAMP, AUDIO)
+ assert entered.wait(3)
+ assert controller.submit("call-1", "patient", 0, TIMESTAMP + 100, AUDIO)
+ assert controller.submit("call-1", "doctor", 1, TIMESTAMP + 200, AUDIO)
+ assert controller.stop("call-1")
+ assert not controller.submit("call-1", "doctor", 2, TIMESTAMP + 300, AUDIO)
+ assert not any(e["type"] == "stopped" for e in events.items)
+ finally:
+ release.set()
+ assert events.wait("stopped")["status"] == "completed"
+ assert [e["type"] for e in events.items] == [
+ "ready",
+ "segment",
+ "segment",
+ "segment",
+ "stopped",
+ ]
+ assert [e["segmentId"] for e in events.items if e["type"] == "segment"] == [
+ "call-1:doctor:0",
+ "call-1:patient:0",
+ "call-1:doctor:1",
+ ]
+ assert controller.stop("call-1")
+ assert not controller.start("call-1")
+
+
+@pytest.mark.parametrize("sequence", [0, -1, True, 1.5, MAX_SEQUENCE + 1, "2"])
+def test_rejects_duplicate_invalid_or_unbounded_sequence(make_controller, sequence) -> None:
+ events = Events()
+ controller = make_controller(events)
+ assert controller.start("call-1")
+ assert controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ assert not controller.submit("call-1", "patient", sequence, TIMESTAMP, AUDIO)
+ assert controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "partial"
+ assert len([e for e in events.items if e["type"] == "segment"]) == 1
+
+
+@pytest.mark.parametrize(
+ ("role", "timestamp", "audio"),
+ [
+ ("unknown", TIMESTAMP, AUDIO),
+ ("patient", 0, AUDIO),
+ ("patient", True, AUDIO),
+ ("patient", float("nan"), AUDIO),
+ ("patient", 253_402_300_800_000, AUDIO),
+ ("patient", TIMESTAMP, "!!!"),
+ ("patient", TIMESTAMP, ""),
+ ("patient", TIMESTAMP, "é"),
+ ("patient", TIMESTAMP, "AA=="),
+ ("patient", TIMESTAMP, "A" * (MAX_BASE64_CHARS + 1)),
+ ],
+ ids=[
+ "role",
+ "zero-time",
+ "bool-time",
+ "nan-time",
+ "large-time",
+ "base64",
+ "empty",
+ "non-ascii",
+ "odd-pcm",
+ "oversized",
+ ],
+)
+def test_input_validation_rejects_bad_metadata_and_audio(
+ make_controller, role, timestamp, audio
+) -> None:
+ events = Events()
+ engine = Engine()
+ controller = make_controller(events, lambda: engine)
+ controller.start("call-1")
+ assert not controller.submit("call-1", role, 0, timestamp, audio)
+ controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "partial"
+ assert events.wait("error")["code"] in {"invalid_audio", "invalid_metadata"}
+ assert not engine.inputs
+
+
+def test_accepts_twelve_seconds_rejects_extra_sample_and_reports_sequence_gap(
+ make_controller,
+) -> None:
+ events = Events()
+ controller = make_controller(events)
+ controller.start("call-1")
+ assert controller.submit(
+ "call-1", "doctor", 0, TIMESTAMP, base64.b64encode(bytes(MAX_PCM_BYTES)).decode()
+ )
+ assert not controller.submit(
+ "call-1", "doctor", 1, TIMESTAMP, base64.b64encode(bytes(MAX_PCM_BYTES + 2)).decode()
+ )
+ assert controller.submit("call-1", "doctor", 2, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "partial"
+ assert {e["code"] for e in events.items if e["type"] == "error"} == {
+ "invalid_audio",
+ "sequence_gap",
+ }
+
+
+def test_silence_and_vad_empty_result_produce_no_fabricated_segment(make_controller) -> None:
+ events = Events()
+ engine = Engine("")
+ controller = make_controller(events, lambda: engine)
+ controller.start("call-1")
+ assert controller.submit(
+ "call-1", "patient", 0, TIMESTAMP, base64.b64encode(bytes(3200)).decode()
+ )
+ assert controller.submit("call-1", "patient", 1, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "completed"
+ assert engine.inputs == [PCM]
+ assert not any(e["type"] == "segment" for e in events.items)
+
+
+def test_queue_overload_is_bounded_coalesced_and_stop_still_drains(make_controller) -> None:
+ events = Events()
+ entered, release = threading.Event(), threading.Event()
+
+ class SlowEngine(Engine):
+ def transcribe(self, pcm):
+ entered.set()
+ assert release.wait(3)
+ return super().transcribe(pcm)
+
+ engine = SlowEngine()
+ controller = make_controller(events, lambda: engine, max_pending_chunks=2)
+ controller.start("call-1")
+ events.wait("ready")
+ try:
+ assert controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ assert entered.wait(3)
+ assert controller.submit("call-1", "patient", 1, TIMESTAMP, AUDIO)
+ assert controller.submit("call-1", "patient", 2, TIMESTAMP, AUDIO)
+ for sequence in range(3, 100):
+ assert not controller.submit("call-1", "patient", sequence, TIMESTAMP, AUDIO)
+ assert controller.stop("call-1")
+ finally:
+ release.set()
+ assert events.wait("stopped")["status"] == "partial"
+ assert len(engine.inputs) == 3
+ assert len([e for e in events.items if e.get("code") == "overloaded"]) == 1
+ assert events.items[-1]["type"] == "stopped"
+
+
+@pytest.mark.parametrize("during_load", [False, True])
+def test_new_session_cancels_old_inflight_result_and_queued_audio(
+ make_controller, during_load
+) -> None:
+ events = Events()
+ entered, release = threading.Event(), threading.Event()
+ engine = Engine()
+ loads = []
+
+ def block():
+ entered.set()
+ assert release.wait(3)
+
+ def factory():
+ loads.append(1)
+ if during_load:
+ block()
+ return engine
+
+ if not during_load:
+ original = engine.transcribe
+
+ def transcribe(pcm):
+ block()
+ return original(pcm)
+
+ engine.transcribe = transcribe
+ controller = make_controller(events, factory)
+ controller.start("call-1")
+ try:
+ if not during_load:
+ events.wait("ready")
+ controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ assert entered.wait(3)
+ controller.submit("call-1", "patient", 1, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert controller.start("call-2")
+ cutoff = len(events.items)
+ assert not controller.submit("call-1", "patient", 2, TIMESTAMP, AUDIO)
+ assert not controller.stop("call-1")
+ finally:
+ release.set()
+ events.wait("ready", "call-2")
+ assert controller.submit("call-2", "doctor", 0, TIMESTAMP, AUDIO)
+ controller.stop("call-2")
+ events.wait("stopped", "call-2")
+ assert all(e["sessionId"] == "call-2" for e in events.items[cutoff:])
+ assert len(loads) == 1
+ assert len(engine.inputs) == (1 if during_load else 2)
+
+
+def test_close_suppresses_callbacks_without_waiting_for_native_inference(make_controller) -> None:
+ events = Events()
+ entered, release = threading.Event(), threading.Event()
+
+ class SlowEngine(Engine):
+ def transcribe(self, pcm):
+ entered.set()
+ assert release.wait(3)
+ return "不"
+
+ controller = make_controller(events, SlowEngine)
+ controller.start("call-1")
+ events.wait("ready")
+ try:
+ controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ assert entered.wait(3)
+ controller.close()
+ count = len(events.items)
+ assert not controller.start("call-2")
+ assert not controller.stop("call-1")
+ finally:
+ release.set()
+ controller._worker.join(3)
+ assert not controller._worker.is_alive()
+ assert len(events.items) == count
+
+
+def test_missing_model_failure_is_explicit_and_stops_partial(make_controller) -> None:
+ events = Events()
+
+ def missing_model():
+ raise LocalTranscriptionError("model_missing")
+
+ controller = make_controller(events, missing_model)
+ controller.start("call-1")
+ assert events.wait("error")["code"] == "model_missing"
+ assert events.wait("stopped")["status"] == "partial"
+ assert not any(e["type"] == "ready" for e in events.items)
+ assert not controller.submit("call-1", "doctor", 0, TIMESTAMP, AUDIO)
+
+
+def test_inference_failure_does_not_leak_data_or_abort_later_chunks(make_controller) -> None:
+ events = Events()
+
+ class FailingEngine(Engine):
+ def transcribe(self, pcm):
+ if not self.inputs:
+ self.inputs.append(pcm)
+ raise RuntimeError("SECRET_PATIENT_DETAILS")
+ return "不"
+
+ controller = make_controller(events, FailingEngine)
+ controller.start("call-1")
+ controller.submit("call-1", "patient", 0, TIMESTAMP, AUDIO)
+ controller.submit("call-1", "patient", 1, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "partial"
+ assert events.wait("error")["code"] == "transcription_failed"
+ assert events.wait("segment")["text"] == "不"
+ assert "SECRET_PATIENT_DETAILS" not in repr(events.items)
+
+
+def test_callback_failure_does_not_kill_worker(make_controller) -> None:
+ events = Events()
+
+ def callback(event):
+ if event["type"] == "ready":
+ raise RuntimeError("detached UI")
+ events(event)
+
+ controller = make_controller(callback)
+ controller.start("call-1")
+ controller.submit("call-1", "doctor", 0, TIMESTAMP, AUDIO)
+ controller.stop("call-1")
+ assert events.wait("stopped")["status"] == "completed"
+
+
+@pytest.mark.parametrize("session", ["", " ", "a" * 129, "x\n", "患者", None, 123])
+def test_invalid_session_cannot_create_worker(make_controller, session) -> None:
+ events = Events()
+ controller = make_controller(events)
+ assert not controller.start(session)
+ assert controller._worker is None
+ assert not events.items
+
+
+def write_model_files(path: Path) -> None:
+ for name in ("model.bin", "config.json", "tokenizer.json", "vocabulary.txt"):
+ (path / name).write_text("test", encoding="utf-8")
+
+
+def test_missing_tokenizer_never_imports_model_or_accesses_network(tmp_path, monkeypatch) -> None:
+ write_model_files(tmp_path)
+ (tmp_path / "tokenizer.json").unlink()
+ original_import = builtins.__import__
+
+ def guarded_import(name, *args, **kwargs):
+ assert name != "faster_whisper"
+ return original_import(name, *args, **kwargs)
+
+ def no_network(*args, **kwargs):
+ pytest.fail("Runtime ASR must not access the network")
+
+ monkeypatch.setattr(builtins, "__import__", guarded_import)
+ monkeypatch.setattr(socket.socket, "connect", no_network)
+ with pytest.raises(LocalTranscriptionError) as raised:
+ FasterWhisperEngine(tmp_path)
+ assert raised.value.code == "model_missing"
+
+
+def test_missing_dependency_is_explicit_without_exposing_exception(tmp_path, monkeypatch) -> None:
+ write_model_files(tmp_path)
+ original_import = builtins.__import__
+
+ def guarded_import(name, *args, **kwargs):
+ if name == "numpy":
+ raise ModuleNotFoundError("internal path / private details")
+ return original_import(name, *args, **kwargs)
+
+ monkeypatch.setattr(builtins, "__import__", guarded_import)
+ with pytest.raises(LocalTranscriptionError) as raised:
+ FasterWhisperEngine(tmp_path)
+ assert raised.value.code == "dependency_missing"
+ assert "private" not in str(raised.value)
+
+
+def test_missing_conversion_dictionary_fails_before_model_ready(tmp_path, monkeypatch) -> None:
+ write_model_files(tmp_path)
+
+ def broken_dictionary(text):
+ raise FileNotFoundError("private path to missing t2s.json")
+
+ def model_must_not_load(*args, **kwargs):
+ pytest.fail("Missing conversion resources must fail before expensive model loading")
+
+ monkeypatch.setitem(sys.modules, "numpy", SimpleNamespace())
+ monkeypatch.setitem(sys.modules, "faster_whisper", SimpleNamespace(WhisperModel=model_must_not_load))
+ monkeypatch.setitem(sys.modules, "faster_whisper.vad", SimpleNamespace(get_vad_model=lambda: None))
+ monkeypatch.setattr(
+ "doctor_workstation.video.local_transcription.simplified_transcript", broken_dictionary
+ )
+ with pytest.raises(LocalTranscriptionError) as raised:
+ FasterWhisperEngine(tmp_path)
+ assert raised.value.code == "conversion_unavailable"
+ assert "private" not in str(raised.value)
+
+
+def test_engine_uses_local_cpu_int8_vad_and_iterates_without_rewriting(
+ tmp_path, monkeypatch
+) -> None:
+ write_model_files(tmp_path)
+ calls = {}
+
+ class Array:
+ def astype(self, dtype):
+ calls["float_dtype"] = dtype
+ return self
+
+ def __truediv__(self, divisor):
+ calls["divisor"] = divisor
+ return self
+
+ def frombuffer(pcm, dtype):
+ calls["pcm"] = pcm
+ calls["pcm_dtype"] = dtype
+ return Array()
+
+ class Model:
+ def __init__(self, path, **kwargs):
+ calls["path"] = path
+ calls["load"] = kwargs
+
+ def transcribe(self, audio, **kwargs):
+ calls["transcribe"] = kwargs
+
+ def segments():
+ calls["iterated"] = True
+ yield SimpleNamespace(text=" 没有。")
+ yield SimpleNamespace(text=" 0.5 mg,不是 5 mg。 ")
+
+ return segments(), None
+
+ def vad():
+ calls["vad_loaded"] = True
+
+ def no_network(*args, **kwargs):
+ pytest.fail("Runtime ASR must not access the network")
+
+ monkeypatch.setattr(socket.socket, "connect", no_network)
+ monkeypatch.setitem(
+ sys.modules, "numpy", SimpleNamespace(frombuffer=frombuffer, float32="float32")
+ )
+ monkeypatch.setitem(sys.modules, "faster_whisper", SimpleNamespace(WhisperModel=Model))
+ monkeypatch.setitem(sys.modules, "faster_whisper.vad", SimpleNamespace(get_vad_model=vad))
+ engine = FasterWhisperEngine(tmp_path)
+ assert engine.transcribe(PCM) == "没有。 0.5 mg,不是 5 mg。"
+ assert calls["path"] == str(tmp_path.resolve())
+ assert calls["load"]["local_files_only"] is True
+ assert calls["load"]["device"] == "cpu"
+ assert calls["load"]["compute_type"] == "int8"
+ assert calls["load"]["num_workers"] == 1
+ assert calls["vad_loaded"] and calls["iterated"]
+ assert calls["pcm"] == PCM and calls["pcm_dtype"] == " None:
+ monkeypatch.setenv("DOCTOR_ASR_MODEL_PATH", str(tmp_path))
+ assert default_model_path() == tmp_path.resolve()
+ info = local_transcription_readiness()
+ assert not info["available"]
+ assert info["modelPath"] == str(tmp_path.resolve())
+ assert "tokenizer.json" in info["missingFiles"]
+ assert not list(tmp_path.iterdir())
diff --git a/app/tests/test_local_video_bridge.py b/app/tests/test_local_video_bridge.py
new file mode 100644
index 000000000..edb68bf89
--- /dev/null
+++ b/app/tests/test_local_video_bridge.py
@@ -0,0 +1,135 @@
+"""Trusted native PCM ingestion and exact transcript/AI identity handoff."""
+from __future__ import annotations
+
+import json
+from types import SimpleNamespace
+from unittest.mock import Mock
+
+import pytest
+
+from doctor_workstation.video import window
+from doctor_workstation.video.security import TrustedDocumentPolicy
+
+pytestmark = pytest.mark.skipif(not window.WEBENGINE_AVAILABLE, reason="optional QtWebEngine")
+TRUSTED = "https://video.example.test/call/index.html"
+
+
+def host(**changes):
+ item = SimpleNamespace(
+ _closing=False, _released=False, _shutdown_requested=False, _injected=True,
+ _start_requested=True, _call_cycle_closed=False,
+ _policy=TrustedDocumentPolicy.from_url(TRUSTED, is_local=False),
+ _page=Mock(), _local_transcription=Mock(), _live_ai=Mock(),
+ _video_ai_timer=Mock(), _asr_session_id="tr-local", _asr_ready=True,
+ _asr_partial=False, _transcription_final_status="completed",
+ lifecycle=SimpleNamespace(call_record_id=71, transcription_session_id="tr-local"),
+ request=SimpleNamespace(user_id="doctor_1", target_user_id="patient_9"),
+ _save_transcript_segment=Mock(),
+ )
+ item._page.url.return_value.toString.return_value = TRUSTED
+ for key, value in changes.items():
+ setattr(item, key, value)
+ item._local_transcription_context_is_trusted = lambda: window._EmbeddedVideoWindow._local_transcription_context_is_trusted(item)
+ item._on_local_transcription = lambda event: window._EmbeddedVideoWindow._on_local_transcription(item, event)
+ return item
+
+
+def chunk(**changes):
+ return {"event": "local-transcription-chunk", "sessionId": "tr-local", "role": "patient",
+ "sequence": 3, "timestamp": 1793332800000.0, "data": "AQACAA==", **changes}
+
+
+def test_pcm_uses_bound_session_and_double_timestamp_is_converted_safely():
+ item = host()
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, chunk())
+ item._local_transcription.submit.assert_called_once_with("tr-local", "patient", 3, 1793332800000, "AQACAA==")
+
+
+@pytest.mark.parametrize("changes", [{"sessionId": "other"}, {"timestamp": float("nan")},
+ {"timestamp": float("inf")}, {"timestamp": -1}, {"timestamp": True}])
+def test_wrong_session_or_unbounded_pcm_metadata_rejected(changes):
+ item = host()
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, chunk(**changes))
+ item._local_transcription.submit.assert_not_called()
+
+
+@pytest.mark.parametrize("changes", [{"_closing": True}, {"_released": True}, {"_injected": False}])
+def test_untrusted_lifecycle_cannot_ingest_audio(changes):
+ item = host(**changes)
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, chunk())
+ item._local_transcription.submit.assert_not_called()
+
+
+def test_navigation_blocks_pcm_and_analysis_commands():
+ item = host()
+ item._page.url.return_value.toString.return_value = "https://another.example.test/"
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, chunk())
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, {"event": "video-ai-action", "action": "refresh"})
+ item._local_transcription.submit.assert_not_called()
+ item._live_ai.handle.assert_not_called()
+
+
+def test_pending_shutdown_drains_pcm_but_cannot_start_new_inference_session():
+ item = host(_shutdown_requested=True)
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, chunk())
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, {"event": "local-transcription-start", "sessionId": "tr-next"})
+ window._EmbeddedVideoWindow._handle_video_assistance_message(item, {"event": "video-ai-action", "action": "refresh"})
+ item._local_transcription.submit.assert_called_once()
+ item._local_transcription.start.assert_not_called()
+ item._live_ai.handle.assert_not_called()
+
+
+def test_asr_segment_is_persisted_with_host_speaker_before_json_display():
+ item = host()
+ event = {"type": "segment", "sessionId": "tr-local", "role": "patient", "segmentId": "tr-local:patient:3",
+ "text": '没有;0.5 mg,不是 5 mg。\u2028', "timestamp": 1793332800000, "isCompleted": True}
+ item._on_local_transcription(event)
+ item._save_transcript_segment.assert_called_once()
+ saved = item._save_transcript_segment.call_args.args[0]
+ assert saved["segment"]["text"] == event["text"]
+ assert saved["segment"]["speaker_user_id"] == "patient_9"
+ script = item._page.runJavaScript.call_args.args[0]
+ assert json.loads(script.split("?.(", 1)[1][:-2]) == event
+ item._live_ai.changed.assert_not_called() # waits for persistence ACK
+
+
+def test_late_asr_segment_cannot_enter_new_call():
+ item = host(_asr_session_id="tr-next")
+ item._on_local_transcription({"type": "segment", "sessionId": "tr-local", "role": "patient"})
+ item._save_transcript_segment.assert_not_called()
+ item._page.runJavaScript.assert_not_called()
+
+
+def test_persistence_ack_is_the_only_ai_dirty_trigger():
+ item = host()
+ window._EmbeddedVideoWindow._on_transcription_completed(item, "segment", "other", "s1", True, "")
+ item._live_ai.changed.assert_not_called()
+ window._EmbeddedVideoWindow._on_transcription_completed(item, "segment", "tr-local", "s1", True, "")
+ item._live_ai.changed.assert_called_once_with("tr-local")
+ window._EmbeddedVideoWindow._on_transcription_completed(item, "segment", "tr-local", "s2", False, "")
+ assert item._asr_partial
+ assert item._live_ai.changed.call_count == 1
+
+
+def test_model_missing_is_failed_and_partial_chunk_is_not_false_ready():
+ item = host(_asr_ready=False)
+ item._on_local_transcription({"type": "error", "sessionId": "tr-local", "message": "本地模型未安装"})
+ item._live_ai.transcription_error.assert_called_once_with("本地模型未安装", status="failed")
+
+
+def test_shutdown_keeps_asr_for_drain_then_closes_it():
+ item = host()
+ window._EmbeddedVideoWindow._close_video_assistance(item, close_asr=False)
+ item._live_ai.close.assert_called_once()
+ item._local_transcription.close.assert_not_called()
+ window._EmbeddedVideoWindow._close_video_assistance(item)
+ item._local_transcription.close.assert_called_once()
+
+
+def test_special_pcm_bridge_bounds_data_and_preserves_epoch():
+ callback = Mock()
+ bridge = window._QtVideoBridge(callback, Mock())
+ bridge.appendLocalTranscriptionChunk("tr-local", "doctor", 0, 1793332800000.0, "x" * 512001)
+ callback.assert_not_called()
+ bridge.appendLocalTranscriptionChunk("tr-local", "doctor", 0, 1793332800000.0, "AQACAA==")
+ assert callback.call_args.args[0]["timestamp"] == 1793332800000.0
diff --git a/app/tests/test_motion.py b/app/tests/test_motion.py
index aba2864ec..94f994f39 100755
--- a/app/tests/test_motion.py
+++ b/app/tests/test_motion.py
@@ -12,17 +12,16 @@ from __future__ import annotations
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
-# The module disables itself under the offscreen platform so widget grabs in the
-# other suites capture settled frames; these tests are about the animation, so
-# they opt back in.
-os.environ["DOCTOR_MOTION"] = "on"
-
import pytest
-from PySide6.QtCore import QEvent, QPoint, QPointF, Qt
-from PySide6.QtGui import QWheelEvent
+from PySide6.QtCore import QAbstractAnimation, QEvent, QPoint, QPointF, QPropertyAnimation, Qt
+from PySide6.QtGui import QKeyEvent, QWheelEvent
from PySide6.QtWidgets import (
+ QAbstractItemView,
QApplication,
+ QGraphicsDropShadowEffect,
QLabel,
+ QListWidget,
+ QPlainTextEdit,
QScrollArea,
QStackedWidget,
QVBoxLayout,
@@ -32,6 +31,13 @@ from PySide6.QtWidgets import (
from doctor_workstation.ui import motion
+@pytest.fixture(autouse=True)
+def enable_motion(monkeypatch: pytest.MonkeyPatch) -> None:
+ # Opt in per test so collecting this module does not animate other suites'
+ # screenshots or leak motion settings across the shared QApplication.
+ monkeypatch.setenv("DOCTOR_MOTION", "on")
+
+
@pytest.fixture(scope="module")
def application() -> QApplication:
return QApplication.instance() or QApplication([])
@@ -122,15 +128,22 @@ def _scroll_area(application: QApplication) -> QScrollArea:
return area
-def _wheel(delta: int) -> QWheelEvent:
+def _wheel(
+ delta: int,
+ *,
+ horizontal: int = 0,
+ pixels: int = 0,
+ modifiers: Qt.KeyboardModifier = Qt.KeyboardModifier.NoModifier,
+ phase: Qt.ScrollPhase = Qt.ScrollPhase.NoScrollPhase,
+) -> QWheelEvent:
return QWheelEvent(
QPointF(50, 50),
QPointF(50, 50),
- QPoint(0, 0),
- QPoint(0, delta),
+ QPoint(0, pixels),
+ QPoint(horizontal, delta),
Qt.MouseButton.NoButton,
- Qt.KeyboardModifier.NoModifier,
- Qt.ScrollPhase.NoScrollPhase,
+ modifiers,
+ phase,
False,
)
@@ -226,3 +239,273 @@ def test_reading_surfaces_get_smooth_scrolling_from_the_theme(
assert getattr(area, "_doctor_smooth_scroll", None) is not None
area.close()
+
+
+def test_repeated_fade_continues_from_current_opacity(application: QApplication) -> None:
+ widget = QWidget()
+ motion.fade_in(widget)
+ first = widget._doctor_motion["fade"]
+ first.setCurrentTime(motion.BASE // 2)
+ opacity = widget.graphicsEffect().opacity()
+
+ motion.fade_in(widget)
+
+ assert widget.graphicsEffect().opacity() == pytest.approx(opacity)
+ assert widget._doctor_motion["fade"].startValue() == pytest.approx(opacity)
+ assert first.state() == QAbstractAnimation.State.Stopped
+ widget.close()
+
+
+def test_fade_out_starts_at_full_opacity(application: QApplication) -> None:
+ widget = QWidget()
+ widget.show()
+
+ motion.fade_out(widget)
+
+ assert widget.graphicsEffect().opacity() == pytest.approx(1.0)
+ widget.close()
+
+
+def test_reversing_fade_does_not_run_cancelled_hide_callback(application: QApplication) -> None:
+ widget = QWidget()
+ widget.show()
+ completed = []
+ motion.fade_out(widget, on_finished=lambda: completed.append(True))
+ outgoing = widget._doctor_motion["fade"]
+ outgoing.setCurrentTime(motion.FAST // 2)
+ opacity = widget.graphicsEffect().opacity()
+
+ motion.fade_in(widget)
+ incoming = widget._doctor_motion["fade"]
+
+ assert incoming.startValue() == pytest.approx(opacity)
+ incoming.setCurrentTime(incoming.duration())
+ application.processEvents()
+ assert widget.isVisible()
+ assert not completed
+ assert widget.graphicsEffect() is None
+ widget.close()
+
+
+def test_previous_fade_cleanup_does_not_delete_reentrant_fade(application: QApplication) -> None:
+ widget = QWidget()
+ widget.show()
+ motion.fade_out(widget, on_finished=lambda: motion.fade_in(widget))
+ outgoing = widget._doctor_motion["fade"]
+
+ outgoing.setCurrentTime(outgoing.duration())
+ incoming = widget._doctor_motion["fade"]
+ effect = widget.graphicsEffect()
+ application.processEvents()
+
+ assert widget.graphicsEffect() is effect
+ assert incoming.state() == QAbstractAnimation.State.Running
+ incoming.setCurrentTime(incoming.duration())
+ application.processEvents()
+ assert widget.graphicsEffect() is None
+ assert widget.isVisible()
+ widget.close()
+
+
+def test_replaced_and_completed_animations_are_released(application: QApplication) -> None:
+ widget = QWidget()
+ destroyed = []
+ for _ in range(10):
+ motion.fade_in(widget)
+ widget._doctor_motion["fade"].destroyed.connect(lambda: destroyed.append(True))
+ fade = widget._doctor_motion["fade"]
+ fade.setCurrentTime(fade.duration())
+ application.processEvents()
+ application.sendPostedEvents(None, QEvent.Type.DeferredDelete)
+
+ assert not widget._doctor_motion
+ assert not widget.findChildren(QPropertyAnimation)
+ assert len(destroyed) == 10
+ widget.close()
+
+
+def test_fades_preserve_existing_graphics_effects(application: QApplication) -> None:
+ widget = QWidget()
+ shadow = QGraphicsDropShadowEffect(widget)
+ widget.setGraphicsEffect(shadow)
+
+ motion.fade_in(widget)
+ assert widget.graphicsEffect() is shadow
+ motion.fade_out(widget)
+ application.processEvents()
+
+ assert widget.graphicsEffect() is shadow
+ assert widget.isHidden()
+ widget.close()
+
+
+def test_repeated_enter_does_not_accumulate_position_offset(application: QApplication) -> None:
+ host = QWidget()
+ widget = QWidget(host)
+ origin = QPoint(10, 20)
+ widget.move(origin)
+ motion.enter(widget)
+ widget._doctor_motion["enter"].setCurrentTime(motion.BASE // 3)
+ position = widget.pos()
+
+ motion.enter(widget)
+
+ assert widget.pos() == position
+ arrival = widget._doctor_motion["enter"]
+ assert arrival.endValue() == origin
+ arrival.setCurrentTime(arrival.duration())
+ assert widget.pos() == origin
+ host.close()
+
+
+def test_disabling_motion_settles_an_active_entry(
+ application: QApplication, monkeypatch: pytest.MonkeyPatch
+) -> None:
+ host = QWidget()
+ widget = QWidget(host)
+ origin = QPoint(10, 20)
+ widget.move(origin)
+ motion.enter(widget)
+ monkeypatch.setenv("DOCTOR_MOTION", "off")
+
+ motion.enter(widget)
+ application.processEvents()
+
+ assert widget.pos() == origin
+ assert widget.graphicsEffect() is None
+ assert not widget._doctor_motion
+ host.close()
+
+
+def test_wheel_reversal_discards_pending_travel(application: QApplication) -> None:
+ area = _scroll_area(application)
+ motion.install_smooth_scroll(area)
+ scroller = area._doctor_smooth_scroll
+ bar = area.verticalScrollBar()
+ bar.setValue(500)
+ for _ in range(4):
+ scroller.eventFilter(area.viewport(), _wheel(-120))
+ scroller._animation.setCurrentTime(30)
+ position = bar.value()
+
+ scroller.eventFilter(area.viewport(), _wheel(120))
+
+ assert scroller._animation.startValue() == position
+ assert scroller._animation.endValue() == position - motion.SCROLL_STEP
+ scroller._animation.setCurrentTime(60)
+ assert bar.value() < position
+ area.close()
+
+
+@pytest.mark.parametrize("interaction", ["set_value", "keyboard", "slider_press", "range_change"])
+def test_direct_scroll_interaction_cancels_pending_wheel(
+ application: QApplication, interaction: str
+) -> None:
+ area = _scroll_area(application)
+ motion.install_smooth_scroll(area)
+ scroller = area._doctor_smooth_scroll
+ bar = area.verticalScrollBar()
+ scroller.eventFilter(area.viewport(), _wheel(-120))
+ scroller._animation.setCurrentTime(30)
+
+ if interaction == "set_value":
+ bar.setValue(500)
+ elif interaction == "keyboard":
+ application.sendEvent(
+ area,
+ QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_Down, Qt.KeyboardModifier.NoModifier),
+ )
+ elif interaction == "slider_press":
+ bar.setSliderDown(True)
+ else:
+ bar.setRange(0, 50)
+
+ assert scroller._animation.state() == QAbstractAnimation.State.Stopped
+ assert scroller._target == bar.value()
+ if interaction == "set_value":
+ scroller.eventFilter(area.viewport(), _wheel(-120))
+ assert scroller._animation.endValue() == 500 + motion.SCROLL_STEP
+ area.close()
+
+
+@pytest.mark.parametrize(
+ "wheel_options",
+ [
+ {"pixels": -8},
+ {"phase": Qt.ScrollPhase.ScrollUpdate},
+ {"phase": Qt.ScrollPhase.ScrollMomentum},
+ {"modifiers": Qt.KeyboardModifier.ControlModifier},
+ {"modifiers": Qt.KeyboardModifier.ShiftModifier},
+ {"horizontal": -120},
+ ],
+)
+def test_native_gestures_cancel_pending_wheel(
+ application: QApplication, wheel_options: dict
+) -> None:
+ area = _scroll_area(application)
+ motion.install_smooth_scroll(area)
+ scroller = area._doctor_smooth_scroll
+ scroller.eventFilter(area.viewport(), _wheel(-120))
+ scroller._animation.setCurrentTime(30)
+ delta = 0 if "horizontal" in wheel_options else -120
+
+ assert not scroller.eventFilter(area.viewport(), _wheel(delta, **wheel_options))
+ assert scroller._animation.state() == QAbstractAnimation.State.Stopped
+ assert scroller._target == area.verticalScrollBar().value()
+ area.close()
+
+
+@pytest.mark.parametrize("kind", ["items", "text_blocks"])
+def test_non_pixel_scrollbars_keep_native_wheel_steps(application: QApplication, kind: str) -> None:
+ if kind == "items":
+ area = QListWidget()
+ area.addItems([f"row {index}" for index in range(300)])
+ area.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerItem)
+ else:
+ area = QPlainTextEdit("\n".join(f"line {index}" for index in range(300)))
+ area.resize(300, 200)
+ area.show()
+ application.processEvents()
+ motion.install_smooth_scroll(area)
+
+ assert not area._doctor_smooth_scroll.eventFilter(area.viewport(), _wheel(-120))
+ application.sendEvent(area.viewport(), _wheel(-120))
+ assert 0 < area.verticalScrollBar().value() < motion.SCROLL_STEP
+ area.close()
+
+
+def test_pending_scroll_reaches_edge_before_handing_wheel_back(application: QApplication) -> None:
+ area = _scroll_area(application)
+ motion.install_smooth_scroll(area)
+ scroller = area._doctor_smooth_scroll
+ bar = area.verticalScrollBar()
+ bar.setValue(bar.maximum() - 20)
+
+ assert scroller.eventFilter(area.viewport(), _wheel(-120))
+ assert scroller.eventFilter(area.viewport(), _wheel(-120))
+ scroller._animation.setCurrentTime(scroller._animation.duration())
+ assert not scroller.eventFilter(area.viewport(), _wheel(-120))
+ area.close()
+
+
+def test_horizontal_scroller_honors_horizontal_and_shift_wheel(application: QApplication) -> None:
+ area = QScrollArea()
+ content = QWidget()
+ content.resize(2000, 1000)
+ area.setWidget(content)
+ area.resize(300, 200)
+ motion.install_smooth_scroll(area, orientation=Qt.Orientation.Horizontal)
+ area.show()
+ application.processEvents()
+ scroller = area._doctor_smooth_scroll
+
+ assert not scroller.eventFilter(area.viewport(), _wheel(-120))
+ assert scroller.eventFilter(area.viewport(), _wheel(0, horizontal=-120))
+ scroller._animation.setCurrentTime(scroller._animation.duration())
+ assert area.horizontalScrollBar().value() == motion.SCROLL_STEP
+ assert area.verticalScrollBar().value() == 0
+ assert scroller.eventFilter(
+ area.viewport(), _wheel(-120, modifiers=Qt.KeyboardModifier.ShiftModifier)
+ )
+ assert scroller._animation.endValue() == motion.SCROLL_STEP * 2
+ area.close()
diff --git a/app/tests/test_prescriptions_tech_blue.py b/app/tests/test_prescriptions_tech_blue.py
index 8a4613f86..3c529ec04 100755
--- a/app/tests/test_prescriptions_tech_blue.py
+++ b/app/tests/test_prescriptions_tech_blue.py
@@ -16,6 +16,7 @@ from PySide6.QtWidgets import QAbstractItemView, QApplication, QPushButton
from doctor_workstation.core import PermissionSet
from doctor_workstation.services import DemoDoctorRepository
from doctor_workstation.ui import icons
+from doctor_workstation.ui.design_system import PALETTE
from doctor_workstation.ui.pages import prescriptions as prescriptions_module
from doctor_workstation.ui.shell import ShellWindow
from doctor_workstation.ui.theme import apply_theme
@@ -222,7 +223,7 @@ def test_sorted_native_row_view_button_targets_visible_record(
def test_blue_icon_disabled_variant_does_not_modify_shared_icon_cache(application) -> None:
- kind, color, size = "pencil", "#1769E8", 19
+ kind, color, size = "pencil", PALETTE["accent"], 19
shared = icons.icon(kind, color, size)
original_key = shared.cacheKey()
original_normal = shared.pixmap(size, size, QIcon.Mode.Normal).toImage()
@@ -230,13 +231,19 @@ def test_blue_icon_disabled_variant_does_not_modify_shared_icon_cache(applicatio
blue = prescriptions_module._blue_prescription_icon(kind, color, size)
+ assert blue is not shared
assert icons.icon(kind, color, size) is shared
assert shared.cacheKey() == original_key
assert shared.pixmap(size, size, QIcon.Mode.Normal).toImage() == original_normal
assert shared.pixmap(size, size, QIcon.Mode.Disabled).toImage() == original_disabled
assert blue.pixmap(size, size, QIcon.Mode.Normal).toImage() == original_normal
- assert blue.pixmap(size, size, QIcon.Mode.Disabled).toImage() == icons.pixmap(kind, "#A4ADBA", size).toImage()
- assert blue.pixmap(size, size, QIcon.Mode.Disabled).toImage() != original_disabled
+ assert blue.pixmap(size, size, QIcon.Mode.Disabled).toImage() == icons.pixmap(kind, PALETTE["disabled"], size).toImage()
+ assert blue.pixmap(size, size, QIcon.Mode.Disabled).toImage() == original_disabled
+ # Both surfaces share the disabled colour; changing the returned icon still
+ # must not mutate the cached icon used by another page.
+ blue.addPixmap(icons.pixmap(kind, PALETTE["danger"], size), QIcon.Mode.Disabled)
+ assert shared.cacheKey() == original_key
+ assert shared.pixmap(size, size, QIcon.Mode.Disabled).toImage() == original_disabled
def test_long_doctor_button_paints_compactly_without_truncating_real_value(shell_factory, application) -> None:
diff --git a/app/tests/test_reception_blue_design.py b/app/tests/test_reception_blue_design.py
index fdc7c696e..801f669be 100755
--- a/app/tests/test_reception_blue_design.py
+++ b/app/tests/test_reception_blue_design.py
@@ -6,6 +6,7 @@ from PySide6.QtGui import QPalette
from PySide6.QtWidgets import QApplication, QFrame, QLabel, QPushButton
from doctor_workstation.core import PermissionSet
+from doctor_workstation.ui.design_system import PALETTE
from doctor_workstation.ui.pages import reception as reception_module
from doctor_workstation.ui.pages.reception import ReceptionPage
from doctor_workstation.ui.theme import apply_theme
@@ -43,12 +44,12 @@ def page(application, monkeypatch):
def test_primary_action_and_reading_ink_use_separate_colors(page, application):
page.video_button.setEnabled(True)
settle(application)
- assert page.video_button.palette().color(QPalette.ColorRole.Button).name() == "#1769e8"
- assert page.video_button.palette().color(QPalette.ColorRole.ButtonText).name() == "#ffffff"
- assert page.case_labels["present"].palette().color(QPalette.ColorRole.WindowText).name() == "#273244"
+ assert page.video_button.palette().color(QPalette.ColorRole.Button).name() == PALETTE["accent"].lower()
+ assert page.video_button.palette().color(QPalette.ColorRole.ButtonText).name() == PALETTE["surface"].lower()
+ assert page.case_labels["present"].palette().color(QPalette.ColorRole.WindowText).name() == PALETTE["text"].lower()
page.video_button.setEnabled(False)
settle(application)
- assert page.video_button.palette().color(QPalette.ColorRole.ButtonText).name() == "#8e8f90"
+ assert page.video_button.palette().color(QPalette.ColorRole.ButtonText).name() == PALETTE["disabled"].lower()
def test_typography_preserves_regular_body_and_distinct_values(page):
diff --git a/app/tests/test_screenshot_preview_size.py b/app/tests/test_screenshot_preview_size.py
new file mode 100644
index 000000000..511bed028
--- /dev/null
+++ b/app/tests/test_screenshot_preview_size.py
@@ -0,0 +1,322 @@
+from __future__ import annotations
+
+import os
+from types import SimpleNamespace
+from typing import Any
+from unittest.mock import Mock
+
+import pytest
+
+os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
+
+from PySide6.QtCore import QRect, QSize, Qt, QUrl
+from PySide6.QtWidgets import QApplication, QMainWindow
+
+from doctor_workstation.app import ApplicationController
+from doctor_workstation.ui import theme
+from doctor_workstation.video import window as video_window
+from doctor_workstation.video.screenshot import ScreenshotPreviewSize
+from doctor_workstation.video.security import TrustedDocumentPolicy
+
+TRUSTED_URL = "https://video.example.test/companion/index.html?mode=call"
+
+
+class _Window:
+ """Supply geometry and state only, so preview sizing cannot alter other settings."""
+
+ def __init__(
+ self,
+ available: QRect | None = None,
+ geometry: QRect | None = None,
+ ) -> None:
+ self.current_geometry = QRect(geometry) if geometry is not None else QRect(1362, 18, 540, 356)
+ self.available = QRect(available) if available is not None else QRect(0, 0, 1920, 1040)
+ self.compact_flag: bool | None = True
+ self.maximized = False
+ self.full_screen = False
+ self.geometry_changes: list[QRect] = []
+
+ def screen(self) -> SimpleNamespace:
+ return SimpleNamespace(availableGeometry=lambda: QRect(self.available))
+
+ def geometry(self) -> QRect:
+ return QRect(self.current_geometry)
+
+ def setGeometry(self, geometry: QRect) -> None: # noqa: N802 - Qt-compatible double
+ self.current_geometry = QRect(geometry)
+ self.geometry_changes.append(QRect(geometry))
+
+ def property(self, name: str) -> bool | None:
+ assert name == "doctorSkipOpenGeometry"
+ return self.compact_flag
+
+ def isMaximized(self) -> bool: # noqa: N802 - Qt-compatible double
+ return self.maximized
+
+ def isFullScreen(self) -> bool: # noqa: N802 - Qt-compatible double
+ return self.full_screen
+
+
+@pytest.fixture
+def qapp() -> QApplication:
+ return QApplication.instance() or QApplication([])
+
+
+@pytest.mark.parametrize(
+ ("available", "target", "expected_size"),
+ [
+ (QRect(0, 0, 1920, 1040), None, QSize(1120, 760)),
+ (QRect(-1920, -120, 1920, 1040), None, QSize(1120, 760)),
+ (QRect(-1280, 180, 1280, 720), QRect(0, 0, 1400, 950), QSize(1232, 672)),
+ (QRect(100, 50, 800, 600), None, QSize(752, 552)),
+ (QRect(0, 0, 1920, 1040), QRect(40, 60, 1360, 850), QSize(1360, 850)),
+ ],
+ ids=["default", "negative-monitor", "bounded-target", "small-screen", "normal-target"],
+)
+def test_preview_expands_within_current_screen_and_restores(
+ available: QRect, target: QRect | None, expected_size: QSize
+) -> None:
+ window = _Window(available, QRect(available.x() + 30, available.y() + 30, 440, 300))
+ original = window.geometry()
+ preview = ScreenshotPreviewSize()
+
+ preview.open(window, target)
+
+ expanded = window.geometry()
+ assert expanded.size() == expected_size
+ assert available.adjusted(24, 24, -24, -24).contains(expanded)
+ assert abs(expanded.center().x() - available.center().x()) <= 1
+ assert abs(expanded.center().y() - available.center().y()) <= 1
+ assert window.compact_flag is True
+
+ preview.restore(window)
+
+ assert window.geometry() == original
+ assert window.compact_flag is True
+
+
+def test_repeated_open_preserves_first_geometry_and_restore_is_idempotent() -> None:
+ window = _Window()
+ original = window.geometry()
+ preview = ScreenshotPreviewSize()
+
+ preview.open(window)
+ expanded = window.geometry()
+ preview.open(window, QRect(0, 0, 1500, 900))
+
+ assert window.geometry() == expanded
+ assert len(window.geometry_changes) == 1
+
+ preview.restore(window)
+ preview.restore(window)
+
+ assert window.geometry() == original
+ assert window.geometry_changes == [expanded, original]
+
+
+@pytest.mark.parametrize("state", ["maximized", "full_screen", "large", "no-screen", "tiny-screen"])
+def test_preview_does_not_modify_windows_that_do_not_need_expansion(state: str) -> None:
+ window = _Window()
+ if state == "large":
+ window.current_geometry = QRect(25, 30, 1300, 850)
+ elif state == "no-screen":
+ window.screen = lambda: None # type: ignore[method-assign, return-value]
+ elif state == "tiny-screen":
+ window.available = QRect(0, 0, 40, 40)
+ else:
+ setattr(window, state, True)
+ original = window.geometry()
+ preview = ScreenshotPreviewSize()
+
+ preview.open(window)
+ preview.restore(window)
+
+ assert window.geometry() == original
+ assert window.geometry_changes == []
+
+
+@pytest.mark.parametrize("change", ["move", "resize", "compact-flag", "maximize", "fullscreen"])
+def test_restore_preserves_external_window_changes_and_forgets_old_snapshot(change: str) -> None:
+ window = _Window()
+ preview = ScreenshotPreviewSize()
+ preview.open(window)
+ expanded = window.geometry()
+ if change == "move":
+ window.current_geometry.translate(40, 15)
+ elif change == "resize":
+ window.current_geometry.setWidth(window.current_geometry.width() + 50)
+ elif change == "compact-flag":
+ window.compact_flag = False
+ elif change == "maximize":
+ window.maximized = True
+ else:
+ window.full_screen = True
+ external_geometry = window.geometry()
+ writes_before_restore = len(window.geometry_changes)
+
+ preview.restore(window)
+
+ assert window.geometry() == external_geometry
+ assert len(window.geometry_changes) == writes_before_restore
+
+ # Even when those external changes later disappear, a late close is harmless.
+ window.current_geometry = expanded
+ window.compact_flag = True
+ window.maximized = False
+ window.full_screen = False
+ preview.restore(window)
+
+ assert window.geometry() == expanded
+ assert len(window.geometry_changes) == writes_before_restore
+
+
+def test_real_window_preserves_theme_opt_out_minimum_and_flags(qapp: QApplication) -> None:
+ theme._install_business_dialog_styling(qapp)
+ main = QMainWindow()
+ main.setProperty("doctorMainWindow", True)
+ main.setGeometry(30, 30, 980, 720)
+ main.show()
+ window = QMainWindow()
+ window.setProperty("doctorSkipOpenGeometry", True)
+ window.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True)
+ window.setMinimumSize(440, 300)
+ window.setGeometry(30, 30, 440, 300)
+ window.show()
+ qapp.processEvents()
+ original = window.geometry()
+ flags = window.windowFlags()
+ minimum = window.minimumSize()
+ preview = ScreenshotPreviewSize()
+ try:
+ preview.open(window, theme.main_window_target_rect(window))
+ qapp.processEvents()
+
+ assert window.width() > original.width()
+ assert window.height() > original.height()
+ assert window.minimumSize() == minimum
+ assert window.windowFlags() == flags
+ assert window.property("doctorSkipOpenGeometry") is True
+
+ preview.restore(window)
+ qapp.processEvents()
+
+ assert window.geometry() == original
+ assert window.minimumSize() == minimum
+ assert window.windowFlags() == flags
+ assert window.property("doctorSkipOpenGeometry") is True
+ finally:
+ window.close()
+ main.close()
+
+
+def test_diagnosis_restore_clears_screenshot_layer_before_restoring_large_window(
+ qapp: QApplication,
+) -> None:
+ theme._install_business_dialog_styling(qapp)
+ window = QMainWindow()
+ window.setProperty("doctorSkipOpenGeometry", True)
+ window.setMinimumSize(440, 300)
+ window.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True)
+ window.setGeometry(30, 30, 440, 300)
+ window.show()
+ qapp.processEvents()
+ compact = window.geometry()
+ normal = QRect(40, 50, 670, 500)
+ preview = ScreenshotPreviewSize()
+ restored_layers: list[QRect] = []
+
+ def restore_screenshot_preview() -> None:
+ preview.restore(window)
+ restored_layers.append(window.geometry())
+
+ window.restore_screenshot_preview = restore_screenshot_preview
+ controller = SimpleNamespace(
+ _video_preview_generation=4,
+ _video_preview_state={
+ "window": window,
+ "geometry": normal,
+ "minimum_size": QSize(500, 360),
+ "maximized": False,
+ "full_screen": False,
+ "stays_on_top": False,
+ },
+ )
+ try:
+ preview.open(window, QRect(0, 0, 600, 450))
+
+ ApplicationController._restore_video_preview(controller, 4, activate=False)
+ qapp.processEvents()
+
+ assert restored_layers == [compact]
+ assert window.geometry() == normal
+ assert window.minimumSize() == QSize(500, 360)
+ assert not window.windowFlags() & Qt.WindowType.WindowStaysOnTopHint
+ assert window.property("doctorSkipOpenGeometry") is False
+ assert controller._video_preview_state is None
+ assert controller._video_preview_generation == 5
+
+ restore_screenshot_preview()
+
+ assert window.geometry() == normal
+ finally:
+ window.close()
+
+
+def _host(**changes: Any) -> SimpleNamespace:
+ return SimpleNamespace(
+ **{
+ "_closing": False,
+ "_released": False,
+ "_shutdown_requested": False,
+ "_media_active": True,
+ "_policy": TrustedDocumentPolicy.from_url(TRUSTED_URL, is_local=False),
+ "_page": SimpleNamespace(url=lambda: QUrl(TRUSTED_URL)),
+ "_screenshot_preview_size": SimpleNamespace(open=Mock()),
+ "restore_screenshot_preview": Mock(),
+ **changes,
+ }
+ )
+
+
+@pytest.mark.parametrize(
+ "changes",
+ [
+ {"_closing": True},
+ {"_released": True},
+ {"_shutdown_requested": True},
+ {"_media_active": False},
+ {"_page": SimpleNamespace(url=lambda: QUrl("about:blank"))},
+ {"_page": SimpleNamespace(url=lambda: QUrl("https://untrusted.example.test/"))},
+ ],
+ ids=["closing", "released", "shutdown", "inactive", "blank-document", "untrusted-document"],
+)
+def test_host_does_not_open_preview_when_inactive_or_untrusted(changes: dict[str, Any]) -> None:
+ host = _host(**changes)
+
+ video_window._EmbeddedVideoWindow._set_screenshot_preview_visible(host, True)
+
+ host._screenshot_preview_size.open.assert_not_called()
+ host.restore_screenshot_preview.assert_not_called()
+
+
+def test_host_uses_normal_window_target_for_trusted_preview(monkeypatch: pytest.MonkeyPatch) -> None:
+ host = _host()
+ target = QRect(30, 40, 1360, 850)
+ target_for_window = Mock(return_value=target)
+ monkeypatch.setattr(theme, "main_window_target_rect", target_for_window)
+
+ video_window._EmbeddedVideoWindow._set_screenshot_preview_visible(host, True)
+
+ target_for_window.assert_called_once_with(host)
+ host._screenshot_preview_size.open.assert_called_once_with(host, target)
+ host.restore_screenshot_preview.assert_not_called()
+
+
+@pytest.mark.parametrize("changes", [{}, {"_shutdown_requested": True}, {"_media_active": False}])
+def test_host_allows_preview_cleanup_after_shutdown_request(changes: dict[str, Any]) -> None:
+ host = _host(**changes)
+
+ video_window._EmbeddedVideoWindow._set_screenshot_preview_visible(host, False)
+
+ host.restore_screenshot_preview.assert_called_once_with()
+ host._screenshot_preview_size.open.assert_not_called()
diff --git a/app/tests/test_text_call_policy.py b/app/tests/test_text_call_policy.py
index 88ccb9671..5bfa572d8 100755
--- a/app/tests/test_text_call_policy.py
+++ b/app/tests/test_text_call_policy.py
@@ -164,6 +164,59 @@ def test_diagnosis_callback_previews_exact_appointment_session(chat_controller):
assert len(case.previews) == 1 # A closed session cannot borrow another appointment's video.
+@pytest.mark.parametrize("permissions, expected", [
+ (None, False),
+ ([], False),
+ (["tcm.diagnosis/read"], False),
+ (["tcm.diagnosis.aiAssistant"], False),
+ (["tcm.diagnosis/aiAssistant"], True),
+ (["tcm.diagnosis/*"], True),
+ (["*"], True),
+])
+def test_im_ai_capability_comes_from_current_shell_permissions(chat_controller, permissions, expected):
+ case = chat_controller
+ case.controller.shell_window.permissions = permissions
+ case.controller._request_video({
+ "patient_id": 8, "diagnosis_id": 123, "appointment_id": 456,
+ "mode": "im", "can_ai_assistant": True,
+ })
+ case.complete(0)
+ assert case.launched[0][1]["can_ai_assistant"] is expected
+
+
+def test_im_ai_permission_is_evaluated_after_ticket_load(chat_controller):
+ case = chat_controller
+ case.controller.shell_window.permissions = ["tcm.diagnosis/aiAssistant"]
+ case.request(456)
+ case.controller.shell_window.permissions = []
+ case.complete(0)
+ assert case.launched[0][1]["can_ai_assistant"] is False
+
+
+@pytest.mark.parametrize("capability, expected", [(True, True), (False, False), (None, False), (1, False), ("true", False)])
+def test_video_launcher_forwards_only_explicit_ai_capability(monkeypatch, capability, expected):
+ from doctor_workstation.video import window as window_module
+ from doctor_workstation.video.launcher import launch_video_call
+
+ launches = []
+ sentinel = object()
+
+ def capture(request, **kwargs):
+ launches.append((request, kwargs))
+ return sentinel
+
+ monkeypatch.setattr(window_module, "open_video_call", capture)
+ result = launch_video_call(
+ ticket(), repository=object(), open_im=True, can_ai_assistant=capability,
+ )
+ assert result is sentinel
+ request, options = launches[0]
+ assert request.diagnosis_id == 123
+ assert request.patient_id == 8
+ assert request.appointment_id == 456
+ assert options["can_ai_assistant"] is expected
+
+
@pytest.mark.parametrize("second_diagnosis", [123, 124])
@pytest.mark.parametrize("completion_order", [(0, 1), (1, 0)])
def test_latest_im_selection_retires_pending_callbacks(chat_controller, second_diagnosis, completion_order):
diff --git a/app/tests/test_transcript_text.py b/app/tests/test_transcript_text.py
new file mode 100644
index 000000000..d56fbfa8a
--- /dev/null
+++ b/app/tests/test_transcript_text.py
@@ -0,0 +1,58 @@
+from __future__ import annotations
+
+import os
+import socket
+from concurrent.futures import ThreadPoolExecutor
+
+os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
+
+import pytest
+from PySide6.QtWidgets import QApplication, QDialog, QPlainTextEdit, QWidget
+
+from doctor_workstation.core.transcript_text import simplified_transcript
+from doctor_workstation.ui.dialogs.diagnosis import DiagnosisDialog
+
+
+@pytest.mark.parametrize(
+ ("source", "expected"),
+ [
+ ("你會說老家話嗎?很會,很會。", "你会说老家话吗?很会,很会。"),
+ ("沒有過敏,沒有吃藥。0.5 mg,不是 5 mg。", "没有过敏,没有吃药。0.5 mg,不是 5 mg。"),
+ ("血壓 120/80 mmHg,血糖 2.00–30.00 mmol/L,HbA1c 6.5%。",
+ "血压 120/80 mmHg,血糖 2.00–30.00 mmol/L,HbA1c 6.5%。"),
+ ("唔係,冇食藥,咩事?", "唔系,冇食药,咩事?"),
+ ("患者:口乾。\n醫生:不?\n患者:不。", "患者:口干。\n医生:不?\n患者:不。"),
+ ("简体,不! \n0.5 mg\tB12", "简体,不! \n0.5 mg\tB12"),
+ ("", ""),
+ ],
+)
+def test_script_conversion_is_offline_and_preserves_clinical_tokens(monkeypatch, source, expected):
+ def no_network(*args, **kwargs):
+ pytest.fail("Script conversion must use bundled dictionaries only")
+
+ monkeypatch.setattr(socket.socket, "connect", no_network)
+ # A fresh thread loads its own dictionaries, even when a prior test ran.
+ with ThreadPoolExecutor(max_workers=1) as pool:
+ assert pool.submit(simplified_transcript, source).result() == expected
+ assert simplified_transcript(expected) == expected
+
+
+def test_historical_transcript_dialog_displays_simplified_without_changing_record(monkeypatch):
+ application = QApplication.instance() or QApplication([])
+ parent = QWidget()
+ record = {"transcript_text": "患者:你會說老家話嗎?\n患者:沒有吃藥,0.5 mg。"}
+ source = DiagnosisDialog._call_transcript_text(record)
+ displayed = []
+
+ def inspect(dialog):
+ displayed.append(dialog.findChild(QPlainTextEdit, "DiagnosisCallTranscriptText").toPlainText())
+ return 0
+
+ monkeypatch.setattr(QDialog, "exec", inspect)
+ try:
+ DiagnosisDialog._view_call_transcript(parent, 12, source)
+ assert displayed == ["患者:你会说老家话吗?\n患者:没有吃药,0.5 mg。"]
+ assert record["transcript_text"] == source
+ finally:
+ parent.close()
+ application.processEvents()
diff --git a/app/tests/test_transcription_start_retry.py b/app/tests/test_transcription_start_retry.py
new file mode 100644
index 000000000..9b4fb77fd
--- /dev/null
+++ b/app/tests/test_transcription_start_retry.py
@@ -0,0 +1,234 @@
+"""Retry a failed storage start without duplicate requests or reopening a call."""
+
+from __future__ import annotations
+
+import logging
+import threading
+from concurrent.futures import Future, ThreadPoolExecutor
+
+import pytest
+
+from doctor_workstation.video.launcher import VideoCallRequest
+from doctor_workstation.video.lifecycle import OrderedCallLifecycle
+
+
+class Repository:
+ def __init__(self, *, fail_first: bool = False, block_attempt: int = 0) -> None:
+ self.fail_first = fail_first
+ self.block_attempt = block_attempt
+ self.attempts: list[dict] = []
+ self.entered = threading.Event()
+ self.release = threading.Event()
+
+ def start_call(self, **_payload):
+ return {"call_record_id": 71}
+
+ def start_call_transcription(self, **payload):
+ self.attempts.append(payload)
+ attempt = len(self.attempts)
+ if attempt == self.block_attempt:
+ self.entered.set()
+ assert self.release.wait(3), "test did not release storage request"
+ if self.fail_first and attempt == 1:
+ raise RuntimeError("temporary storage failure")
+
+ def finish_call_transcription(self, **_payload):
+ return True
+
+ def end_call(self, **_payload):
+ return True
+
+
+@pytest.fixture
+def make_lifecycle():
+ lifecycles = []
+
+ def make(**options):
+ repository = Repository(**options)
+ request = VideoCallRequest(
+ sdk_app_id=1400123456,
+ user_id="doctor-test",
+ user_sig="test-ticket",
+ target_user_id="patient-test",
+ diagnosis_id=12,
+ )
+ lifecycle = OrderedCallLifecycle(request, repository, logging.getLogger(__name__))
+ lifecycles.append((lifecycle, repository))
+ assert lifecycle.start().result(timeout=2) is True
+ return lifecycle, repository
+
+ yield make
+ for lifecycle, repository in lifecycles:
+ repository.release.set()
+ lifecycle.end("test-cleanup").result(timeout=3)
+ assert lifecycle.wait(3)
+
+
+def test_failed_storage_start_retries_same_session_then_reuses_success(make_lifecycle):
+ lifecycle, repository = make_lifecycle(fail_first=True)
+ failed = lifecycle.start_transcription("tr-retry", language="zh")
+ with pytest.raises(RuntimeError, match="temporary storage failure"):
+ failed.result(timeout=2)
+
+ retry = lifecycle.start_transcription("tr-retry", language="zh")
+ assert retry is not failed
+ assert retry.result(timeout=2) is True
+ assert lifecycle.start_transcription("tr-retry") is retry
+ assert lifecycle.transcription_session_id == "tr-retry"
+ assert len(repository.attempts) == 2
+ assert (
+ repository.attempts[0]
+ == repository.attempts[1]
+ == {
+ "diagnosis_id": 12,
+ "call_record_id": 71,
+ "transcription_session_id": "tr-retry",
+ "language": "zh",
+ }
+ )
+
+
+def test_inflight_start_is_reused_without_blocking_caller(make_lifecycle):
+ lifecycle, repository = make_lifecycle(block_attempt=1)
+ first = lifecycle.start_transcription("tr-running")
+ try:
+ assert repository.entered.wait(2)
+ assert not first.done()
+ assert lifecycle.start_transcription("tr-running") is first
+ assert len(repository.attempts) == 1
+ finally:
+ repository.release.set()
+ assert first.result(timeout=2) is True
+
+
+def test_concurrent_retry_callers_share_one_new_request(make_lifecycle):
+ lifecycle, repository = make_lifecycle(fail_first=True, block_attempt=2)
+ with pytest.raises(RuntimeError, match="temporary storage failure"):
+ lifecycle.start_transcription("tr-concurrent").result(timeout=2)
+ try:
+ with ThreadPoolExecutor(max_workers=4) as callers:
+ futures = list(
+ callers.map(lambda _: lifecycle.start_transcription("tr-concurrent"), range(4))
+ )
+ assert repository.entered.wait(2)
+ assert all(future is futures[0] for future in futures)
+ assert not futures[0].done()
+ assert len(repository.attempts) == 2
+ finally:
+ repository.release.set()
+ assert futures[0].result(timeout=2) is True
+
+
+def test_false_completion_can_retry_without_changing_identity(make_lifecycle):
+ lifecycle, repository = make_lifecycle()
+ # Seed the documented False completion (e.g. call-start dependency had not
+ # succeeded), then exercise retry against a now-available actual lifecycle.
+ previous: Future[bool] = Future()
+ previous.set_result(False)
+ lifecycle._transcription_session_id = "tr-false"
+ lifecycle._transcription_start_future = previous
+
+ retry = lifecycle.start_transcription("tr-false")
+ assert retry is not previous
+ assert retry.result(timeout=2) is True
+ assert lifecycle.start_transcription("tr-false") is retry
+ assert len(repository.attempts) == 1
+ assert repository.attempts[0]["transcription_session_id"] == "tr-false"
+
+
+def test_cancelled_queued_start_can_retry_same_session(make_lifecycle):
+ lifecycle, repository = make_lifecycle()
+ entered, release = threading.Event(), threading.Event()
+
+ def occupy_worker():
+ entered.set()
+ assert release.wait(3)
+
+ lifecycle._worker.submit("test-block", occupy_worker)
+ try:
+ assert entered.wait(2)
+ cancelled = lifecycle.start_transcription("tr-cancelled")
+ assert cancelled.cancel()
+ retry = lifecycle.start_transcription("tr-cancelled")
+ assert retry is not cancelled
+ finally:
+ release.set()
+ assert retry.result(timeout=2) is True
+ assert len(repository.attempts) == 1
+
+
+@pytest.mark.parametrize("state", ["running", "succeeded", "failed", "false"])
+def test_session_identity_cannot_change_even_after_failure(make_lifecycle, state):
+ lifecycle, repository = make_lifecycle(
+ fail_first=state == "failed", block_attempt=1 if state == "running" else 0
+ )
+ if state == "false":
+ first: Future[bool] = Future()
+ first.set_result(False)
+ lifecycle._transcription_session_id = "tr-original"
+ lifecycle._transcription_start_future = first
+ else:
+ first = lifecycle.start_transcription("tr-original")
+ if state == "running":
+ assert repository.entered.wait(2)
+ elif state == "failed":
+ with pytest.raises(RuntimeError, match="temporary storage failure"):
+ first.result(timeout=2)
+ else:
+ assert first.result(timeout=2)
+ try:
+ with pytest.raises(RuntimeError, match="another transcription session"):
+ lifecycle.start_transcription("tr-different")
+ assert lifecycle.transcription_session_id == "tr-original"
+ finally:
+ repository.release.set()
+
+
+@pytest.mark.parametrize("terminal", ["finish", "end"])
+@pytest.mark.parametrize("failed", [False, True])
+def test_finish_or_end_blocks_restart_before_and_after_completion(make_lifecycle, terminal, failed):
+ lifecycle, repository = make_lifecycle(fail_first=failed)
+ first = lifecycle.start_transcription("tr-terminal")
+ if failed:
+ with pytest.raises(RuntimeError, match="temporary storage failure"):
+ first.result(timeout=2)
+ else:
+ assert first.result(timeout=2)
+
+ ending = (
+ lifecycle.finish_transcription(status="partial")
+ if terminal == "finish"
+ else lifecycle.end("test-terminal")
+ )
+ error = "already stopped" if terminal == "finish" else "already ended"
+ with pytest.raises(RuntimeError, match=error):
+ lifecycle.start_transcription("tr-terminal")
+ ending.result(timeout=2)
+ with pytest.raises(RuntimeError, match=error):
+ lifecycle.start_transcription("tr-terminal")
+ assert len(repository.attempts) == 1
+
+
+@pytest.mark.parametrize("terminal", ["finish", "end"])
+def test_terminal_request_blocks_start_even_while_original_start_is_running(
+ make_lifecycle, terminal
+):
+ lifecycle, repository = make_lifecycle(block_attempt=1)
+ first = lifecycle.start_transcription("tr-draining")
+ try:
+ assert repository.entered.wait(2)
+ ending = (
+ lifecycle.finish_transcription()
+ if terminal == "finish"
+ else lifecycle.end("test-draining")
+ )
+ assert not first.done()
+ assert not ending.done()
+ error = "already stopped" if terminal == "finish" else "already ended"
+ with pytest.raises(RuntimeError, match=error):
+ lifecycle.start_transcription("tr-draining")
+ finally:
+ repository.release.set()
+ assert first.result(timeout=2) is True
+ assert ending.result(timeout=2) is True
+ assert len(repository.attempts) == 1
diff --git a/app/tests/test_ui_contract.py b/app/tests/test_ui_contract.py
index 7bc78229b..648072cb1 100755
--- a/app/tests/test_ui_contract.py
+++ b/app/tests/test_ui_contract.py
@@ -295,6 +295,48 @@ def test_real_demo_login_reaches_success_without_widget_adapter(
application.processEvents()
+def test_login_password_group_keeps_focus_when_reveal_is_keyboard_focused(tmp_path: Any) -> None:
+ application = QApplication.instance() or QApplication([])
+ apply_theme(application)
+ window = LoginWindow(
+ object(), settings=QSettings(str(tmp_path / "focus.ini"), QSettings.Format.IniFormat),
+ )
+ window.show()
+ application.processEvents()
+ group = window.password_edit.parentWidget()
+ geometry = group.geometry()
+ try:
+ for control in (window.password_edit, window.reveal_button):
+ control.setFocus()
+ application.processEvents()
+ assert group.property("focused") is True
+ assert group.geometry() == geometry
+ window.login_button.setFocus()
+ application.processEvents()
+ assert group.property("focused") is False
+ assert group.geometry() == geometry
+ finally:
+ window.close()
+
+
+def test_compact_login_keeps_the_whole_form_visible(tmp_path: Any) -> None:
+ application = QApplication.instance() or QApplication([])
+ apply_theme(application)
+ window = LoginWindow(
+ object(), settings=QSettings(str(tmp_path / "compact.ini"), QSettings.Format.IniFormat),
+ )
+ window.resize(860, 640)
+ window.show()
+ application.processEvents()
+ try:
+ assert not window.brand_panel.isVisible()
+ assert window.login_scroll.verticalScrollBar().maximum() == 0
+ assert window.card.height() >= window.card.minimumSizeHint().height()
+ assert window.login_button.isVisibleTo(window)
+ finally:
+ window.close()
+
+
def test_remembered_password_survives_a_new_login_window(tmp_path: Any) -> None:
application = QApplication.instance() or QApplication([])
settings_path = tmp_path / "remember-password.ini"
diff --git a/app/tests/test_ui_detail_refinements.py b/app/tests/test_ui_detail_refinements.py
index acac857b1..c19fb5681 100755
--- a/app/tests/test_ui_detail_refinements.py
+++ b/app/tests/test_ui_detail_refinements.py
@@ -38,6 +38,8 @@ def page(application, monkeypatch):
def test_reception_prompts_remain_readable_in_a_narrow_workspace(page, application):
+ # The responsive workspace exposes insights in its second tab.
+ page.workbench.mode_tabs.setCurrentIndex(1)
settle(application)
for button in page.ai_prompt_buttons:
assert button.width() >= button.minimumSizeHint().width()
@@ -48,6 +50,8 @@ def test_reception_prompts_remain_readable_in_a_narrow_workspace(page, applicati
def test_hidden_tall_consultation_does_not_expand_daily_records(page, application):
+ # Force real overflow: a short case is allowed to fill the viewport.
+ page.case_labels["present"].setText("Long clinical history\n" * 80)
page.detail_tabs.setCurrentIndex(0)
settle(application)
consultation_height = page.clinical_pages.height()
diff --git a/app/tests/test_video_contract.py b/app/tests/test_video_contract.py
index 1aeeeffda..2f591bf58 100755
--- a/app/tests/test_video_contract.py
+++ b/app/tests/test_video_contract.py
@@ -62,7 +62,7 @@ def test_companion_archives_cloud_video_local_mixed_audio_and_transcript() -> No
assert "operations.push(stopLocalRecording())" in source
assert "operations.push(stopTranscription('completed'))" in source
assert "Promise.allSettled(operations)" in source
- assert "腾讯云混流视频、本机语音录音和实时转写均已启动" in source
+ assert "本机录音已启动" in source
def test_companion_watches_room_id_for_the_entire_call_cycle() -> None:
@@ -83,7 +83,7 @@ def test_companion_watches_room_id_for_the_entire_call_cycle() -> None:
assert "diagnosisId: activeConfig.diagnosisId" in room_source
-def test_room_binding_is_acknowledged_and_transcriber_room_is_a_fallback() -> None:
+def test_room_binding_is_acknowledged_independently_of_cloud_transcription() -> None:
companion_source = (
PROJECT_ROOT / "video_companion" / "src" / "main.ts"
).read_text(encoding="utf-8")
@@ -91,8 +91,11 @@ def test_room_binding_is_acknowledged_and_transcriber_room_is_a_fallback() -> No
PROJECT_ROOT / "src" / "doctor_workstation" / "video" / "window.py"
).read_text(encoding="utf-8")
- assert "observeRoomId(roomId)" in companion_source
- assert "onRealtimeTranscriberStarted: (roomId)" in companion_source
+ assert "observeRoomId(readRoomId())" in companion_source
+ assert "getAITranscriberManager" in companion_source
+ assert "startRealtimeTranscriber" in companion_source
+ assert "sourceLanguage: 'zh'" in companion_source
+ assert "LocalPcmCapture" not in companion_source
assert "function roomBindingResult(" in companion_source
assert "if (boundRoomId) return" in companion_source
assert "roomBindingResult?.(" in window_source
@@ -186,7 +189,7 @@ def test_local_audio_capture_keeps_and_persists_its_own_call_room_identity() ->
assert "store.bind_identity(" in source
-def test_companion_shows_incremental_subtitles_but_only_persists_final_segments() -> None:
+def test_companion_displays_only_native_normalized_cloud_transcript_acks() -> None:
main_source = (
PROJECT_ROOT / "video_companion" / "src" / "main.ts"
).read_text(encoding="utf-8")
@@ -196,13 +199,18 @@ def test_companion_shows_incremental_subtitles_but_only_persists_final_segments(
handler = main_source.split("function handleTranscriberMessage", 1)[1].split(
"function subscribeTranscriber", 1
)[0]
+ acknowledgement = main_source.split("function transcriptionResult", 1)[1].split(
+ "function videoAiAction", 1
+ )[0]
- assert "showLiveCaption(message)" in handler
- assert "if (message.isCompleted !== true) return" in handler
- assert handler.index("showLiveCaption(message)") < handler.index(
- "if (message.isCompleted !== true) return"
- )
- assert 'aria-label="实时语音字幕"' in component_source
+ assert "transcription-segment" in handler
+ assert "showLiveCaption(" not in handler
+ assert "message.isCompleted !== true" in handler
+ assert "sessionId === transcriptionSessionId" in acknowledgement
+ assert "normalizedSegment?.segmentId === segmentId" in acknowledgement
+ assert "normalizedSegment.isCompleted === true" in acknowledgement
+ assert "showLiveCaption(normalizedSegment)" in acknowledgement
+ assert 'aria-label="腾讯云实时转写的对话原文"' in component_source
assert "liveCaptions.value" in component_source
assert "caption.speaker" in component_source
assert "caption.text" in component_source
@@ -219,7 +227,7 @@ def test_companion_keeps_transcript_and_patient_case_visible_in_a_side_rail() ->
assert "liveCaptions.value = [...previous, caption].slice(-120)" in main_source
assert "liveCaptionClearTimer" not in main_source
- assert 'aria-label="患者病例与实时对话"' in component_source
+ assert 'aria-label="AI辅助、对话原文与患者资料"' in component_source
assert 'id="patient-case-title"' in component_source
assert 'id="live-transcript-title"' in component_source
assert 'aria-label="打开完整诊单"' in component_source
@@ -269,7 +277,7 @@ def test_video_diagnosis_entry_uses_existing_permission_scoped_drawer() -> None:
assert "not modeless and not self._standalone_readonly" in diagnosis_source
compact_styles = styles.split("@media (max-width: 700px)", 1)[1]
assert ".consultation-rail { display: none; }" in compact_styles
- assert ".capture-button { display: none; }" in compact_styles
+ assert ".capture-button { display: none; }" not in compact_styles
assert "on_open_diagnosis=on_open_diagnosis" in launcher_source
assert "event: 'open-diagnosis-request'" in main_source
@@ -559,7 +567,7 @@ def test_built_video_companion_contains_the_patient_case_rail() -> None:
assert ".consultation-rail" in styles
assert ".video-layer--with-rail" in styles
assert "patientCase" in scripts
- assert "患者病例与实时对话" in scripts
+ assert "AI辅助、对话原文与患者资料" in scripts
def test_companion_screenshot_requires_doctor_confirmation_before_upload() -> None:
@@ -573,7 +581,8 @@ def test_companion_screenshot_requires_doctor_confirmation_before_upload() -> No
"watch(", 1
)[0]
- assert "screenshotPreview.value = canvas.toDataURL" in capture
+ assert "await captureVideoStage(videoStage.value)" in capture
+ assert "generation === screenshotGeneration" in capture
assert "onSaveScreenshot" not in capture
assert "await props.onSaveScreenshot(screenshotPreview.value)" in confirm
assert "确认画面后再保存到患者资料" in source
diff --git a/app/tests/test_video_screenshot.py b/app/tests/test_video_screenshot.py
new file mode 100644
index 000000000..6d0e0870a
--- /dev/null
+++ b/app/tests/test_video_screenshot.py
@@ -0,0 +1,379 @@
+from __future__ import annotations
+
+import base64
+import json
+from collections.abc import Mapping
+from types import SimpleNamespace
+from typing import Any
+from unittest.mock import Mock
+
+import pytest
+from PySide6.QtCore import QRect, QUrl
+from PySide6.QtGui import QColor, QImage, QPainter
+
+from doctor_workstation.video import window
+from doctor_workstation.video.screenshot import capture_view_region
+from doctor_workstation.video.security import TrustedDocumentPolicy
+
+TRUSTED_URL = "https://video.example.test/companion/index.html?mode=call"
+REGION_KEYS = ("x", "y", "width", "height", "viewportWidth", "viewportHeight")
+
+
+def _region(**changes: Any) -> dict[str, Any]:
+ return {
+ "x": 120,
+ "y": 80,
+ "width": 480,
+ "height": 320,
+ "viewportWidth": 1000,
+ "viewportHeight": 800,
+ **changes,
+ }
+
+
+class _View:
+ """Keep grab coordinates logical, as QWidget does, and its image physical."""
+
+ def __init__(
+ self,
+ width: int = 1000,
+ height: int = 800,
+ *,
+ zoom: float = 1,
+ dpr: float = 1,
+ source: QImage | None = None,
+ ) -> None:
+ self._width = width
+ self._height = height
+ self._zoom = zoom
+ self.dpr = dpr
+ self.source = source
+ self.grabbed: list[QRect] = []
+
+ def width(self) -> int:
+ return self._width
+
+ def height(self) -> int:
+ return self._height
+
+ def zoomFactor(self) -> float: # noqa: N802 - Qt API
+ return self._zoom
+
+ def rect(self) -> QRect:
+ return QRect(0, 0, self._width, self._height)
+
+ def grab(self, rect: QRect) -> SimpleNamespace:
+ self.grabbed.append(QRect(rect))
+ physical_rect = QRect(
+ round(rect.x() * self.dpr),
+ round(rect.y() * self.dpr),
+ round(rect.width() * self.dpr),
+ round(rect.height() * self.dpr),
+ )
+ if self.source is not None:
+ image = self.source.copy(physical_rect)
+ else:
+ image = QImage(physical_rect.size(), QImage.Format.Format_RGB32)
+ image.fill(QColor("#143b67"))
+ image.setDevicePixelRatio(self.dpr)
+ return SimpleNamespace(toImage=lambda: image)
+
+
+def _decode_jpeg(data_url: str) -> QImage:
+ prefix = "data:image/jpeg;base64,"
+ assert data_url.startswith(prefix)
+ data = base64.b64decode(data_url[len(prefix) :], validate=True)
+ assert data.startswith(b"\xff\xd8")
+ image = QImage.fromData(data, "JPEG")
+ assert not image.isNull()
+ return image
+
+
+@pytest.mark.parametrize("zoom", [0.8, 1, 1.25, 1.5, 2])
+def test_css_coordinates_follow_webengine_zoom(zoom: float) -> None:
+ view = _View(round(1000 * zoom), round(800 * zoom), zoom=zoom)
+
+ image = _decode_jpeg(capture_view_region(view, _region()))
+
+ expected = QRect(round(120 * zoom), round(80 * zoom), round(480 * zoom), round(320 * zoom))
+ assert view.grabbed == [expected]
+ assert image.size() == expected.size()
+
+
+def test_fractional_edges_round_inward_and_exclude_adjacent_patient_panel() -> None:
+ source = QImage(1250, 1000, QImage.Format.Format_RGB32)
+ source.fill(QColor("red"))
+ painter = QPainter(source)
+ # Only complete logical pixels inside the fractional video rectangle are safe.
+ expected = QRect(17, 26, 374, 249)
+ painter.fillRect(expected, QColor("#143b67"))
+ painter.end()
+ view = _View(1250, 1000, zoom=1.25, source=source)
+
+ image = _decode_jpeg(
+ capture_view_region(view, _region(x=13.1, y=20.2, width=300.4, height=200.4))
+ )
+
+ assert view.grabbed == [expected]
+ for x, y in ((0, 0), (373, 0), (0, 248), (373, 248), (187, 124)):
+ color = image.pixelColor(x, y)
+ assert color.blue() > color.red() + 50
+
+
+@pytest.mark.parametrize(
+ ("changes", "expected"),
+ [
+ ({"x": -20, "y": -10, "width": 150, "height": 110}, QRect(0, 0, 130, 100)),
+ ({"x": 950, "y": 760, "width": 100, "height": 80}, QRect(950, 760, 50, 40)),
+ ({"x": -50, "y": -50, "width": 1200, "height": 1000}, QRect(0, 0, 1000, 800)),
+ ],
+)
+def test_capture_is_clipped_to_the_visible_viewport(
+ changes: dict[str, int], expected: QRect
+) -> None:
+ view = _View()
+
+ image = _decode_jpeg(capture_view_region(view, _region(**changes)))
+
+ assert view.grabbed == [expected]
+ assert image.size() == expected.size()
+
+
+@pytest.mark.parametrize("key", REGION_KEYS)
+@pytest.mark.parametrize(
+ "value",
+ [float("nan"), float("inf"), float("-inf"), True, False, None, "12"],
+ ids=["nan", "infinity", "negative-infinity", "true", "false", "null", "string"],
+)
+def test_invalid_coordinate_values_are_rejected_before_grab(key: str, value: Any) -> None:
+ view = _View()
+
+ with pytest.raises(ValueError):
+ capture_view_region(view, _region(**{key: value}))
+
+ assert view.grabbed == []
+
+
+@pytest.mark.parametrize("key", REGION_KEYS)
+def test_missing_coordinates_are_rejected_before_grab(key: str) -> None:
+ view = _View()
+ region = _region()
+ del region[key]
+
+ with pytest.raises(ValueError):
+ capture_view_region(view, region)
+
+ assert view.grabbed == []
+
+
+@pytest.mark.parametrize("key", ["width", "height", "viewportWidth", "viewportHeight"])
+@pytest.mark.parametrize("value", [0, -1])
+def test_empty_or_negative_sizes_are_rejected_before_grab(key: str, value: int) -> None:
+ view = _View()
+
+ with pytest.raises(ValueError):
+ capture_view_region(view, _region(**{key: value}))
+
+ assert view.grabbed == []
+
+
+@pytest.mark.parametrize(
+ "changes",
+ [
+ {"x": 1000},
+ {"y": 800},
+ {"x": -480},
+ {"y": -320},
+ {"x": 12.2, "width": 0.2},
+ {"y": 12.2, "height": 0.2},
+ ],
+)
+def test_offscreen_or_subpixel_empty_regions_are_rejected(changes: dict[str, Any]) -> None:
+ view = _View()
+
+ with pytest.raises(ValueError):
+ capture_view_region(view, _region(**changes))
+
+ assert view.grabbed == []
+
+
+@pytest.mark.parametrize("width,height,zoom", [(1200, 800, 1), (1000, 900, 1), (1000, 800, 1.25)])
+def test_resize_or_zoom_race_rejects_stale_viewport(width: int, height: int, zoom: float) -> None:
+ view = _View(width, height, zoom=zoom)
+
+ with pytest.raises(ValueError, match="尺寸已变化"):
+ capture_view_region(view, _region())
+
+ assert view.grabbed == []
+
+
+@pytest.mark.parametrize("dpr", [1, 1.25, 2])
+def test_dpr_changes_encoded_pixels_without_scaling_grab_coordinates(dpr: float) -> None:
+ view = _View(1250, 1000, zoom=1.25, dpr=dpr)
+
+ image = _decode_jpeg(capture_view_region(view, _region()))
+
+ assert view.grabbed == [QRect(150, 100, 600, 400)]
+ assert (image.width(), image.height()) == (round(600 * dpr), round(400 * dpr))
+
+
+@pytest.mark.parametrize(
+ "width,height,dpr,expected",
+ [
+ (3000, 1500, 1, (1920, 960)),
+ (1500, 3000, 1, (960, 1920)),
+ (1600, 900, 2, (1920, 1080)),
+ (320, 240, 1, (320, 240)),
+ ],
+)
+def test_jpeg_longest_edge_is_limited_to_1920_without_upscaling(
+ width: int, height: int, dpr: float, expected: tuple[int, int]
+) -> None:
+ view = _View(width, height, dpr=dpr)
+ region = _region(
+ x=0, y=0, width=width, height=height, viewportWidth=width, viewportHeight=height
+ )
+
+ image = _decode_jpeg(capture_view_region(view, region))
+
+ assert (image.width(), image.height()) == expected
+ assert view.grabbed == [QRect(0, 0, width, height)]
+
+
+def test_null_grab_and_jpeg_encoding_failure_are_reported() -> None:
+ view = _View()
+ view.grab = Mock(return_value=SimpleNamespace(toImage=lambda: QImage()))
+ with pytest.raises(ValueError, match="截屏失败"):
+ capture_view_region(view, _region())
+
+ image = SimpleNamespace(
+ isNull=lambda: False, width=lambda: 480, height=lambda: 320, save=lambda *_: False
+ )
+ view.grab = Mock(return_value=SimpleNamespace(toImage=lambda: image))
+ with pytest.raises(ValueError, match="图片生成失败"):
+ capture_view_region(view, _region())
+
+
+def _host(view: _View, **changes: Any) -> SimpleNamespace:
+ return SimpleNamespace(
+ **{
+ "_closing": False,
+ "_released": False,
+ "_shutdown_requested": False,
+ "_media_active": True,
+ "_policy": TrustedDocumentPolicy.from_url(TRUSTED_URL, is_local=False),
+ "_page": SimpleNamespace(url=lambda: QUrl(TRUSTED_URL)),
+ "web_view": view,
+ "lifecycle": SimpleNamespace(save_screenshot=Mock()),
+ **changes,
+ }
+ )
+
+
+def test_bridge_returns_preview_without_saving_until_explicit_save() -> None:
+ view = _View()
+ host = _host(view)
+ events: list[Mapping[str, Any]] = []
+ bridge = window._QtVideoBridge(
+ events.append,
+ lambda region: window._EmbeddedVideoWindow._capture_screenshot_preview(host, region),
+ )
+
+ result = json.loads(bridge.captureScreenshot(json.dumps(_region())))
+
+ assert set(result) == {"dataUrl"}
+ assert _decode_jpeg(result["dataUrl"]).size() == QRect(0, 0, 480, 320).size()
+ assert events == []
+ host.lifecycle.save_screenshot.assert_not_called()
+ bridge.saveScreenshot(result["dataUrl"])
+ assert events == [
+ {"source": "doctor-call", "event": "screenshot", "dataUrl": result["dataUrl"]}
+ ]
+
+
+@pytest.mark.parametrize("payload", [None, 12, "", "{", "null", "[]", '"region"', " " * 2049])
+def test_bridge_rejects_invalid_payloads_without_calling_capture(payload: Any) -> None:
+ capture = Mock()
+ notify = Mock()
+ bridge = window._QtVideoBridge(notify, capture)
+
+ result = json.loads(bridge.captureScreenshot(payload))
+
+ assert set(result) == {"error"}
+ assert result["error"]
+ capture.assert_not_called()
+ notify.assert_not_called()
+
+
+@pytest.mark.parametrize(
+ "value",
+ [float("nan"), float("inf"), True, 0, -1, 10**400],
+ ids=["nan", "infinity", "boolean", "empty", "negative", "oversized-integer"],
+)
+def test_bridge_returns_error_for_invalid_region_values(value: Any) -> None:
+ view = _View()
+ notify = Mock()
+ bridge = window._QtVideoBridge(notify, lambda region: capture_view_region(view, region))
+
+ result = json.loads(bridge.captureScreenshot(json.dumps(_region(width=value))))
+
+ assert set(result) == {"error"}
+ assert result["error"]
+ assert view.grabbed == []
+ notify.assert_not_called()
+
+
+@pytest.mark.parametrize("error_type", [ValueError, TypeError, RuntimeError])
+def test_bridge_reports_capture_failure_without_exposing_error_details(
+ error_type: type[Exception],
+) -> None:
+ notify = Mock()
+ bridge = window._QtVideoBridge(
+ notify, Mock(side_effect=error_type("private path or patient information"))
+ )
+
+ result = json.loads(bridge.captureScreenshot(json.dumps(_region())))
+
+ assert set(result) == {"error"}
+ assert "private" not in result["error"]
+ notify.assert_not_called()
+
+
+@pytest.mark.parametrize(
+ "changes",
+ [
+ {"_closing": True},
+ {"_released": True},
+ {"_shutdown_requested": True},
+ {"_media_active": False},
+ ],
+)
+def test_host_rejects_capture_when_call_is_inactive_or_closing(changes: dict[str, bool]) -> None:
+ view = _View()
+ host = _host(view, **changes)
+
+ with pytest.raises(ValueError, match="已关闭"):
+ window._EmbeddedVideoWindow._capture_screenshot_preview(host, _region())
+
+ assert view.grabbed == []
+ host.lifecycle.save_screenshot.assert_not_called()
+
+
+@pytest.mark.parametrize(
+ "url",
+ [
+ "about:blank",
+ "https://untrusted.example.test/companion/index.html?mode=call",
+ "https://video.example.test/other",
+ "https://video.example.test/companion/index.html?mode=other",
+ ],
+)
+def test_host_rejects_capture_after_navigation_away_from_trusted_document(url: str) -> None:
+ view = _View()
+ host = _host(view, _page=SimpleNamespace(url=lambda: QUrl(url)))
+
+ with pytest.raises(ValueError, match="页面不可用"):
+ window._EmbeddedVideoWindow._capture_screenshot_preview(host, _region())
+
+ assert view.grabbed == []
+ host.lifecycle.save_screenshot.assert_not_called()
diff --git a/app/uv.lock b/app/uv.lock
index c01961c3a..342abd964 100755
--- a/app/uv.lock
+++ b/app/uv.lock
@@ -1,6 +1,10 @@
version = 1
revision = 3
requires-python = ">=3.11"
+resolution-markers = [
+ "python_full_version >= '3.12'",
+ "python_full_version < '3.12'",
+]
[[package]]
name = "altgraph"
@@ -24,6 +28,64 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
]
+[[package]]
+name = "av"
+version = "18.1.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.12'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8d/f4/f22114d30d3435e38c6af2b4870f37b864403dca6ae7af747a289ce0a18e/av-18.1.0.tar.gz", hash = "sha256:47bfc286e1bc9de7ab4681fc2b575cd2460a66919d31ffe1bd5aa54fae531a28", size = 4451061, upload-time = "2026-08-12T22:28:18.761Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/d4/d7cdc8bff143c17a6d35924375ae28dd692cacde38700a7d419fde54f44a/av-18.1.0-cp311-abi3-macosx_11_0_x86_64.whl", hash = "sha256:ae75d8bb6467895ed1f8572ededf7ffa49eac07f6e483222f5d7d62a41d12f04", size = 22546147, upload-time = "2026-08-12T22:27:11.851Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/c9/37a619297492256b77d5ed906e7d8166c10a26ed251dccf1ae03ab19bff6/av-18.1.0-cp311-abi3-macosx_14_0_arm64.whl", hash = "sha256:b30a4e8d934558e19602b68998a4d9ac9f250fa0dacef216f7e8e40153b13316", size = 18217603, upload-time = "2026-08-12T22:27:14.713Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/84/2464ffb64c08c5ce8b522c8e74594714414e3b0575267652c5c51c0574b9/av-18.1.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6fc837cc51adf80331ac850779cd53b5d4c4460b0ebe9057a02a921c6736f19d", size = 33640142, upload-time = "2026-08-12T22:27:17.835Z" },
+ { url = "https://files.pythonhosted.org/packages/27/3a/204dbfc3e08eb4cdc6e6ff57be02150bc44523ebdb50182d10025792ebd9/av-18.1.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:8a032e8d8ebc73dec079364b9b4a6837638a2d106e8472314e685ffbf163e700", size = 35786210, upload-time = "2026-08-12T22:27:20.984Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/99/b0d04ec553ff9a7e00455458dfa3a39c8a8f627b273056b4e5fe57d590de/av-18.1.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:3c8b1f8b46f99d52e2d8b0ed5d0cdadf172d24794d46e2077b16e44ed08e26ff", size = 39379798, upload-time = "2026-08-12T22:27:24.432Z" },
+ { url = "https://files.pythonhosted.org/packages/56/b1/e00d4feae59160149df6126585e726fdc6300798fd40c5dd324879e81f68/av-18.1.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ab5ac081bc9eaf54109120d4e56284674fecfbe520d9aa1707c7fa911ec5f4d2", size = 34690321, upload-time = "2026-08-12T22:27:27.769Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/94/836fa987e3084d11a21489f11357fb24843ef3aa8faf74ddddfc603d5062/av-18.1.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:191224788d87af06c31784a395bb73f14b72f33d7f4871ace0157de2abdc6276", size = 36859932, upload-time = "2026-08-12T22:27:31.403Z" },
+ { url = "https://files.pythonhosted.org/packages/33/b4/76ba21e46704f632004276b85289a1582e95f5eff760436d6149875a1881/av-18.1.0-cp311-abi3-win_amd64.whl", hash = "sha256:ea1480b7a8d5405cb5f382b344731bf125fd2c1c6fae3964f6c48595628387ff", size = 27595679, upload-time = "2026-08-12T22:27:35.177Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/ad/a3135884c5753b09773176b97201ae602f67ad14206c395ff838d66bf9b0/av-18.1.0-cp311-abi3-win_arm64.whl", hash = "sha256:5509ec12aaa19fd6601de13cfa6f4cdad450da07982118510592875d970454d6", size = 20257584, upload-time = "2026-08-12T22:27:38.472Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/5b/4a756265d7fb164336c8d377bca21c39cfa2c178be23cedee840a69b59c5/av-18.1.0-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:b36b0bae9e4c62f9487c99481ec15e4e3870fcc868522cd6d18fc2d6bfa04f01", size = 22795654, upload-time = "2026-08-12T22:27:42.016Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/cc/1bc841462114a1adf4f7d87456ab78a6972e23271e71865fcd2bbd0e7360/av-18.1.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:025f84494cb23278498f03b0d8117d3e47a1cbc9c44b97eb31875cf02251e46b", size = 18435735, upload-time = "2026-08-12T22:27:45.787Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/20/005500ed17a2e62a5e4bb94aa3786942560ec2f55ec1895ebf174c87abef/av-18.1.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:08a9ae288299cfcbf739dba4ad0c53b9b71f45184303dd45947920d022fed695", size = 37090807, upload-time = "2026-08-12T22:27:50.14Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/f7/11e7f6d848d3690c31ca4f8578167393e619177f1493ccc93b9400852d4e/av-18.1.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:cf8a17466bef07765dbdecc9e66ed9b25d20b4e14f654fbf35345a58ac45fa0c", size = 38976836, upload-time = "2026-08-12T22:27:54.565Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/63/b271473b24e806062d31191e40c6d65545e9cf59f80f044eba56dcbba0f4/av-18.1.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d49a5c542dfdc00f43c6cdb6cc41dac1781ee206fe180b56aa7433dfa816dfae", size = 40896630, upload-time = "2026-08-12T22:27:59.118Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/9f/2ab7fa292a947ad3466ed8e655eefa3b82f535d7ea598c297b4471a937c4/av-18.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5548b79e2bf1f59b3e9aedc918a72d9dc45b9adaac10ff9470d5dbdda0002e47", size = 37895673, upload-time = "2026-08-12T22:28:03.98Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/d8/04507c57249b399c3e4f23f01d221532f357338b5316fd2858fbd343127d/av-18.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7ea063f6690193ea335a1d592d6e0274350d45e2ed6af83ee107cb90cbfd84f", size = 39992431, upload-time = "2026-08-12T22:28:08.736Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/d6/bc4b95bea9c2353a7e4d62a3fcfad9adcf0f881741c6ce01ee179d539ce3/av-18.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e4d48b9f12cad009cc72fe4f4099107de5e819c95f82767f4fd01a01481c0661", size = 28497798, upload-time = "2026-08-12T22:28:13.003Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/d2/0c277a46f12647c1833f40496e132fb6001e0d19e6144b5ea30896461feb/av-18.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:5cd9085028902c9880622bd37a12fd4b33060f06a52311f6f4867ca9f29a2c3b", size = 21421979, upload-time = "2026-08-12T22:28:16.48Z" },
+]
+
+[[package]]
+name = "av"
+version = "19.0.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.12'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/23/01/76b6bf563fe907597cf58f10d10168e93fe588b6db9f2658db87e87efa7e/av-19.0.2.tar.gz", hash = "sha256:bebbc52598886480f4d861c575dc2b020785d6c04e1308680ddcc545e1b94c66", size = 4277157, upload-time = "2026-10-21T03:45:30.799Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4a/2f/f51f37820741134516e841053d5ecebf6350fbd451adcbff9ead96aa1244/av-19.0.2-cp312-abi3-macosx_11_0_x86_64.whl", hash = "sha256:f5f7bcf987567cd3f9b01f1c375c59bf59d8a5b98c9c5c154aeda7a11e0c5dce", size = 22627374, upload-time = "2026-10-21T03:44:28.296Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/42/067d0bcd2c07103f18cc23b510a8289dd80330e984c49d51ce0bafcee017/av-19.0.2-cp312-abi3-macosx_14_0_arm64.whl", hash = "sha256:b0dff6dfcc6ff9944fbbff15bc4ee2d90a2c1695d493bdea96e86f48823e9feb", size = 18556422, upload-time = "2026-10-21T03:44:31.267Z" },
+ { url = "https://files.pythonhosted.org/packages/de/0c/448f89f76cf5e4da35dd6294a1e8155b75daa8839f2f2fa353775855d152/av-19.0.2-cp312-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:04c8e412642c652cb2b1997a9cb2114546ee7d894600c631f4be8ceb26a0d0d2", size = 32683287, upload-time = "2026-10-21T03:44:34.588Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/7f/9f1237feb894afa472ef834aa1fbfe4d6398f28dc7e86a1b418650204c36/av-19.0.2-cp312-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c1da7aad0fa6c13b4a5c1e7985be0d13f8526a96284573acaf3d55ead6d3fe8", size = 34990159, upload-time = "2026-10-21T03:44:37.637Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/b5/1bde0e54e525d88ad8f5becae657f8142543fd3be9d10b72141f041ca868/av-19.0.2-cp312-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:9d4f9f78c0ce1f20deb72626fdb3c723757f61a8cd6fbb7dd44d9401884a91fd", size = 44422922, upload-time = "2026-10-21T03:44:41.847Z" },
+ { url = "https://files.pythonhosted.org/packages/08/21/65997929fa4dd7c20f64e742aa87205a8d65485718a2ab51633756078e83/av-19.0.2-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dfe7af5aa8243afd5d4778f85ad1a7c948e37fad272869da1f8f93f8d57fa7ad", size = 33754699, upload-time = "2026-10-21T03:44:45.772Z" },
+ { url = "https://files.pythonhosted.org/packages/30/44/4de8c0ff5a5e25ceb0841efc0a4a7530a22d61800bc0cc19a1d03aa04358/av-19.0.2-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:44d3faae747cf04a33f39db8ae983ff3d93adc864ee663bc186b25b686803c3e", size = 36014845, upload-time = "2026-10-21T03:44:49.64Z" },
+ { url = "https://files.pythonhosted.org/packages/32/5a/743a83666ded197df8b9957e2800bef9a39d52b23be2ca211bbd14b5fb22/av-19.0.2-cp312-abi3-win_amd64.whl", hash = "sha256:3ce5a1d7b916d13c16ac58f1756f0fee4af2d53f02bc1403e18550b50d375a22", size = 28150949, upload-time = "2026-10-21T03:44:53.434Z" },
+ { url = "https://files.pythonhosted.org/packages/42/fe/e79d786628d9c0428f72214dbe4b90ee0c625e04d552a604d5235ff35515/av-19.0.2-cp312-abi3-win_arm64.whl", hash = "sha256:79a277b077e3768a0ea9f881ca0b3bc96d4135a8d3a7a579938adb58718d0dfd", size = 20708023, upload-time = "2026-10-21T03:44:56.435Z" },
+ { url = "https://files.pythonhosted.org/packages/08/f5/e7988f64d3debf50748f1c4372a3dac70cfe53720563056cb57bd77771a6/av-19.0.2-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:b632e026f4375037438a6b2b5d6a489e55bc9504fad22078991ef96211bec2a9", size = 22911715, upload-time = "2026-10-21T03:44:59.378Z" },
+ { url = "https://files.pythonhosted.org/packages/76/86/dbe91321e6b233970c7fdfdb82cb1750a745e5779ab9ee69a6ce2589b1cb/av-19.0.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:32a8d37bde9e24ad0cc855140cbeecde17a363d7dc7928dcfc71a34b5f3ed387", size = 18864540, upload-time = "2026-10-21T03:45:02.227Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/c7/afca86772d825f5eb5fd8d1a193b206ed9a4a0d74ffbe5bbe0a19521ed7d/av-19.0.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:1e7cb7b66a832bce8996af5b94f1cf4014a05ff51e0005feac4cb2566d711020", size = 36479296, upload-time = "2026-10-21T03:45:05.955Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/71/6c6fc7e80dd5aa71109cb9324638620c40b7de8f677a6446d2f744295587/av-19.0.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:b559ff381bd800c46fee6a17d7e22a3443708cdd58d0901ae91d27cf5dd0578c", size = 38467551, upload-time = "2026-10-21T03:45:09.493Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/93/fa67f5d4180e57e7f740053fd855a6d312f4848f1e5582b8d3ab131184dd/av-19.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:91924f5c836b1cbf89fe1522c642f98e89a733124908561fd49dc7a70e9b6d10", size = 46223361, upload-time = "2026-10-21T03:45:13.396Z" },
+ { url = "https://files.pythonhosted.org/packages/25/f9/f98627770ccb4761e8cb87edd8b4bcf91549288bca95130c1a91ea7cdcb8/av-19.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ae4618eab172f8135596972252f39c7399291c921e661c1771ba26b9254b800f", size = 37349208, upload-time = "2026-10-21T03:45:17.213Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/3a/183b4f96a604a8544180e256d16f9a6c0534d6b7db22dc22fb0842aa96fc/av-19.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8596fad2017d380708de35ddf9d34f808b8488c912cdc3f361691d866d9dc32d", size = 39475989, upload-time = "2026-10-21T03:45:20.658Z" },
+ { url = "https://files.pythonhosted.org/packages/22/6e/84b65c58171a6d75a5d129a9cf856ca730843f8c476f08033e7f9d4a1af6/av-19.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:9db27c2248112a8eed3edd3ca83cf4405f52a402cda2eb1956035e646e6b99c6", size = 29064804, upload-time = "2026-10-21T03:45:24.24Z" },
+ { url = "https://files.pythonhosted.org/packages/60/4e/d96cc9fff457069c52754f63151a0340cb4886330d58e09061f203696b60/av-19.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:0e425d631510ca21e47c58f3837a9dceae0453c24e926408c8a12b95239cbbd6", size = 21916888, upload-time = "2026-10-21T03:45:27.298Z" },
+]
+
[[package]]
name = "backports-tarfile"
version = "1.2.0"
@@ -105,6 +167,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e3/26/2cde30fdde421130bfc18f70395731a6e6b2053c6a1978a5258ff04e72fa/cffi-2.1.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:7da0c5eff80f0197f3b3d1232ec5a682a9325f4ae9016a78f5f5ca35f9ced1f5", size = 225539, upload-time = "2026-08-03T21:21:09.911Z" },
]
+[[package]]
+name = "click"
+version = "8.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz", hash = "sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", size = 382235, upload-time = "2026-08-26T13:33:14.56Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" },
+]
+
[[package]]
name = "colorama"
version = "0.4.6"
@@ -281,6 +352,96 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/62/15/219075012ab13e8905f3cd572204f4acb4b111df787104346b9bc0cea789/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:07479a1cb08219ab719147e742e76090c9c773321959bb94946fffdd397a6437", size = 4699593, upload-time = "2026-07-31T14:24:59.951Z" },
]
+[[package]]
+name = "ctranslate2"
+version = "4.8.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
+ { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
+ { name = "pyyaml" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/01/4bdbbb7f564725629dfa638c4492997e12697822d5f5855a61705d116bb3/ctranslate2-4.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7b6cd9e832e47c00d3da14976b1621b065d8680a7d27a95a009af4a41e169ac", size = 1489306, upload-time = "2026-10-25T19:04:02.114Z" },
+ { url = "https://files.pythonhosted.org/packages/da/a7/c9cd5ab778b2f1eed8c4552e94c236e4e26a3742ffd54eb8ec54880fec8f/ctranslate2-4.8.4-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:2c366cb89ffcd99f76e44dfbb199979d450a9c698dae5eefd65e94a7ef25443c", size = 12167392, upload-time = "2026-10-25T19:04:03.775Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/f9/e0250f31eadfbb70e467b2c33867399665ab783ecc3fff18412595b1693f/ctranslate2-4.8.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd6ed9d10b46b9bc2ee801ea9624acf28bd53ffddfd5e92d23b2340dbc4d6474", size = 18793231, upload-time = "2026-10-25T19:04:06.692Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/fb/c20dd76f7636bdef710e2f6e8419db3a07687cec65e78228ff3624875afe/ctranslate2-4.8.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1037b3f51d18f1546120686670d71fcdaf85a0500fffccc56d8439ded5d284e5", size = 42428932, upload-time = "2026-10-25T19:04:10.532Z" },
+ { url = "https://files.pythonhosted.org/packages/45/a0/7f9744949aac9a143a1245511fb0ce5f62434aed9b1ca026cb72d9ff6e5f/ctranslate2-4.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:01bfca5d6e1736e38602511066a437677470c690e1458fa7c72ff322a3cfc4f9", size = 20369372, upload-time = "2026-10-25T19:04:13.542Z" },
+ { url = "https://files.pythonhosted.org/packages/45/18/68692f8cf2684690cc6f2b407fa6d5909895cac37aa9d1df1bc5849017f9/ctranslate2-4.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:36ebf8d2f5b7af176cef7869cd98a1c722ee01c177168fda5c9a045fc930be67", size = 1490254, upload-time = "2026-10-25T19:04:15.694Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/2f/7495643e0d5f530f927bbaf9daecb180606fe484d6afc056fcb773974344/ctranslate2-4.8.4-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:1094d0128657903677b3be3aab9186bf28ac8d89a4676fb590bcabf3c7605971", size = 12172517, upload-time = "2026-10-25T19:04:17.411Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/0f/f7aad2355dbb4a0115d9265f0ab04feddfd506388d19bfe7e0387fd7c5e1/ctranslate2-4.8.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a102683e7dc5d0cd0c31de5771ce4c27fffa837721470e7aae64ebffa64f3206", size = 18976989, upload-time = "2026-10-25T19:04:19.951Z" },
+ { url = "https://files.pythonhosted.org/packages/39/42/ab136f76cf379ed97d3f95563ad227fdd5cdbbeb20eaa797b0962be62b1a/ctranslate2-4.8.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d1830d12c84b2240bf51893ee6bfe24a671dccfd232b05a74ef197d27fb164a", size = 42669573, upload-time = "2026-10-25T19:04:23.931Z" },
+ { url = "https://files.pythonhosted.org/packages/af/25/cca7f6807d37cbfd9eebed8bbf136f5214c31d7d66de267ad05b676e9deb/ctranslate2-4.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:056db4b4c2a31b7811d453155a3d6ab316ddb1dc104f413beee7bce26bcbf92d", size = 20371102, upload-time = "2026-10-25T19:04:26.986Z" },
+ { url = "https://files.pythonhosted.org/packages/56/83/f96841f2123ee983c41a69477ca00f171d75e6434a4c40c0e3decbe457bb/ctranslate2-4.8.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:183a21b4c0da1846f8c3faac0267c497d7bdc8dd43350e23fa4f584b4ba2d4ba", size = 1490195, upload-time = "2026-10-25T19:04:29.168Z" },
+ { url = "https://files.pythonhosted.org/packages/40/ef/570715e8b607df28e129e913a496f41e6efa2665b85e3536f54e87b31d1e/ctranslate2-4.8.4-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:a547c5970c17c3259a59e731e5479579463b2d3a6235862a99a46654437faeb9", size = 12172432, upload-time = "2026-10-25T19:04:31.073Z" },
+ { url = "https://files.pythonhosted.org/packages/db/5a/29467590dbc2fe339e159da946f9192f231cfd753d36dd30095de88d6578/ctranslate2-4.8.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4ed771f82c4078113d811c5f9ad0a4597bb79f54784adb58fd50d69b04cb7a5", size = 18959426, upload-time = "2026-10-25T19:04:33.746Z" },
+ { url = "https://files.pythonhosted.org/packages/17/0b/430c7f43bc06cbdb5f9f66dac1ce13c1d713e03e729b295856a51ac33043/ctranslate2-4.8.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:271e77faf49ff9fa117b490b9008ac0b294744c19dabc93087e202299c1a8e27", size = 42612303, upload-time = "2026-10-25T19:04:37.457Z" },
+ { url = "https://files.pythonhosted.org/packages/37/ae/4fbe636b36fd4fd4266e309d050548c1ae0a23c88ef73ef89c6485db99d1/ctranslate2-4.8.4-cp313-cp313-win_amd64.whl", hash = "sha256:d9523961651ac0f51e4e62d03307609ff93d828b32ae92dc8b14a7e55243f6f2", size = 20371182, upload-time = "2026-10-25T19:04:40.548Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/3e/3f133db61ec4483b67ca264b63ae5fef9d60c0c5d6f253fad3f9bbf9e850/ctranslate2-4.8.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:87145e4ebdabd19c7bc8eb1f96a30b2df2b6923e6bdea8c97c637c872962f51a", size = 1490930, upload-time = "2026-10-25T19:04:43.285Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/fb/b38afe110dc1af43a45434e4c37564371e10ce9e91a3b200dda4494cc851/ctranslate2-4.8.4-cp314-cp314-macosx_11_0_x86_64.whl", hash = "sha256:40d49ce50fc38432eae920c36a13fb943fc73363934ff699986eadaf1a9e178b", size = 12172898, upload-time = "2026-10-25T19:04:45.409Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/e1/2f4b85f47567b934fb3e38da9f76451fd243f5111daf3dcef7b9211dfb7d/ctranslate2-4.8.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec9639dd36511eecf23bbc99a61a8fe77f16e2169e8dd35be6502ae3b2147a20", size = 18934359, upload-time = "2026-10-25T19:04:48.674Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/f4/d14d4ad8d1eac0e49aafcc11ff9ec83ac5758ae23acc526f15b73c980c19/ctranslate2-4.8.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e838fb78e8db9daee96187a08c3d0839bf45bd4853afda839f3b4b4979336ed6", size = 42590297, upload-time = "2026-10-25T19:04:52.638Z" },
+ { url = "https://files.pythonhosted.org/packages/50/98/6bd005eb63150a8d029aa06076180bc3452243b56da592c770128ac6f47b/ctranslate2-4.8.4-cp314-cp314-win_amd64.whl", hash = "sha256:4b322215f3b8eaab1db45b9e6aebfb8ddfe1336651e15a569c90826bfdb4b136", size = 20638792, upload-time = "2026-10-25T19:04:55.966Z" },
+ { url = "https://files.pythonhosted.org/packages/89/7b/51b68b23870e9e09c3dda27e629b78dbbc259750036474bea8e38171f721/ctranslate2-4.8.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fc200ff85351d6e6f7403c43857086df8ebc754bf243a77079fee7c2156ada5", size = 1517691, upload-time = "2026-10-25T19:04:58.538Z" },
+ { url = "https://files.pythonhosted.org/packages/45/9d/83f3f40d0e07878f62eb3b633ca186fe163b3c4fbdb960ab7bb66064a625/ctranslate2-4.8.4-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:1cf96ce8f625166ef67358b42c798271b307bb0b4a1d39a9965ff848f17f9d74", size = 12199614, upload-time = "2026-10-25T19:05:00.307Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/e3/a1a4b5a2b66acda963f08a6e73a4866ad79fa7bd079569be881da8d08f25/ctranslate2-4.8.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:230b5216b71f5502d6ae0d9151c646aa69de7817b2e424ee67d6a87a9aeb19e1", size = 19315986, upload-time = "2026-10-25T19:05:03.08Z" },
+ { url = "https://files.pythonhosted.org/packages/78/69/8750a4bd23c85a41d14686de0fadb101d5241a2a79e0c5a36d56d04c69ba/ctranslate2-4.8.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbf71062d93031ad709a20588a6d2cb624f66253c53e8509c8f9410078d53bd9", size = 42942312, upload-time = "2026-10-25T19:05:07.228Z" },
+ { url = "https://files.pythonhosted.org/packages/22/3e/94c4fb70d2844b5b396fa29e04139013292b8129feab427c6241953a1a6f/ctranslate2-4.8.4-cp314-cp314t-win_amd64.whl", hash = "sha256:81397be8ef6c7966ebe5b549244114e543f19219976d7e1437fdebb624f296c0", size = 20665797, upload-time = "2026-10-25T19:05:10.444Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/de/7dd4ad23e7fa5c0ebb3be622d94283a73885847f886c7803e5e683617548/ctranslate2-4.8.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:ed6d6e53e9414f702868f8c9543da8b526b8d1703dd0c1136c99d01c8e6b0614", size = 1491298, upload-time = "2026-10-25T19:05:12.626Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/4a/a37f99662f23132282540b33c26080dc498d66a3dd63418026d6bf143639/ctranslate2-4.8.4-cp315-cp315-macosx_11_0_x86_64.whl", hash = "sha256:18286b049aa9afb1df301bf627eb8dcbe4e9069810e7e3e4ef069e55a68b5934", size = 12172901, upload-time = "2026-10-25T19:05:14.422Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/7d/56ef3c91f58c1ad99daaf1b4ff798109e6a73ae5784549e0bcc3efe37b6f/ctranslate2-4.8.4-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ac23582ee919235fd6a73ab383eb7cb97b544dc7c70fcc445dc22de7d70dc90", size = 18944558, upload-time = "2026-10-25T19:05:17.362Z" },
+ { url = "https://files.pythonhosted.org/packages/58/cc/07a6c500aa65910691eb345fb4fca463906168cd75c6dde8735f02f01746/ctranslate2-4.8.4-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6139f57b316420469d1400968d40185ff7b99123d45a88ab3112d364809fffb", size = 42613272, upload-time = "2026-10-25T19:05:21.321Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/93/c3f255c6a7e7aded6c3fcabbb383d5b9277f05ff62d960dd9a99dae698f1/ctranslate2-4.8.4-cp315-cp315-win_amd64.whl", hash = "sha256:a6c28ac653a3598d3a978e9c9c629c3a4f30072b0d0473be2880d3d82599e11a", size = 20638838, upload-time = "2026-10-25T19:05:24.766Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/9f/890c9c520135642c5c338c0687872f41e65e25dd1d58a217d514258c9211/ctranslate2-4.8.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:8eb7a167ff37ddc2c0237064fd25101fe00775a7deaf1f094be9c7f88694d54c", size = 1518152, upload-time = "2026-10-25T19:05:27.037Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/80/08a06ade4d67b63384189c280edfd00be9a5ec3b9f6c0d263d322b7c12e5/ctranslate2-4.8.4-cp315-cp315t-macosx_11_0_x86_64.whl", hash = "sha256:63a715c34b5e3c462e5680ea32ea12bad30ada8db1a6d99fc8e0e541d6117542", size = 12199353, upload-time = "2026-10-25T19:05:29.26Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/1d/b44cd0038a265768ba649bd45359e6029be670fd6f0135a5d07637d38182/ctranslate2-4.8.4-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82caf13dce0563d96a92e0bcfe541f3ff73875b4d3d9335e8dfc46a66d0e2a51", size = 19368566, upload-time = "2026-10-25T19:05:32.297Z" },
+ { url = "https://files.pythonhosted.org/packages/01/76/81a2e86d63183c597ef977c03d19166bab0857c1a92bdcfe394770bbd274/ctranslate2-4.8.4-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8849e5dfd27f3e5ad781d327f477434badfcb3deead4c4758ceeb621aed930a7", size = 43008255, upload-time = "2026-10-25T19:05:36.566Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/f7/d3ca639be986018bc1ee06e8c07652c44fc7c65b70022f161a7adce2d014/ctranslate2-4.8.4-cp315-cp315t-win_amd64.whl", hash = "sha256:b8f5ea44f93342cb460642f966bb87bf79d3fdcded6db049001cca28e82c0be8", size = 20666116, upload-time = "2026-10-25T19:05:39.895Z" },
+]
+
+[[package]]
+name = "faster-whisper"
+version = "1.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "av", version = "18.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
+ { name = "av", version = "19.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
+ { name = "ctranslate2" },
+ { name = "huggingface-hub" },
+ { name = "onnxruntime" },
+ { name = "tokenizers" },
+ { name = "tqdm" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/99/49ee85903dee060d9f08297b4a342e5e0bcfca2f027a07b4ee0a38ab13f9/faster_whisper-1.2.1-py3-none-any.whl", hash = "sha256:79a66ad50688c0b794dd501dc340a736992a6342f7f95e5811be60b5224a26a7", size = 1118909, upload-time = "2025-10-31T11:35:47.794Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "4.2.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/28/3893324bcadf8f89b1616637468d766af3f625008c0735bf704fdfa86617/filelock-4.2.4.tar.gz", hash = "sha256:c6d8663535e1650ee430507b4ffbac7b464dd64b7647ea0112a9f406499d163d", size = 652444, upload-time = "2026-10-19T01:57:51.001Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/1b/5e74289a1878e666bb4b65fe5805a04cafcac2aa5f519ef1ead67ef91c56/filelock-4.2.4-py3-none-any.whl", hash = "sha256:301241438c57936ef93f4243a94f2559022268bfcf9b375a9a72eb0f8db8358e", size = 162475, upload-time = "2026-10-19T01:57:49.419Z" },
+]
+
+[[package]]
+name = "flatbuffers"
+version = "25.12.19"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" },
+]
+
+[[package]]
+name = "fsspec"
+version = "2026.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/77/cd/9be253869fc42e764de7f3dedd6969af7d44ff9c3375214a3442a6f3fc08/fsspec-2026.9.0.tar.gz", hash = "sha256:0f08147951c8cb31d844c3547d631053b127863b60be04cf06e121333ee0e2fe", size = 333545, upload-time = "2026-09-18T17:50:42.825Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl", hash = "sha256:8dd6e646e99ea382bd85f97a45e6b526a442d79423a7dc673f1e2756d05fcb5f", size = 221738, upload-time = "2026-09-18T17:50:41.341Z" },
+]
+
[[package]]
name = "h11"
version = "0.16.0"
@@ -290,6 +451,30 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
]
+[[package]]
+name = "hf-xet"
+version = "1.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a3/ed/54c8ef80981b548649edda8f1302e5a42edb4e97672d742ee020c97f4856/hf_xet-1.7.1.tar.gz", hash = "sha256:89d06f4975e807eefc6f6777180f452cfb86f6c79f2a6caa6fb28809c84c6777", size = 993876, upload-time = "2026-10-28T15:09:54.834Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/65/94/c8447b413386554c528808eb147ade34669dce5ddf97cd9368345821bc1d/hf_xet-1.7.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:4498ae151a4576d18f8714302c9be16aceda4b34ed028b3f5226656377d77163", size = 3816404, upload-time = "2026-10-28T15:09:17.957Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/99/8889221e6f156a0167b5a07e20913ff50dee60832879c3471798156df91a/hf_xet-1.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fc2767e5b6ba9f74aa5b86728e64cef48668bed91c50e7313ba1d78f7c510c75", size = 3563533, upload-time = "2026-10-28T15:09:20.255Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/42/f9d4df9447fb8d502963f02569d069bf5c3b7d772a8a869b7773eb194c48/hf_xet-1.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cfcb057a0e9dc337839056f3eb11b2d7e3b594686a56f37a0e4458071b6f84ca", size = 4211327, upload-time = "2026-10-28T15:09:22.651Z" },
+ { url = "https://files.pythonhosted.org/packages/17/b0/abda85b0b444526c650ed8b8a208aa1fed0b8c872c194c3a8e19f0a11cd2/hf_xet-1.7.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:6e6639f77da484eb36671d86262a48f7904946f31f6ce980dcf0690f2dfdc1c4", size = 3988957, upload-time = "2026-10-28T15:09:29.21Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/44/7e608548a11bfacf3f8ad0c82c7e95034d36a042b38d8772dc74fc31b75d/hf_xet-1.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b269c6fe9f5c8104561b7320458a07865f64d159ee1306487be6f95ed9960013", size = 4193780, upload-time = "2026-10-28T15:09:31.291Z" },
+ { url = "https://files.pythonhosted.org/packages/61/db/2116ce2701399bbb2fd42e438fc24e3b1743ed2c210bebfdca173b6e686c/hf_xet-1.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bfa59cfeea1d3161bb6b86e8ceaaf1ee4bd07b0353222c27cfb643e0521c04d4", size = 4421379, upload-time = "2026-10-28T15:09:33.303Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/2c/8ec86426c7e09877d5e143cffaa97c7021857ebdf91f1ff0d59a73e48009/hf_xet-1.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4e649d3e9fd045a8563cf1346a6f67bbe3fa8215f5cce9b84042c876f26fe02c", size = 3825028, upload-time = "2026-10-28T15:09:35.391Z" },
+ { url = "https://files.pythonhosted.org/packages/84/ae/49ef831fbba17570663e68663bd69dbdba6abd38481b7884c5baf16dbdc2/hf_xet-1.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:4b5bc399ad059a2a7484f185162666fb7ecd77b573e8bafc336fd38a5741a522", size = 3656777, upload-time = "2026-10-28T15:09:37.335Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/cd/cd5c2a9145f406008cb35ae91ad48877ca6439bee3b64b5061e673b963df/hf_xet-1.7.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e2f21d368a84f798cd394549292e3abe3be22d362aaf13fdd10b0f85a630590c", size = 3809415, upload-time = "2026-10-28T15:09:39.566Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/7b/e3fada39f556579503808a93e51231bb2f926f4633c038bc9c5237f6c39c/hf_xet-1.7.1-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:46d09bc6200388622f6aeb6db6d7b47060f63c483b6fb637e0e13e87470bfabf", size = 3573230, upload-time = "2026-10-28T15:09:41.356Z" },
+ { url = "https://files.pythonhosted.org/packages/91/99/105c23da56161acdc4e5b3022ae6d225ab54269a44eb7303f41e3a7be09e/hf_xet-1.7.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f26bfd4a6e31b4e37e749a07e8642589406e8537be05eccfd633a92b95e2fb51", size = 4219728, upload-time = "2026-10-28T15:09:43.24Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/de/861af7b14825974ea3c787c224f08758046ed17615d7c79c7571e7f26353/hf_xet-1.7.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b7fe4b5c4cc912a2c7b36538c6696d3312bd1471835ee814c3dd3dfc5509c3b9", size = 4000405, upload-time = "2026-10-28T15:09:45.481Z" },
+ { url = "https://files.pythonhosted.org/packages/94/bd/9cf9db82e60962b203489c89f5fb9809f417b7385da50d8a60bb79c299a0/hf_xet-1.7.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1b710504674091061d4f26fb7991773992dad091f8e162d0a8c965c3ec7427fe", size = 4202381, upload-time = "2026-10-28T15:09:47.315Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/e7/1521ffbecec428bbba62f495ba91ea294b1cada4c6289a7354be4edc7823/hf_xet-1.7.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:aaa2cf2f7a35bd653a365f6444ac0860b7b5ec11b7658090005d4aa6e10ae60b", size = 4430493, upload-time = "2026-10-28T15:09:49.113Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/56/e0f82a9f31772c2db59ca95e85beeb99e6da1a55f47d3fedac1b23ea1bc9/hf_xet-1.7.1-cp38-abi3-win_amd64.whl", hash = "sha256:d6e2c99e5dc7d6fa301e92e79a4f02cf962620dfc9fef84b687df597845cd72a", size = 3833194, upload-time = "2026-10-28T15:09:51.295Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/ce/faaa9326f8dce6e3e6eef1738a27834e77eebd3c0db00e5757a01dee0f7e/hf_xet-1.7.1-cp38-abi3-win_arm64.whl", hash = "sha256:c1f2c5685e89ee251e885c65ab366d981f555b2c8857642f4f8ee1e7dc4efdf6", size = 3665289, upload-time = "2026-10-28T15:09:53.107Z" },
+]
+
[[package]]
name = "httpcore"
version = "1.0.9"
@@ -303,6 +488,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
]
+[[package]]
+name = "httpcore2"
+version = "2.16.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "h11" },
+ { name = "truststore" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c0/61/afa9d6b7452f9eca73f73d45324eb0bb52f098fd5e6049bf6b8263be9b4e/httpcore2-2.16.0.tar.gz", hash = "sha256:c72cd0413563b17e1cd8354677dff887466f8ec2551679759e93126534428643", size = 69886, upload-time = "2026-10-21T07:09:45.31Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/af/c2/ce417c397afa5181f0e3c6ff01a4d01639414e1adef08730d97571297151/httpcore2-2.16.0-py3-none-any.whl", hash = "sha256:5c4358319f2602d984ad93182c9fee5160f22e9da7babdda870a5e7c4e2dc34f", size = 85070, upload-time = "2026-10-21T07:09:42.802Z" },
+]
+
[[package]]
name = "httpx"
version = "0.28.1"
@@ -318,6 +516,52 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
]
+[[package]]
+name = "httpx2"
+version = "2.16.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio", marker = "sys_platform != 'emscripten'" },
+ { name = "httpcore2", marker = "sys_platform != 'emscripten'" },
+ { name = "httpx2-jsfetch", marker = "python_full_version >= '3.12' and sys_platform == 'emscripten'" },
+ { name = "idna" },
+ { name = "truststore", marker = "sys_platform != 'emscripten'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/43/73/5ca2cedf5e4e50423d1c258877865a6b62793633b561c58499f8aeb33b7e/httpx2-2.16.0.tar.gz", hash = "sha256:0d54c98128e8f2ff7fbbde0fca8c359e5f032edeaaaac443cdb7f31f685bcd7f", size = 103116, upload-time = "2026-10-21T07:09:46.348Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/3d/2e4bc4fd1ef9770871669adb348d612a6e4786b303a23f9935b81c48dd60/httpx2-2.16.0-py3-none-any.whl", hash = "sha256:fd2c5d7909e8d86fe92d53020c310ca0e4e431b838c207c5754b9bbf0308d49a", size = 97880, upload-time = "2026-10-21T07:09:44.01Z" },
+]
+
+[[package]]
+name = "httpx2-jsfetch"
+version = "1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/0e5636363151a2a1795e0a77617168b9ca438e1748ec05fc9b5687f93d64/httpx2_jsfetch-1.0.tar.gz", hash = "sha256:70a0e3eabfef7cce5ad9c629f7d01ca05e418f586646f4ddf14782e4c1454c60", size = 6872, upload-time = "2026-08-07T00:13:07.492Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9b/43/832f631d32e4f1211caa2ba368317739fe71f0b8530e4c9d15dc454bac2a/httpx2_jsfetch-1.0-py3-none-any.whl", hash = "sha256:cb916b707601e69a07721aabc8f3f6659be3a6893bc1ff5c6f9e02241df2da32", size = 6382, upload-time = "2026-08-07T00:13:06.567Z" },
+]
+
+[[package]]
+name = "huggingface-hub"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "filelock" },
+ { name = "fsspec" },
+ { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'ARM64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
+ { name = "httpx2" },
+ { name = "packaging" },
+ { name = "pyyaml" },
+ { name = "tqdm" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/46/dd/585639d95f6a987c0bdfb9045f050f4ad67240775644ba7a4fdc5aca3a3b/huggingface_hub-2.3.0.tar.gz", hash = "sha256:0b783b37f200f1d25bef2344a997c7d410f4437fbe9d8fd965f958e75cec7aef", size = 1063410, upload-time = "2026-10-23T08:52:06.594Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/89/5f6ef1162d0323f167b6baab04d1b4bd6a946161a8af6d86f622d9d79aa1/huggingface_hub-2.3.0-py3-none-any.whl", hash = "sha256:5da369600233568a126eb5578754935b2add9446b42d9e2fc0927d56840ac1a5", size = 855161, upload-time = "2026-10-23T08:52:04.78Z" },
+]
+
[[package]]
name = "idna"
version = "3.18"
@@ -332,7 +576,7 @@ name = "importlib-metadata"
version = "9.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "zipp" },
+ { name = "zipp", marker = "python_full_version < '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" }
wheels = [
@@ -432,6 +676,211 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192", size = 72226, upload-time = "2026-05-22T14:14:28.824Z" },
]
+[[package]]
+name = "numpy"
+version = "2.4.6"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.12'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" },
+ { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" },
+ { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" },
+ { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" },
+ { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" },
+ { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" },
+ { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" },
+ { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" },
+ { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" },
+ { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" },
+ { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" },
+ { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" },
+ { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" },
+ { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" },
+ { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" },
+ { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" },
+ { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" },
+ { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" },
+ { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" },
+ { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" },
+ { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" },
+ { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" },
+ { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" },
+ { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" },
+ { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" },
+ { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" },
+ { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" },
+ { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" },
+ { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" },
+ { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" },
+ { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "2.5.4"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.12'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/95/b0/c7453d0b6e2073c3264468b106ee1563750cecc910965e67357e3698c83e/numpy-2.5.4.tar.gz", hash = "sha256:9a94cf751c9ad8ebaa835bcd3d40dacf8534ad086b88c38029b65123c7999d2a", size = 20866315, upload-time = "2026-10-10T20:05:31.422Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d0/97/ba2074e92b7befea137e77ea8471e768bbd87c339b7e8c9f5a931949f977/numpy-2.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c6342f54c67093cae5c0227eb0eb772fdb79f2a2c37a6eb278b9909ee06aa356", size = 17001609, upload-time = "2026-10-10T20:02:40.843Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/a9/bac826765e971d8e16e2064e9ac7525fd69b40ac17c905033a7f5442023f/numpy-2.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b11e8fda06a7d69f15ebf542660b74466c2e51094800c1fb794f47ad4faeef17", size = 12015718, upload-time = "2026-10-10T20:02:43.45Z" },
+ { url = "https://files.pythonhosted.org/packages/31/2f/5ea3570fcb8ccd0882bea99436a513b2c85dad8f774a2057849130a8fb99/numpy-2.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9cb18a327b49c5c337f972b03682f6a49855525faaf3c0d3e9c96cd0fd8880a8", size = 5451717, upload-time = "2026-10-10T20:02:46.169Z" },
+ { url = "https://files.pythonhosted.org/packages/34/f2/b4fc1bafca03868220b5eaf729d2f21ebd7d7b151c0f9e144fe212bbca35/numpy-2.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:aec3fc4b32ff82421274f5d205c559c51c840c8df66a78efd7f3612dd005a26a", size = 6789926, upload-time = "2026-10-10T20:02:48.139Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/96/8319e2457ae4333c62c815c7006b869a4f60985c1e01024c2f8c6c040fe5/numpy-2.5.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe4d21ab149f15e4e6043dfb0de87e6e5f34ac176cde83060e9802981fca2ac2", size = 15695312, upload-time = "2026-10-10T20:02:50.115Z" },
+ { url = "https://files.pythonhosted.org/packages/43/a3/c799c62e19c337e6d3770b08e475887fb30ce8477d3c09efca6b2f0228a6/numpy-2.5.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbde6962867ee75b48b0ee29b2b9372ec5d617799dbaf38e82dc0596f2f7738a", size = 16727283, upload-time = "2026-10-10T20:02:53.186Z" },
+ { url = "https://files.pythonhosted.org/packages/39/6b/3604e53fb00314d0dc1b94ec9125a1484f649c0a17480b1f0f0c7a9d6250/numpy-2.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:381a7a3d2e65e64c0ec302795ab9dc12bb1e73f150904699c153716177eebdaf", size = 17047890, upload-time = "2026-10-10T20:02:56.038Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/7a/e8b58a5289a0d464c52885de47c35a935cdd70c03a4c3ab94a5126416dd0/numpy-2.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b89d0aaae2fe498c648f4c4795c084db535af5bd98ef942b2a3681fb74ce8645", size = 18485839, upload-time = "2026-10-10T20:02:59.018Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/c9/47094f597015009f310b8c900def59065ef1ff5a6fe7b51fc65ec58ec2c6/numpy-2.5.4-cp312-cp312-win32.whl", hash = "sha256:9968ab7e49b93ac6e1c3b2239732183152c9150f16308d30b66a372cffe3483c", size = 6138936, upload-time = "2026-10-10T20:03:01.626Z" },
+ { url = "https://files.pythonhosted.org/packages/12/33/fefe62073dc8acfd0f2b9ed7c003af2f50aa61555e113e6db02b8f79f145/numpy-2.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7b1b6353e36a7e50de2973a38d705c88ee93adcf120673cee7f45a4a3fa223a", size = 12573091, upload-time = "2026-10-10T20:03:04.349Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/07/161270b0c2eec56e4c905f6d6d22e1b836887b2cb189d3f5820aa588e9dd/numpy-2.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:aa1cce2ff3f8d953de38b76bf44602caeb69f101430208f64a10067f7cb4b1d3", size = 10521630, upload-time = "2026-10-10T20:03:06.767Z" },
+ { url = "https://files.pythonhosted.org/packages/67/14/1c3ee0118a8fce08565a5d8482631608426a33af10a01077fada5dc7c119/numpy-2.5.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2377da2dd3ba2c1200956acbab2a358c83b8e1f8531191672d1cd6ad83250d53", size = 16997729, upload-time = "2026-10-10T20:03:09.291Z" },
+ { url = "https://files.pythonhosted.org/packages/83/8c/b0ea9477fb1f0d4484bbc5cba21678cc9969704d8d7f3f158d1db35f8e14/numpy-2.5.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7415db95818b39ec475a5eea54d9e3b6bc83e3912158e46da3438cdce399804d", size = 12009826, upload-time = "2026-10-10T20:03:11.946Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/84/6a3d75b3ba3dfe84ac0053450753d1e6d250a8bf80f66474cc46d1fb643f/numpy-2.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6d6a71b9d9a97c03633aa12565ef2825ffa036cc1d99cfd50dacf0f128af4fe2", size = 5445803, upload-time = "2026-10-10T20:03:14.329Z" },
+ { url = "https://files.pythonhosted.org/packages/61/18/bb993f267ca20b376e07092a16793a5b31ed3138751e9ba480011a14d742/numpy-2.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d8200f16437b289a5bb927c6e184eccc3e8389bc0070fea4cd5b9e13c1757959", size = 6786220, upload-time = "2026-10-10T20:03:16.602Z" },
+ { url = "https://files.pythonhosted.org/packages/db/b6/135bb0953b61dc21c6cafa14b424ae666944e4899cf140e00c2b322a1a45/numpy-2.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2e71b04c6cad90026e544501bbe0ab9290fa8a4d845e7e8c0d124fb429c988", size = 15689178, upload-time = "2026-10-10T20:03:18.721Z" },
+ { url = "https://files.pythonhosted.org/packages/da/24/3bd070f3269dc609d8f26b2643f62ef91bb415841c0b294805aaf7fe06da/numpy-2.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6ffa07666f8da0eef81d149934a626d0d95fbd6838432a33e66245423a9062c0", size = 16718044, upload-time = "2026-10-10T20:03:21.386Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/8e/9d15bd356b0a019c965312b1a3c6a727cac4cae5bc40045fbc12ce4cff9c/numpy-2.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fa3328f784fc8277fc48026f6cad516f5c561c5d8e2e39b3c9e0c8f23223b34", size = 17048364, upload-time = "2026-10-10T20:03:24.468Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/fe/9d5b560db964f15871885f2250795d15945f8699e17ef90c0c2ff4c875b2/numpy-2.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b86966fbe4ad7de710422175572bcdc75fdedadfb54bc6fab7deabccddd7780b", size = 18474904, upload-time = "2026-10-10T20:03:27.895Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/98/d27552990f1bd611ef3e7466adadc78312ea2df63b83aad47fdc3d3ca8df/numpy-2.5.4-cp313-cp313-win32.whl", hash = "sha256:5258bc06526964be5face2fc6f756857a3f24f21ec3e72ca131337a75b165d6c", size = 6134537, upload-time = "2026-10-10T20:03:30.511Z" },
+ { url = "https://files.pythonhosted.org/packages/90/8c/140a40398a66b4471211be1affdb6ed24c486d581bd28d07b7f2fcb69540/numpy-2.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:8b4d2fd2d34e5f8c9235ee787de5631a37a28402b15cb80814df973d2be54129", size = 12566113, upload-time = "2026-10-10T20:03:32.612Z" },
+ { url = "https://files.pythonhosted.org/packages/34/52/01d205e5e8ccb27b2b0b141e801f22b830198c979111b0fa44771438d9a9/numpy-2.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:bc39ac66a7a9a3fbd6134fda43136b60ffde99c8f4501e64e0d2b24da137babf", size = 10519523, upload-time = "2026-10-10T20:03:35.163Z" },
+ { url = "https://files.pythonhosted.org/packages/99/ba/005cb5edd580d2f84d7ca3206b92dc17d4388e56e6f87ffe8f2762f83139/numpy-2.5.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c668b2f0d651605b58892644b0e302c7157f7159544227758c896982ef384b18", size = 17005499, upload-time = "2026-10-10T20:03:37.961Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/49/fee7587c33ee35f7977f9051d7f2023d4e7246d62710c80f20c2361ea232/numpy-2.5.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ffa6ce09a1c6a08e9667dd9c97aa0b14184e8d18f2a14b78b2a2328c9147f076", size = 12019666, upload-time = "2026-10-10T20:03:40.606Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/b2/c6ce165acffceb15a82c07b9cc77d391f86b3f379ba62911908ae5d34b91/numpy-2.5.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:956555e0603a4d38019ae6925711cb9dc43195c076a928accf7ea5d50bddfe53", size = 5455617, upload-time = "2026-10-10T20:03:43.138Z" },
+ { url = "https://files.pythonhosted.org/packages/77/7f/dd85ce260a669a89be06842cf355d7353a33e6cfbc590fb8ebb947d88dc9/numpy-2.5.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2c2c4afffdeb7920e445028dd71eb932cac3e704792e964bc2a232426d4f1255", size = 6791932, upload-time = "2026-10-10T20:03:44.874Z" },
+ { url = "https://files.pythonhosted.org/packages/63/d6/34b0a2b0741386a63025a65a2c09caaaaaad6d0ca95b66cd65c30dd7fcb5/numpy-2.5.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4054173604cd8658796053f1f3bc0befb68ec1c0762c57fdad61e199256a8617", size = 15710899, upload-time = "2026-10-10T20:03:46.839Z" },
+ { url = "https://files.pythonhosted.org/packages/16/d5/928078d2b28f26829b138b4a6c3980045022fb409f570657a224ae60ef4e/numpy-2.5.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d549420b8858885cea8838a727842249218b9c1da24dd517e25c9c7a948310a3", size = 16721710, upload-time = "2026-10-10T20:03:49.489Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/cf/673fd1b8f4cd78eb6320e87ec4c90ac19c095644259e3749853a405c70f4/numpy-2.5.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:823874a507a84af050493b622affde94b6f7c3a0dc22cb2801381bc03b871c00", size = 17066182, upload-time = "2026-10-10T20:03:52.25Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/92/a77b5061b1b3e2643928c37976d79ee173e1b171ed158b7a3c61056b41bc/numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4e263278bfb5ee6409db8aedbc4cc32973b1b82bc1e8d3c668551d04d83a7e37", size = 18480315, upload-time = "2026-10-10T20:03:55.39Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/1d/1486ef3d3fb2279fd93c4c43c1bbbf1ca389a19816696684409f71babaab/numpy-2.5.4-cp314-cp314-win32.whl", hash = "sha256:cfd73180400042a7c532d30c5e287bdd03c59ff9ee1b4c0316af0539e29dfe23", size = 6185739, upload-time = "2026-10-10T20:03:58.186Z" },
+ { url = "https://files.pythonhosted.org/packages/52/9a/e1e512ebc948d5b9dd33b08736760f0ebbed2848fd4eda1f553088a6dcee/numpy-2.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:2ca144f15135b6212a5c47b1e2aeca6e412f102f95a2d5d88d8aec77eb255de3", size = 12703552, upload-time = "2026-10-10T20:04:00.28Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/05/de709a982d7bbcd688a3fad71f002e9ff80c2db39e03ee726609b610f1d1/numpy-2.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:468397ba3c64427474706e5c9123fe266395496714dc684294eac75cd4930d1e", size = 10803901, upload-time = "2026-10-10T20:04:02.659Z" },
+ { url = "https://files.pythonhosted.org/packages/13/34/083570ada3bb2a30fbe5d77c8c6fef9141144a15d33e6f793a67e9749ab8/numpy-2.5.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1ef3aa6d7e29bb13677323114280b05acc57607fa2300e66432d665d5418a162", size = 12138695, upload-time = "2026-10-10T20:04:05.012Z" },
+ { url = "https://files.pythonhosted.org/packages/94/06/1f9c24db48eef0c2d1207e3b11fffb0478e39dfd8c1e1be7476936885eed/numpy-2.5.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:98b053943e5a0474ec0da309d2cb9d3f18ea57f8a2067c2ab7b5f763d1068380", size = 5574615, upload-time = "2026-10-10T20:04:07.316Z" },
+ { url = "https://files.pythonhosted.org/packages/da/0f/593fba2e1560e949123bc7d2fc48b5893d56e58cd4bd5a273d2fbf60b220/numpy-2.5.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:b64a85f40e154983960a4167d4c1d57a50c7f109b3d3264a3a984154e90a8454", size = 6889383, upload-time = "2026-10-10T20:04:09.918Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/9f/b799dfdce4e05e80ed4bc815c71ff343a11533b2c0ffc221cae8538cda63/numpy-2.5.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a813ed7719bf45463c51779e6a98d0385fe905e48447526938a4b8337333d551", size = 15753763, upload-time = "2026-10-10T20:04:12.278Z" },
+ { url = "https://files.pythonhosted.org/packages/34/88/16c5f12f86f5ad2817c4d103205131fc6c8acb3d1878af05a1a4f23ec859/numpy-2.5.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9b80cdf5cedba0e90d93fa5f9a333c4d65bd545cd669b71bb97ce2b703c9d73", size = 16757212, upload-time = "2026-10-10T20:04:14.799Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/4f/a1fe40e18a898e6a5089f4f0d891f0a493eb0574d5b34458f0fbe5aa3e5c/numpy-2.5.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2199ed071f460487c8db2c0e5c0b564494190edb4772fe80f9aad88b2604def5", size = 17116471, upload-time = "2026-10-10T20:04:17.58Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/46/e923a11c78e65c1722e7aaad817c06bd591324174b9d28ce5d31eee4d432/numpy-2.5.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:64f9c9878c1938476365e11ccfb6b770f3b9e5f045ccddc514235041e6959365", size = 18524063, upload-time = "2026-10-10T20:04:20.365Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/fa/84ab064514440c1f64a1b21088f2c82756defdd05e07c75ab233899565b2/numpy-2.5.4-cp314-cp314t-win32.whl", hash = "sha256:64d1c8ac28a4077cf987e0a71a7a0ef7e2df70722f07f0baa42dbb7eb6938647", size = 6340926, upload-time = "2026-10-10T20:04:22.865Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/7e/6cd886876f435b10685db9b9f7eeb70356f99e052116f4e5f11c5792c714/numpy-2.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:067374eb538c34c745436365cf7b0112595c1d326f21ce4ff340f61230239fbb", size = 12901584, upload-time = "2026-10-10T20:04:24.99Z" },
+ { url = "https://files.pythonhosted.org/packages/38/1b/3c1684f6a06f7307f2335fca6e486cb162847fb97e91d65f8eb5cabad213/numpy-2.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:e94aef2c639da4a960ad0db8e06471208d8589974953d78b61d345b4eb99e394", size = 10891152, upload-time = "2026-10-10T20:04:27.52Z" },
+ { url = "https://files.pythonhosted.org/packages/08/f4/3224deff3af2bef6bc0b175369698d8cb348f3d91d9bb0286cd5c9eae9e0/numpy-2.5.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:8dddfbee2e68d26d0d7d7d9cb247b1fd4409241cce32d815a11d97ec2cfde179", size = 17003231, upload-time = "2026-10-10T20:04:30.021Z" },
+ { url = "https://files.pythonhosted.org/packages/be/75/fee0b8c6d94b44b2fdfae74f6a4ad5a138739589a8aebaec28ce4e713ed5/numpy-2.5.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:81e3420b27048b65eb14c3acf0c174a8cb0e023277716110347d2dcb26026dad", size = 12018300, upload-time = "2026-10-10T20:04:32.519Z" },
+ { url = "https://files.pythonhosted.org/packages/47/c0/d0b335a499a04b65f532c3f034346ef390f81299060f928492dabc1e0272/numpy-2.5.4-cp315-cp315-macosx_14_0_arm64.whl", hash = "sha256:0b4724a19de67bea8cfc4970798efa78bcbbe2ac2613cfac16721a42d44de2a5", size = 5454250, upload-time = "2026-10-10T20:04:34.943Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/0e/461b3783c03d668052e6a21b01b673db6ffcb7831fd32d9aa5368c1cd426/numpy-2.5.4-cp315-cp315-macosx_14_0_x86_64.whl", hash = "sha256:2132418bf8dd124a427ca9e6a1daf9ee1a87185344c95119ceae868b99466da1", size = 6789644, upload-time = "2026-10-10T20:04:37.258Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/02/5dad269b02166965a7b4ca14adaddd75dbee0de42435bfecf561b84ba5a6/numpy-2.5.4-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:325518d4245b9e331387702aa58c2ce1dc4cdcbb41dfb4ccd5dcbc7e08db1266", size = 15704353, upload-time = "2026-10-10T20:04:39.616Z" },
+ { url = "https://files.pythonhosted.org/packages/93/3a/01360c8036822ed9f7aa32189a77d1476567ec1e8e1383522389e4faac45/numpy-2.5.4-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56733449d2544178beaa4545cee357370440cf056c197f9c7bfb19dbfdd0e86d", size = 16718648, upload-time = "2026-10-10T20:04:42.383Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/5c/b863a2c093c4d6f21a597fcaf24ead0835c09ab16a8312d5a5a8868af683/numpy-2.5.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:5ec3753760c1a6d8bb91200666e545c3a9728e6269dfb5d6ce02340996698aa3", size = 17059053, upload-time = "2026-10-10T20:04:44.976Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/60/ced4f57f9a1258a0af74f17cb0b0c2700b5c67cd6678823c803b263e4df3/numpy-2.5.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:b1185012870173de7ae33d370bd45b1cf5baee747ea4b97036b65f4e93016877", size = 18477406, upload-time = "2026-10-10T20:04:47.863Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/bd/0ef22dafaafcc7d4bb3ca26b8d2afbd55dedad8eaba99a8c864e1997456f/numpy-2.5.4-cp315-cp315-win32.whl", hash = "sha256:298eca75243f2cbbfdb460560b9fb2a1792a33cf2ab4286efd43d92e8d3df508", size = 6185133, upload-time = "2026-10-10T20:04:50.467Z" },
+ { url = "https://files.pythonhosted.org/packages/50/bc/d2651b155ecc608a77e6f4d15495c11f14f19bb98f8bf0c5b0d38f86dda1/numpy-2.5.4-cp315-cp315-win_amd64.whl", hash = "sha256:332f3378fe077dd850e677ec01bdcc4f22368fb5d50ef10b2c79230b1bf5a592", size = 12703085, upload-time = "2026-10-10T20:04:52.63Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/d2/45e404f8abb26fb9eda12b94012936873e827b1be76f2ee7890be128312e/numpy-2.5.4-cp315-cp315-win_arm64.whl", hash = "sha256:d4cccbbc78717966f764cd3af4fb70276fa01fc7a2688af11c78901fa5c04f05", size = 10801451, upload-time = "2026-10-10T20:04:55.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/c3/2ae14e09cfdb67dc187a342e15308a21c15bf4d2071f8079e6aee5fe56dc/numpy-2.5.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:950ea81d57ef070665581b6e1b5f6a029306423cd1739c5b95fe78aa30db6b9d", size = 17097121, upload-time = "2026-10-10T20:04:58.403Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/cf/305ae624ef8a039414317224abe9ec9c2fe7ea3c2e1cf204d43ff6b2ffb9/numpy-2.5.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c05ede731b03fb1b7591faca9389ade3267d2bddf1ad8882bb3f2cc5e101694f", size = 12135439, upload-time = "2026-10-10T20:05:01.65Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/a8/f75c63813aef95827bb2c0d13b12803016853056e8792c280058cdbfe783/numpy-2.5.4-cp315-cp315t-macosx_14_0_arm64.whl", hash = "sha256:5fbf7141bbfd63aea22f435c9062a032b9ea0082fe9845dad7f021d3f1234e71", size = 5571451, upload-time = "2026-10-10T20:05:04.135Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/0f/f17763f983868b5c49b4101ebd7e00760bd1769478a6bb6a8de6e085bbac/numpy-2.5.4-cp315-cp315t-macosx_14_0_x86_64.whl", hash = "sha256:3573cd22564692a5b899ec344e5d5b9cc4576f2985b96f22af3564ed54f2710f", size = 6883356, upload-time = "2026-10-10T20:05:06.249Z" },
+ { url = "https://files.pythonhosted.org/packages/67/a7/8af04c5a79e047996cfa38854dcfbececdd0343a7c933a46fdd03ef6f5da/numpy-2.5.4-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c109eac9cd439193678f69d70733c1108487546ca8eafc107b510ae10c1aecd", size = 15750991, upload-time = "2026-10-10T20:05:08.376Z" },
+ { url = "https://files.pythonhosted.org/packages/57/7a/648254290d0c504faa8f2d07aa206660c728802c781a6f3fc68ab7cb5d71/numpy-2.5.4-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80d6ef6e8620eb2c2b4c4caad50b5935d6db3cde2d51581b55dcc79e14016d1d", size = 16757675, upload-time = "2026-10-10T20:05:11.393Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/fe/4a8c3cdb0c70400cfe4c5bec42d3099a5673802a95064614b33e07b82aa1/numpy-2.5.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:77045a4b175bbf5316ec08003880804336c78f92281a1b72222b274ea85ec5ac", size = 17113846, upload-time = "2026-10-10T20:05:14.49Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/7e/619692bb67778702c0e9eb2d468568a7573f4e269386ea61aed01ee4e557/numpy-2.5.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:0f02a46e49cfb6c73bdb7aea1c0d3461dbae9aba613542b65f657cd3d17b9fab", size = 18522915, upload-time = "2026-10-10T20:05:17.33Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/b5/4da41c328788f575838f97a098fe8ca691ebc6f6fd73ad4a262ee40b184d/numpy-2.5.4-cp315-cp315t-win32.whl", hash = "sha256:ad62a416ddcf863bf44bba76fbf6b53366ab0692e294f51cae4b5fbe0d246788", size = 6335804, upload-time = "2026-10-10T20:05:19.921Z" },
+ { url = "https://files.pythonhosted.org/packages/98/94/6482ddfa3d312490cb9358f375bf2ad56427dbea8769187158e94d653753/numpy-2.5.4-cp315-cp315t-win_amd64.whl", hash = "sha256:38f47be9f74ab870d2633b5456ae519c43758a8d1fd05342f0ce4ecc034396ee", size = 12890095, upload-time = "2026-10-10T20:05:21.875Z" },
+ { url = "https://files.pythonhosted.org/packages/48/7f/c2d1b436b6e7cfebac140c2579a298344b85f2991a2ce5c3615cefb29400/numpy-2.5.4-cp315-cp315t-win_arm64.whl", hash = "sha256:7a14a461d9340f1b46b8648578aed9cdb8b3b018a8fac6c1dde2c9192a01a87f", size = 10883718, upload-time = "2026-10-10T20:05:28.547Z" },
+]
+
+[[package]]
+name = "onnxruntime"
+version = "1.31.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "flatbuffers" },
+ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
+ { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
+ { name = "packaging" },
+ { name = "protobuf" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fa/44/e9e04a60f726d16ba3abe30ab267e1569e061f7f6f0e175ee103661e1780/onnxruntime-1.31.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:60b6b69bfe580eab576cacc5d132a0e9cf2a37fcfd18d46dd191042b1d1ed0d7", size = 20871676, upload-time = "2026-10-26T19:26:00.372Z" },
+ { url = "https://files.pythonhosted.org/packages/02/ee/b173a49293b146b54bd057bf8681a015aef764d8f56d999ad8c6e53ab18d/onnxruntime-1.31.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:da05378364c44d4407e463982d2bf8d5e4cfea873283757e48beeb41df97b7f3", size = 21413526, upload-time = "2026-10-26T19:26:03.573Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/1d/0f85ee31a3d93f2243a5cc29252becf858f53ac5cfa6c9c15d9ffe107eea/onnxruntime-1.31.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:5752bd508126ae7c49894d3b9d2e83f0c3d487319246d04c444b393308d7ad7f", size = 23753652, upload-time = "2026-10-26T19:26:06.944Z" },
+ { url = "https://files.pythonhosted.org/packages/69/82/2e2bf967ade9567d77c307533566ef56a19c32e2114fc062a405703def88/onnxruntime-1.31.1-cp311-cp311-win_amd64.whl", hash = "sha256:c3d91b5de31e2fc82d71bd65b2b22bddee8b49057a3a36338e9a868e0ea90c05", size = 14885761, upload-time = "2026-10-26T19:26:09.8Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/c6/1995e04cc964c6abac426f59525b41c31f766c9392cabfb1e67c51718823/onnxruntime-1.31.1-cp311-cp311-win_arm64.whl", hash = "sha256:93800007a7023b3ab26ad72e6463d0d57d84ead49a2f6341954d91438e046bc0", size = 14735267, upload-time = "2026-10-26T19:26:12.915Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/f7/cecc0efeeea83bff2f7789ae1b80f27fa0f0210d6d9d66d1f0031a6b5e47/onnxruntime-1.31.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:96dd2564b10ea7153ad9c207e7cd8e5917cb3ba521e0e0a62ac03486fdc8d56c", size = 20882125, upload-time = "2026-10-26T19:26:16.256Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/e4/1ed1a7a5f4702d899091fa2b976d377995250c307326ec8dc9ae6378aa13/onnxruntime-1.31.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0b9a492176886992e0e875f06bc0367e333f5fff11711a2d642e18b02f3009cc", size = 21420803, upload-time = "2026-10-26T19:26:19.487Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/27/c6a823bac55b2977bea2027c3ec9393a2c1002cb9a09eb40354563e02730/onnxruntime-1.31.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:1f3dea47f2f0e5117c2404cea7d21fd253ae7836a3bf167a501cdfbb2600d536", size = 23760988, upload-time = "2026-10-26T19:26:23.153Z" },
+ { url = "https://files.pythonhosted.org/packages/45/b2/793b4051d8dc6acb379ead9b72050f0ffa283ca49a6904add2e218b83e2e/onnxruntime-1.31.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae8a9a351efda685cc59a66226cdefaa37a126c1d66872ca23a2de9425326130", size = 14888466, upload-time = "2026-10-26T19:26:25.816Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/72/09d635ab4b6137d8ac63d4911a37dad8b1ef15a77d20b65d7ed40fdca012/onnxruntime-1.31.1-cp312-cp312-win_arm64.whl", hash = "sha256:fe8b9ac1ae8e894e12c47ee82e4f6dfc1835768133687257866469fda80d0bf1", size = 14740724, upload-time = "2026-10-26T19:26:28.682Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/93/d2b855793302ef57d55cc0583b72a00a8dcb01d9bdb3adac380f09b050e8/onnxruntime-1.31.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e4ad067d36e2220218e085d7223283b2ee1bc73d887e811fd14d21cf901a11ee", size = 20881825, upload-time = "2026-10-26T19:26:31.51Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/e1/633d4994db0620d31f34d9962119bc4ebd0b2ef4c9a030f91c7843fb9672/onnxruntime-1.31.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:dcaedc50333876f3829ab966b242147f0e548229e29c36fe44622ecf748c25ee", size = 21420628, upload-time = "2026-10-26T19:26:34.487Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/0a/c887bcb84a9455b2723825381a77af38611a80f996f804e20fde5f671b63/onnxruntime-1.31.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:74a6a52994616c4d18b33db1e13c226333a70a6ba07480a5cab9c2a50dff1430", size = 23760717, upload-time = "2026-10-26T19:26:37.721Z" },
+ { url = "https://files.pythonhosted.org/packages/59/bf/a1d282b4c753ba3e9b31f4c11abd2bc2390513dc5e3792ca3b78e42401c3/onnxruntime-1.31.1-cp313-cp313-win_amd64.whl", hash = "sha256:0558f29d5f6ac09957390c9c5495931485ee8ae7f0ce781ccee86a0ae5c2348b", size = 14888304, upload-time = "2026-10-26T19:26:41.032Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/fd/529135287474dbaf19d9362ccda61998128ab18507f78bc82931e1bbaf22/onnxruntime-1.31.1-cp313-cp313-win_arm64.whl", hash = "sha256:075147c2e2430b4b29c436bffa78537b902a6ed58ed66f99ae3c6795e2081cb5", size = 14740772, upload-time = "2026-10-26T19:26:44.042Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/d4/56ea7d601695be4018ccc6bb9a47637a1deaccc5c4db6c6ad272e48d88e2/onnxruntime-1.31.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:ae0987aedb9ae589f3395615c58b22aad2eae6657b14508cec70c24b367cfad1", size = 21432641, upload-time = "2026-10-26T19:26:47.065Z" },
+ { url = "https://files.pythonhosted.org/packages/05/10/e37d9f06dae61cecaad344aef213a19643b66761a06667bdfe5282c1fb37/onnxruntime-1.31.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6711108bcddf8b401145fb31ac93776b8ca6e7e7e56acdfa9d478575b8df9a2f", size = 23773876, upload-time = "2026-10-26T19:26:50.371Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/55/b511099a435972b86b5d04ef374cdca8de920311cc979180029b80145bf5/onnxruntime-1.31.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:8536ac43682caa7492c46d6cfd4c3c8db288dcf0619508431a22170b670ee1d0", size = 20883427, upload-time = "2026-10-26T19:26:54.067Z" },
+ { url = "https://files.pythonhosted.org/packages/06/ef/98f0060d6cf58f9f663268fef65fe729120b8fbe26ef35eaa2c8d9030d33/onnxruntime-1.31.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:c878686b75cade1ed59131aa018ab004b1e64368b0d54041912450b9642cf04f", size = 21421619, upload-time = "2026-10-26T19:26:57.332Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/74/a891a659ccc427469de0d7bdbd5ff770a35f73084ee590ce02456cf61f7f/onnxruntime-1.31.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:c20d7f15d84427db070b163f78c2c7146cc93edd6113fa7327671259a24184fe", size = 23762999, upload-time = "2026-10-26T19:27:00.865Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/e9/9112e9322aef42bff80e805915b61cdcbb82577589bdd42dedf73a5ff9b6/onnxruntime-1.31.1-cp314-cp314-win_amd64.whl", hash = "sha256:0a3998e18cb667ef54287556bd62291a788ed235723dd90c83b2294b24e71d81", size = 15268752, upload-time = "2026-10-26T19:27:03.629Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/ee/b69384d9b94c6bf3beb030bcba25dc573e490d3136117be0f78d79078d35/onnxruntime-1.31.1-cp314-cp314-win_arm64.whl", hash = "sha256:fc01b4e7c0a81778fb741bcf5c16b7871d196275f6240720a8b8bfd9f0c0af14", size = 15153930, upload-time = "2026-10-26T19:27:06.159Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/5b/beeb6acb5a9e17311b4ebc36fe91ac4893200ddb290257fb072509a7c26b/onnxruntime-1.31.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:564d7b83fb3e94fb3d18629c6b339e9bce10966dd29a8442c433175aac3d60fd", size = 21432341, upload-time = "2026-10-26T19:27:09.131Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/3d/a5b15c4ab9d67a384da5a2c10fb569e643076c28179fe1a265af7d8f1b87/onnxruntime-1.31.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:4d5f5fcc01f0c334d282a8991eab44e7752ad01c47b336d848ba43eb38084958", size = 23772582, upload-time = "2026-10-26T19:27:12.025Z" },
+]
+
+[[package]]
+name = "opencc-python-reimplemented"
+version = "0.1.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8d/6d/c6f37eed651dd6b752e50f80a93396cdaa42a6acc6ce05ad7452303ea511/opencc-python-reimplemented-0.1.7.tar.gz", hash = "sha256:4f777ea3461a25257a7b876112cfa90bb6acabc6dfb843bf4d11266e43579dee", size = 482566, upload-time = "2023-02-11T03:58:42.25Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/30/6b/055b7806f320cc8f2cdf23c5f70221c0dc1683fca9ffaf76dfc2ad4b91b6/opencc_python_reimplemented-0.1.7-py2.py3-none-any.whl", hash = "sha256:41b3b92943c7bed291f448e9c7fad4b577c8c2eae30fcfe5a74edf8818493aa6", size = 481813, upload-time = "2023-02-11T03:58:39.66Z" },
+]
+
[[package]]
name = "packaging"
version = "26.3"
@@ -468,6 +917,21 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
+[[package]]
+name = "protobuf"
+version = "7.36.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d9/89/5b8517baa72f84a67b8a307ba953c91057af618bf40bf676f3c03551f8f0/protobuf-7.36.2.tar.gz", hash = "sha256:497d0463ff3316681da6c0b9e8d06cb465d61abce00b613ab42226175644d1bb", size = 512737, upload-time = "2026-09-17T20:07:59.326Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/72/98342feb672507c8f3a69e34b4fa8961f608edba5c1a48a6f47156d92cb5/protobuf-7.36.2-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:cbc70b17ee27e28894c7fee8bb04be1abead49e936bc70eb60052531eee2079e", size = 456039, upload-time = "2026-09-17T20:07:51.542Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/ea/91fdf7c2b8bbd49cde056f00a9df6773532987e1c00fe2830b895af95c7e/protobuf-7.36.2-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:e11e1f0180583a2af89db6a2ecd9e8dc40aa6d2988ca175bfd0e6d12ea72d74e", size = 344219, upload-time = "2026-09-17T20:07:52.914Z" },
+ { url = "https://files.pythonhosted.org/packages/17/ab/5fd5f8ece73fad885c5a09aa849b32d70472f954ba3a92d3bb5974ea953b/protobuf-7.36.2-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:f4fee11ec330d238b34a05c9b675f693c20415d1c5bd7d5320cc2f8a798eb9cf", size = 357223, upload-time = "2026-09-17T20:07:53.985Z" },
+ { url = "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:89f23aa53c24553a2416fd4fd1ec06f74fa42b14b546d8883128813f775bbfd2", size = 343223, upload-time = "2026-09-17T20:07:54.931Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/1b/dcc64f358fcb51811b58ae40b3d28f820725f116d86487cc20bd4b130701/protobuf-7.36.2-cp310-abi3-win32.whl", hash = "sha256:912c1221170e16c08d1f086762f563dd61ff83c18b5fa6652952dfaded66f728", size = 442998, upload-time = "2026-09-17T20:07:55.826Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/55/b77bda4e5e5f5971fb51b07663694690e9afdb9402136c16a522bd621cad/protobuf-7.36.2-cp310-abi3-win_amd64.whl", hash = "sha256:a300819d441e078a5608c0d3c709796bb548136058fda017ae51d425b44fd353", size = 456514, upload-time = "2026-09-17T20:07:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl", hash = "sha256:bdb3a345d48db958e6ce1f18e508beb0cc981d64f24088427549c866cd039f1e", size = 179806, upload-time = "2026-09-17T20:07:58.211Z" },
+]
+
[[package]]
name = "pycparser"
version = "3.0"
@@ -622,6 +1086,61 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
]
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" },
+ { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" },
+ { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" },
+ { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" },
+ { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
+]
+
[[package]]
name = "ruff"
version = "0.16.2"
@@ -681,6 +1200,40 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/98/d1/f15ca0e1666faae02c945f48e745ea35f8fcd8243b176109b4e2c4251f47/shiboken6-6.11.1-cp310-abi3-win_arm64.whl", hash = "sha256:7c8d9af17db4495d4fa5b1c393f218311c4855546b9dfa6a0bd21bcd66b55e9d", size = 1784170, upload-time = "2026-05-13T09:47:07.617Z" },
]
+[[package]]
+name = "tokenizers"
+version = "0.23.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "huggingface-hub" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e0/7c/2cabb2174e772636683008f2c5621949b645da7d303c596589e84516a184/tokenizers-0.23.3.tar.gz", hash = "sha256:cded33237c77caeef62944d32aa9a7ef42bdce2b3497e18d137e072a8c4be438", size = 385286, upload-time = "2026-10-09T10:16:55.759Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/aa/2e/4ce5b9716f26e526eff6b0502ebed4ea8d7161f03b3c77617c9f25528e97/tokenizers-0.23.3-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9d2b5c97daf61688c2ad1803ca851800feaba50fb68d5821779e9ea5880d968c", size = 3148800, upload-time = "2026-10-09T10:00:51.457Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/72/01e49f032bb346e5aaf06c10c74fe8aeec847173adbadd66eb7c53054bf2/tokenizers-0.23.3-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:68649e97d5b43c44c031d8d848874a6eecae8f8fe40ea989aa777a5a83aca716", size = 3101381, upload-time = "2026-10-09T10:00:54.063Z" },
+ { url = "https://files.pythonhosted.org/packages/15/fc/ae987741829b1cd547668c4c94be732ae3eefd1d74344e64c3d2ca714acd/tokenizers-0.23.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec82e80e65a862275b97c3d90b7a523df8d9519ee48aeb4e9625b2cc909274e0", size = 3519944, upload-time = "2026-10-09T10:00:55.885Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/da/cc8f6c030afaf05fbddc608158fbb761dca46913cbeba6b112e59fc82e2a/tokenizers-0.23.3-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c64a0713180ff16829d4e7f39a658b77ea11443af4e1aa46523692943c9b1414", size = 3397695, upload-time = "2026-10-09T10:00:57.444Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/f1/256f78d1365fa2cd3ea6db716883d74667c8cbb6a21f15fa5b89a773cdc2/tokenizers-0.23.3-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddedfd4b3b4be6be24ff6ca645c4a37fddfd305f6f3e354c54cf10b715c48215", size = 3753125, upload-time = "2026-10-09T10:01:00.165Z" },
+ { url = "https://files.pythonhosted.org/packages/60/93/eee007ac2fcbf4ecfce7fbc354826cf3611f56bdb886f3e91b1f7dd06b8f/tokenizers-0.23.3-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a89614730d7b80940a5d2ed9320e1ec8add5a745c6151d8d05071b7215505b6", size = 4018598, upload-time = "2026-10-09T10:01:02.05Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/f9/0c96c4739461fce9d8d865b416728081bf6230022d7163bd6244f35f4b31/tokenizers-0.23.3-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e88646b8580c5ad7f4361477f1298e9cc01771a1ee9aecfe32c47b8ff614cc38", size = 3602442, upload-time = "2026-10-09T10:01:03.77Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/40/6706b82693715581457c6d5423eaa7faae576bb0526c5738a57085eb4449/tokenizers-0.23.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:376851d22bcf9d650a5c3090bb83e6cf9e895fbf0595369fa4cd43c1f69b5f87", size = 3396193, upload-time = "2026-10-09T10:01:05.48Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/0c/85946de40e25b7364b8f1bcf56def129069acd5bb364b7c86a32919e1a23/tokenizers-0.23.3-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:bf501c40b72d2d5c8623620210430e9cac1ce47a46e45b34107b70a1557d46b0", size = 3553483, upload-time = "2026-10-09T10:01:07.387Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/6b/8d615d92cad1d511ca5ab188d1c7c167f0b3d295cc0d96207f9f82d486d8/tokenizers-0.23.3-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:114e2b55ed177179d59f4ab98200a4471e11e78f9e4b5a922d146740f96fcf52", size = 9972248, upload-time = "2026-10-09T10:01:09.437Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/7d/a922e37ddd58d1b463bbc2ad08120c8f59c60b814cd353519a116b24f8ba/tokenizers-0.23.3-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:d3407fb7b9c4d75dd68850ffd7180bc0a5d2dbaf0762d888e612f31fec3f9c6b", size = 9802957, upload-time = "2026-10-09T10:01:11.869Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/06/5d3f506a86ae0699a0e4ea05c05978f9aee169ef2c1d844e68c971cf8194/tokenizers-0.23.3-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:84513ef0aeb8bf8f4ea11a2e8a7ac163ec5288aa115e649a59b470ac5c3107df", size = 10145487, upload-time = "2026-10-09T10:01:14.268Z" },
+ { url = "https://files.pythonhosted.org/packages/26/e5/065625317690ea3548d834dad81f48ea1fd32e4964610e658e195d7fe28e/tokenizers-0.23.3-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e05ab7baf7f47b406a95fea6f3b0a484b2ddcd9e1d14b68844c457eb755085a3", size = 10266026, upload-time = "2026-10-09T10:16:33.054Z" },
+ { url = "https://files.pythonhosted.org/packages/77/4e/babede85d0d19f5e3deeef0063e01848141329934d3d77c31b5cab5ac2b4/tokenizers-0.23.3-cp310-abi3-win32.whl", hash = "sha256:1ebf28794e7e4954e20a7f70fbea410b2d1f0418f7dbbca97ca384fcfef38c25", size = 2588086, upload-time = "2026-10-09T10:16:35.686Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/6c/24f074c9a0efb98e61b20aafe6b2641922d5db24e447d5d6daffd9e17555/tokenizers-0.23.3-cp310-abi3-win_amd64.whl", hash = "sha256:1f0823bb00c5fdc98e487354d54dd55a03848d61a1a0bf29a68c77f24f3b26c3", size = 2872101, upload-time = "2026-10-09T10:16:37.533Z" },
+ { url = "https://files.pythonhosted.org/packages/53/77/a476b6f73a661c11d113a342d2326b91506cf2285f0995d1212a6bb2022d/tokenizers-0.23.3-cp310-abi3-win_arm64.whl", hash = "sha256:7e48734d2de9260d86f03ab056d2cfeeff3869f61dbd49aaa15a2793b5f3458b", size = 2742580, upload-time = "2026-10-09T10:16:39.244Z" },
+ { url = "https://files.pythonhosted.org/packages/65/46/f66baaedd42414a3f583c47379dc350e3e1f858a690d2574fd85ae70681b/tokenizers-0.23.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:efa3d7318406b4d115dce61ad5061953f1f44b128e79c020ce4615d763e23b6e", size = 3154274, upload-time = "2026-10-09T10:16:40.876Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/41/8de8c63b2d935eee5a0f42011fb7b786ffafeab0b8eb6d17acb8af2293b7/tokenizers-0.23.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a4fbb3662f9f59d199d61338e54b4bcc11d07ebbb1aeb3540dacb2be9c521cb7", size = 3077805, upload-time = "2026-10-09T10:16:42.856Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/08/b1cbae8dc8fc7c91f992ac2d87a086e9b3f25a28814047ca16a82fe8c87b/tokenizers-0.23.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de536665495cb4b409d25bade41963f801aff4225c19a6b804b048f7d14e34c7", size = 3491678, upload-time = "2026-10-09T10:16:45.093Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/0d/aac0cb2f3a1fdbef514145b4c5f2df4d05deeb1ee8f73ae641a1b4a62a85/tokenizers-0.23.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cc24bb457dd4a8af89c8fcb40074d570129ec473df2a866c276ee55db4749d7", size = 3367420, upload-time = "2026-10-09T10:16:47.112Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/1d/41a697d0c193a320b243fbd68b2057b6eb2f01ecf80899e1a16e646ff699/tokenizers-0.23.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:acd5c57b4bd3e56e246e2731a3a3a6825a7a7d89b7e3b761ba80bc521710f04b", size = 9945973, upload-time = "2026-10-09T10:16:49.326Z" },
+ { url = "https://files.pythonhosted.org/packages/37/e9/b56e619fcd583000a2b1254bb46af8dc6a174d3ba3329f454ad5a95a2be2/tokenizers-0.23.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82eb480f6f1c21cea3349dec32cf1a6384c6c1e775f00f83b0d51197bc013687", size = 10237491, upload-time = "2026-10-09T10:16:51.943Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/68/f58b3beb95f3b62816e91e5e768e684cd63e58f9cbece22036dae3b1c971/tokenizers-0.23.3-cp314-cp314t-win_amd64.whl", hash = "sha256:1554a6eed34d9d6a78d23360f4e06df8dffab1ae08c7e8488e0b3e3b36cc266f", size = 2847654, upload-time = "2026-10-09T10:16:54.166Z" },
+]
+
[[package]]
name = "tomli"
version = "2.4.1"
@@ -735,6 +1288,27 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" },
]
+[[package]]
+name = "tqdm"
+version = "4.70.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0d/ea/b2a5bd54b28a324dae8211928b2d730b6547500342c7e6c6dea08bd0a485/tqdm-4.70.1.tar.gz", hash = "sha256:cefd0eca11b2a37a3aee776544d4f4ae913f02688135b5556b8788dfa474afc4", size = 171846, upload-time = "2026-09-11T07:25:16.601Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl", hash = "sha256:c293e525e6fef9c20e8728fd4612df02a0aa31bb5fe91ecd93e123b1b7bffa73", size = 80199, upload-time = "2026-09-11T07:25:14.599Z" },
+]
+
+[[package]]
+name = "truststore"
+version = "0.10.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/9f/c5201d42a484c061e528825fc8e2d565f5abd50a4ced6fb7d29c4ec99b2b/truststore-0.10.5.tar.gz", hash = "sha256:30d36967ccaded5cbb38d602c433f53600036c79d502f4533a49b60a03bbefcd", size = 28091, upload-time = "2026-10-12T22:27:31.808Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/e9/3a7820be2bb0fe53b6bc9c3be26d3d1158004e4c3ab953aa6840b955b1e9/truststore-0.10.5-py3-none-any.whl", hash = "sha256:9aaaedaefaf06d8b206278cf8b5012bc897f485a874503501e12d776df78951c", size = 19017, upload-time = "2026-10-12T22:27:30.377Z" },
+]
+
[[package]]
name = "typing-extensions"
version = "4.16.0"
@@ -750,6 +1324,7 @@ source = { editable = "." }
dependencies = [
{ name = "httpx" },
{ name = "keyring" },
+ { name = "opencc-python-reimplemented" },
{ name = "platformdirs" },
{ name = "pyside6" },
{ name = "python-dotenv" },
@@ -764,11 +1339,16 @@ dev = [
{ name = "pytest-cov" },
{ name = "ruff" },
]
+local-asr = [
+ { name = "faster-whisper" },
+]
[package.metadata]
requires-dist = [
+ { name = "faster-whisper", marker = "extra == 'local-asr'", specifier = "==1.2.1" },
{ name = "httpx", specifier = ">=0.27.2,<1" },
{ name = "keyring", specifier = ">=25.5,<26" },
+ { name = "opencc-python-reimplemented", specifier = "==0.1.7" },
{ name = "platformdirs", specifier = ">=4.3,<5" },
{ name = "pyinstaller", marker = "extra == 'build'", specifier = ">=6.11,<7" },
{ name = "pyside6", specifier = ">=6.8.2,<7" },
@@ -777,7 +1357,7 @@ requires-dist = [
{ name = "python-dotenv", specifier = ">=1.0.1,<2" },
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9,<1" },
]
-provides-extras = ["build", "dev"]
+provides-extras = ["build", "dev", "local-asr"]
[[package]]
name = "zipp"
diff --git a/app/video_companion/README.md b/app/video_companion/README.md
index 90ea31789..565f58e1d 100755
--- a/app/video_companion/README.md
+++ b/app/video_companion/README.md
@@ -16,6 +16,14 @@ npm run build
## 宿主契约
+截屏通过 `qtVideoBridge.captureScreenshot(region, callback)` 获取 QtWebEngine 实际渲染的视频区域,保留主画面裁切、本地小窗、镜像和可见控件。`region` 为包含 `x`、`y`、`width`、`height`、`viewportWidth`、`viewportHeight` 的 JSON,使用 CSS 像素;宿主处理窗口缩放与显示 DPI,并返回包含 `dataUrl` 或 `error` 的 JSON。
+
+截取仅生成内存预览,医生点击“确认并上传”后才调用 `saveScreenshot`。该功能需要同步更新桌面宿主与前端资源。
+
+预览显示后发送 `screenshot-preview` 通知(`visible: true/false`)。宿主将小窗临时放大到正常窗口尺寸,取消、提交或结束通话后恢复原位置和大小;先抓图再放大,避免改变截图内容。图片按预览区域等比例放大显示。
+
+打开诊单后的通话小窗,标题栏“×”用于恢复原大窗,通话与录音继续。结束视频、正常大窗关闭、退出登录及程序退出仍走完整的挂断和录音收尾流程。
+
页面加载后会暴露:
```ts
diff --git a/app/video_companion/dist/assets/index-BMSk91Wa.css b/app/video_companion/dist/assets/index-BMSk91Wa.css
deleted file mode 100755
index 583f49d13..000000000
--- a/app/video_companion/dist/assets/index-BMSk91Wa.css
+++ /dev/null
@@ -1 +0,0 @@
-:root{font-family:Microsoft YaHei UI,PingFang SC,Noto Sans CJK SC,system-ui,sans-serif;color:#132238;background:#eef3fb;font-synthesis:none;text-rendering:optimizeLegibility}*{box-sizing:border-box}html,body,#app{width:100%;height:100%;margin:0;overflow:hidden}button,textarea,input{font:inherit}button{cursor:pointer}button:disabled{cursor:not-allowed;opacity:.55}.consultation-shell{width:100%;height:100%;min-width:760px;min-height:540px;background:#eef3fb}.chat-panel{display:grid;grid-template-rows:74px minmax(0,1fr) auto;width:100%;height:100%;background:#f7f9fd}.chat-header{display:flex;align-items:center;gap:14px;padding:12px 20px;border-bottom:1px solid #d7dfef;background:#fffffff5}.patient-avatar{display:grid;place-items:center;width:44px;height:44px;border-radius:14px;color:#fff;background:#5267df;font-size:18px;font-weight:700}.chat-heading{min-width:0;flex:1}.chat-heading h1{margin:0;font-size:18px;line-height:1.4}.chat-heading p{display:flex;align-items:center;gap:7px;margin:3px 0 0;color:#71809a;font-size:12px}.connection-dot{width:7px;height:7px;border-radius:50%;background:#a3adbd}.connection-dot--online{background:#24a77c;box-shadow:0 0 0 3px #24a77c1f}.primary-action,.send-button,.capture-button{border:1px solid #5166df;border-radius:9px;color:#fff;background:#5267df;font-weight:600}.secondary-action{padding:9px 13px;border:1px solid #c8d2e7;border-radius:9px;color:#43526b;background:#fff;font-weight:600}.secondary-action:hover{border-color:#7385e9;color:#4055ca;background:#f5f7ff}.primary-action{display:flex;gap:8px;align-items:center;padding:10px 16px}.primary-action:hover,.send-button:hover,.capture-button:hover{background:#4055ca}.message-list{overflow-y:auto;padding:18px max(24px,calc((100% - 920px)/2));background:radial-gradient(circle at 12% 16%,rgba(82,103,223,.055),transparent 25%),#f3f6fb}.load-more{display:block;margin:0 auto 18px;padding:6px 12px;border:1px solid #d6deed;border-radius:999px;color:#66758e;background:#fff;font-size:12px}.empty-chat{display:grid;justify-items:center;margin-top:min(16vh,110px);color:#7c89a0;text-align:center}.empty-chat__icon{display:grid;place-items:center;width:62px;height:62px;margin-bottom:12px;border:1px solid #d2daeb;border-radius:20px;color:#5267df;background:#fff;font-weight:800}.empty-chat h2{margin:0;color:#34425a;font-size:17px}.empty-chat p{margin:7px 0;font-size:13px}.message-row{display:flex;flex-direction:column;align-items:flex-start;margin:12px 0}.message-row--mine{align-items:flex-end}.message-row--call-status{align-items:center;margin:16px 0}.call-status-event{display:inline-flex;align-items:center;gap:8px;min-height:32px;padding:0 12px;border:1px solid #dce2f2;border-radius:999px;color:#617092;background:#ffffffeb;font-size:12px;box-shadow:0 4px 14px #111f460a}.call-status-event__icon{display:grid;place-items:center;width:20px;height:20px;border-radius:7px;color:#5761f4;background:#eef0ff;font-size:11px}.call-status-event strong{color:#34425f;font-weight:700}.call-status-event time{color:#8b97b2;font-variant-numeric:tabular-nums}.call-status-event--connected{border-color:#bdebdc;background:#f2fbf7}.call-status-event--connected .call-status-event__icon{color:#11986f;background:#dff7ee}.call-status-event--failed{border-color:#f3c8cf;background:#fff5f6}.call-status-event--failed .call-status-event__icon{color:#c43f50;background:#ffe6e9}.message-meta{margin:0 8px 5px;color:#8995a9;font-size:11px}.message-bubble{max-width:min(72%,620px);padding:10px 13px;border:1px solid #d8e0ed;border-radius:5px 15px 15px;background:#fff;box-shadow:0 4px 14px #1d2f500d;line-height:1.6;word-break:break-word}.message-row--mine .message-bubble{border-color:#5267df;border-radius:15px 5px 15px 15px;color:#fff;background:#5267df}.message-bubble p{margin:0;white-space:pre-wrap}.message-image,.message-video{display:block;max-width:360px;max-height:280px;border-radius:9px}.message-file{display:flex;align-items:center;gap:8px;color:inherit;text-decoration:none}.message-bubble audio{max-width:320px}.composer{padding:10px 18px 14px;border-top:1px solid #d7dfef;background:#fff}.composer-toolbar{display:flex;align-items:center;justify-content:space-between;min-height:30px;color:#8a96a9;font-size:11px}.composer-toolbar button{padding:5px 9px;border:0;border-radius:7px;color:#5267df;background:#eef1ff;font-size:12px}.composer-row{display:grid;grid-template-columns:minmax(0,1fr) 86px;gap:12px}.composer textarea{width:100%;min-height:68px;max-height:150px;padding:10px 12px;resize:vertical;border:1px solid #ced8ea;border-radius:10px;outline:none;color:#15233a;background:#fbfcff;line-height:1.5}.composer textarea:focus{border-color:#6678ed;box-shadow:0 0 0 3px #5267df1c}.send-button{align-self:end;height:40px}.inline-notice{margin-bottom:7px;color:#3f6f62;font-size:12px}.inline-notice--error{color:#c14455}.video-layer{position:relative;display:grid;grid-template-columns:minmax(0,1fr);width:100%;height:100%;min-height:420px;overflow:hidden;color:#f7f8fa;background:radial-gradient(circle at 50% 35%,rgba(60,86,130,.28),transparent 38%),#090d14}.video-layer--with-rail{grid-template-columns:minmax(0,1fr) clamp(330px,31vw,380px)}.video-layer--overlay{position:fixed;z-index:1000;inset:0}.video-stage{position:relative;min-width:0;min-height:0;overflow:hidden;background:radial-gradient(circle at 50% 35%,rgba(60,86,130,.28),transparent 38%),#090d14}.call-kit,.video-layer :is(.TUICallKit-desktop,.TUICallKit-mobile,#tuicallkit-id){width:100%!important;height:100%!important;max-width:none!important;max-height:none!important}.status-card{position:absolute;inset:50% auto auto 50%;display:grid;grid-template-columns:12px minmax(0,1fr);gap:18px;width:min(520px,calc(100% - 48px));padding:30px 32px;transform:translate(-50%,-50%);border:1px solid rgba(255,255,255,.1);border-radius:20px;background:#131920eb;box-shadow:0 24px 70px #00000052}.eyebrow{margin:0 0 12px;color:#a3afbf;font-size:12px;font-weight:700;letter-spacing:.12em}.status-card h2{margin:0;font-size:clamp(22px,3.2vw,34px);font-weight:600;line-height:1.25}.status-hint{margin:14px 0 0;color:#9aa5b1;font-size:14px}.status-dot{width:10px;height:10px;margin-top:5px;border-radius:50%;background:#77818c;box-shadow:0 0 0 5px #77818c1f}.status-dot--starting,.status-dot--live{background:#52c99a;box-shadow:0 0 0 5px #52c99a24}.status-dot--error{background:#f26d6d;box-shadow:0 0 0 5px #f26d6d24}.live-status{position:absolute;z-index:20;top:18px;left:50%;display:flex;align-items:center;gap:10px;padding:9px 14px;transform:translate(-50%);border:1px solid rgba(255,255,255,.1);border-radius:999px;background:#0b0f14cc;font-size:13px}.live-status .status-dot{width:7px;height:7px;margin:0;box-shadow:none}.consultation-rail{position:relative;z-index:55;display:grid;grid-template-rows:auto minmax(0,1.08fr) minmax(0,.92fr);min-width:0;min-height:0;overflow:hidden;border-left:1px solid #dce3f0;color:#15233a;background:#f6f8fc;box-shadow:-16px 0 38px #040c1a29}.consultation-rail__header{display:grid;grid-template-columns:42px minmax(0,1fr) auto;gap:11px;align-items:center;min-height:74px;padding:13px 16px;border-bottom:1px solid #e2e7f1;background:#fff}.consultation-rail__avatar{display:grid;place-items:center;width:42px;height:42px;border-radius:13px;color:#fff;background:#5761f4;font-size:17px;font-weight:700}.consultation-rail__identity{display:grid;gap:3px;min-width:0}.consultation-rail__identity strong{overflow:hidden;color:#111f46;font-size:16px;line-height:1.3;text-overflow:ellipsis;white-space:nowrap}.consultation-rail__identity span{overflow:hidden;color:#7886a3;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.diagnosis-chip{padding:5px 7px;border-radius:6px;color:#4a56d5;background:#eef0ff;font-size:10px;font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}.consultation-rail__actions{display:grid;flex:0 0 auto;justify-items:end;gap:5px}.open-diagnosis-button{display:inline-flex;align-items:center;gap:4px;min-height:28px;padding:5px 8px;border:1px solid #cfd5ff;border-radius:7px;color:#3f4bc5;background:#fff;font-size:11px;font-weight:700;white-space:nowrap}.open-diagnosis-button:hover,.open-diagnosis-button:focus-visible{border-color:#6874e7;background:#f3f4ff;outline:none}.open-diagnosis-button:disabled{cursor:not-allowed;opacity:.55}.case-panel,.transcript-panel{display:grid;grid-template-rows:auto minmax(0,1fr);min-height:0;overflow:hidden}.case-panel{border-bottom:1px solid #dde4f0}.rail-section-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:48px;padding:10px 16px;border-bottom:1px solid #e5e9f2;background:#ffffffb8}.rail-section-heading>div{display:flex;align-items:center;gap:8px}.rail-section-heading h2{margin:0;color:#1b2945;font-size:14px;font-weight:700;letter-spacing:-.01em}.rail-section-heading>span{overflow:hidden;max-width:154px;color:#8b97ad;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.rail-section-heading__index{color:#6874e7;font-family:Cascadia Mono,SFMono-Regular,Consolas,monospace;font-size:10px;font-weight:700}.case-panel__content,.live-captions{min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-color:#b9c3d5 transparent;scrollbar-width:thin}.case-panel__content{padding:5px 16px 14px}.case-field-list{display:grid}.case-field{display:grid;grid-template-columns:72px minmax(0,1fr);gap:10px;padding:10px 0;border-bottom:1px solid #e5e9f2}.case-field:last-child{border-bottom:0}.case-field>span{padding-top:2px;color:#7a879d;font-size:11px;font-weight:600}.case-field p{margin:0;color:#263551;font-size:12px;line-height:1.55;overflow-wrap:anywhere;white-space:pre-wrap}.case-field--risk>span{color:#bc3e4e}.case-field--risk p{color:#9f3141;font-weight:600}.live-captions{display:grid;align-content:start;gap:9px;padding:12px 14px 18px;background:#f2f5fa}.caption-entry{padding:10px 11px;border-left:2px solid #6571e8;border-radius:0 9px 9px 0;background:#fff;box-shadow:0 4px 14px #1e2e4c0b}.caption-entry--partial{border-left-color:#9ca6b7;opacity:.78}.caption-entry header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:5px}.caption-entry strong{color:#4a56d5;font-size:11px}.caption-entry time{color:#9aa5b7;font-size:10px;font-variant-numeric:tabular-nums}.caption-entry p{margin:0;color:#24334e;font-size:13px;line-height:1.58;overflow-wrap:anywhere;white-space:pre-wrap}.transcript-state{position:relative;padding-left:12px}.transcript-state:before{position:absolute;top:50%;left:0;width:6px;height:6px;transform:translateY(-50%);border-radius:50%;background:#a5adbb;content:""}.transcript-state--active{color:#168260!important}.transcript-state--active:before{background:#24b987;box-shadow:0 0 0 3px #24b9871f}.rail-empty{display:grid;gap:5px;align-content:center;min-height:112px;padding:18px;color:#8a96aa;text-align:center}.rail-empty strong{color:#53617a;font-size:12px}.rail-empty span{font-size:11px;line-height:1.55}.rail-empty--case{min-height:100%}.video-actions{position:absolute;z-index:40;right:22px;bottom:24px;display:flex;gap:10px}.video-actions button{padding:10px 15px;border-radius:10px;font-weight:600}.recording-status{display:inline-flex;align-items:center;gap:8px;padding:10px 15px;border:1px solid rgba(255,255,255,.24);border-radius:10px;color:#fff;background:#161d27e0;font-size:13px;font-weight:600}.recording-status--active{border-color:#f46373a3;background:#7e2332e6}.recording-status--error{border-color:#f26d6d8f;color:#ffe4e7;background:#641f28e0}.recording-indicator{width:9px;height:9px;border-radius:50%;background:#f46373;box-shadow:0 0 0 4px #f4637329}.recording-status--active .recording-indicator{animation:recording-pulse 1.25s ease-in-out infinite}@keyframes recording-pulse{50%{box-shadow:0 0 0 8px #f463730a;opacity:.72}}.hangup-button{border:1px solid #b44755;color:#fff;background:#a12f3de6}.hangup-button:hover{background:#be394d}.video-notice{position:absolute;z-index:40;left:22px;bottom:26px;max-width:calc(100% - 420px);padding:9px 12px;border:1px solid rgba(82,201,154,.35);border-radius:9px;color:#d9f8eb;background:#144e3ed6;font-size:13px}.video-notice--error{border-color:#f26d6d66;color:#ffe4e7;background:#641f28e0}.screenshot-dialog-backdrop{position:absolute;z-index:120;inset:0;display:grid;place-items:center;padding:24px;background:#070b13c2;backdrop-filter:blur(5px)}.screenshot-dialog{display:grid;grid-template-rows:auto minmax(0,1fr) auto auto;gap:14px;width:min(920px,92vw);max-height:calc(100vh - 48px);padding:20px;overflow:hidden;border:1px solid #e2e7f4;border-radius:18px;color:#111f46;background:#fff;box-shadow:0 28px 90px #040a1b57}.screenshot-dialog>header,.screenshot-dialog>footer{display:flex;align-items:center;justify-content:space-between;gap:16px}.screenshot-dialog h2{margin:2px 0 0;font-size:20px;line-height:1.35}.screenshot-dialog .eyebrow{margin:0;color:#5761f4}.screenshot-dialog>header>button{width:36px;height:36px;border:0;border-radius:9px;color:#7886aa;background:#f2f4fb;font-size:24px}.screenshot-preview-frame{display:grid;place-items:center;min-height:260px;overflow:hidden;border-radius:12px;background:#0b0f16}.screenshot-preview-frame img{display:block;max-width:100%;max-height:min(62vh,650px);object-fit:contain}.screenshot-dialog__hint{margin:0;color:#617092;font-size:13px}.screenshot-dialog>footer{justify-content:flex-end}.screenshot-dialog>footer button{min-width:112px;padding:10px 18px;border-radius:9px;font-weight:700}.screenshot-cancel{border:1px solid #dfe4f1;color:#3f4e75;background:#fff}.screenshot-confirm{border:1px solid #5761f4;color:#fff;background:#5761f4}.screenshot-confirm:hover{background:#4c57e9}@media (max-width: 820px){.consultation-shell{min-width:620px}.message-list{padding-inline:18px}.message-bubble{max-width:82%}}@media (max-width: 980px){.consultation-shell{min-width:760px}.video-layer--with-rail{grid-template-columns:minmax(0,1fr) 310px}.video-actions{right:12px;bottom:14px;left:12px;flex-wrap:wrap;justify-content:flex-end}.recording-status{flex-basis:100%;width:fit-content;margin-left:auto;font-size:11px}.consultation-rail__header{padding-inline:12px}.diagnosis-chip{display:none}.case-panel__content,.rail-section-heading{padding-inline:12px}}@media (max-width: 700px){.consultation-shell{min-width:0}.video-layer,.video-stage{min-height:280px}.video-layer--with-rail{grid-template-columns:minmax(0,1fr)}.consultation-rail{display:none}.video-actions{right:10px;bottom:10px;left:auto;gap:6px}.recording-status,.capture-button{display:none}.video-actions button{padding:8px 11px;border-radius:8px;font-size:11px}.live-status{top:10px;padding:7px 10px;font-size:11px}}:root{color:#111f46;background:#eef3fd}.consultation-shell{background:#eef3fd}.chat-panel{background:#f7f9fe}.chat-header,.composer{border-color:#e6eaf5;background:#fffffffa}.patient-avatar{background:linear-gradient(135deg,#5761f4,#7769f7)}.chat-heading p,.empty-chat,.message-meta,.composer-toolbar{color:#7886aa}.connection-dot--online{background:#17a77d;box-shadow:0 0 0 3px #17a77d1f}.primary-action,.send-button,.capture-button{border-color:#5761f4;background:linear-gradient(90deg,#5761f4,#7769f7)}.primary-action:hover,.send-button:hover,.capture-button:hover{background:#4c57e9}.secondary-action{border-color:#e6eaf5;color:#3f4e75}.secondary-action:hover{border-color:#5761f4;color:#4451e2;background:#f0f2ff}.message-list{background:radial-gradient(circle at 12% 16%,rgba(87,97,244,.055),transparent 25%),#f7f9fe}.load-more,.empty-chat__icon,.message-bubble{border-color:#e6eaf5}.load-more{color:#7886aa}.empty-chat__icon{color:#5761f4}.empty-chat h2{color:#111f46}.message-bubble{box-shadow:0 4px 14px #111f460d}.message-row--mine .message-bubble{border-color:#5761f4;background:#5761f4}.composer-toolbar button{color:#4451e2;background:#f0f2ff}.composer textarea{border-color:#e6eaf5;color:#111f46;background:#fafbfe}.composer textarea:focus{border-color:#8d9bff;box-shadow:0 0 0 3px #5761f41c}.video-actions button{border-radius:9px}.recording-status{border-color:#e6eaf5e0;border-radius:9px;color:#3f4e75;background:#fffffff2}.recording-status--active,.recording-status--error{border-color:#f15b6773;color:#b63849;background:#fff1f3f5}.recording-indicator{background:#f15b67;box-shadow:0 0 0 4px #f15b6729}@keyframes recording-pulse{50%{box-shadow:0 0 0 8px #f15b670a;opacity:.72}}.hangup-button{border-color:#f15b67;background:#f15b67}.hangup-button:hover{background:#d94857}.video-notice{border-color:#17a77d59;color:#12765b;background:#eaf9f3f2}.video-notice--error{border-color:#f15b6766;color:#b63849;background:#fff1f3f5}
diff --git a/app/video_companion/dist/assets/index-CNqfE3p9.js b/app/video_companion/dist/assets/index-CTyzVIZB.js
similarity index 55%
rename from app/video_companion/dist/assets/index-CNqfE3p9.js
rename to app/video_companion/dist/assets/index-CTyzVIZB.js
index 1df8c941d..ff8f0596b 100755
--- a/app/video_companion/dist/assets/index-CNqfE3p9.js
+++ b/app/video_companion/dist/assets/index-CTyzVIZB.js
@@ -1,4 +1,4 @@
-(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const I of document.querySelectorAll('link[rel="modulepreload"]'))l(I);new MutationObserver(I=>{for(const h of I)if(h.type==="childList")for(const f of h.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&l(f)}).observe(document,{childList:!0,subtree:!0});function r(I){const h={};return I.integrity&&(h.integrity=I.integrity),I.referrerPolicy&&(h.referrerPolicy=I.referrerPolicy),I.crossOrigin==="use-credentials"?h.credentials="include":I.crossOrigin==="anonymous"?h.credentials="omit":h.credentials="same-origin",h}function l(I){if(I.ep)return;I.ep=!0;const h=r(I);fetch(I.href,h)}})();var mg=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function yW(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function kU(t){if(t.__esModule)return t;var i=t.default;if(typeof i=="function"){var r=function l(){return this instanceof l?Reflect.construct(i,arguments,this.constructor):i.apply(this,arguments)};r.prototype=i.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(t).forEach(function(l){var I=Object.getOwnPropertyDescriptor(t,l);Object.defineProperty(r,l,I.get?I:{enumerable:!0,get:function(){return t[l]}})}),r}var z1={exports:{}},HoA=z1.exports,n8;function qoA(){return n8||(n8=1,function(t,i){(function(r,l){t.exports=l()})(HoA,function(){const r=s=>s===void 0,l=s=>typeof s=="string",I=s=>{var n;return(n=Object.prototype.toString.call(s).match(/^\[object (.*)\]$/))===null||n===void 0?void 0:n[1].toLowerCase()},h=s=>typeof Array.isArray=="function"?Array.isArray(s):I(s)==="array",f=s=>s!==null&&typeof s=="object",w=s=>h(s)||f(s),_=s=>{if(typeof s!="string")return!1;const n=s[0];return!/[^a-zA-Z0-9]/.test(n)},b=s=>{if(typeof s!="object"||s===null)return!1;const n=Object.getPrototypeOf(s);if(n===null)return!0;let g=n;for(;Object.getPrototypeOf(g)!==null;)g=Object.getPrototypeOf(g);return n===g};function U(s=99999999){return Math.round(Math.random()*s)}const j=(s,n,g,u)=>{if(!w(s)||!w(n))return 0;let E=0;const m=Object.keys(n);let D;for(let M=0,T=m.length;M"u"&&typeof uni.requireNativePlugin=="function",io=ut&&typeof wx.miniapp=="object",Eo=typeof uni<"u",Vs=_e&&typeof tt.enterChat=="function",ki=ut||XA||_e||Ut||gi||To||Fi,ns=typeof window>"u"&&!ki&&typeof mg<"u"&&mg.NativeScriptGlobals!==void 0,jo=typeof mg<"u"&&(mg.nativeModuleProxy!==void 0||mg.ReactNative!==void 0),Ao=typeof wx<"u"&&typeof wx.getAccountInfoSync=="function"&&!!wx.getAccountInfoSync().plugin,zt=typeof uni<"u"?!ki:typeof window<"u"&&!ki&&!jo,oo=XA?qq:_e?tt:Ut?swan:gi?my:ut?wx:To?uni:Fi?jd:{},bi=zt&&window&&window.navigator&&window.navigator.userAgent||"",vs=/(micromessenger|webbrowser)/i.test(bi),HA=function(){let s="WEB";return vs?s="WEB":XA?s="QQ_MP":_e?s="TT_MP":Ut?s="BAIDU_MP":gi?s="ALI_MP":ut?s=io?"DONUT_NATIVE_APP":"WX_MP":To?s="UNI_NATIVE_APP":ns?s="NS_NATIVE_APP":jo&&(s="RN_NATIVE_APP"),nA[s]}(),le=/iPad/i.test(bi),Ve=/iPhone/i.test(bi)&&!le,Ft=/iPod/i.test(bi),nt=Ve||le||Ft,It=function(){const s=bi.match(/OS (\d+)_/i);return s&&s[1]?s[1]:null}(),Ai=/Android/i.test(bi),ei=function(){const s=bi.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);if(!s)return null;const n=s[1]&&parseFloat(s[1]),g=s[2]&&parseFloat(s[2]);return n&&g?parseFloat(`${s[1]}.${s[2]}`):n||null}(),ke=/Firefox/i.test(bi),Ze=/Edge/i.test(bi),vt=!Ze&&/Chrome/i.test(bi),_t=/MSIE/.test(bi)||bi.indexOf("Trident")>-1&&bi.indexOf("rv:11.0")>-1,Oi=function(){const s=/MSIE\s(\d+)\.\d/.exec(bi);let n=s&&parseFloat(s[1]);return!n&&/Trident\/7.0/i.test(bi)&&/rv:11.0/.test(bi)&&(n=11),n}(),po=/Safari/i.test(bi)&&!vt&&!Ai&&!Ze,No=/Windows/i.test(bi),so=/MAC OS X/i.test(bi),Go=zt&&typeof Worker<"u"&&!_t,An=Ai||nt,rn=function(){if(typeof window>"u"||window.navigator===void 0)return!1;const{standalone:s}=window.navigator;return!(!nt||s||po)}();function Es(){let s="unknown";if(so&&(s="mac"),No&&(s="windows"),nt&&(s="ios"),Ai&&(s="android"),ki)try{const{platform:n}=oo.getSystemInfoSync();n!==void 0&&(s=n)}catch(n){console.error(n)}return s}const an=typeof process<"u"&&process.versions!==void 0&&process.versions.node!==void 0&&typeof window>"u";function Do(s,n){var g={};for(var u in s)Object.prototype.hasOwnProperty.call(s,u)&&n.indexOf(u)<0&&(g[u]=s[u]);if(s!=null&&typeof Object.getOwnPropertySymbols=="function"){var E=0;for(u=Object.getOwnPropertySymbols(s);E{oo.request({url:g,data:u,method:n,timeout:E,header:{"content-type":zr},success:M=>m(M.data),fail:()=>D(new Error(`{"message":"Network error","code":${Jn}}`))})}):an?void 0:new Promise((m,D)=>{const M=new XMLHttpRequest,T=setTimeout(()=>{M.abort(),D(new Error(`{"message":"Request timeout","code":${Qr}}`))},E);M.onreadystatechange=function(){if(M.readyState===4)if(clearTimeout(T),M.status===200||M.status===304)try{m(M.responseText?JSON.parse(M.responseText):null)}catch{m(M.responseText)}else D(new Error(`{"message":"Network error","code":${Jn}}`))},M.open(n,g,!0),M.setRequestHeader("Content-type",zr),M.send(u||null)})})}function Rs(s){if(s==null)return!0;if(typeof s=="boolean")return!1;if(typeof s=="number")return s===0;if(typeof s=="string"||typeof s=="function"||Array.isArray(s))return s.length===0;if(s instanceof Error)return s.message==="";if(b(s)){for(const n in s)if(Object.prototype.hasOwnProperty.call(s,n))return!1;return!0}return(Object.prototype.toString.call(s)==="[object Map]"||Object.prototype.toString.call(s)==="[object Set]"||Object.prototype.toString.call(s)==="[object File]")&&s.size===0}function or(s,n){if(s===null||typeof s!="object")return s;const g=n||new WeakMap;if(g.has(s))return g.get(s);if(s instanceof Date)return new Date(s.getTime());if(s instanceof RegExp)return new RegExp(s.source,s.flags);if(s instanceof Map){const m=new Map;return g.set(s,m),s.forEach((D,M)=>{m.set(or(M,g),or(D,g))}),m}if(s instanceof Set){const m=new Set;return g.set(s,m),s.forEach(D=>{m.add(or(D,g))}),m}if(Array.isArray(s)){const m=[];return g.set(s,m),s.forEach(D=>{m.push(or(D,g))}),m}const u=Object.getPrototypeOf(s),E=Object.create(u);return g.set(s,E),[...Object.getOwnPropertyNames(s),...Object.getOwnPropertySymbols(s)].forEach(m=>{if(m==="__ob__"||m==="__v_skip"||m==="__v_isRef"||m==="__v_isReadonly")return;const D=Object.getOwnPropertyDescriptor(s,m);D&&(D.get||D.set?Object.defineProperty(E,m,D):E[m]=or(s[m],g))}),E}function en(s,n,g){const u=new WeakSet,E=(m,D)=>{if(n&&(D=n(m,D)),D===void 0)return"undefined";if(D===null)return null;if(Number.isNaN(D))return"NaN";if(D===1/0)return"Infinity";if(D===-1/0)return"-Infinity";if(typeof D=="function")return`[Function: ${D.name||"anonymous"}]`;if(typeof D=="symbol")return D.toString();if(typeof D=="bigint")return`${D.toString()}n`;if(typeof D=="object"&&D!==null){if(u.has(D))return"[Circular]";u.add(D)}return D instanceof Date?D.toISOString():D instanceof Error?{name:D.name,message:D.message}:D instanceof Map?{dataType:"Map",value:Array.from(D.entries())}:D instanceof Set?{dataType:"Set",value:Array.from(D.values())}:D};try{return JSON.stringify(s,E,g)}catch(m){return console.error("Failed to stringify:",m),""}}function wn(){let s,n;return{promise:new Promise((g,u)=>{s=g,n=u}),resolve:s,reject:n}}var Ht,yg=Object.freeze({__proto__:null,ANDROID_VERSION:ei,IE_VERSION:Oi,IN_ALIPAY_MINI_APP:gi,IN_BAIDU_MINI_APP:Ut,IN_BROWSER:zt,IN_DONUT_NATIVE_APP:io,IN_FEISHU_MINI_APP:Vs,IN_JD_MINI_APP:Fi,IN_MINI_APP:ki,IN_NODE:an,IN_NS_NATIVE_APP:ns,IN_QQ_MINI_APP:XA,IN_RN_APP:jo,IN_TT_MINI_APP:_e,IN_TT_MINI_GAME:je,IN_UNI_APP:Eo,IN_UNI_NATIVE_APP:To,IN_WX_MINI_APP:ut,IN_WX_MINI_APP_DESK:Kt,IN_WX_MINI_GAME:ge,IN_WX_MINI_PLUGIN:Ao,IOS_VERSION:It,IS_ANDROID:Ai,IS_CHROME:vt,IS_EDGE:Ze,IS_FIREFOX:ke,IS_IE:_t,IS_IOS:nt,IS_IPAD:le,IS_IPHONE:Ve,IS_IPOD:Ft,IS_MAC:so,IS_SAFARI:po,IS_WECHAT:vs,IS_WIN:No,IS_WORKER_AVAILABLE:Go,MINI_APP_NAMESPACE:oo,USER_AGENT:bi,base16EncodeBinaryString:IA,deepCopyWithMethods:or,deepMerge:j,generatePromise:wn,getPlatformType:Es,getType:I,httpRequest:Pi,isArray:h,isArrayOrObject:w,isEmpty:Rs,isH5:An,isIOSWebView:rn,isNumber:s=>s!==null&&(typeof s=="number"&&!Number.isNaN(s-0)||typeof s=="object"&&s.constructor===Number),isObject:f,isPlainObject:b,isString:l,isUndefined:r,isUniIOSApp:function(){return To&&uni.getDeviceInfo().platform.toLocaleLowerCase()==="ios"},isValidRequestKey:_,platform:HA,randomInt:U,randomString:function(){const s="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";let n="";for(let g=32;g>0;--g)n+=s[Math.floor(62*Math.random())];return n},safeStringify:en});class On{constructor(){this.listeners={}}on(n,g,u){this.listeners[n]||(this.listeners[n]=[]),this.listeners[n].push({fn:g,context:u})}off(n,g,u){var E;g&&(this.listeners[n]=(E=this.listeners[n])===null||E===void 0?void 0:E.filter(m=>{const D=m.fn===g,M=!u||m.context===u;return!(D&&M)}))}emit(n,...g){const u=this.listeners[n];u&&u.forEach(E=>{const{fn:m,context:D}=E;try{m.apply(D,g)}catch(M){console.warn(`Error in event handler for ${n} error: ${en(M)}`)}})}once(n,g,u){const E=(...m)=>{g.apply(u,m),this.off(n,E)};this.on(n,E)}}(function(s){s.BUSINESS_COMMAND="business_command",s.C2C_REALTIME_MESSAGE="c2c_realtime_message",s.C2C_MESSAGE_MODIFIED="c2c_message_modified",s.C2C_REVOKED_MESSAGE="c2c_message_revoked",s.GROUP_REALTIME_MESSAGE="group_realtime_message",s.GROUP_MESSAGE_MODIFIED="group_message_modified",s.GROUP_MESSAGE_REVOKED="group_message_revoked",s.C2C_MESSAGE_READ_RECEIPT="c2c_message_read_receipt",s.MESSAGE_REACTION_UPDATED="message_reaction_updated",s.MESSAGE_REACTION_UPDATED_SYNC="message_reaction_updated_sync",s.GROUP_AT_TIPS="group_at_tips",s.USER_STATUS_UPDATE="user_status_update",s.FRIEND_LIST_MODIFIED="friend_list_modified",s.PROFILE_MODIFIED="profile_modified",s.CONV_MODIFIED="conversation_modified",s.GROUP_TIPS_NOTIFICATION="group_tips_notification",s.GROUP_MESSAGE_READ_RECEIPT="group_message_read_receipt",s.GROUP_MESSAGE_READ_SYNC="group_message_read_sync",s.GROUP_SYSTEM_NOTIFICATION="group_system_notification",s.C2C_MESSAGE_PEER_READ="c2c_message_peer_read",s.C2C_MESSAGE_READ_SYNC="c2c_message_read_sync",s.C2C_REMIND_TYPE_SYNC="c2c_remind_type_sync",s.FOLLOW_LIST_UPDATED="follow_list_updated",s.MESSAGE_EXTENSIONS_UPDATED="message_extensions_updated",s.ALL_MESSAGE_READ="all_message_read",s.CONVERSATION_MARK_UPDATED="conversation_mark_updated",s.CONVERSATION_GROUP_ADD="conversation_group_add",s.CONVERSATION_GROUP_DELETED="conversation_group_deleted",s.CONVERSATION_GROUP_UPDATED="conversation_group_updated",s.ALL_RECEIVE_MESSAGE_OPTION="all_receive_message_option",s.TOPIC_AT_TIPS="topic_at_tips",s.TOPIC_TIPS_NOTIFICATION="topic_tips_notification",s.TOPIC_SYSTEM_NOTIFICATION="topic_system_notification",s.TOPIC_MESSAGE_READ_SYNC="topic_message_read_sync",s.TOPIC_LATEST_MESSAGE="topic_latest_message",s.GROUP_MESSAGE_PINNED="group_message_pinned"})(Ht||(Ht={}));const Gn=[16,17];function Js(s){var n;const g=[];return(n=s?.GroupTips)===null||n===void 0||n.forEach(u=>{var E;u.GroupInfo.MillionGroupFlag===2?g.push(Ht.TOPIC_TIPS_NOTIFICATION):Gn.includes((E=u?.MsgBody)===null||E===void 0?void 0:E.OpType)?g.push(Ht.GROUP_MESSAGE_PINNED):g.push(Ht.GROUP_TIPS_NOTIFICATION)}),g}const pr=[{conditions:[{type:"event",value:100}],subType:Ht.BUSINESS_COMMAND},{conditions:[{type:"event",value:24}],subType:Ht.ALL_RECEIVE_MESSAGE_OPTION},{conditions:[{type:"event",value:26}],subType:Ht.TOPIC_LATEST_MESSAGE},{conditions:[{type:"hasKey",value:"C2cMsgArray"}],subType:Ht.C2C_REALTIME_MESSAGE},{conditions:[{type:"hasKey",value:"C2cMsgModNotifys"}],subType:Ht.C2C_MESSAGE_MODIFIED},{conditions:[{type:"hasKey",value:"ProfileDataMod"}],subType:Ht.PROFILE_MODIFIED},{conditions:[{type:"hasKey",value:"UserStatusList"}],subType:Ht.USER_STATUS_UPDATE},{conditions:[{type:"hasKey",value:"FriendListMod"}],subType:Ht.FRIEND_LIST_MODIFIED},{conditions:[{type:"hasKey",value:"GroupMsgArray"}],subType:Ht.GROUP_REALTIME_MESSAGE},{conditions:[{type:"hasKey",value:"GroupMsgModNotifys"}],subType:Ht.GROUP_MESSAGE_MODIFIED},{conditions:[{type:"hasKey",value:"C2cNotifyMsgArray"}],subTypeParser:function(s){var n;const g=[];return(n=s?.C2cNotifyMsgArray)===null||n===void 0||n.forEach(u=>{u.WithdrawC2cMsgNotify&&g.push(Ht.C2C_REVOKED_MESSAGE),u.C2cReadedReceipt&&g.push(Ht.C2C_MESSAGE_PEER_READ),u.ReadC2cMsgNotify&&g.push(Ht.C2C_MESSAGE_READ_SYNC),u.MuteNotificationsSync&&g.push(Ht.C2C_REMIND_TYPE_SYNC)}),g}},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:4}],subTypeParser:Js},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:5}],subTypeParser:function(s){var n;const g=[];return(n=s?.GroupTips)===null||n===void 0||n.forEach(u=>{Array.isArray(u.MsgBody.GroupWithdrawInfoArray)?g.push(Ht.GROUP_MESSAGE_REVOKED):Array.isArray(u.MsgBody.GroupMsgReceiptList)?g.push(Ht.GROUP_MESSAGE_READ_RECEIPT):Array.isArray(u.MsgBody.GroupReadInfoArray)?u.MsgBody.GroupReadInfoArray[0].TopicId?g.push(Ht.TOPIC_MESSAGE_READ_SYNC):g.push(Ht.GROUP_MESSAGE_READ_SYNC):u.GroupInfo.MillionGroupFlag===2?g.push(Ht.TOPIC_SYSTEM_NOTIFICATION):g.push(Ht.GROUP_SYSTEM_NOTIFICATION)}),g}},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:6}],subTypeParser:Js},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:12}],subTypeParser:function(s){var n;const g=[];return(n=s?.GroupTips)===null||n===void 0||n.forEach(u=>{const{GroupAtTips:{TopicId:E}}=u;E?g.push(Ht.TOPIC_AT_TIPS):g.push(Ht.GROUP_AT_TIPS)}),g}},{conditions:[{type:"hasKey",value:"RecentContactMod"}],subTypeParser:function(s){var n;const g=[];return(n=s?.RecentContactMod)===null||n===void 0||n.forEach(u=>{switch(u.PushType){case ze.CONV_MARK_UPDATED:g.push(Ht.CONVERSATION_MARK_UPDATED);break;case ze.CONV_GROUP_ADDED:g.push(Ht.CONVERSATION_GROUP_ADD);break;case ze.CONV_GROUP_DELETED:g.push(Ht.CONVERSATION_GROUP_DELETED);break;case ze.CONV_GROUP_UPDATED:g.push(Ht.CONVERSATION_GROUP_UPDATED);break;default:g.push(Ht.CONV_MODIFIED)}}),g}},{conditions:[{type:"hasKey",value:"MsgReactionNotifyList"}],subType:Ht.MESSAGE_REACTION_UPDATED},{conditions:[{type:"hasKey",value:"MsgReactionNotify"}],subType:Ht.MESSAGE_REACTION_UPDATED_SYNC},{conditions:[{type:"hasKey",value:"C2cMsgInfo"}],subType:Ht.C2C_MESSAGE_READ_RECEIPT},{conditions:[{type:"hasKey",value:"FollowChangeList"}],subType:Ht.FOLLOW_LIST_UPDATED},{conditions:[{type:"hasKey",value:"MsgExtensionNotify"}],subType:Ht.MESSAGE_EXTENSIONS_UPDATED},{conditions:[{type:"hasKey",value:"C2CReadAllMsg"}],subType:Ht.ALL_MESSAGE_READ}];var Pn;function mr(s){var n;const g=Array.isArray((n=s?.body)===null||n===void 0?void 0:n.EventArray)?s.body.EventArray:[],u=[];return g.forEach(E=>{E.Flag=s.body.Flag;const m=pr.find(M=>M.conditions.every(T=>{switch(T.type){case"event":return E.Event===T.value;case"hasKey":return Object.prototype.hasOwnProperty.call(E,T.value);default:return!1}}));if(!m)return null;let D=[];typeof m.subTypeParser=="function"?D=m.subTypeParser(E):m.subType&&(D=m.subType),Array.isArray(D)?D.forEach(M=>{u.push({type:`${Pn.SERVER_PUSH_MESSAGE}:${M}`,data:E})}):u.push({type:`${Pn.SERVER_PUSH_MESSAGE}:${D}`,data:E})}),u}(function(s){s.SERVER_PUSH_MESSAGE="im_open_push.msg_push",s.SERVER_PUSH_MESSAGE_MULTIPLE="im_open_push.multi_msg_push_ws",s.ERROR="error"})(Pn||(Pn={}));const mo={[Pn.SERVER_PUSH_MESSAGE]:mr,[Pn.SERVER_PUSH_MESSAGE_MULTIPLE]:mr,[Pn.ERROR]:function(s){const{errorCode:n}=s;return[{type:`error:${n}`,data:s}]}},gn=new class{constructor(){this._outerEventEmitter=null,this._innerEventEmitter=null,this._filteredCallbackMap=new Map,this._outerEventEmitter=new On,this._innerEventEmitter=new On,this.InnerEventSubType=Ht}subscribeInnerEvent(s,n,g,u,E){var m;let D,M,T,P;["string","number"].includes(typeof n)?(T=`${s}:${n}`,P=g,M=u,D=E):(T=s,P=n,M=g,D=typeof u=="function"?u:void 0),D?this._subscribeWithFilter(T,P,M,D):(m=this._innerEventEmitter)===null||m===void 0||m.on(T,P,M)}emitInnerEvent(s,n){var g,u;if((g=this._innerEventEmitter)===null||g===void 0||g.emit(s,n),Object.keys(mo).includes(s)){const E=(u=mo[s])===null||u===void 0?void 0:u.call(mo,n);E?.forEach(m=>{var D;m&&((D=this._innerEventEmitter)===null||D===void 0||D.emit(m.type,m.data))})}}subscribeOuterEvent(s,n,g){var u;(u=this._outerEventEmitter)===null||u===void 0||u.on(s,n,g)}unSubscribeOuterEvent(s,n,g){var u;(u=this._outerEventEmitter)===null||u===void 0||u.off(s,n,g)}unSubscribeInnerEvent(s,n,g,u){if(["string","number"].includes(typeof n)){const E=g,m=`${s}:${n}`;this._unsubscribeEvent(m,E,u)}else{const E=n;this._unsubscribeEvent(s,E,g)}}emitOuterEvent(s,n){var g;(g=this._outerEventEmitter)===null||g===void 0||g.emit(s,n)}getOuterEventEmitter(){return this._outerEventEmitter}rest(){this._outerEventEmitter=null,this._innerEventEmitter=null}_subscribeWithFilter(s,n,g,u){var E;const m=D=>{u.call(g,D)&&n.call(g,D)};this._filteredCallbackMap.has(s)||this._filteredCallbackMap.set(s,[]),this._filteredCallbackMap.get(s).push({originalCallback:n,filteredCallback:m,filter:u,context:g}),(E=this._innerEventEmitter)===null||E===void 0||E.on(s,m,g)}_unsubscribeEvent(s,n,g){var u,E;const m=this._filteredCallbackMap.get(s);if(m){const D=m.findIndex(M=>M.originalCallback===n&&M.context===g);if(D!==-1){const{filteredCallback:M}=m[D];return(u=this._innerEventEmitter)===null||u===void 0||u.off(s,M,g),m.splice(D,1),void(m.length===0&&this._filteredCallbackMap.delete(s))}}(E=this._innerEventEmitter)===null||E===void 0||E.off(s,n,g)}};class Sl{constructor(){this._socket=null}connectSocket(n){return this._socket=new WebSocket(n),this._socket}send(n){var g,u;try{(g=this._socket)===null||g===void 0||g.send(n)}catch(E){(u=this._onSendFail)===null||u===void 0||u.call(this,E)}}bindSocketHandlers(n){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=n;this._socket&&(this._socket.binaryType="arraybuffer",this._socket.onopen=g,this._socket.onmessage=u,this._socket.onclose=E,this._socket.onerror=m,this._onSendFail=D)}unbindSocketHandlers(){this._socket&&(this._socket.onopen=null,this._socket.onmessage=null,this._socket.onclose=null,this._socket.onerror=null)}disconnect(){this._socket&&(this._socket.close(),this._socket=null)}}class cn{constructor(n){this._onError=n.onError}connectSocket(n){const g=this;return this._socket=oo.connectSocket({url:n,header:{"content-type":"application/json"},complete:()=>{},fail:u=>g._onError(u)}),this._socket}send(n){var g;(g=this._socket)===null||g===void 0||g.send({data:n,fail:this._onSendFail})}bindSocketHandlers(n){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=n;this._socket&&(this._socket.onClose(E),this._socket.onOpen(g),this._socket.onMessage(u),this._socket.onError(m),this._onSendFail=D)}unbindSocketHandlers(){this._socket&&(this._socket.onClose(()=>{}),this._socket.onOpen(()=>{}),this._socket.onMessage(()=>{}),this._socket.onError(()=>{}))}disconnect(){this._socket&&(this._socket.close(),this._socket=null)}}const fr="CONNECT",Ls="SEND",Jc="DISCONNECT",ms="OPEN",as="MESSAGE",Ru="CLOSE",Wa="ERROR",Cs="SEND_FAIL";class sg{constructor(){this._worker=null,this._blobUrl=null}connectSocket(n){const g=new Blob([`
+(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const I of document.querySelectorAll('link[rel="modulepreload"]'))c(I);new MutationObserver(I=>{for(const C of I)if(C.type==="childList")for(const f of C.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&c(f)}).observe(document,{childList:!0,subtree:!0});function s(I){const C={};return I.integrity&&(C.integrity=I.integrity),I.referrerPolicy&&(C.referrerPolicy=I.referrerPolicy),I.crossOrigin==="use-credentials"?C.credentials="include":I.crossOrigin==="anonymous"?C.credentials="omit":C.credentials="same-origin",C}function c(I){if(I.ep)return;I.ep=!0;const C=s(I);fetch(I.href,C)}})();var yg=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ZW(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function zU(t){if(t.__esModule)return t;var i=t.default;if(typeof i=="function"){var s=function c(){return this instanceof c?Reflect.construct(i,arguments,this.constructor):i.apply(this,arguments)};s.prototype=i.prototype}else s={};return Object.defineProperty(s,"__esModule",{value:!0}),Object.keys(t).forEach(function(c){var I=Object.getOwnPropertyDescriptor(t,c);Object.defineProperty(s,c,I.get?I:{enumerable:!0,get:function(){return t[c]}})}),s}var uY={exports:{}},GsA=uY.exports,U8;function bsA(){return U8||(U8=1,function(t,i){(function(s,c){t.exports=c()})(GsA,function(){const s=n=>n===void 0,c=n=>typeof n=="string",I=n=>{var r;return(r=Object.prototype.toString.call(n).match(/^\[object (.*)\]$/))===null||r===void 0?void 0:r[1].toLowerCase()},C=n=>typeof Array.isArray=="function"?Array.isArray(n):I(n)==="array",f=n=>n!==null&&typeof n=="object",w=n=>C(n)||f(n),_=n=>{if(typeof n!="string")return!1;const r=n[0];return!/[^a-zA-Z0-9]/.test(r)},N=n=>{if(typeof n!="object"||n===null)return!1;const r=Object.getPrototypeOf(n);if(r===null)return!0;let g=r;for(;Object.getPrototypeOf(g)!==null;)g=Object.getPrototypeOf(g);return r===g};function L(n=99999999){return Math.round(Math.random()*n)}const q=(n,r,g,u)=>{if(!w(n)||!w(r))return 0;let E=0;const m=Object.keys(r);let D;for(let v=0,T=m.length;v"u"&&typeof uni.requireNativePlugin=="function",Hi=ze&&typeof wx.miniapp=="object",Vi=typeof uni<"u",ws=Qt&&typeof tt.enterChat=="function",Ui=ze||Ve||Qt||Pt||ii||ao||bi,es=typeof window>"u"&&!Ui&&typeof yg<"u"&&yg.NativeScriptGlobals!==void 0,Ro=typeof yg<"u"&&(yg.nativeModuleProxy!==void 0||yg.ReactNative!==void 0),oo=typeof wx<"u"&&typeof wx.getAccountInfoSync=="function"&&!!wx.getAccountInfoSync().plugin,$t=typeof uni<"u"?!Ui:typeof window<"u"&&!Ui&&!Ro,so=Ve?qq:Qt?tt:Pt?swan:ii?my:ze?wx:ao?uni:bi?jd:{},Ri=$t&&window&&window.navigator&&window.navigator.userAgent||"",Qs=/(micromessenger|webbrowser)/i.test(Ri),HA=function(){let n="WEB";return Qs?n="WEB":Ve?n="QQ_MP":Qt?n="TT_MP":Pt?n="BAIDU_MP":ii?n="ALI_MP":ze?n=Hi?"DONUT_NATIVE_APP":"WX_MP":ao?n="UNI_NATIVE_APP":es?n="NS_NATIVE_APP":Ro&&(n="RN_NATIVE_APP"),tA[n]}(),Ie=/iPad/i.test(Ri),Ye=/iPhone/i.test(Ri)&&!Ie,Lt=/iPod/i.test(Ri),at=Ye||Ie||Lt,Et=function(){const n=Ri.match(/OS (\d+)_/i);return n&&n[1]?n[1]:null}(),ei=/Android/i.test(Ri),Jt=function(){const n=Ri.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);if(!n)return null;const r=n[1]&&parseFloat(n[1]),g=n[2]&&parseFloat(n[2]);return r&&g?parseFloat(`${n[1]}.${n[2]}`):r||null}(),Le=/Firefox/i.test(Ri),$e=/Edge/i.test(Ri),Tt=!$e&&/Chrome/i.test(Ri),Gt=/MSIE/.test(Ri)||Ri.indexOf("Trident")>-1&&Ri.indexOf("rv:11.0")>-1,Ji=function(){const n=/MSIE\s(\d+)\.\d/.exec(Ri);let r=n&&parseFloat(n[1]);return!r&&/Trident\/7.0/i.test(Ri)&&/rv:11.0/.test(Ri)&&(r=11),r}(),po=/Safari/i.test(Ri)&&!Tt&&!ei&&!$e,To=/Windows/i.test(Ri),zi=/MAC OS X/i.test(Ri),wo=$t&&typeof Worker<"u"&&!Gt,ds=ei||at,rs=function(){if(typeof window>"u"||window.navigator===void 0)return!1;const{standalone:n}=window.navigator;return!(!at||n||po)}();function Vo(){let n="unknown";if(zi&&(n="mac"),To&&(n="windows"),at&&(n="ios"),ei&&(n="android"),Ui)try{const{platform:r}=so.getSystemInfoSync();r!==void 0&&(n=r)}catch(r){console.error(r)}return n}const Hs=typeof process<"u"&&process.versions!==void 0&&process.versions.node!==void 0&&typeof window>"u";function vo(n,r){var g={};for(var u in n)Object.prototype.hasOwnProperty.call(n,u)&&r.indexOf(u)<0&&(g[u]=n[u]);if(n!=null&&typeof Object.getOwnPropertySymbols=="function"){var E=0;for(u=Object.getOwnPropertySymbols(n);E{so.request({url:g,data:u,method:r,timeout:E,header:{"content-type":Ur},success:v=>m(v.data),fail:()=>D(new Error(`{"message":"Network error","code":${xn}}`))})}):Hs?void 0:new Promise((m,D)=>{const v=new XMLHttpRequest,T=setTimeout(()=>{v.abort(),D(new Error(`{"message":"Request timeout","code":${Zn}}`))},E);v.onreadystatechange=function(){if(v.readyState===4)if(clearTimeout(T),v.status===200||v.status===304)try{m(v.responseText?JSON.parse(v.responseText):null)}catch{m(v.responseText)}else D(new Error(`{"message":"Network error","code":${xn}}`))},v.open(r,g,!0),v.setRequestHeader("Content-type",Ur),v.send(u||null)})})}function ts(n){if(n==null)return!0;if(typeof n=="boolean")return!1;if(typeof n=="number")return n===0;if(typeof n=="string"||typeof n=="function"||Array.isArray(n))return n.length===0;if(n instanceof Error)return n.message==="";if(N(n)){for(const r in n)if(Object.prototype.hasOwnProperty.call(n,r))return!1;return!0}return(Object.prototype.toString.call(n)==="[object Map]"||Object.prototype.toString.call(n)==="[object Set]"||Object.prototype.toString.call(n)==="[object File]")&&n.size===0}function Kn(n,r){if(n===null||typeof n!="object")return n;const g=r||new WeakMap;if(g.has(n))return g.get(n);if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);if(n instanceof Map){const m=new Map;return g.set(n,m),n.forEach((D,v)=>{m.set(Kn(v,g),Kn(D,g))}),m}if(n instanceof Set){const m=new Set;return g.set(n,m),n.forEach(D=>{m.add(Kn(D,g))}),m}if(Array.isArray(n)){const m=[];return g.set(n,m),n.forEach(D=>{m.push(Kn(D,g))}),m}const u=Object.getPrototypeOf(n),E=Object.create(u);return g.set(n,E),[...Object.getOwnPropertyNames(n),...Object.getOwnPropertySymbols(n)].forEach(m=>{if(m==="__ob__"||m==="__v_skip"||m==="__v_isRef"||m==="__v_isReadonly")return;const D=Object.getOwnPropertyDescriptor(n,m);D&&(D.get||D.set?Object.defineProperty(E,m,D):E[m]=Kn(n[m],g))}),E}function _s(n,r,g){const u=new WeakSet,E=(m,D)=>{if(r&&(D=r(m,D)),D===void 0)return"undefined";if(D===null)return null;if(Number.isNaN(D))return"NaN";if(D===1/0)return"Infinity";if(D===-1/0)return"-Infinity";if(typeof D=="function")return`[Function: ${D.name||"anonymous"}]`;if(typeof D=="symbol")return D.toString();if(typeof D=="bigint")return`${D.toString()}n`;if(typeof D=="object"&&D!==null){if(u.has(D))return"[Circular]";u.add(D)}return D instanceof Date?D.toISOString():D instanceof Error?{name:D.name,message:D.message}:D instanceof Map?{dataType:"Map",value:Array.from(D.entries())}:D instanceof Set?{dataType:"Set",value:Array.from(D.values())}:D};try{return JSON.stringify(n,E,g)}catch(m){return console.error("Failed to stringify:",m),""}}function ln(){let n,r;return{promise:new Promise((g,u)=>{n=g,r=u}),resolve:n,reject:r}}var qt,Xa=Object.freeze({__proto__:null,ANDROID_VERSION:Jt,IE_VERSION:Ji,IN_ALIPAY_MINI_APP:ii,IN_BAIDU_MINI_APP:Pt,IN_BROWSER:$t,IN_DONUT_NATIVE_APP:Hi,IN_FEISHU_MINI_APP:ws,IN_JD_MINI_APP:bi,IN_MINI_APP:Ui,IN_NODE:Hs,IN_NS_NATIVE_APP:es,IN_QQ_MINI_APP:Ve,IN_RN_APP:Ro,IN_TT_MINI_APP:Qt,IN_TT_MINI_GAME:Ai,IN_UNI_APP:Vi,IN_UNI_NATIVE_APP:ao,IN_WX_MINI_APP:ze,IN_WX_MINI_APP_DESK:ot,IN_WX_MINI_GAME:ge,IN_WX_MINI_PLUGIN:oo,IOS_VERSION:Et,IS_ANDROID:ei,IS_CHROME:Tt,IS_EDGE:$e,IS_FIREFOX:Le,IS_IE:Gt,IS_IOS:at,IS_IPAD:Ie,IS_IPHONE:Ye,IS_IPOD:Lt,IS_MAC:zi,IS_SAFARI:po,IS_WECHAT:Qs,IS_WIN:To,IS_WORKER_AVAILABLE:wo,MINI_APP_NAMESPACE:so,USER_AGENT:Ri,base16EncodeBinaryString:lA,deepCopyWithMethods:Kn,deepMerge:q,generatePromise:ln,getPlatformType:Vo,getType:I,httpRequest:qi,isArray:C,isArrayOrObject:w,isEmpty:ts,isH5:ds,isIOSWebView:rs,isNumber:n=>n!==null&&(typeof n=="number"&&!Number.isNaN(n-0)||typeof n=="object"&&n.constructor===Number),isObject:f,isPlainObject:N,isString:c,isUndefined:s,isUniIOSApp:function(){return ao&&uni.getDeviceInfo().platform.toLocaleLowerCase()==="ios"},isValidRequestKey:_,platform:HA,randomInt:L,randomString:function(){const n="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";let r="";for(let g=32;g>0;--g)r+=n[Math.floor(62*Math.random())];return r},safeStringify:_s});class Ln{constructor(){this.listeners={}}on(r,g,u){this.listeners[r]||(this.listeners[r]=[]),this.listeners[r].push({fn:g,context:u})}off(r,g,u){var E;g&&(this.listeners[r]=(E=this.listeners[r])===null||E===void 0?void 0:E.filter(m=>{const D=m.fn===g,v=!u||m.context===u;return!(D&&v)}))}emit(r,...g){const u=this.listeners[r];u&&u.forEach(E=>{const{fn:m,context:D}=E;try{m.apply(D,g)}catch(v){console.warn(`Error in event handler for ${r} error: ${_s(v)}`)}})}once(r,g,u){const E=(...m)=>{g.apply(u,m),this.off(r,E)};this.on(r,E)}}(function(n){n.BUSINESS_COMMAND="business_command",n.C2C_REALTIME_MESSAGE="c2c_realtime_message",n.C2C_MESSAGE_MODIFIED="c2c_message_modified",n.C2C_REVOKED_MESSAGE="c2c_message_revoked",n.GROUP_REALTIME_MESSAGE="group_realtime_message",n.GROUP_MESSAGE_MODIFIED="group_message_modified",n.GROUP_MESSAGE_REVOKED="group_message_revoked",n.C2C_MESSAGE_READ_RECEIPT="c2c_message_read_receipt",n.MESSAGE_REACTION_UPDATED="message_reaction_updated",n.MESSAGE_REACTION_UPDATED_SYNC="message_reaction_updated_sync",n.GROUP_AT_TIPS="group_at_tips",n.USER_STATUS_UPDATE="user_status_update",n.FRIEND_LIST_MODIFIED="friend_list_modified",n.PROFILE_MODIFIED="profile_modified",n.CONV_MODIFIED="conversation_modified",n.GROUP_TIPS_NOTIFICATION="group_tips_notification",n.GROUP_MESSAGE_READ_RECEIPT="group_message_read_receipt",n.GROUP_MESSAGE_READ_SYNC="group_message_read_sync",n.GROUP_SYSTEM_NOTIFICATION="group_system_notification",n.C2C_MESSAGE_PEER_READ="c2c_message_peer_read",n.C2C_MESSAGE_READ_SYNC="c2c_message_read_sync",n.C2C_REMIND_TYPE_SYNC="c2c_remind_type_sync",n.FOLLOW_LIST_UPDATED="follow_list_updated",n.MESSAGE_EXTENSIONS_UPDATED="message_extensions_updated",n.ALL_MESSAGE_READ="all_message_read",n.CONVERSATION_MARK_UPDATED="conversation_mark_updated",n.CONVERSATION_GROUP_ADD="conversation_group_add",n.CONVERSATION_GROUP_DELETED="conversation_group_deleted",n.CONVERSATION_GROUP_UPDATED="conversation_group_updated",n.ALL_RECEIVE_MESSAGE_OPTION="all_receive_message_option",n.TOPIC_AT_TIPS="topic_at_tips",n.TOPIC_TIPS_NOTIFICATION="topic_tips_notification",n.TOPIC_SYSTEM_NOTIFICATION="topic_system_notification",n.TOPIC_MESSAGE_READ_SYNC="topic_message_read_sync",n.TOPIC_LATEST_MESSAGE="topic_latest_message",n.GROUP_MESSAGE_PINNED="group_message_pinned"})(qt||(qt={}));const hn=[16,17];function Ls(n){var r;const g=[];return(r=n?.GroupTips)===null||r===void 0||r.forEach(u=>{var E;u.GroupInfo.MillionGroupFlag===2?g.push(qt.TOPIC_TIPS_NOTIFICATION):hn.includes((E=u?.MsgBody)===null||E===void 0?void 0:E.OpType)?g.push(qt.GROUP_MESSAGE_PINNED):g.push(qt.GROUP_TIPS_NOTIFICATION)}),g}const Ir=[{conditions:[{type:"event",value:100}],subType:qt.BUSINESS_COMMAND},{conditions:[{type:"event",value:24}],subType:qt.ALL_RECEIVE_MESSAGE_OPTION},{conditions:[{type:"event",value:26}],subType:qt.TOPIC_LATEST_MESSAGE},{conditions:[{type:"hasKey",value:"C2cMsgArray"}],subType:qt.C2C_REALTIME_MESSAGE},{conditions:[{type:"hasKey",value:"C2cMsgModNotifys"}],subType:qt.C2C_MESSAGE_MODIFIED},{conditions:[{type:"hasKey",value:"ProfileDataMod"}],subType:qt.PROFILE_MODIFIED},{conditions:[{type:"hasKey",value:"UserStatusList"}],subType:qt.USER_STATUS_UPDATE},{conditions:[{type:"hasKey",value:"FriendListMod"}],subType:qt.FRIEND_LIST_MODIFIED},{conditions:[{type:"hasKey",value:"GroupMsgArray"}],subType:qt.GROUP_REALTIME_MESSAGE},{conditions:[{type:"hasKey",value:"GroupMsgModNotifys"}],subType:qt.GROUP_MESSAGE_MODIFIED},{conditions:[{type:"hasKey",value:"C2cNotifyMsgArray"}],subTypeParser:function(n){var r;const g=[];return(r=n?.C2cNotifyMsgArray)===null||r===void 0||r.forEach(u=>{u.WithdrawC2cMsgNotify&&g.push(qt.C2C_REVOKED_MESSAGE),u.C2cReadedReceipt&&g.push(qt.C2C_MESSAGE_PEER_READ),u.ReadC2cMsgNotify&&g.push(qt.C2C_MESSAGE_READ_SYNC),u.MuteNotificationsSync&&g.push(qt.C2C_REMIND_TYPE_SYNC)}),g}},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:4}],subTypeParser:Ls},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:5}],subTypeParser:function(n){var r;const g=[];return(r=n?.GroupTips)===null||r===void 0||r.forEach(u=>{Array.isArray(u.MsgBody.GroupWithdrawInfoArray)?g.push(qt.GROUP_MESSAGE_REVOKED):Array.isArray(u.MsgBody.GroupMsgReceiptList)?g.push(qt.GROUP_MESSAGE_READ_RECEIPT):Array.isArray(u.MsgBody.GroupReadInfoArray)?u.MsgBody.GroupReadInfoArray[0].TopicId?g.push(qt.TOPIC_MESSAGE_READ_SYNC):g.push(qt.GROUP_MESSAGE_READ_SYNC):u.GroupInfo.MillionGroupFlag===2?g.push(qt.TOPIC_SYSTEM_NOTIFICATION):g.push(qt.GROUP_SYSTEM_NOTIFICATION)}),g}},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:6}],subTypeParser:Ls},{conditions:[{type:"hasKey",value:"GroupTips"},{type:"event",value:12}],subTypeParser:function(n){var r;const g=[];return(r=n?.GroupTips)===null||r===void 0||r.forEach(u=>{const{GroupAtTips:{TopicId:E}}=u;E?g.push(qt.TOPIC_AT_TIPS):g.push(qt.GROUP_AT_TIPS)}),g}},{conditions:[{type:"hasKey",value:"RecentContactMod"}],subTypeParser:function(n){var r;const g=[];return(r=n?.RecentContactMod)===null||r===void 0||r.forEach(u=>{switch(u.PushType){case We.CONV_MARK_UPDATED:g.push(qt.CONVERSATION_MARK_UPDATED);break;case We.CONV_GROUP_ADDED:g.push(qt.CONVERSATION_GROUP_ADD);break;case We.CONV_GROUP_DELETED:g.push(qt.CONVERSATION_GROUP_DELETED);break;case We.CONV_GROUP_UPDATED:g.push(qt.CONVERSATION_GROUP_UPDATED);break;default:g.push(qt.CONV_MODIFIED)}}),g}},{conditions:[{type:"hasKey",value:"MsgReactionNotifyList"}],subType:qt.MESSAGE_REACTION_UPDATED},{conditions:[{type:"hasKey",value:"MsgReactionNotify"}],subType:qt.MESSAGE_REACTION_UPDATED_SYNC},{conditions:[{type:"hasKey",value:"C2cMsgInfo"}],subType:qt.C2C_MESSAGE_READ_RECEIPT},{conditions:[{type:"hasKey",value:"FollowChangeList"}],subType:qt.FOLLOW_LIST_UPDATED},{conditions:[{type:"hasKey",value:"MsgExtensionNotify"}],subType:qt.MESSAGE_EXTENSIONS_UPDATED},{conditions:[{type:"hasKey",value:"C2CReadAllMsg"}],subType:qt.ALL_MESSAGE_READ}];var Us;function rr(n){var r;const g=Array.isArray((r=n?.body)===null||r===void 0?void 0:r.EventArray)?n.body.EventArray:[],u=[];return g.forEach(E=>{E.Flag=n.body.Flag;const m=Ir.find(v=>v.conditions.every(T=>{switch(T.type){case"event":return E.Event===T.value;case"hasKey":return Object.prototype.hasOwnProperty.call(E,T.value);default:return!1}}));if(!m)return null;let D=[];typeof m.subTypeParser=="function"?D=m.subTypeParser(E):m.subType&&(D=m.subType),Array.isArray(D)?D.forEach(v=>{u.push({type:`${Us.SERVER_PUSH_MESSAGE}:${v}`,data:E})}):u.push({type:`${Us.SERVER_PUSH_MESSAGE}:${D}`,data:E})}),u}(function(n){n.SERVER_PUSH_MESSAGE="im_open_push.msg_push",n.SERVER_PUSH_MESSAGE_MULTIPLE="im_open_push.multi_msg_push_ws",n.ERROR="error"})(Us||(Us={}));const fo={[Us.SERVER_PUSH_MESSAGE]:rr,[Us.SERVER_PUSH_MESSAGE_MULTIPLE]:rr,[Us.ERROR]:function(n){const{errorCode:r}=n;return[{type:`error:${r}`,data:n}]}},$s=new class{constructor(){this._outerEventEmitter=null,this._innerEventEmitter=null,this._filteredCallbackMap=new Map,this._outerEventEmitter=new Ln,this._innerEventEmitter=new Ln,this.InnerEventSubType=qt}subscribeInnerEvent(n,r,g,u,E){var m;let D,v,T,P;["string","number"].includes(typeof r)?(T=`${n}:${r}`,P=g,v=u,D=E):(T=n,P=r,v=g,D=typeof u=="function"?u:void 0),D?this._subscribeWithFilter(T,P,v,D):(m=this._innerEventEmitter)===null||m===void 0||m.on(T,P,v)}emitInnerEvent(n,r){var g,u;if((g=this._innerEventEmitter)===null||g===void 0||g.emit(n,r),Object.keys(fo).includes(n)){const E=(u=fo[n])===null||u===void 0?void 0:u.call(fo,r);E?.forEach(m=>{var D;m&&((D=this._innerEventEmitter)===null||D===void 0||D.emit(m.type,m.data))})}}subscribeOuterEvent(n,r,g){var u;(u=this._outerEventEmitter)===null||u===void 0||u.on(n,r,g)}unSubscribeOuterEvent(n,r,g){var u;(u=this._outerEventEmitter)===null||u===void 0||u.off(n,r,g)}unSubscribeInnerEvent(n,r,g,u){if(["string","number"].includes(typeof r)){const E=g,m=`${n}:${r}`;this._unsubscribeEvent(m,E,u)}else{const E=r;this._unsubscribeEvent(n,E,g)}}emitOuterEvent(n,r){var g;(g=this._outerEventEmitter)===null||g===void 0||g.emit(n,r)}getOuterEventEmitter(){return this._outerEventEmitter}rest(){this._outerEventEmitter=null,this._innerEventEmitter=null}_subscribeWithFilter(n,r,g,u){var E;const m=D=>{u.call(g,D)&&r.call(g,D)};this._filteredCallbackMap.has(n)||this._filteredCallbackMap.set(n,[]),this._filteredCallbackMap.get(n).push({originalCallback:r,filteredCallback:m,filter:u,context:g}),(E=this._innerEventEmitter)===null||E===void 0||E.on(n,m,g)}_unsubscribeEvent(n,r,g){var u,E;const m=this._filteredCallbackMap.get(n);if(m){const D=m.findIndex(v=>v.originalCallback===r&&v.context===g);if(D!==-1){const{filteredCallback:v}=m[D];return(u=this._innerEventEmitter)===null||u===void 0||u.off(n,v,g),m.splice(D,1),void(m.length===0&&this._filteredCallbackMap.delete(n))}}(E=this._innerEventEmitter)===null||E===void 0||E.off(n,r,g)}};class Sc{constructor(){this._socket=null}connectSocket(r){return this._socket=new WebSocket(r),this._socket}send(r){var g,u;try{(g=this._socket)===null||g===void 0||g.send(r)}catch(E){(u=this._onSendFail)===null||u===void 0||u.call(this,E)}}bindSocketHandlers(r){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=r;this._socket&&(this._socket.binaryType="arraybuffer",this._socket.onopen=g,this._socket.onmessage=u,this._socket.onclose=E,this._socket.onerror=m,this._onSendFail=D)}unbindSocketHandlers(){this._socket&&(this._socket.onopen=null,this._socket.onmessage=null,this._socket.onclose=null,this._socket.onerror=null)}disconnect(){this._socket&&(this._socket.close(),this._socket=null)}}class An{constructor(r){this._onError=r.onError}connectSocket(r){const g=this;return this._socket=so.connectSocket({url:r,header:{"content-type":"application/json"},complete:()=>{},fail:u=>g._onError(u)}),this._socket}send(r){var g;(g=this._socket)===null||g===void 0||g.send({data:r,fail:this._onSendFail})}bindSocketHandlers(r){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=r;this._socket&&(this._socket.onClose(E),this._socket.onOpen(g),this._socket.onMessage(u),this._socket.onError(m),this._onSendFail=D)}unbindSocketHandlers(){this._socket&&(this._socket.onClose(()=>{}),this._socket.onOpen(()=>{}),this._socket.onMessage(()=>{}),this._socket.onError(()=>{}))}disconnect(){this._socket&&(this._socket.close(),this._socket=null)}}const ur="CONNECT",Ds="SEND",Sg="DISCONNECT",fs="OPEN",re="MESSAGE",At="CLOSE",Zt="ERROR",Jo="SEND_FAIL";class ha{constructor(){this._worker=null,this._blobUrl=null}connectSocket(r){const g=new Blob([`
let _socket = null;
self.onmessage = (event) => {
@@ -95,26 +95,26 @@
_socket = null;
}
}
-`],{type:"application/javascript"});this._worker=new Worker(URL.createObjectURL(g)),this._worker.postMessage({type:fr,url:n})}send(n){var g,u;try{(g=this._worker)===null||g===void 0||g.postMessage({type:Ls,data:n})}catch(E){(u=this._onSendFail)===null||u===void 0||u.call(this,E)}}bindSocketHandlers(n){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=n;if(this._worker){const M={[ms]:g,[as]:u,[Ru]:E,[Wa]:m,[Cs]:D};this._onSendFail=D,this._worker.onmessage=T=>{var P;const{type:W}=T?.data||{};typeof M[W]=="function"&&((P=M[W])===null||P===void 0||P.call(M,T?.data))}}}unbindSocketHandlers(){this._worker&&(this._worker.onmessage=null)}disconnect(){this._worker&&(this._worker.postMessage({type:Jc}),this._worker.terminate(),this._worker=null),this._blobUrl&&(URL.revokeObjectURL(this._blobUrl),this._blobUrl=null)}}class HI{}var As,$i=new class{constructor(){this._store=new Map}get(s){return this._store.get(s)}getStorage(s){return ki?gi?my.getStorageSync({key:s}).data:oo.getStorageSync(s):this._canUseLocalStorage()?localStorage.getItem(s):{}}set(s,n){const g=this._store.get(s)||{};n instanceof Map?this._store.set(s,n):this._store.set(s,Object.assign(Object.assign({},g),n))}setStorage(s,n){ki?gi?my.setStorageSync({key:s,data:JSON.stringify(n)}):oo.setStorageSync(s,JSON.stringify(n)):this._canUseLocalStorage()&&localStorage.setItem(s,JSON.stringify(n))}clear(s){typeof s=="string"?this._store.set(s,{}):this._store.clear()}clearLocalStorage(s){this._canUseLocalStorage()&&(typeof s=="string"?localStorage.setItem(s,""):localStorage.clear())}reset(){this.clear()}_canUseLocalStorage(){return typeof window<"u"&&navigator&&navigator.cookieEnabled&&localStorage}};class pc{connectSocket(n){return this._socket=oo.connectSocket({url:n,header:{"content-type":"application/json"},multiple:!0,complete:()=>{}}),this._socket}send(n){var g;(g=this._socket)===null||g===void 0||g.send({data:n,fail:this._onSendFail})}bindSocketHandlers(n){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=n;this._socket&&(this._socket.onClose(E),this._socket.onOpen(g),this._socket.onMessage(M=>u(M?.data)),this._socket.onError(()=>m),this._onSendFail=D)}unbindSocketHandlers(){this._socket&&(this._socket.onClose(()=>{}),this._socket.onOpen(()=>{}),this._socket.onMessage(()=>{}),this._socket.onError(()=>{}))}disconnect(){this._socket&&(this._socket.close(),this._socket=null)}}(function(s){s[s.CONNECTED=0]="CONNECTED",s[s.CONNECTING=1]="CONNECTING",s[s.DISCONNECTED=2]="DISCONNECTED"})(As||(As={}));class ng{constructor(n){this._url="",this._readyState=As.DISCONNECTED,this._url=n,this._id=U(),this._emitter=new On,gi?this._socket=new pc:ut||To||_e||XA||Fi||Ut?this._socket=new cn({onError:this._onError.bind(this)}):an?this._socket=new HI:this._canUseWebWorker()?this._socket=new sg:this._socket=new Sl,this.connect()}connect(){this.doOpen(),this._bindSocketHandlers()}doOpen(){[As.CONNECTED,As.CONNECTING].includes(this._readyState)||(this._readyState=As.CONNECTING,this._ws=this._socket.connectSocket(this._url))}send(n){this._readyState!==As.CONNECTED?this.reconnect():this._socket.send(n)}reconnect(){[As.CONNECTED,As.CONNECTING].includes(this._readyState)||(this.disconnect(),this.doOpen())}getId(){return this._id}on(n,g,u){this._emitter.on(n,g,u)}off(n,g,u){this._emitter.off(n,g,u)}isConnected(){return this._readyState===As.CONNECTED}disconnect(){this._readyState=As.DISCONNECTED,this._unbindSocketHandlers(),this._socket.disconnect()}_onOpen(n){this._readyState===As.CONNECTING&&(this._readyState=As.CONNECTED,this._emitter.emit("connect",{socketId:this._id,event:n}))}_onMessage(n){this._emitter.emit("message",n)}_onClose(n){this._readyState=As.DISCONNECTED,this._emitter.emit("close",{socketId:this._id,event:n})}_onError(n){this._readyState=As.DISCONNECTED,this._emitter.emit("error",{socketId:this._id,error:n})}_onSendFail(n){this._readyState=As.DISCONNECTED,this._emitter.emit("sendFail",{socketId:this._id,error:n})}_bindSocketHandlers(){this._socket.bindSocketHandlers({onOpen:this._onOpen.bind(this),onMessage:this._onMessage.bind(this),onClose:this._onClose.bind(this),onError:this._onError.bind(this),onSendFail:this._onSendFail.bind(this)})}_unbindSocketHandlers(){this._socket.unbindSocketHandlers()}_canUseWebWorker(){const n=$i.get("cloudConfig")||{};return(r(n.isWorkerEnabled)||n.isWorkerEnabled==="1")&&Go}}const Dg={[gt.SINGAPORE]:[[2e7,3e7],[172e7,173e7]],[gt.KOREA]:[[3e7,4e7],[173e7,174e7]],[gt.GERMANY]:[[4e7,5e7],[174e7,175e7]],[gt.IND]:[[5e7,6e7],[175e7,176e7]],[gt.JPN]:[[6e7,7e7],[176e7,177e7]],[gt.USA]:[[7e7,8e7],[177e7,178e7]],[gt.INDONESIA]:[[8e7,9e7],[178e7,179e7]],[gt.KSA]:[[9e7,1e8],[179e7,18e8]]};function ua(s){var n;if(!((n=$i.get("instance"))===null||n===void 0)&&n.oversea)return gt.OVERSEA;for(const g of Object.keys(Dg))for(const[u,E]of Dg[g])if(s>=u&&s`${iA}=${W[iA]}`).join("&"));var W;return g?`${s}/binfo?${P}&compress=gzip`:`${s}/info?${P}`}function Hs(s){const n=$i.get("instance"),{sdkAppId:g,testEnv:u,proxyServer:E}=n,m=ua(g);if(u)return Hn(pt.TEST[m].DEFAULT,{isBinary:s});if(!Rs(E))return Hn(E,{isBinary:s});const D=pt.PRODUCTION[m],M=zt&&D.ANYCAST,T=zt,P=!!D.BACKUP_CN;return Hn({[bo.INITIAL]:()=>(_o=bo.DEFAULT,D.DEFAULT),[bo.DEFAULT]:()=>(_o=bo.IPV6,D.IPV6),[bo.IPV6]:()=>(_o=bo.BACKUP,D.BACKUP),[bo.BACKUP]:()=>T?(_o=bo.BACKUP_WEB_ONLY,function(W){const iA=Math.floor(10001*Math.random())+1e4;return W.replace("*",String(iA))}(D.BACKUP_WEB_ONLY)):P?(_o=bo.BACKUP_CN,D.BACKUP_CN):M?(_o=bo.ANYCAST,D.ANYCAST):D.DEFAULT,[bo.BACKUP_WEB_ONLY]:()=>P?(_o=bo.BACKUP_CN,D.BACKUP_CN):M?(_o=bo.ANYCAST,D.ANYCAST):D.DEFAULT,[bo.BACKUP_CN]:()=>(_o=M?bo.ANYCAST:bo.DEFAULT,D[_o]),[bo.ANYCAST]:()=>(_o=bo.DEFAULT,D.ANYCAST="",D.DEFAULT)}[_o](),{isBinary:s})}var Sg=new class{constructor(){this._timeOffsetWithServer=0}getServerTimeMs(){return Date.now()+this._timeOffsetWithServer}getServerTimeSeconds(){return Math.floor(this.getServerTimeMs()/1e3)}getTimeOffsetWithServer(){return this._timeOffsetWithServer}calculateTimeOffsetWithServer(s,n){const g=Date.now(),u=g-s;this._timeOffsetWithServer=n+u-g}};const mc=16;var fn=new class{constructor(){this._tasks=[],this._timer=null,this._taskMap=new Map}_addTaskToScheduler(s){const{id:n}=s;this.removeTask(n),this._tasks.push(s),this._taskMap.set(n,s),this._sort(),this._scheduleNextTask()}_createTask(s){const{id:n,callback:g,context:u,isOnce:E=!1,intervalMs:m=mc}=s,D=Math.max(m,mc);return{id:n,nextExecuteTime:Date.now()+D,intervalMs:m,callback:g,context:u,isOnce:E}}addTask(s){const n=this._createTask(s);this._addTaskToScheduler(n)}addOnceTask(s){const n=this._createTask(Object.assign(Object.assign({},s),{isOnce:!0}));this._addTaskToScheduler(n)}removeTask(s){const n=this._tasks.findIndex(g=>g.id===s);n>-1&&(this._tasks.splice(n,1),this._taskMap.delete(s),this._scheduleNextTask())}updateTaskInterval(s,n){const g=this._taskMap.get(s);g&&(g.intervalMs=n,g.nextExecuteTime=Date.now()+n,this._sort(),this._scheduleNextTask())}clearAllTasks(){this._tasks=[],this._taskMap.clear(),this._timer&&(clearTimeout(this._timer),this._timer=null)}dispose(){this.clearAllTasks()}_sort(){this._tasks.sort((s,n)=>s.nextExecuteTime-n.nextExecuteTime)}_scheduleNextTask(){this._timer&&(clearTimeout(this._timer),this._timer=null);const s=this._tasks[0];if(s){const n=Math.max(0,s.nextExecuteTime-Date.now());this._timer=setTimeout(()=>this._execute(),n)}}_execute(){const s=Date.now();for(;this._tasks.length&&this._tasks[0].nextExecuteTime<=s;){const n=this._tasks[0];try{n.context?n.callback.call(n.context):n.callback(),n.isOnce?this.removeTask(n.id):(n.nextExecuteTime=s+n.intervalMs,this._sort())}catch(g){console.warn(`Task ${n.id} execution failed:`,g),n.isOnce&&this.removeTask(n.id)}}this._scheduleNextTask()}};function Ga(s){const n=[];for(let g=0;g=55296&&u<=56319){const E=s.charCodeAt(++g)-56320+(u-55296<<10)+65536;n.push(240|E>>18,128|E>>12&63,128|E>>6&63,128|63&E)}else u<=127?n.push(u):u<=2047?n.push(192|u>>6,128|63&u):n.push(224|u>>12,128|u>>6&63,128|63&u)}return new Uint8Array(n)}function In(s){const n=Array.isArray(s)?[]:Object.create(null);for(const g in s)Object.prototype.hasOwnProperty.call(s,g)&&_(g)&&s[g]!=null&&(s[g]===null||typeof s[g]!="object"?n[g]=s[g]:n[g]=In(s[g]));return n}function fs(s,n){if(mA.includes(s))return 0;const g=Ga(JSON.stringify(n));let u=4294967295;const{length:E}=g;for(let m=0;m>>=1:u=u>>>1^3988292384}return(4294967295^u)>>>0}function Ea(s){const{servcmd:n,data:g}=s,u=function(m){const D=$i.get("login")||{},M=$i.get("instance")||{};return{servcmd:m,ver:"v4",platform:HA,websdkappid:537048168,websdkversion:"1.7.3",a2:D.a2Key||void 0,tinyid:D.tinyID||void 0,status_instid:D.statusInstanceId||0,sdkappid:M.sdkAppId,contenttype:"json",reqtime:Math.floor(Date.now()/1e3),identifier:D.a2Key?void 0:D.userId,usersig:D.a2Key?void 0:D.userSig,sdkability:478343027,sdkability_ext:IA(""),cappid:M.applicationID||0,tjgID:"",seq:Sa(),cs:0}}(n),E=In(g);return u.cs=fs(n,E),{head:u,body:E}}function yn(s){const{servcmd:n,data:g}=s,u=function(m){const D=$i.get("login")||{},M=$i.get("instance")||{};return{servcmd:m,ver:"v4",platform:HA,websdkappid:537048168,websdkversion:"1.7.3",sdkappid:M.sdkAppId,contenttype:"",reqtime:Math.floor(Date.now()/1e3),identifier:"",usersig:"",status_instid:D.statusInstanceId||0,sdkability:478343027,sdkability_ext:IA(""),cappid:M.applicationID||0,seq:Sa(),cs:0}}(n),E=In(g);return u.cs=fs(n,E),{head:u,body:E}}let ba=U();function Sa(){return ba=ba<2415919103?ba+1:U(),ba}function $(){var s;const n=$i.get("login")||{},g=$i.get("instance")||{};return{sdk_type:30,sdk_app_id:g.sdkAppId,sdk_version:"1.6.18",tiny_id:Number(n.tinyID),user_id:n.userId||((s=$i.get("webPush"))===null||s===void 0?void 0:s.userId),platform:HA,instance_id:g.instanceId,trace_id:new Date().getTime()}}var K,vA=Object.freeze({__proto__:null,calcBodyCRC:fs,filterProtocolDataInvalidFields:In,generateCosSpecifiedData:function(s){const{servcmd:n,data:g}=s,u=function(m){const D=$i.get("login")||{},M=$i.get("instance")||{};return{servcmd:m,ver:"v4",platform:HA,websdkappid:537048168,websdkversion:"1.7.3",sdkappid:M.sdkAppId,contenttype:"json",reqtime:Math.floor(Date.now()/1e3),identifier:D.userId,usersig:D.userSig,status_instid:D.statusInstanceId||0,sdkability:478343027,sdkability_ext:IA(""),cappid:M.applicationID||0,seq:Sa(),cs:0}}(n),E=In(g);return u.cs=fs(n,E),{head:u,body:E}},generateProtocolData:Ea,generateSSOLogProtocolData:yn,generateSequence:Sa,getCommonHead:$,getHostSite:ua,taskScheduler:fn,timeManager:Sg});(function(s){s[s.info=4]="info",s[s.warning=5]="warning",s[s.error=6]="error"})(K||(K={}));const qA={method:"extension",networkType:"network_type",eventType:"event_type",code:"error_code",message:"error_message",moreMessage:"more_message",duplicate:"duplicate",costTime:"cost_time",level:"level",uiPlatform:"ui_platform",timestamp:"timestamp"};class ee{constructor(n){this.level=K.info,this._canSendLog=!0,this._logCreatedAt=Sg.getServerTimeMs(),this.timestamp=0,this.networkType=8,this.code=0,this.moreMessage="",this.method="",this.message="",this.costTime=0,this.duplicate=!1,this.eventType=0,this.uiPlatform=this._getUiPlatform(),this._sdkEdition=this._getSDKEdition();const{method:g,eventType:u=0,message:E="",costTime:m=0,error:D,uiPlatform:M,moreMessage:T="",code:P=0,startTime:W=0}=n||{};this.eventType=u,this.method=g,this.message=E,this.costTime=m,this.moreMessage=`${T} startTime:${W}`,this.code=P,D&&this.setError(D),Rs(M)||(this.uiPlatform=M)}setMoreMessage(n){this.moreMessage=`${this.moreMessage} ${n}`}updateLogCreatedAtByTimeOffset(){this._logCreatedAt+=Sg.getTimeOffsetWithServer()}end(n=!1){this._canSendLog&&(this._canSendLog=!1,this.timestamp=Sg.getServerTimeMs(),this._ssoLogModule.pushToLogQueue(this._convertSSOLogDataKeyToServe()),n&&this._ssoLogModule.uploadSSOLogData())}setError(n){var g;return n instanceof Error?this._canSendLog?(!((g=$i.get("netWorkMonitor"))===null||g===void 0)&&g.isNetworkOnline&&(n.errorCode&&(this.code=n.errorCode),n.errorMessage&&this.setMoreMessage(n.errorMessage)),this.level=K.error,this):this:(console.warn("SSOLogData.setError value not instanceof Error, please check!"),this)}setLogInfo(n){return Object.keys(n).forEach(g=>{Object.keys(qA).includes(g)&&(this[g]=n[g])}),this}setSSOLogModule(n){this._ssoLogModule=n}_convertSSOLogDataKeyToServe(){const n={};return Object.keys(this).forEach(g=>{const u=g;qA[u]&&(n[qA[u]]=this[u])}),n}_getUiPlatform(){var n;const g=(n=$i.get("instance"))===null||n===void 0?void 0:n.scene;if(typeof g=="string"){const u=Number(g);return isNaN(u)?void 0:u}}_getSDKEdition(){var n;return(n=$i.get("instance"))===null||n===void 0?void 0:n.sdkEdition}}var fe;(function(s){s.RECONNECTED="reconnected",s.CLOUD_CONFIG_UPDATE="cloud_config_update",s.SOCKET_DISCONNECTED="socket_disconnected"})(fe||(fe={}));var xe=fe;const Oe=20,rt=6e4,dt=[4,5,6],Mt="report-logger";var xt=new class{constructor(){this._sdkAppIdBlackList=[],this._tinyIdWhiteList=[],this._reportLevel=[4,5,6],this._minThreshold=Oe,this._maxThreshold=100,this._waitingTime=rt,this._lastReportAt=Date.now(),this._ssoLogMap=new Map,this._logLevel=lA.DEBUG,this._throttleConfig={global:{throttleTime:Pe,maxCount:pe},single:{throttleTime:Ee,maxCount:de}},this._globalThrottle={count:0,startTime:Date.now()},this._singleThrottleMap=new Map,gn.subscribeInnerEvent(xe.CLOUD_CONFIG_UPDATE,this._handleCloudConfigUpdate,this),fn.addTask({id:Mt,intervalMs:1e3,callback:this._checkAndReportIfDue,context:this}),this._logQueue=[],this._savePlatFormInfo()}_handleCloudConfigUpdate(s){const{evt_rpt_threshold:n=Oe,evt_rpt_waiting:g=rt,evt_rpt_level:u=dt,evt_rpt_sdkappid_bl:E="",evt_rpt_tinyid_wl:m="",evt_rpt_global_throttle_time:D=Pe,evt_rpt_global_throttle_count:M=pe,evt_rpt_single_throttle_time:T=Ee,evt_rpt_single_throttle_count:P=de}=s||{};this._sdkAppIdBlackList=E.split(",").map(W=>Number(W)),this._waitingTime=Number(g),this._minThreshold=n,this._reportLevel=u,this._tinyIdWhiteList=m.split(","),this._throttleConfig={global:{throttleTime:D,maxCount:M},single:{throttleTime:T,maxCount:P}}}createSSOLogData(s){const n=new ee(s);return n.setSSOLogModule(this),this._ssoLogMap.set(s.method,n),n}getSSOLogData(s){return this._ssoLogMap.get(s)||{}}pushToLogQueue(s){s&&(this._logQueue.push(s),this._shouldUploadImmediately()&&this.uploadSSOLogData())}setLogLevel(s){[lA.DEBUG,lA.ERROR,lA.INFO,lA.NONE,lA.WARN].includes(s)&&(this._logLevel=s)}debug(s,n="",g){this._log(lA.DEBUG,s,n,g)}info(s,n="",g){this._log(lA.INFO,s,n,g)}warn(s,n="",g){this._log(lA.WARN,s,n,g)}error(s,n="",g){this._log(lA.ERROR,s,n,g)}_shouldUploadImmediately(){return this._logQueue.length>=this._minThreshold}_isReportDue(){return Date.now()>=this._lastReportAt+this._waitingTime}_checkAndReportIfDue(){this._isReportDue()&&this._logQueue.length>0&&this.uploadSSOLogData()}uploadSSOLogData(){return pA(this,void 0,void 0,function*(){if(this._logQueue.length===0)return;const s=this._logQueue.slice();this._logQueue=[];try{const n=this._filterLogs(s);if(n.length===0)return void(this._lastReportAt=Date.now());const g={Header:$(),Event:n};Rs(g.Header.user_id)||(yield function(u){const E="imopenstat.tim_web_report_v2",m=yn({servcmd:E,data:u}),D=`${m.head.seq}${E}`;return De.sendPacket(m,{requestId:D})}(g))}catch(n){this._requeueFailedLogs(s),this.debug("uploadSSOLogData",en(n))}finally{this._lastReportAt=Date.now()}})}_requeueFailedLogs(s){this._logQueue=s.concat(this._logQueue);const n=this._logQueue.length-200;n>0&&(this._logQueue.splice(0,n),this.debug("uploadSSOLogData",`log queue overflow, dropped ${n} oldest logs`))}_savePlatFormInfo(){var s,n;if(ut){const g=(n=(s=wx.getAccountInfoSync)===null||s===void 0?void 0:s.call(wx))===null||n===void 0?void 0:n.miniProgram;if(g){const{appId:u,envVersion:E}=g;$i.set("instance",{appId:u,envVersion:E})}}else zt&&$i.set("instance",{href:window.location.href})}_filterLogs(s){const{tinyID:n}=$i.get("login")||{},{sdkAppId:g}=$i.get("instance")||{};return this._sdkAppIdBlackList.includes(g)&&!this._tinyIdWhiteList.includes(n)?[]:s.filter(u=>this._reportLevel.includes(u.level))}_checkThrottle(s){return!!this._checkGlobalThrottle()||this._checkSingleThrottle(s)}_checkGlobalThrottle(){const s=Date.now();if(s-this._globalThrottle.startTime>=this._throttleConfig.global.throttleTime)this._globalThrottle.count=1,this._globalThrottle.startTime=s;else if(this._globalThrottle.count++,this._globalThrottle.count>this._throttleConfig.global.maxCount)return!0;return!1}_checkSingleThrottle(s){const n=Date.now(),g=this._singleThrottleMap.get(s);return g?n-g.startTime>=this._throttleConfig.single.throttleTime?(g.count=1,g.startTime=n,!1):g.count>=this._throttleConfig.single.maxCount||(g.count++,!1):(this._singleThrottleMap.set(s,{count:1,startTime:n}),!1)}_shouldLog(s){return s>=this._logLevel&&this._logLevel!==lA.NONE}_shouldReport(s){return this._reportLevel.includes(WA[s])}_formatLog(s,n,g,u){const E=new Date,m=`${E.getHours()}:${E.getMinutes()}:${E.getSeconds()}:${E.getMilliseconds()}`,D=`<${lA[s]}>`;return _t||ki?[`${cA} [${m}] ${D} [${n}] ${g}`]:["%c%s%c%s","background:#0abf5b; padding:1px; border-radius:3px; color: #fff",cA,"",`[${m}] ${D} [${n}] ${g} params: ${en(u)}`]}_log(s,n,g,u){if(this._shouldLog(s)){const E=this._formatLog(s,n,g,u);TA[s].apply(console,E)}if(this._shouldReport(s)){const E=this._getThrottleKey(n,g,u);this._checkThrottle(E)||this.createSSOLogData(Object.assign(Object.assign({message:g},u),{method:n})).end()}}_getThrottleKey(s,n,g){const u=`${s}${n}${en(Object.assign(Object.assign({},g),{costTime:""}))}`,E=Ga(JSON.stringify(u));let m=4294967295;const{length:D}=E;for(let M=0;M>>=1:m=m>>>1^3988292384}return`${(4294967295^m)>>>0}`}reset(){console.log("SSO_LOG_MODULE.reset"),fn.removeTask(Mt),gn.unSubscribeInnerEvent(xe.CLOUD_CONFIG_UPDATE,this._handleCloudConfigUpdate,this),this._lastReportAt=0,this.uploadSSOLogData(),this._sdkAppIdBlackList=[],this._tinyIdWhiteList=[],this._minThreshold=Oe,this._maxThreshold=100,this._waitingTime=rt,this._logQueue=[],this._logLevel=lA.DEBUG,this._globalThrottle={count:0,startTime:Date.now()},this._singleThrottleMap.clear()}};const Ii=15e3,ct="Channel",Pt="channel_schedule_task",Ji="channel_reconnect_task",Ki="connected",qs="connecting",Mi="disconnected",zo=1e3,Mg="network_status_change",sr="activity_status_change",yr="send_fail",xn="reconnect_failed",Ml="socket_error",Ks="socket_close";function aI(s){return s&&s.__esModule&&Object.prototype.hasOwnProperty.call(s,"default")?s.default:s}function Wg(s){return Wg=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(n){return typeof n}:function(n){return n&&typeof Symbol=="function"&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},Wg(s)}function fc(s){throw new Error('Could not dynamically require "'+s+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}var wu,Ma={exports:{}},vl=(wu||(wu=1,function(s){s.exports=function n(g,u,E){function m(T,P){if(!u[T]){if(!g[T]){if(!P&&fc)return fc(T);if(D)return D(T,!0);var W=new Error("Cannot find module '"+T+"'");throw W.code="MODULE_NOT_FOUND",W}var iA=u[T]={exports:{}};g[T][0].call(iA.exports,function(EA){return m(g[T][1][EA]||EA)},iA,iA.exports,n,g,u,E)}return u[T].exports}for(var D=fc,M=0;M>>6:(EA<65536?iA[xA++]=224|EA>>>12:(iA[xA++]=240|EA>>>18,iA[xA++]=128|EA>>>12&63),iA[xA++]=128|EA>>>6&63),iA[xA++]=128|63&EA);return iA},u.buf2binstring=function(W){return P(W,W.length)},u.binstring2buf=function(W){for(var iA=new E.Buf8(W.length),EA=0,RA=iA.length;EA>10&1023,SA[RA++]=56320|1023&kA)}return P(SA,RA)},u.utf8border=function(W,iA){var EA;for((iA=iA||W.length)>W.length&&(iA=W.length),EA=iA-1;0<=EA&&(192&W[EA])==128;)EA--;return EA<0||EA===0?iA:EA+M[W[EA]]>iA?EA:iA}},{"./common":1}],3:[function(n,g,u){g.exports=function(E,m,D,M){for(var T=65535&E,P=E>>>16&65535,W=0;D!==0;){for(D-=W=2e3>>1:m>>>1;D[M]=m}return D}();g.exports=function(m,D,M,T){var P=E,W=T+M;m^=-1;for(var iA=T;iA>>8^P[255&(m^D[iA])];return-1^m}},{}],6:[function(n,g,u){g.exports=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}},{}],7:[function(n,g,u){g.exports=function(E,m){var D,M,T,P,W,iA,EA,RA,kA,xA,LA,SA,OA,JA,ae,ne,_i,Ti,Lt,Ni,cs,Me,mt,UA,ni;D=E.state,M=E.next_in,UA=E.input,T=M+(E.avail_in-5),P=E.next_out,ni=E.output,W=P-(m-E.avail_out),iA=P+(E.avail_out-257),EA=D.dmax,RA=D.wsize,kA=D.whave,xA=D.wnext,LA=D.window,SA=D.hold,OA=D.bits,JA=D.lencode,ae=D.distcode,ne=(1<>>=Lt=Ti>>>24,OA-=Lt,(Lt=Ti>>>16&255)==0)ni[P++]=65535&Ti;else{if(!(16&Lt)){if(!(64&Lt)){Ti=JA[(65535&Ti)+(SA&(1<>>=Lt,OA-=Lt),OA<15&&(SA+=UA[M++]<>>=Lt=Ti>>>24,OA-=Lt,!(16&(Lt=Ti>>>16&255))){if(!(64&Lt)){Ti=ae[(65535&Ti)+(SA&(1<>>=Lt,OA-=Lt,(Lt=P-W)>3,SA&=(1<<(OA-=Ni<<3))-1,E.next_in=M,E.next_out=P,E.avail_in=M>>24&255)+(Me>>>8&65280)+((65280&Me)<<8)+((255&Me)<<24)}function SA(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new E.Buf16(320),this.work=new E.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function OA(Me){var mt;return Me&&Me.state?(mt=Me.state,Me.total_in=Me.total_out=mt.total=0,Me.msg="",mt.wrap&&(Me.adler=1&mt.wrap),mt.mode=RA,mt.last=0,mt.havedict=0,mt.dmax=32768,mt.head=null,mt.hold=0,mt.bits=0,mt.lencode=mt.lendyn=new E.Buf32(kA),mt.distcode=mt.distdyn=new E.Buf32(xA),mt.sane=1,mt.back=-1,iA):EA}function JA(Me){var mt;return Me&&Me.state?((mt=Me.state).wsize=0,mt.whave=0,mt.wnext=0,OA(Me)):EA}function ae(Me,mt){var UA,ni;return Me&&Me.state?(ni=Me.state,mt<0?(UA=0,mt=-mt):(UA=1+(mt>>4),mt<48&&(mt&=15)),mt&&(mt<8||15=Gi.wsize?(E.arraySet(Gi.window,mt,UA-Gi.wsize,Gi.wsize,0),Gi.wnext=0,Gi.whave=Gi.wsize):(ni<(_s=Gi.wsize-Gi.wnext)&&(_s=ni),E.arraySet(Gi.window,mt,UA-ni,_s,Gi.wnext),(ni-=_s)?(E.arraySet(Gi.window,mt,UA-ni,ni,0),Gi.wnext=ni,Gi.whave=Gi.wsize):(Gi.wnext+=_s,Gi.wnext===Gi.wsize&&(Gi.wnext=0),Gi.whave>>8&255,UA.check=D(UA.check,dg,2,0),Nt=Tt=0,UA.mode=2;break}if(UA.flags=0,UA.head&&(UA.head.done=!1),!(1&UA.wrap)||(((255&Tt)<<8)+(Tt>>8))%31){Me.msg="incorrect header check",UA.mode=30;break}if((15&Tt)!=8){Me.msg="unknown compression method",UA.mode=30;break}if(Nt-=4,Va=8+(15&(Tt>>>=4)),UA.wbits===0)UA.wbits=Va;else if(Va>UA.wbits){Me.msg="invalid window size",UA.mode=30;break}UA.dmax=1<>8&1),512&UA.flags&&(dg[0]=255&Tt,dg[1]=Tt>>>8&255,UA.check=D(UA.check,dg,2,0)),Nt=Tt=0,UA.mode=3;case 3:for(;Nt<32;){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>8&255,dg[2]=Tt>>>16&255,dg[3]=Tt>>>24&255,UA.check=D(UA.check,dg,4,0)),Nt=Tt=0,UA.mode=4;case 4:for(;Nt<16;){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>8),512&UA.flags&&(dg[0]=255&Tt,dg[1]=Tt>>>8&255,UA.check=D(UA.check,dg,2,0)),Nt=Tt=0,UA.mode=5;case 5:if(1024&UA.flags){for(;Nt<16;){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>8&255,UA.check=D(UA.check,dg,2,0)),Nt=Tt=0}else UA.head&&(UA.head.extra=null);UA.mode=6;case 6:if(1024&UA.flags&&(xi<(Bo=UA.length)&&(Bo=xi),Bo&&(UA.head&&(Va=UA.head.extra_len-UA.length,UA.head.extra||(UA.head.extra=new Array(UA.head.extra_len)),E.arraySet(UA.head.extra,ni,Gi,Bo,Va)),512&UA.flags&&(UA.check=D(UA.check,ni,Bo,Gi)),xi-=Bo,Gi+=Bo,UA.length-=Bo),UA.length))break A;UA.length=0,UA.mode=7;case 7:if(2048&UA.flags){if(xi===0)break A;for(Bo=0;Va=ni[Gi+Bo++],UA.head&&Va&&UA.length<65536&&(UA.head.name+=String.fromCharCode(Va)),Va&&Bo>9&1,UA.head.done=!0),Me.adler=UA.check=0,UA.mode=12;break;case 10:for(;Nt<32;){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>=7&Nt,Nt-=7&Nt,UA.mode=27;break}for(;Nt<3;){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>=1)){case 0:UA.mode=14;break;case 1:if(Ni(UA),UA.mode=20,mt!==6)break;Tt>>>=2,Nt-=2;break A;case 2:UA.mode=17;break;case 3:Me.msg="invalid block type",UA.mode=30}Tt>>>=2,Nt-=2;break;case 14:for(Tt>>>=7&Nt,Nt-=7&Nt;Nt<32;){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>16^65535)){Me.msg="invalid stored block lengths",UA.mode=30;break}if(UA.length=65535&Tt,Nt=Tt=0,UA.mode=15,mt===6)break A;case 15:UA.mode=16;case 16:if(Bo=UA.length){if(xi>>=5,Nt-=5,UA.ndist=1+(31&Tt),Tt>>>=5,Nt-=5,UA.ncode=4+(15&Tt),Tt>>>=4,Nt-=4,286>>=3,Nt-=3}for(;UA.have<19;)UA.lens[rS[UA.have++]]=0;if(UA.lencode=UA.lendyn,UA.lenbits=7,_I={bits:UA.lenbits},Yl=T(0,UA.lens,0,19,UA.lencode,0,UA.work,_I),UA.lenbits=_I.bits,Yl){Me.msg="invalid code lengths set",UA.mode=30;break}UA.have=0,UA.mode=19;case 19:for(;UA.have>>16&255,wI=65535&Yg,!((_r=Yg>>>24)<=Nt);){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>=_r,Nt-=_r,UA.lens[UA.have++]=wI;else{if(wI===16){for(iE=_r+2;Nt>>=_r,Nt-=_r,UA.have===0){Me.msg="invalid bit length repeat",UA.mode=30;break}Va=UA.lens[UA.have-1],Bo=3+(3&Tt),Tt>>>=2,Nt-=2}else if(wI===17){for(iE=_r+3;Nt>>=_r)),Tt>>>=3,Nt-=3}else{for(iE=_r+7;Nt>>=_r)),Tt>>>=7,Nt-=7}if(UA.have+Bo>UA.nlen+UA.ndist){Me.msg="invalid bit length repeat",UA.mode=30;break}for(;Bo--;)UA.lens[UA.have++]=Va}}if(UA.mode===30)break;if(UA.lens[256]===0){Me.msg="invalid code -- missing end-of-block",UA.mode=30;break}if(UA.lenbits=9,_I={bits:UA.lenbits},Yl=T(P,UA.lens,0,UA.nlen,UA.lencode,0,UA.work,_I),UA.lenbits=_I.bits,Yl){Me.msg="invalid literal/lengths set",UA.mode=30;break}if(UA.distbits=6,UA.distcode=UA.distdyn,_I={bits:UA.distbits},Yl=T(W,UA.lens,UA.nlen,UA.ndist,UA.distcode,0,UA.work,_I),UA.distbits=_I.bits,Yl){Me.msg="invalid distances set",UA.mode=30;break}if(UA.mode=20,mt===6)break A;case 20:UA.mode=21;case 21:if(6<=xi&&258<=gr){Me.next_out=Or,Me.avail_out=gr,Me.next_in=Gi,Me.avail_in=xi,UA.hold=Tt,UA.bits=Nt,M(Me,ln),Or=Me.next_out,_s=Me.output,gr=Me.avail_out,Gi=Me.next_in,ni=Me.input,xi=Me.avail_in,Tt=UA.hold,Nt=UA.bits,UA.mode===12&&(UA.back=-1);break}for(UA.back=0;xg=(Yg=UA.lencode[Tt&(1<>>16&255,wI=65535&Yg,!((_r=Yg>>>24)<=Nt);){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>ac)])>>>16&255,wI=65535&Yg,!(ac+(_r=Yg>>>24)<=Nt);){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>=ac,Nt-=ac,UA.back+=ac}if(Tt>>>=_r,Nt-=_r,UA.back+=_r,UA.length=wI,xg===0){UA.mode=26;break}if(32&xg){UA.back=-1,UA.mode=12;break}if(64&xg){Me.msg="invalid literal/length code",UA.mode=30;break}UA.extra=15&xg,UA.mode=22;case 22:if(UA.extra){for(iE=UA.extra;Nt>>=UA.extra,Nt-=UA.extra,UA.back+=UA.extra}UA.was=UA.length,UA.mode=23;case 23:for(;xg=(Yg=UA.distcode[Tt&(1<>>16&255,wI=65535&Yg,!((_r=Yg>>>24)<=Nt);){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>ac)])>>>16&255,wI=65535&Yg,!(ac+(_r=Yg>>>24)<=Nt);){if(xi===0)break A;xi--,Tt+=ni[Gi++]<>>=ac,Nt-=ac,UA.back+=ac}if(Tt>>>=_r,Nt-=_r,UA.back+=_r,64&xg){Me.msg="invalid distance code",UA.mode=30;break}UA.offset=wI,UA.extra=15&xg,UA.mode=24;case 24:if(UA.extra){for(iE=UA.extra;Nt>>=UA.extra,Nt-=UA.extra,UA.back+=UA.extra}if(UA.offset>UA.dmax){Me.msg="invalid distance too far back",UA.mode=30;break}UA.mode=25;case 25:if(gr===0)break A;if(Bo=ln-gr,UA.offset>Bo){if((Bo=UA.offset-Bo)>UA.whave&&UA.sane){Me.msg="invalid distance too far back",UA.mode=30;break}Bo>UA.wnext?(Bo-=UA.wnext,Il=UA.wsize-Bo):Il=UA.wnext-Bo,Bo>UA.length&&(Bo=UA.length),_C=UA.window}else _C=_s,Il=Or-UA.offset,Bo=UA.length;for(gr_i?(Lt=Il[_C+xA[mt]],Ni=Nt[tE+xA[mt]]):(Lt=96,Ni=0),SA=1<>Or)+(OA-=SA)]=Ti<<24|Lt<<16|Ni,OA!==0;);for(SA=1<>=1;if(SA!==0?(Tt&=SA-1,Tt+=SA):Tt=0,mt++,--ln[Me]==0){if(Me===ni)break;Me=W[iA+xA[mt]]}if(_s{const M=new Uint8Array(D).slice(4);let T;try{T=vl.inflate(M,{to:"string"})}catch(P){console.error("inflate error",P)}return T})(s.data):function(D){const M=new Uint8Array(D);let T="",P=0;const{length:W}=M;for(;P0)for(let kA=0;kA{var u;const{uplinkData:E,canResend:m,resolve:D,reject:M,timeout:T}=n;if(m){this._pendingRequests.set(g,{resolve:D,reject:M,timestamp:Date.now(),uplinkData:E,timeout:T,canResend:m});const P=this._isBinarySupported?Ga(E).buffer:E;(u=this._socketAdapter)===null||u===void 0||u.send(P)}else this._pendingRequests.delete(g)})}_onConnect(s){const{socketId:n,event:g={}}=s||{};this._connectionId=n,this._connectionEstablishedTime=Date.now();const u=Date.now()-this._connectionStartTime,E=`${ct}.onConnect cost:${u} ms. socketID:${n} res:${JSON.stringify(g)}`;if(this._ssoLog({method:"onConnect",message:E}),this._checkPendingRequestsAndResend(),this._sendHeartbeatIfReady(),this._isReconnecting){const m=`${ct}.reconnect success`;this._ssoLog({method:"reconnectSuccess",message:m}),gn.emitInnerEvent(xe.RECONNECTED),this._isReconnecting=!1}this._resetReconnectDelay(),this._handleConnectStateChange({state:Ki,shouldEmitEvent:!0,shouldAttemptReconnect:!1})}_sendAck(s){const n=Ea({servcmd:"openim.ws_msg_push_ack",data:{SessionData:s}});this.sendPacket(n)}_executeScheduledTaskIfReady(){return pA(this,void 0,void 0,function*(){this._clearTimeoutRequest(),this._sendHeartbeatIfReady()})}_canSendHeartbeat(){var s;return((s=this._socketAdapter)===null||s===void 0?void 0:s.isConnected())&&Date.now()>=this._nextHeartbeatAt&&!this._isHeartbeatInProgress}_sendHeartbeat(){return pA(this,void 0,void 0,function*(){var s;const n=Ea({servcmd:"heartbeat.alive",data:{}});try{const g=`${n.head.seq}${n.head.servcmd}`;yield this.sendPacket(n,{requestId:g,timeout:3e3})}catch(g){const u=(s=$i.get("netWorkMonitor"))===null||s===void 0?void 0:s.isNetworkOnline,E=`${ct}.sendHeartbeat failed. isNetWorkOnline:${u} error: ${en(g)}`;this._ssoLog({method:"sendHeartbeatError",message:E}),this._handleConnectStateChange({state:Mi,shouldEmitEvent:!0,shouldAttemptReconnect:!0})}})}_sendHeartbeatIfReady(){return pA(this,void 0,void 0,function*(){this._canSendHeartbeat()&&(this._isHeartbeatInProgress=!0,yield this._sendHeartbeat(),this._isHeartbeatInProgress=!1)})}_updateHeartbeatTime(){this._nextHeartbeatAt=To?Date.now()+5e3:Date.now()+1e4}_handleNetworkStatusChange(s){const n=`${ct}.networkStatusChange ${JSON.stringify(s)}`;this._ssoLog({method:"networkStatusChange",message:n});const{isNetworkOnline:g,networkType:u}=s;g&&u!=="none"?this._handleConnectStateChange({state:Ki,shouldEmitEvent:!1,shouldAttemptReconnect:!0,reason:Mg}):this._handleConnectStateChange({state:Mi,shouldEmitEvent:!1,shouldAttemptReconnect:!0,reason:Mg})}isPrivateNetWork(){const s=$i.get("instance")||{};return s.proxyServer&&!s.fileDownloadProxy}_handleConnectStateChange(s){const{state:n,shouldAttemptReconnect:g,shouldEmitEvent:u,reason:E}=s,m=`${ct}._handleConnectStateChange currentConnectState: ${this._currentConnectState} shouldAttemptReconnect: ${g} shouldEmitEvent: ${u} reason: ${E}`;this._currentConnectState!==n&&(this._ssoLog({method:"handleConnectStateChange",message:m}),u&&(xt.info("_handleConnectStateChange",` from ${this._currentConnectState} to ${n}`),gn.emitOuterEvent("netStateChange",{name:"netStateChange",data:{state:n}}),this._currentConnectState=n,n===Mi&&gn.emitInnerEvent(xe.SOCKET_DISCONNECTED)),g&&(this._resetReconnectDelay(),fn.addTask({id:Ji,intervalMs:this._intendedDelay,callback:this._scheduleReconnectWithBackoff,context:this})))}_handleActivityStatusChange(s){var n,g;const u=(g=(n=this._socketAdapter)===null||n===void 0?void 0:n._ws)===null||g===void 0?void 0:g.readyState,E=`${ct}.activityStatusChange ${JSON.stringify(s)} readyState: ${u}`;xt.debug("activityStatusChange",E),u===3&&this._handleConnectStateChange({state:Mi,shouldEmitEvent:!0,shouldAttemptReconnect:!0,reason:sr})}_resetReconnectDelay(){var s;xt.debug(`${ct}._resetReconnectDelay`),fn.removeTask(Ji);const n=(s=$i.get("activityMonitor"))===null||s===void 0?void 0:s.isActive;this._intendedDelay=n?zo:1e3}_scheduleReconnectWithBackoff(){var s;const n=(s=$i.get("activityMonitor"))===null||s===void 0?void 0:s.isActive;this._intendedDelay=n?Math.min(5e3,Math.max(zo,1.5*this._intendedDelay)):Math.min(3e5,Math.max(1e3,1.5*this._intendedDelay));const g=new Date().toTimeString().slice(0,8),u=`${ct}.scheduleReconnectWithBackoff timeStr: ${g} intendedDelay: ${this._intendedDelay}`;xt.debug(u),this.reconnect(),fn.updateTaskInterval(Ji,this._intendedDelay)}_ssoLog(s){const{method:n,message:g}=s;xt.info(n,g)}_diagnose(){this.isPrivateNetWork()||(this._lastDiagnoseAt=Date.now(),function(s){pA(this,void 0,void 0,function*(){const n=s.split("/")[2];if(!n.startsWith("ws"))return;const g=`https://${n}/v3/netcheck/getconninfo?${s.slice(s.indexOf("info?")+5)}&reqtime=${Date.now()}`;try{yield Pi({method:"GET",url:g,data:{}})}catch(u){xt.warn("diagnoseBySSO",`diagnoseBySSO failed. error:${u.message}`)}})}(this._url),function(s){pA(this,void 0,void 0,function*(){const n=`https://boce-cdn.my-imcloud.com/v3/netcheck/getconninfo?${s.slice(s.indexOf("info?")+5)}&reqtime=${Date.now()}`;try{yield Pi({method:"GET",url:n,data:{}})}catch(g){xt.warn(`diagnoseByCDN', 'diagnoseByCDN failed. error:${g.message}`)}})}(this._url),this._beforeSendInterceptors=[])}_clearTimeoutRequest(){for(const[s,n]of this._pendingRequests.entries()){const{reject:g,timestamp:u,timeout:E}=n;Date.now()-u>=E&&(this._pendingRequests.delete(s),Date.now()-this._lastDiagnoseAt>=3e4&&this._diagnose(),g({errorCode:Qr,errorInfo:"NETWORK_TIMEOUT",data:{requestId:s}}))}}_updateIsBinarySupported(){var s;if(!((s=$i.get("instance"))===null||s===void 0)&&s.devMode)return void(this._isBinarySupported=!1);const n=Es();if((gi||ut&&n==="windows"||Vs)&&(this._isBinarySupported=!1),To){const{uniRuntimeVersion:g=""}=oo.getSystemInfoSync();(function(u){const E=u.split(".").map(Number),[m=0,D=0,M=0]=E;return m>2||!(m<2)&&(D>2||!(D<2)&&M>=6)})(g)||(this._isBinarySupported=!1)}}_isCompressedData(s){const n=new Uint8Array(s);return n[0]===67&&n[1]===79&&n[2]===77&&n[3]===80}};const ye={init:function(s){$i.set("instance",s),De.init()},destroy:function(){De.dispose(),$i.clear(),fn.dispose()},notificationCenter:gn,channel:De,store:$i,ssoLog:xt,utils:yg,common:vA,constants:Dt},vg=s=>typeof s=="function";function rg(s,n,g){const u=g||[];if(!s||!n)return!1;const E=Object.keys(s).filter(D=>!u.includes(D)),m=Object.keys(n).filter(D=>!u.includes(D));return E.length===m.length&&E.every(D=>!!n.hasOwnProperty(D)&&(typeof s[D]=="object"&&s[D]!==null?rg(s[D],n[D],g):s[D]===n[D]))}var Rg;(function(s){s.SDK_READY="sdkStateReady",s.SDK_NOT_READY="sdkStateNotReady",s.SDK_DESTROY="sdkDestroy",s.MESSAGE_RECEIVED="onMessageReceived",s.ROOM_CUSTOM_DATA_RECEIVED="onRoomCustomDataReceived",s.MESSAGE_MODIFIED="onMessageModified",s.MESSAGE_REVOKED="onMessageRevoked",s.MESSAGE_READ_BY_PEER="onMessageReadByPeer",s.MESSAGE_READ_RECEIPT_RECEIVED="onMessageReadReceiptReceived",s.MESSAGE_EXTENSIONS_UPDATED="onMessageExtensionsUpdated",s.MESSAGE_EXTENSIONS_DELETED="onMessageExtensionsDeleted",s.MESSAGE_REACTIONS_UPDATED="onMessageReactionsUpdated",s.CONVERSATION_LIST_UPDATED="onConversationListUpdated",s.TOTAL_UNREAD_MESSAGE_COUNT_UPDATED="onTotalUnreadMessageCountUpdated",s.CONVERSATION_GROUP_LIST_UPDATED="onConversationGroupListUpdated",s.CONVERSATION_IN_GROUP_UPDATED="onConversationInGroupUpdated",s.GROUP_LIST_UPDATED="onGroupListUpdated",s.GROUP_ATTRIBUTES_UPDATED="groupAttributesUpdated",s.GROUP_COUNTER_UPDATED="onGroupCounterUpdated",s.TOPIC_CREATED="onTopicCreated",s.TOPIC_DELETED="onTopicDeleted",s.TOPIC_UPDATED="onTopicUpdated",s.PROFILE_UPDATED="onProfileUpdated",s.USER_STATUS_UPDATED="onUserStatusUpdated",s.BLACKLIST_UPDATED="blacklistUpdated",s.FRIEND_LIST_UPDATED="onFriendListUpdated",s.FRIEND_GROUP_LIST_UPDATED="onFriendGroupListUpdated",s.FRIEND_APPLICATION_LIST_UPDATED="onFriendApplicationListUpdated",s.MY_FOLLOWERS_LIST_UPDATED="onMyFollowersListUpdated",s.MY_FOLLOWING_LIST_UPDATED="onMyFollowingListUpdated",s.MUTUAL_FOLLOWERS_LIST_UPDATED="onMutualFollowersListUpdated",s.KICKED_OUT="kickedOut",s.ERROR="error",s.NET_STATE_CHANGE="netStateChange",s.ALL_RECEIVE_MESSAGE_OPT_UPDATED="onAllReceiveMessageOptUpdated",s.SERVER_CONFIG_UPDATED="onServerConfigUpdated",s.PINNED_GROUP_MESSAGE_UPDATED="onPinnedGroupMessageUpdated",s.WEB_PUSH_MESSAGE_RECEIVED="onWebPushMessageReceived",s.GROUP_ONLINE_MEMBER_COUNT_CHANGED="onGroupOnlineMemberCountChanged",s.RICH_STATUS_CHANGED="onRichStatusChanged"})(Rg||(Rg={}));var Dn,Dr=Rg;(function(s){s.LOGOUT="logout",s.DESTROY="destroy",s.CLOUD_CONFIG_UPDATE="cloud_config_update",s.PROFILE_UPDATE="profile_updated",s.ERROR="error",s.RECONNECTED="reconnected",s.FORCE_OFFLINE="im_open_status.stat_forceoffline",s.COMMERCIAL_CONFIG_PUSH="im_sdk_config_mgr.push_imsdk_purchase_bitsv2",s.OVERLOAD_PUSH="OverLoadPush.notify2",s.NEW_MESSAGE="new_message",s.MESSAGE_PUSH="im_open_push.msg_push",s.MESSAGE_DELETED="message_deleted",s.MESSAGE_REVOKED="message_revoked",s.MESSAGE_MODIFIED="message_modified",s.SOCKET_DISCONNECTED="socket_disconnected",s.CONVERSATION_UPDATED="conversation_updated",s.TOPIC_MESSAGE_DELETED="topic_message_deleted",s.TOPIC_MESSAGE_REVOKED="topic_message_revoked",s.TOPIC_MESSAGE_MODIFIED="topic_message_modified",s.TOPIC_NEW_MESSAGE="topic_new_message",s.QUALITY_STAT="quality_stat",s.SYNC_CONVERSATION_LIST="sync_conversation_list",s.HISTORY_MESSAGE_FETCHED="history_message_fetched"})(Dn||(Dn={}));var ui,no=Dn;(function(s){s.NEW_INVITATION_RECEIVED="newInvitationReceived",s.INVITEE_ACCEPTED="ts_invitee_accepted",s.INVITEE_REJECTED="ts_invitee_rejected",s.INVITATION_CANCELLED="ts_invitation_cancelled",s.INVITATION_TIMEOUT="ts_invitation_timeout",s.INVITATION_MODIFIED="ts_invitation_modified"})(ui||(ui={}));var qc=ui;const zg=Object.assign({},{KICKED_OUT_MULT_ACCOUNT:"multipleAccount",KICKED_OUT_MULT_DEVICE:"multipleDevice",KICKED_OUT_USERSIG_EXPIRED:"userSigExpired",KICKED_OUT_REST_API:"REST_API_Kick"}),wg={MSG_TEXT:"TIMTextElem",MSG_IMAGE:"TIMImageElem",MSG_AUDIO:"TIMSoundElem",MSG_FILE:"TIMFileElem",MSG_FACE:"TIMFaceElem",MSG_VIDEO:"TIMVideoFileElem",MSG_LOCATION:"TIMLocationElem",MSG_GRP_TIP:"TIMGroupTipElem",MSG_GRP_SYS_NOTICE:"TIMGroupSystemNoticeElem",MSG_CUSTOM:"TIMCustomElem",MSG_MERGER:"TIMRelayElem",MSG_STREAM:"TIMStreamElem"};var Yr;(function(s){s.UNSENT="unSend",s.SUCCESS="success",s.FAIL="fail"})(Yr||(Yr={}));const yc={modify:no.MESSAGE_MODIFIED,delete:no.MESSAGE_DELETED,revoke:no.MESSAGE_REVOKED};var Kc;(function(s){s[s.FORWARD=0]="FORWARD",s[s.BACKWARD=1]="BACKWARD"})(Kc||(Kc={}));const ag=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},wg),{MSG_PRIORITY_HIGH:"High",MSG_PRIORITY_NORMAL:"Normal",MSG_PRIORITY_LOW:"Low",MSG_PRIORITY_LOWEST:"Lowest"}),{RECEIVE_WITH_OFFLINE_PUSH_EXCEPT_AT:"AcceptNotNotifyExceptAt",NOT_RECEIVE_OFFLINE_PUSH_EXCEPT_AT:"AcceptNotNotifyExceptAt",NOT_RECEIVE_MSG_EXCEPT_AT:"NotReceiveMsgExceptAt",MSG_AT_ALL:"__kImSDK_MesssageAtALL__"}),{MSG_REMIND_ACPT_AND_NOTE:"AcceptAndNotify",MSG_REMIND_ACPT_NOT_NOTE:"AcceptNotNotify",MSG_REMIND_DISCARD:"Discard"}),{MessageStatus:Yr,Direction:Kc}),_u={[yc.modify]:no.TOPIC_MESSAGE_MODIFIED,[yc.delete]:no.TOPIC_MESSAGE_DELETED,[yc.revoke]:no.TOPIC_MESSAGE_REVOKED},SE={GENDER_UNKNOWN:"Gender_Type_Unknown",GENDER_FEMALE:"Gender_Type_Female",GENDER_MALE:"Gender_Type_Male",USER_STATUS_UNKNOWN:0,USER_STATUS_ONLINE:1,USER_STATUS_OFFLINE:2,USER_STATUS_UNLOGINED:3,USER_NOT_FOUND:"@TLS#NOT_FOUND"},_g=Object.assign({},SE),ka={CONV_C2C:"C2C",CONV_GROUP:"GROUP",CONV_TOPIC:"TOPIC",CONV_SYSTEM:"@TIM#SYSTEM"},Dc=Object.assign(Object.assign(Object.assign(Object.assign({},ka),{CONV_AT_ME:1,CONV_AT_ALL:2,CONV_AT_ALL_AT_ME:3}),{CONV_MARK_TYPE_STAR:1,CONV_MARK_TYPE_UNREAD:2,CONV_MARK_TYPE_FOLD:4,CONV_MARK_TYPE_HIDE:8}),{READ_ALL_C2C_MSG:"readAllC2CMessage",READ_ALL_GROUP_MSG:"readAllGroupMessage",READ_ALL_MSG:"readAllMessage"}),ME=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},{SNS_TYPE_NO_RELATION:"CheckResult_Type_NoRelation",SNS_TYPE_A_WITH_B:"CheckResult_Type_AWithB",SNS_TYPE_B_WITH_A:"CheckResult_Type_BWithA",SNS_TYPE_BOTH_WAY:"CheckResult_Type_BothWay"}),{ALLOW_TYPE_ALLOW_ANY:"AllowType_Type_AllowAny",ALLOW_TYPE_NEED_CONFIRM:"AllowType_Type_NeedConfirm",ALLOW_TYPE_DENY_ANY:"AllowType_Type_DenyAny"}),{SNS_ADD_TYPE_SINGLE:"Add_Type_Single",SNS_ADD_TYPE_BOTH:"Add_Type_Both"}),{SNS_DELETE_TYPE_SINGLE:"Delete_Type_Single",SNS_DELETE_TYPE_BOTH:"Delete_Type_Both"}),{SNS_APPLICATION_TYPE_BOTH:"Pendency_Type_Both",SNS_APPLICATION_SENT_TO_ME:"Pendency_Type_ComeIn",SNS_APPLICATION_SENT_BY_ME:"Pendency_Type_SendOut",SNS_APPLICATION_AGREE:"Response_Action_Agree",SNS_APPLICATION_AGREE_AND_ADD:"Response_Action_AgreeAndAdd"}),{SNS_CHECK_TYPE_BOTH:"CheckResult_Type_Both",SNS_CHECK_TYPE_SINGLE:"CheckResult_Type_Single"}),{FORBID_TYPE_NONE:"AdminForbid_Type_None",FORBID_TYPE_SEND_OUT:"AdminForbid_Type_SendOut"}),La={GRP_WORK:"Private",GRP_PUBLIC:"Public",GRP_MEETING:"ChatRoom",GRP_AVCHATROOM:"AVChatRoom",GRP_COMMUNITY:"Community",GRP_ROOM:"Room",GRP_LIVE:"Live"},sa={COMMUNITY:"@TGS#_",TOPIC:"@TOPIC#_"},Tg={JOINED:1,QUITTED:2,KICKED:3,ADMIN_SET:4,ADMIN_CANCELED:5,GROUP_PROFILE_UPDATED:6,GROUP_MEMBER_PROFILE_UPDATED:7,TOPIC_PROFILE_UPDATED:8},gI=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},La),{GRP_MBR_ROLE_OWNER:"Owner",GRP_MBR_ROLE_ADMIN:"Admin",GRP_MBR_ROLE_MEMBER:"Member",GRP_MBR_ROLE_CUSTOM:"Custom"}),{GRP_TIP_MBR_JOIN:1,GRP_TIP_MBR_QUIT:2,GRP_TIP_MBR_KICKED_OUT:3,GRP_TIP_MBR_SET_ADMIN:4,GRP_TIP_MBR_CANCELED_ADMIN:5,GRP_TIP_GRP_PROFILE_UPDATED:6,GRP_TIP_MBR_PROFILE_UPDATED:7,GRP_TIP_BAN_AVCHATROOM_MEMBER:10,GRP_TIP_UNBAN_AVCHATROOM_MEMBER:11}),{JOIN_OPTIONS_FREE_ACCESS:"FreeAccess",JOIN_OPTIONS_NEED_PERMISSION:"NeedPermission",JOIN_OPTIONS_DISABLE_APPLY:"DisableApply",JOIN_STATUS_SUCCESS:"JoinedSuccess",JOIN_STATUS_ALREADY_IN_GROUP:"AlreadyInGroup",JOIN_STATUS_WAIT_APPROVAL:"WaitAdminApproval"}),{INVITE_OPTIONS_DISABLE_INVITE:"DisableInvite",INVITE_OPTIONS_NEED_PERMISSION:"NeedPermission",INVITE_OPTIONS_FREE_ACCESS:"FreeAccess"}),{GRP_PROFILE_OWNER_ID:"ownerID",GRP_PROFILE_CREATE_TIME:"createTime",GRP_PROFILE_LAST_INFO_TIME:"lastInfoTime",GRP_PROFILE_MEMBER_NUM:"memberNum",GRP_PROFILE_MAX_MEMBER_NUM:"maxMemberNum",GRP_PROFILE_JOIN_OPTION:"joinOption",GRP_PROFILE_INVITE_OPTION:"inviteOption",GRP_PROFILE_INTRODUCTION:"introduction",GRP_PROFILE_NOTIFICATION:"notification",GRP_PROFILE_MUTE_ALL_MBRS:"muteAllMembers"}),{GROUP_ID_PREFIX:sa,GROUP_TIPS_OPERATION_TYPE:Tg}),hs={IOS_OFFLINE_PUSH_NO_SOUND:"push.no_sound",IOS_OFFLINE_PUSH_DEFAULT_SOUND:"default"},Lo=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},zg),ag),_g),Dc),ME),gI),hs),{NET_STATE_CONNECTING:"connecting",NET_STATE_DISCONNECTED:"disconnected",NET_STATE_CONNECTED:"connected"}),da={NO_SDKAPPID:2e3,NO_TINYID:2022,NO_A2KEY:2023,USER_NOT_LOGGED_IN:2024,REPEAT_LOGIN:2025,MSG_SEND_FAIL:2100,MSG_SEND_FAIL_NOT_IN_AV:2101,MSG_SEND_GRP_WITH_TOPIC_FAIL:2115,MSG_INSTANCE_REQUIRED:2105,MSG_INVALID_CONV_TYPE:2106,MSG_REVOKE_FAIL:2110,MSG_DELETE_FAIL:2111,MSG_UNREAD_ALL_FAIL:2112,READ_RECEIPT_MSG_LIST_EMPTY:2114,CANNOT_DELETE_GRP_SYSTEM_NOTICE:2116,NOT_MY_FRIEND:2700,NETWORK_ERROR:2800,NETWORK_TIMEOUT:2801,NO_NETWORK:2805,UNCAUGHT_ERROR:2903,INVALID_OPERATION:2905,SDK_IS_NOT_READY:2999,LOGGING_IN:3e3,LOGIN_FAILED:3001,KICKED_OUT_MULT_DEVICE:3002,KICKED_OUT_MULT_ACCOUNT:3003,KICKED_OUT_USERSIG_EXPIRED:3004,LOGGED_OUT:3005,KICKED_OUT_REST_API:3006,NO_USE:3122,OPTIONS_IS_EMPTY:3153,MSG_A2KEY_EXPIRED:20002,ACCOUNT_A2KEY_EXPIRED:70001,HELLO_ANSWER_KICKED_OUT:1002,OPEN_SERVICE_OVERLOAD_ERROR:60022},nr={BASIC:"1",STANDARD:"2",PROFESSIONAL:"3",NODE:"4"},Yt={SYNC_SERVER_INFO_AFTER_RE_ONLINE:"sync-server-info-after-re-online",SYNC_SERVER_INFO_AFTER_LOGIN:"sync-server-info-after-login",RECEIVE_C2C_NEW_MESSAGE:"receive-c2c-new-message",RECEIVE_GROUP_NEW_MESSAGE:"receive-group-new-message",RECEIVE_GROUP_TIPS_NOTIFICATION:"receive-group-tips-notification"},qt={USER_STATUS_UPDATE:"user-status-update",CONVERSATION_RECOVER:"conversation-recover",HISTORY_MESSAGE_RECOVER:"history-message-recover",BLACKLIST_RECOVER:"blacklist-recover",FRIEND_RECOVER:"friend-recover",GROUP_ATTRIBUTE_CACHE_CLEAR:"group-attribute-cache-clear",UNREAD_MESSAGE_RECOVER:"unread-message-recover",HANDLE_NEW_MESSAGE:"handle-new-message",HANDLE_CONVERSATION_PROFILE_UPDATED:"handle-conversation-profile-updated",COMMERCIAL_CONFIG_UPDATE:"commercial-config-update",UNREAD_MESSAGE_SYNC:"unread-message-sync",FRIEND_AND_BLACKLIST_SYNC:"friend-and-blacklist-sync",SIGNALING_MESSAGE_RECOVER:"signaling-message-recover",GROUP_LIST_SYNC:"group-list-sync",CONVERSATION_LIST_SYNC:"conversation-list-sync",USER_PROFILE_SYNC:"user-profile-sync",CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED:"conversation-update-after-unread-sync-finished",CONVERSATION_UPDATE_AFTER_GROUP_LIST_SYNC_FINISHED:"conversation-update-after-group-list-sync-finished",HANDLE_C2C_NEW_MESSAGE:"handle-c2c-new-message",HANDLE_GROUP_NEW_MESSAGE:"handle-group-new-message",CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE:"create-or-update-conversation-by-receive-new-message",HANDLE_GROUP_TIPS_FROM_SYNC_UNREAD:"handle-group-tips-from-sync-unread",HANDLE_C2C_REVOKED_MESSAGE_FROM_SYNC_UNREAD:"handle-c2c-revoked-message-from-sync-unread",GROUP_REVOKED_NOTICE_RECOVER:"group-revoked-notice-recover",CLOUD_CONFIG_SYNC:"cloud-config-sync",UPDATE_GROUP_NEXT_SEQUENCE:"update-group-next-sequence",EMIT_C2C_MESSAGE_EVENT:"emit-c2c-message-event",EMIT_GROUP_MESSAGE_EVENT:"emit-group-message-event",CONVERSATION_GROUP_LIST_SYNC:"conversation-group-list-sync",CONVERSATION_GROUP_UPDATE:"conversation-group-update",UPDATE_TOPIC_AFTER_UNREAD_SYNC_FINISHED:"update-topic-after-unread-sync-finished",UPDATE_TOPIC_BY_RECEIVE_NEW_MESSAGE:"update-topic-by-received-new-message",TOPIC_REQUEST_INFO_RESET:"topic-request-info-reset",QUALITY_REPORT:"quality-report",GROUP_TIPS_RECOVER:"group-tips-recover",HANDLE_GROUP_TIPS_NOTIFICATION:"handle-group-tips-notification",C2C_HISTORY_MESSAGE_RECOVER:"c2c-history-message-recover",FRIEND_APPLICATION_LIST_RECOVER:"friend-application-list-recover",EMIT_GROUP_TIPS_EVENT:"emit-group-tips-event",STREAM_MESSAGE_RECOVER:"stream-message-recover"},Ng={[Yt.SYNC_SERVER_INFO_AFTER_RE_ONLINE]:[{stepId:qt.USER_STATUS_UPDATE},{stepId:qt.GROUP_ATTRIBUTE_CACHE_CLEAR},{stepId:qt.UNREAD_MESSAGE_SYNC,dependency:qt.C2C_HISTORY_MESSAGE_RECOVER},{stepId:qt.CONVERSATION_RECOVER},{stepId:qt.HISTORY_MESSAGE_RECOVER,dependency:qt.CONVERSATION_RECOVER},{stepId:qt.BLACKLIST_RECOVER},{stepId:qt.FRIEND_RECOVER},{stepId:qt.FRIEND_APPLICATION_LIST_RECOVER},{stepId:qt.GROUP_REVOKED_NOTICE_RECOVER,dependency:qt.HISTORY_MESSAGE_RECOVER},{stepId:qt.GROUP_TIPS_RECOVER,dependency:qt.HISTORY_MESSAGE_RECOVER},{stepId:qt.TOPIC_REQUEST_INFO_RESET},{stepId:qt.HANDLE_C2C_REVOKED_MESSAGE_FROM_SYNC_UNREAD,dependency:qt.UNREAD_MESSAGE_SYNC},{stepId:qt.HANDLE_GROUP_TIPS_FROM_SYNC_UNREAD,dependency:qt.UNREAD_MESSAGE_SYNC},{stepId:qt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,dependency:[qt.UNREAD_MESSAGE_SYNC,qt.CONVERSATION_RECOVER]},{stepId:qt.EMIT_C2C_MESSAGE_EVENT,dependency:[qt.UNREAD_MESSAGE_SYNC,qt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED],skipIfDependencyMissing:!1},{stepId:qt.C2C_HISTORY_MESSAGE_RECOVER,dependency:qt.CONVERSATION_RECOVER},{stepId:qt.STREAM_MESSAGE_RECOVER}],[Yt.SYNC_SERVER_INFO_AFTER_LOGIN]:[{stepId:qt.COMMERCIAL_CONFIG_UPDATE},{stepId:qt.CLOUD_CONFIG_SYNC},{stepId:qt.USER_PROFILE_SYNC},{stepId:qt.UNREAD_MESSAGE_SYNC},{stepId:qt.FRIEND_AND_BLACKLIST_SYNC},{stepId:qt.GROUP_LIST_SYNC},{stepId:qt.CONVERSATION_LIST_SYNC},{stepId:qt.SIGNALING_MESSAGE_RECOVER,dependency:qt.UNREAD_MESSAGE_SYNC},{stepId:qt.UPDATE_TOPIC_AFTER_UNREAD_SYNC_FINISHED,dependency:[qt.UNREAD_MESSAGE_SYNC]},{stepId:qt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,dependency:[qt.UNREAD_MESSAGE_SYNC,qt.CONVERSATION_LIST_SYNC]},{stepId:qt.CONVERSATION_UPDATE_AFTER_GROUP_LIST_SYNC_FINISHED,dependency:[qt.GROUP_LIST_SYNC,qt.CONVERSATION_LIST_SYNC]},{stepId:qt.CONVERSATION_GROUP_LIST_SYNC},{stepId:qt.CONVERSATION_GROUP_UPDATE,dependency:[qt.CONVERSATION_LIST_SYNC,qt.CONVERSATION_GROUP_LIST_SYNC]},{stepId:qt.QUALITY_REPORT}],[Yt.RECEIVE_C2C_NEW_MESSAGE]:[{stepId:qt.HANDLE_C2C_NEW_MESSAGE},{stepId:qt.UNREAD_MESSAGE_SYNC},{stepId:qt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,dependency:qt.HANDLE_C2C_NEW_MESSAGE},{stepId:qt.EMIT_C2C_MESSAGE_EVENT,dependency:[qt.HANDLE_C2C_NEW_MESSAGE,qt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE],skipIfDependencyMissing:!1},{stepId:qt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,dependency:[qt.UNREAD_MESSAGE_SYNC]}],[Yt.RECEIVE_GROUP_NEW_MESSAGE]:[{stepId:qt.HANDLE_GROUP_NEW_MESSAGE},{stepId:qt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,dependency:qt.HANDLE_GROUP_NEW_MESSAGE},{stepId:qt.UPDATE_GROUP_NEXT_SEQUENCE,dependency:qt.HANDLE_GROUP_NEW_MESSAGE},{stepId:qt.UPDATE_TOPIC_BY_RECEIVE_NEW_MESSAGE,dependency:qt.HANDLE_GROUP_NEW_MESSAGE},{stepId:qt.EMIT_GROUP_MESSAGE_EVENT,dependency:[qt.HANDLE_GROUP_NEW_MESSAGE,qt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE],skipIfDependencyMissing:!1}],[Yt.RECEIVE_GROUP_TIPS_NOTIFICATION]:[{stepId:qt.HANDLE_GROUP_TIPS_NOTIFICATION},{stepId:qt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,dependency:qt.HANDLE_GROUP_TIPS_NOTIFICATION},{stepId:qt.EMIT_GROUP_TIPS_EVENT,dependency:[qt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,qt.HANDLE_GROUP_TIPS_NOTIFICATION],skipIfDependencyMissing:!1}]},cI={MESSAGE_SEND_SUCCESS_RATE:"messageSendSuccessRate"},rr={TOTAL_COUNT:"sendMessageTotalCount",SUCCESS_COUNT:"sendMessageSuccessCount",FAILED_COUNT:"sendMessageFailedCount",SEND_COST:"sendMessageCost"},qI=["login","getMyProfile","getUserProfile","updateMyProfile","setSelfStatus","getUserStatus","subscribeUserStatus","unsubscribeUserStatus","modifyMessage","deleteGroupMember","dismissGroup","getGroupMemberList","getGroupOnlineMemberCount","joinGroup","markGroupMemberList","quitGroup","searchCloudMessages","searchCloudGroups","searchCloudGroupMembers","searchCloudUsers","getMyFollowingList","getMyFollowersList","getMutualFollowersList","followUser","unfollowUser","getUserFollowInfo","checkFollowType","getFriendProfile","addFriend","deleteFriend","updateFriend","checkFriend","setFriendApplicationRead","createFriendGroup","deleteFriendGroup","addToFriendGroup","removeFromFriendGroup","renameFriendGroup","changeGroupOwner","createGroup","dismissGroup","getGroupList","getGroupOnlineMemberCount","getGroupProfile","searchGroupByID","updateGroupProfile","handleGroupApplication","deleteGroupAttributes","getGroupAttributes","initGroupAttributes","setGroupAttributes","addGroupMember","deleteGroupMember","getGroupMemberList","getGroupMemberProfile","setGroupMemberMuteTime","setGroupMemberNameCard","setGroupMemberRole","deleteMessage","revokeMessage","setMessageExtensions","getMessageExtensions","deleteMessageExtensions","getMessageList","addMessageReaction","removeMessageReaction","clearHistoryMessage","sendMessageReadReceipt","getMessageReadReceiptList","getGroupMessageReadMemberList","createMergerMessage","invite","accept","cancel","reject","modifyInvitation","deleteConversation","pinConversation","setMessageRead","setAllMessageRead","getConversationList","getTotalUnreadMessageCount","renameConversationGroup","deleteConversationGroup","markConversation","setConversationCustomData","deleteConversationsFromGroup","addConversationsToGroup","createConversationGroup"];var za=Object.freeze({__proto__:null,ERROR_CODE:da,InnerEvent:no,NEED_LOG_API:qI,OuterConstant:Lo,OuterEvent:Dr,PUSH:hs,QUALITY_METRICS:cI,SDK_EDITION:nr,SDK_INFO:{VERSION:"1.7.3",APPID:537048168},SEND_MESSAGE_STAT:rr,SignalingEvent:qc,WEB_PUSH_ACCOUNT_TYPE:1,WORKFLOW_DEFINITIONS:Ng,WORKFLOW_NAME:Yt,WORKFLOW_STEP:qt}),na,un,Sn;(function(s){s[s.USER_INITIATED=0]="USER_INITIATED",s[s.KICKED_OUT=1]="KICKED_OUT"})(na||(na={})),function(s){s[s.multipleAccount=1]="multipleAccount",s[s.multipleDevice=2]="multipleDevice",s[s.restApi=3]="restApi"}(un||(un={})),function(s){s[s.multipleDevice=3002]="multipleDevice",s[s.multipleAccount=3003]="multipleAccount",s[s.usersigExpired=70001]="usersigExpired",s[s.restApi=20002]="restApi"}(Sn||(Sn={}));const Tu={[un.multipleAccount]:"multipleAccount",[un.multipleDevice]:"multipleDevice",[un.restApi]:"REST_API_Kick",[Sn.multipleAccount]:"multipleAccount",[Sn.multipleDevice]:"multipleDevice",[Sn.restApi]:"REST_API_Kick",[Sn.usersigExpired]:"userSigExpired"},Gg="login_online_presence_task",{ERROR:Ua,DESTROY:jc,FORCE_OFFLINE:KI}=no,{KICKED_OUT_MULT_ACCOUNT:vE,KICKED_OUT_MULT_DEVICE:lI,KICKED_OUT_REST_API:Nu,ACCOUNT_A2KEY_EXPIRED:Rl,MSG_A2KEY_EXPIRED:Sc}=da;class Gu{init(){const{notificationCenter:n}=ye;n.subscribeInnerEvent(KI,this._handleForceOfflineFromServerPush,this),n.subscribeInnerEvent(Ua,Sc,this._handleForceOfflineFromResponse,this,this._isChatLoginEvent),n.subscribeInnerEvent(Ua,Rl,this._handleForceOfflineFromResponse,this,this._isChatLoginEvent),n.subscribeInnerEvent(Ua,vE,this._handleForceOfflineFromResponse,this),n.subscribeInnerEvent(Ua,lI,this._handleForceOfflineFromResponse,this),n.subscribeInnerEvent(Ua,Nu,this._handleForceOfflineFromResponse,this),n.subscribeInnerEvent(jc,this._dispose,this)}_handleForceOfflineFromServerPush(n){var g;if(((g=ye.store.get("login"))===null||g===void 0?void 0:g.isLoggedIn)===!0){const{EventArray:u=[]}=n?.body||{};this._extractKickedOutMessages(u).forEach(E=>{const{KickoutMsgNotify:{KickType:m,NewInstInfo:D,Instid:M}}=E;this._isCurrentInstanceKickedOut(M)&&this._processKickedOutReasonInfo({kickedOutReasonCode:m,newInstanceInfo:D})})}}_extractKickedOutMessages(n){return n.reduce((g,u)=>[...g,...u.C2cNotifyMsgArray||[]],[]).filter(g=>{var u;return this._isKickedOut((u=g?.KickoutMsgNotify)===null||u===void 0?void 0:u.KickType)})}_handleForceOfflineFromResponse(n){const{errorCode:g}=n;this._processKickedOutReasonInfo({kickedOutReasonCode:g})}_processKickedOutReasonInfo(n){return pA(this,void 0,void 0,function*(){const{kickedOutReasonCode:g}=n,{ssoLog:u,utils:{safeStringify:E}}=ye;try{this._logKickedOutEvent(n),this._shouldLogoutAfterKickedOut(g)?yield ye.login.loginAction.logout(na.KICKED_OUT):ye.login.loginAction.handleLogoutCompleted()}catch(m){u.debug("_processKickedOutReasonInfo",` fail ${E(m)}`)}finally{ye.notificationCenter.emitOuterEvent(Dr.KICKED_OUT,{data:{type:Tu[g]},name:Dr.KICKED_OUT})}})}_logKickedOutEvent(n){const{kickedOutReasonCode:g,newInstanceInfo:u={}}=n,E=`type:${Tu[g]} newInstanceInfo: ${JSON.stringify(u)}`;ye.ssoLog.warn("kickedOut",E)}_isKickedOut(n){return[un.multipleAccount,un.multipleDevice,un.restApi].includes(n)}_isChatLoginEvent(n){const{requestHead:g}=n||{};return g?.idtype!==1}_shouldLogoutAfterKickedOut(n){return![Sn.usersigExpired,un.restApi].includes(n)}_isCurrentInstanceKickedOut(n){const{isLoggedIn:g,statusInstanceId:u}=ye.store.get("login")||{};return g===!0&&n===u}_dispose(){const{notificationCenter:n}=ye;n.unSubscribeInnerEvent(KI,this._handleForceOfflineFromServerPush,this),n.unSubscribeInnerEvent(Ua,Rl,this._handleForceOfflineFromResponse,this),n.unSubscribeInnerEvent(Ua,Sc,this._handleForceOfflineFromResponse,this),n.unSubscribeInnerEvent(Ua,vE,this._handleForceOfflineFromResponse,this),n.unSubscribeInnerEvent(Ua,lI,this._handleForceOfflineFromResponse,this),n.unSubscribeInnerEvent(Ua,Nu,this._handleForceOfflineFromResponse,this),n.unSubscribeInnerEvent(jc,this._dispose,this)}}function bu(s){return pA(this,void 0,void 0,function*(){const n="im_open_status.wslogin",g=ye.common.generateProtocolData({servcmd:n,data:{State:"Online",is_web_uniapp:0,InstType:0,CustomInfo:s}}),u=`${g.head.seq}${n}`,E=yield ye.channel.sendPacket(g,{timeout:9e4,requestId:u});if(E){const{HelloInterval:m,InstId:D,TinyId:M,TimeStamp:T,CustomStatus:P,PurchaseBits:W,A2Key:iA,RichMsgAuthKey:EA,ErrorCode:RA,ErrorInfo:kA,ActionStatus:xA}=E;return{helloInterval:m,instanceID:D,tinyID:M,timeStamp:T,customStatus:P,purchaseBits:W,a2Key:iA,authKey:EA,errorCode:RA,errorInfo:kA,actionStatus:xA}}})}function wl(){const{store:s}=ye;return ua(s.get("instance").sdkAppId)!==gt.CHINA}function rs(s){var n;try{const g=$i.getStorage("errorMessage");if(!s||!g)return"";const u=((n=JSON.parse(g))===null||n===void 0?void 0:n.errorMessage)||{},{code:E,replacement1:m="",replacement2:D=""}=s;if(!E)return"";const M=wl()?`${E}_en`:`${E}_cn`;let T=u[u[M]?M:E]||"";return T&&(m&&(T=T.replace("$replacement1",m)),D&&(T=T.replace("$replacement2",D))),T}catch(g){return console.warn("Error parsing stored error messages:",g),""}}class gs extends Error{constructor(n={}){n.code=n.code||n.errorCode;let{functionName:g="Unknown",code:u,message:E="",data:m="",moreMessage:D="",errorMessage:M=""}=n;M=(u?rs(n):"")||M||E;let T=u?`${g} failed. error: {"message": ${M}, "code": ${u}}`:`${g} failed. error: {"message": ${M}}`;T=`${T} ${D}`,super(),this.code=u,this.errorCode=u,this.errorMessage=M,this.message=T,this.data=m}}function ud(s,n){var g;if(s&&((g=ye.store.get("login"))===null||g===void 0?void 0:g.isLoggedIn)!==!0)throw new gs({code:da.USER_NOT_LOGGED_IN,functionName:n})}function II(s,n,g){if(Array.isArray(s))for(let u=0;u{return P===(W=u,Object.prototype.toString.call(W).match(/^\[object (.*)\]$/)[1].toLowerCase());var W})){for(let W=0;W{const{interceptor:E,context:m}=u;E.apply(m,[g])})}(s)}function Mc(s,n){RE.push({interceptor:s,context:n})}function Wc(s){const{params:n,auth:g}=s;n&&typeof n=="object"&&Object.assign(_l,n),g&&typeof g=="object"&&Object.assign(Ed,g)}function tn(s){return ye.store.get("commercialConfig").get(s)}class ws{constructor(){this._handlers=new Map,this._activeWorkflows=new Map,this._stepStartTimes=new Map,this._logHandlers={start:(n,g)=>{const u=Date.now();g?(this._stepStartTimes.set(`${n}-${g}`,u),ye.ssoLog.debug("_executeWorkflowStep",`[Workflow ${n}] Step ${g} started at ${new Date(u).toISOString()}`)):(this._workflowStartTimes.set(n,u),ye.ssoLog.debug("_executeWorkflowStep",`[Workflow ${n}] started at ${new Date(u).toISOString()}`))},success:(n,g)=>{const u=Date.now();if(g){const E=this._stepStartTimes.get(`${n}-${g}`),m=E?u-E:0;this._stepStartTimes.delete(`${n}-${g}`),ye.ssoLog.debug("_executeWorkflowStep",`[Workflow ${n}] Step ${g} completed successfully at ${new Date(u).toISOString()} (${m}ms)`)}else{const E=this._workflowStartTimes.get(n),m=E?u-E:0;this._workflowStartTimes.delete(n),ye.ssoLog.debug("_executeWorkflowStep",`[Workflow ${n}] completed successfully at ${new Date(u).toISOString()} (${m}ms)`)}},error:(n,g,u)=>{const{ssoLog:E,utils:{safeStringify:m}}=ye,D=Date.now();if(g){const M=this._stepStartTimes.get(`${n}-${g}`),T=M?D-M:0;this._stepStartTimes.delete(`${n}-${g}`),E.error("_executeWorkflowStep",`[Workflow ${n}] Step ${g} failed at ${new Date(D).toISOString()} (${T}ms) ${m(u)}`,{error:u})}else{const M=this._workflowStartTimes.get(n),T=M?D-M:0;this._workflowStartTimes.delete(n),E.error("_executeWorkflowStep",`[Workflow ${n}] failed at ${new Date(D).toISOString()} (${T}ms) ${m(u)}`,{error:u})}}}}static getInstance(){return ws._instance||(ws._instance=new ws),ws._instance}static setInstance(n){ws._instance=n}init(){this._initializeWorkflows()}registerWorkflowStep(n,g,u,E){if(!this._handlers.has(n))return void ye.ssoLog.debug("registerWorkflowStep",`Workflow '${n}' not defined in core`);if(!Ng[n].find(D=>D.stepId===g))return void ye.ssoLog.debug("registerWorkflowStep",`Step '${g}' not defined in workflow '${n}'`);const m=this._handlers.get(n);m.has(g)||m.set(g,E?u.bind(E):u)}executeWorkflow(n,g){return pA(this,void 0,void 0,function*(){if(!this._validateWorkflow(n))return;ye.ssoLog.debug("executeWorkflow",`[Workflow ${n}] Started execution at ${new Date().toISOString()}`);const u=Ng[n],E={},m={cancelled:!1};this._activeWorkflows.set(n,{cancelToken:m});try{const D=new Map;u.forEach(T=>{D.set(T.stepId,T)});const M={workflowName:n,pendingSteps:new Set(u.map(T=>T.stepId)),completedSteps:new Set,runningSteps:new Set,stepMap:D,stepResults:E,data:g,cancelToken:m};yield new Promise((T,P)=>{const W=()=>{if(m.cancelled)return void T();this._getExecutableSteps({pendingSteps:M.pendingSteps,completedSteps:M.completedSteps,stepMap:M.stepMap,workflowName:n}).filter(iA=>!M.runningSteps.has(iA)).forEach(iA=>{M.completedSteps.has(iA)||M.runningSteps.has(iA)||this._executeWorkflowStep(iA,M,{onComplete:()=>{if(M.pendingSteps.size===0)return void T();this._getExecutableSteps({pendingSteps:M.pendingSteps,completedSteps:M.completedSteps,stepMap:M.stepMap,workflowName:n}).filter(EA=>!M.runningSteps.has(EA)).length===0&&M.runningSteps.size===0&&(ye.ssoLog.debug("executeWorkflow",`Workflow ${n} completed with some steps skipped due to dependency failures`),T())},onError:P,onStepComplete:W})})};W()}),ye.ssoLog.debug("executeWorkflow",`[Workflow ${n}] Completed execution at ${new Date().toISOString()}`)}catch(D){ye.ssoLog.error("executeWorkflow",`[Workflow ${n}] Failed execution at ${new Date().toISOString()}`,{error:D})}finally{this._activeWorkflows.delete(n)}})}_executeWorkflowStep(n,g,u){return pA(this,void 0,void 0,function*(){const{workflowName:E,runningSteps:m,stepMap:D,stepResults:M,data:T}=g;m.add(n),this._logWorkflowExecution(E,n,"start");try{const P=D.get(n);let W=null;P?.dependency&&(l(P.dependency)?W=M[P.dependency]:Array.isArray(P.dependency)&&(W={},P.dependency.forEach(EA=>{W[EA]=M[EA]})));const iA=this._handlers.get(E).get(n);if(iA){const EA=yield Promise.resolve(iA({data:T,result:W}));M[n]=EA,this._logWorkflowExecution(E,n,"success")}g.completedSteps.add(n)}catch(P){const W=`[Workflow].${E}.${n}`,{errorCode:iA,errorInfo:EA=`${W} failed`}=P||{},RA=new gs({functionName:W,code:iA,message:EA});ye.ssoLog.error(W,EA,{error:RA}),this._logWorkflowExecution(E,n,"error",P),u.onError(P)}finally{m.delete(n),g.pendingSteps.delete(n),u.onStepComplete(),u.onComplete()}})}reset(){this._cancelAllWorkflows()}destroy(){this.reset(),this._handlers.clear()}_initializeWorkflows(){Object.keys(Ng).forEach(n=>{this._handlers.has(n)||this._handlers.set(n,new Map)})}_cancelWorkFlow(n){const g=this._activeWorkflows.get(n);if(!g)return;const{cancelToken:u}=g;u.cancelled=!0,this._activeWorkflows.delete(n)}_cancelAllWorkflows(){Object.keys(Ng).forEach(n=>{this._cancelWorkFlow(n)})}_validateWorkflow(n){return Ng[n]?!!this._handlers.get(n):!1}_getExecutableSteps(n){const{pendingSteps:g,completedSteps:u,stepMap:E,workflowName:m}=n;return Array.from(g).filter(D=>{const M=E.get(D)||{},{dependency:T,skipIfDependencyMissing:P=!0}=M;if(!T)return!0;if(l(T))return this._isStepRegistered({workflowName:m,stepId:T})?u.has(T):!P;if(h(T)){if(T.filter(W=>!this._isStepRegistered({workflowName:m,stepId:W})).length>0&&P)return!1;for(const W of T)if(!u.has(W))return!1;return!0}return!1})}_isStepRegistered(n){var g;const{workflowName:u,stepId:E}=n;return(g=this._handlers.get(u))===null||g===void 0?void 0:g.has(E)}_logWorkflowExecution(n,g,u,E){this._logHandlers[u](n,g)}}const Ca=new Map,Xr=({type:s,groupID:n})=>s===Lo.GRP_COMMUNITY||`${n}`.startsWith(sa.COMMUNITY)&&!`${n}`.includes(sa.TOPIC),zc=(s="")=>{const n=s.startsWith("GROUP")?s.replace("GROUP",""):s;return n.startsWith(sa.COMMUNITY)&&`${n}`.includes(sa.TOPIC)},dd="openim",Zg="million_group_open_http_svc";function gg(s){return pA(this,void 0,void 0,function*(){const{servcmd:n,data:g}=function(m){const{data:D}=m;return wE(D)||Xg(D)}(s)?function(m){let{servcmd:D,data:M}=m;return Xg(M)?function(T){const{servcmd:P,data:W}=T;let{GroupId:iA=""}=W;const EA=iA;return[iA]=EA.split(sa.TOPIC),{servcmd:qn(P),data:Object.assign(Object.assign({},W),{GroupId:iA,TopicId:EA})}}(m):(wE(M)&&(D=qn(D)),{servcmd:D,data:M})}(s):s,u=ye.common.generateProtocolData({servcmd:n,data:g}),E=`${u.head.seq}${n}`;return ye.channel.sendPacket(u,{requestId:E,timeout:s.timeout})})}function wE(s){const{Type:n,GroupId:g,GroupIdList:u=[]}=s,E=g||u[0]||"";return Xr({type:n,groupID:E})}function Xg(s){const{GroupId:n=""}=s;return zc(n)}function qn(s){if(s.includes(dd))return s;const n=s.split(".")[1];return`${Zg}.${n}`}function Ar(){var s;return(s=ye.store.get("login"))===null||s===void 0?void 0:s.userId}const Fa=s=>h(s)||f(s),Cd=(s,n,g,u)=>{if(!Fa(s)||!Fa(n))return 0;let E=0;const m=Object.keys(n);let D;for(let M=0,T=m.length;M{if(r(n))return"";if(s===Lo.MSG_TEXT)return n.text||"";const g=jI[s];return g?ku(g):""},Xc=[{cmd:"ws_get_user_status",interval:5,count:20},{cmd:"ws_status_subscribe",interval:5,count:20},{cmd:"ws_status_unsubscribe",interval:5,count:20},{cmd:"get_group_self_member_info",interval:5,count:20},{cmd:"modify_group_base_info",interval:1,count:8},{cmd:"get_pendency",interval:1,count:15},{cmd:"set_group_attr",interval:5,count:10},{cmd:"modify_group_attr",interval:5,count:10},{cmd:"delete_group_attr",interval:5,count:10},{cmd:"clear_group_attr",interval:5,count:10},{cmd:"get_group_attr",interval:5,count:20},{cmd:"update_group_counter",interval:5,count:20},{cmd:"get_group_counter",interval:5,count:20},{cmd:"get_topic",interval:1,count:10},{cmd:"read_all_unread_msg",interval:1,count:1},{cmd:"query",interval:5,count:20}],WI="im_sdk_config_mgr.fetch_config",EI="im_sdk_config_mgr.push_configv2",$c="cloud-config",Al=2996,va=new class{init(s){this.core=s}};function bg(s){return pA(this,void 0,void 0,function*(){const{sdkAppId:n}=va.core.store.get("instance")||{},g=va.core.helper.generateProtocolData({servcmd:WI,data:{uint32_sdkappid:n,uint64_version:s}}),u=`${g.head.seq}${WI}`;return va.core.channel.sendPacket(g,{requestId:u})})}var ys=new class{constructor(){this._core=null,this._expirationTime=0,this._version=0,this._isFetching=!1,this._cmdFrequencyLimitMap=new Map,this._methodCallFrequencyMap=new Map}install(s){this._core=s;const{notificationCenter:n,InnerEvent:g,helper:u,constants:{WORKFLOW_NAME:E,WORKFLOW_STEP:m},channel:D}=s;n.subscribeInnerEvent(EI,this._handlePushedConfig,this),u.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_LOGIN,m.CLOUD_CONFIG_SYNC,this._handleLoginSuccess,this),n.subscribeInnerEvent(g.LOGOUT,this._reset,this),n.subscribeInnerEvent(g.DESTROY,this._dispose,this),u.registerExperimentalAPI("getServerConfig",this),this._updateCmdFreqLimitMap(Xc),D.registerBeforeSendInterceptor(this.checkMethodCallOverLimit,this)}getServerConfig(s){return pA(this,void 0,void 0,function*(){var n;const g={code:0,data:""};return s&&(g.data=((n=this._core.store.get("cloudConfig"))===null||n===void 0?void 0:n[s])||""),g})}checkMethodCallOverLimit(s){if(!this._cmdFrequencyLimitMap.has(s))return;if(!this._methodCallFrequencyMap.has(s))return void this._methodCallFrequencyMap.set(s,{startTime:Date.now(),methodCallCounter:1});const{count:n,interval:g}=this._cmdFrequencyLimitMap.get(s);let{startTime:u,methodCallCounter:E}=this._methodCallFrequencyMap.get(s);if(Date.now()-u>1e3*g)this._methodCallFrequencyMap.set(s,{startTime:Date.now(),methodCallCounter:1});else if(E+=1,this._methodCallFrequencyMap.set(s,{startTime:u,methodCallCounter:E}),E>n)throw new this._core.helper.ChatError({code:Al,replacement1:s})}_handlePushedConfig(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=this._core;n.info("_handlePushedConfig",g(s)),yield this._updateCloudConfig(s)})}_handleLoginSuccess(){return pA(this,void 0,void 0,function*(){const{ssoLog:s,utils:{safeStringify:n}}=this._core;try{if(this._canFetch()){const g=yield bg(this._version);s.info("_fetchCloudConfigIfLogin",n(g)),yield this._updateCloudConfig(g)}this._core.helper.taskScheduler.addTask({id:$c,intervalMs:1e3,callback:this._fetchCloudConfigIfReady,context:this})}catch(g){s.debug("_fetchCloudConfigIfLogin",n(g))}})}_fetchCloudConfigIfReady(){return pA(this,void 0,void 0,function*(){const{ssoLog:s,utils:{safeStringify:n}}=this._core;if(this._canFetch())try{const g=yield bg(this._version);s.info("_fetchCloudConfigIfReady",n(g)),yield this._updateCloudConfig(g)}catch(g){s.error("_fetchCloudConfigIfReady",n(g))}})}_updateCloudConfig(s){return pA(this,void 0,void 0,function*(){const n=this._parseCloudConfig(s);n&&(this._core.store.set("cloudConfig",n),yield this._parseCmdFreqLimit(),this._core.notificationCenter.emitInnerEvent(this._core.InnerEvent.CLOUD_CONFIG_UPDATE,n),this._core.notificationCenter.emitOuterEvent(this._core.OuterEvent.SERVER_CONFIG_UPDATED,{name:this._core.OuterEvent.SERVER_CONFIG_UPDATED,data:{config:n}}))})}_canFetch(){const{isLoggedIn:s}=this._core.store.get("login")||{};return s&&!this._isFetching&&Date.now()>=this._expirationTime}_parseCloudConfig(s){const{int32_error_code:n,str_error_message:g,str_json_config:u,uint32_expired_time:E,uint32_sdkappid:m,uint64_version:D}=s;let M=null;if(n===0){if(this._version!==D)try{M=JSON.parse(u),this._version=D}catch{}this._expirationTime=Date.now()+1e3*E}else this._expirationTime=n===void 0?Date.now()+36e5:Date.now()+12e4;return M}_parseCmdFreqLimit(){return pA(this,void 0,void 0,function*(){var s;let n=(s=yield this.getServerConfig("cmd_frequency_limit"))===null||s===void 0?void 0:s.data;const{isEmpty:g}=this._core.utils;if(!g(n))try{n=JSON.parse(n),this._updateCmdFreqLimitMap(n)}catch(u){console.warn(u)}})}_updateCmdFreqLimitMap(s){s.forEach(n=>{this._cmdFrequencyLimitMap.set(n.cmd,{interval:n.interval,count:n.count})})}_reset(){this._core.helper.taskScheduler.removeTask($c),this._core.store.clear("cloudConfig"),this._updateCmdFreqLimitMap(Xc),this._methodCallFrequencyMap.clear(),this._expirationTime=0,this._version=0,this._isFetching=!1}_dispose(){const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(EI,this._handlePushedConfig,this),s.unSubscribeInnerEvent(n.LOGOUT,this._reset,this),s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this),this._reset()}};class Kn{constructor(n=0,g=0){this.high=n,this.low=g}equal(n){return n!==null&&this.low===n.low&&this.high===n.high}toString(){const n=Number(this.high).toString(16);let g=Number(this.low).toString(16);if(g.length<8){let u=8-g.length;for(;u;)g=`0${g}`,u--}return n+g}}const vc={SEARCH_GRP_SNS:new Kn(0,Math.pow(2,1)).toString(),AV_HISTORY_MSG:new Kn(0,Math.pow(2,2)).toString(),GRP_COMMUNITY:new Kn(0,Math.pow(2,3)).toString(),MSG_TO_SPECIFIED_GRP_MBR:new Kn(0,Math.pow(2,4)).toString(),AV_MBR_LIST:new Kn(0,Math.pow(2,6)).toString(),USER_STATUS:new Kn(0,Math.pow(2,7)).toString(),CONV_MARK:new Kn(0,Math.pow(2,9)).toString(),CONV_GROUP:new Kn(0,Math.pow(2,10)).toString(),AV_BAN_MBR:new Kn(0,Math.pow(2,11)).toString(),MSG_EXT:new Kn(0,Math.pow(2,13)).toString(),GRP_COUNTER:new Kn(0,Math.pow(2,15)).toString(),PLUGIN_TRANSLATE:new Kn(Math.pow(2,6)).toString(),PLUGIN_VOICE_TO_TEXT:new Kn(Math.pow(2,7)).toString(),PLUGIN_CS:new Kn(Math.pow(2,8)).toString(),PLUGIN_PUSH:new Kn(Math.pow(2,9)).toString(),PLUGIN_BOT:new Kn(Math.pow(2,10)).toString(),MSG_REACTION:new Kn(Math.pow(2,16)).toString(),FOLLOW:new Kn(Math.pow(2,20)).toString()},zI="CommercialConfig",ZI="commercial-config";var _E=new class{constructor(){this._core=null,this._expirationTime=0,this._isFetching=!1,this._featureMap=new Map,this._methodKeyMap=new Map,this._purchaseBits="0"}install(s){this._core=s;const{helper:n,notificationCenter:g,constants:{WORKFLOW_NAME:u,WORKFLOW_STEP:E,InnerEvent:m}}=s;g.subscribeInnerEvent(m.COMMERCIAL_CONFIG_PUSH,this._handlePushedConfig,this),g.subscribeInnerEvent(m.LOGOUT,this._handleLogout,this),g.subscribeInnerEvent(m.DESTROY,this._dispose,this),n.registerWorkflowStep(u.SYNC_SERVER_INFO_AFTER_LOGIN,E.COMMERCIAL_CONFIG_UPDATE,this._syncCommercialConfig,this),s.helper.registerExperimentalAPI("isCommercialAbilityEnabled",this),s.helper.registerExperimentalAPI("queryCommercialAbility",this)}isCommercialAbilityEnabled(s){return pA(this,void 0,void 0,function*(){const n=parseInt(s,10).toString(2),{length:g}=n;let u,E=!0;for(let m=g-1,D=0;m>=0;m--,D++)if(n.charAt(m)==="1"&&(u=D<32?new Kn(0,2**D).toString():new Kn(2**(D-32),0).toString(),!this._featureMap.get(u))){E=!1;break}return this._core.ssoLog.debug("isFeatureEnabled",`${zI}.isFeatureEnabled decimalNumber:${s} key:${u} ret:${E}`),{code:0,data:{enabled:E}}})}queryCommercialAbility(){return this._purchaseBits}_fetchAndParseCommercialConfig(){return pA(this,void 0,void 0,function*(){var s;const{ssoLog:n,utils:{safeStringify:g},common:{buildAndSendPacket:u}}=this._core;try{this._isFetching=!0;const E=yield u({servcmd:"im_sdk_config_mgr.fetch_imsdk_purchase_bitsv2",data:{uint32_sdkappid:(s=this._core.store.get("instance"))===null||s===void 0?void 0:s.sdkAppId}});E&&(this._parseCommercialConfig(E),this._core.store.set("commercialConfig",this._methodKeyMap))}catch(E){n.error("_fetchAndParseCommercialConfig",g(E))}finally{this._isFetching=!1}})}_syncCommercialConfig(s){return pA(this,void 0,void 0,function*(){const{purchaseBits:n}=s?.data||{};n&&(this._parsePurchaseBits(n),this._core.store.set("commercialConfig",this._methodKeyMap)),this._canFetch()&&(yield this._fetchAndParseCommercialConfig()),this._core.helper.taskScheduler.addTask({id:ZI,intervalMs:1e3,callback:this._fetchCommercialConfigIfReady,context:this})})}_canFetch(){var s;const n=(s=this._core.store.get("login"))===null||s===void 0?void 0:s.isLoggedIn,g=Date.now()>=this._expirationTime;return n&&!this._isFetching&&g}_handlePushedConfig(s){s?.body&&(this._parseCommercialConfig(s.body),this._core.store.set("commercialConfig",this._methodKeyMap))}_fetchCommercialConfigIfReady(){return pA(this,void 0,void 0,function*(){this._canFetch()&&(yield this._fetchAndParseCommercialConfig())})}_parseCommercialConfig(s){const{ssoLog:n}=this._core;if(typeof s!="object")return;const{int32_error_code:g,str_error_message:u,str_purchase_bits:E,uint32_expired_time:m}=s;g===0?(this._parsePurchaseBits(E),this._expirationTime=Date.now()+1e3*m):g===void 0?(n.warn("_parseCommercialConfig",`${zI}._parseCommercialConfig failed. Invalid message format:`,s),this._expirationTime=Date.now()+36e5):(n.warn("_parseCommercialConfig",`${zI}._parseCommercialConfig errorCode:${g} errorMessage:${u}`),this._expirationTime=Date.now()+12e4)}_isValidPurchaseBits(s){return s&&typeof s=="string"&&s.length>=1&&s.length<=64&&/[01]{1,64}/.test(s)}_parsePurchaseBits(s){const{ssoLog:n,utils:{safeStringify:g}}=this._core;if(this._isValidPurchaseBits(s)){this._purchaseBits=s,this._featureMap.clear(),this._methodKeyMap.clear();let u=null;for(let E=s.length-1,m=0;E>=0;E--,m++)if(u=m<32?new Kn(0,2**m).toString():new Kn(2**(m-32),0).toString(),s[E]==="1"){this._featureMap.set(u,!0);const D=this._getKeyByValue(vc,u);D&&this._methodKeyMap.set(D,!0)}else{this._featureMap.set(u,!1);const D=this._getKeyByValue(vc,u);D&&this._methodKeyMap.set(D,!1)}}else n.warn("_parsePurchaseBits",`${zI}.parsePurchaseBits invalid purchases:${g(s)}`)}_getKeyByValue(s,n){const g=Object.entries(s).find(([u,E])=>E===n);return g?g[0]:void 0}_handleLogout(){this._reset()}_dispose(){this._reset(),this._core.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.COMMERCIAL_CONFIG_PUSH,this._handlePushedConfig,this),this._core.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),this._core.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this)}_reset(){this._core.helper.taskScheduler.removeTask(ZI),this._core.store.set("commercialConfig",{}),this._expirationTime=0,this._isFetching=!1,this._featureMap.clear(),this._purchaseBits="0"}},rh=new class{constructor(){this._core=null,this._serverOverloadInfoMap=new Map}install(s){this._core=s;const{notificationCenter:n,InnerEvent:g,channel:u}=this._core;n.subscribeInnerEvent(g.OVERLOAD_PUSH,this._handleOverLoadPush,this),n.subscribeInnerEvent(g.LOGOUT,this._reset,this),n.subscribeInnerEvent(g.DESTROY,this._dispose,this),u.registerBeforeSendInterceptor(this.checkServerOverload,this)}checkServerOverload(s){if(!this._serverOverloadInfoMap.has(s))return;const{overloadStartTimestamp:n,delaySeconds:g}=this._serverOverloadInfoMap.get(s);if(Date.now()-n<=1e3*g)throw new this._core.helper.ChatError({functionName:s,message:"service is busy, please try again later"});this._serverOverloadInfoMap.delete(s)}_handleOverLoadPush(s){const{OverLoadServCmd:n,DelaySecs:g}=s;this._serverOverloadInfoMap.set(n,{overloadStartTimestamp:Date.now(),delaySeconds:g})}_reset(){this._serverOverloadInfoMap.clear()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.OVERLOAD_PUSH,this._handleOverLoadPush,this),s.unSubscribeInnerEvent(n.LOGOUT,this._reset,this),s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}},IC=new class{constructor(){this.name="ConfigCenter"}install(s){va.init(s),ys.install(s),_E.install(s),rh.install(s)}},ah=new class{constructor(){this.name="ErrorMessage",this._core=null}install(s){return pA(this,void 0,void 0,function*(){if(this._core=s,this._canFetch()){const n=yield this._fetchErrorMessage();if(!n)return;const g=this._parseResponse(n);this._saveErrorMessage(g)}})}_canFetch(){const s=this._core.store.getStorage("errorMessage");return!s||this._isExpired(s)}_saveErrorMessage(s){this._core.store.setStorage("errorMessage",{errorMessage:s,errorMessageSavedTime:new Date().getTime()})}_fetchErrorMessage(){return pA(this,void 0,void 0,function*(){try{return yield this._core.helper.httpRequest({method:"GET",url:"https://web.sdk.qcloud.com/im/download/error-message/v3/0.0.6/tim-error-message.txt"})}catch(s){console.error(s)}})}_isExpired(s){if(!s)return!0;const{errorMessageSavedTime:n}=s;return n&&new Date().getTime()-n>=6048e5}_parseResponse(s){if(typeof s=="string"){const n=s.split(`;
-`),g={},u=new RegExp(/'/g);for(let E=0;E{var JA,ae,ne;const _i=function(Ti,Lt){const{From_Account:Ni,From_AccountHeadurl:cs,From_AccountNick:Me,IsNeedReadReceipt:mt,MsgBody:UA,MsgClientTime:ni,MsgRandom:_s,MsgSeq:Gi,MsgTimeStamp:Or,SendMsgControl:xi,SupportMessageExtension:gr,To_Account:Tt,TinyId:Nt,MsgCheckResult:tE,CloudCustomData:ln,IsPeerRead:Bo,MsgFlagBits:Il,MsgVersion:_C,EventArray:_r}=Ti;return{from:Ni,avatar:cs,nick:Me,needReadReceipt:mt===1,readReceiptSentByPeer:Bo,clientTime:ni,messageFlagBits:Il,random:_s,sequence:Gi,time:Or,messageControlInfo:xi,isSupportExtension:gr,to:Tt,tinyID:Nt,checkResult:tE,cloudCustomData:ln,messageVersion:_C,eventArray:_r,elements:Lt.message.messageHelper.parseServerPushMessageElement(UA)}}(OA,xA);if(!((ne=(ae=(JA=OA?.EventArray)===null||JA===void 0?void 0:JA[0])===null||ae===void 0?void 0:ae.hasOwnProperty)===null||ne===void 0)&&ne.call(ae,"C2cNotifyMsgArray"))SA.push(...function(Ti){var Lt;const Ni=[];return(Lt=Ti.EventArray)===null||Lt===void 0||Lt.forEach(cs=>{var Me,mt;const{C2cNotifyMsgArray:UA}=cs,ni=(mt=(Me=UA?.[0])===null||Me===void 0?void 0:Me.WithdrawC2cMsgNotify)===null||mt===void 0?void 0:mt.C2cWithdrawInfoArray;Array.isArray(ni)&&Ni.push(...ni)}),Ni}(OA));else{const Ti=xA.message.messageFactory.createMessage(Object.assign(Object.assign({},_i),{conversationType:"C2C",flow:"in"})),{elements:Lt}=_i;Ti.setElement(Lt),LA.push(Ti)}}),{unreadMessageList:LA,revokedMessageList:SA}}(T.MsgList,n);return{syncFlag:T?.SyncFlag,unreadMessageList:EA,revokedMessageList:RA,unreadCountList:P,overflowUnreadCountList:W,cookie:T?.Cookie,groupTipList:iA}}catch(T){console.warn(T)}})}var kg,ro;(function(s){s[s.START_SYNC=0]="START_SYNC",s[s.SYNCING=1]="SYNCING",s[s.SYNC_COMPLETE=2]="SYNC_COMPLETE"})(kg||(kg={})),function(s){s[s.LOGIN_SUCCESS=0]="LOGIN_SUCCESS",s[s.NEW_MESSAGE_RECEIVED=1]="NEW_MESSAGE_RECEIVED"}(ro||(ro={}));var uC=new class{constructor(){this.name="UnreadMessageSynchronizer",this._unreadDBMessageMap=new Map,this._cookie="",this._localConversationIDListBeforeDisconnect=[]}install(s){this._core=s;const{constants:n}=s;s.helper.registerWorkflowStep(n.WORKFLOW_NAME.SYNC_SERVER_INFO_AFTER_RE_ONLINE,n.WORKFLOW_STEP.UNREAD_MESSAGE_SYNC,this._syncUnreadDBMessageAfterReOnline,this),s.helper.registerWorkflowStep(n.WORKFLOW_NAME.RECEIVE_C2C_NEW_MESSAGE,n.WORKFLOW_STEP.UNREAD_MESSAGE_SYNC,this._syncUnreadDBMessageAfterNewMessageReceived,this),s.helper.registerWorkflowStep(n.WORKFLOW_NAME.SYNC_SERVER_INFO_AFTER_LOGIN,n.WORKFLOW_STEP.UNREAD_MESSAGE_SYNC,this._syncUnreadDBMessageAfterLogin,this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.SOCKET_DISCONNECTED,this._handleDisconnect,this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.LOGOUT,this._reset,this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this)}_syncUnreadMessage(s){return pA(this,void 0,void 0,function*(){const{isAfterReOnline:n=!1,isAfterNewMessageReceived:g=!1,isAfterLogin:u=!1}=s||{};let E=kg.START_SYNC;const m=[],D=[],M=[],T=[];for(;this._canContinueSync({cookie:this._cookie,syncFlag:E});){const P=yield this._fetchUnreadDBMessage({cookie:this._cookie,syncFlag:E,syncTriggerEvent:g?ro.NEW_MESSAGE_RECEIVED:ro.LOGIN_SUCCESS});if(!P)break;const{unreadMessageList:W=[],revokedMessageList:iA=[],overflowUnreadCountList:EA,unreadCountList:RA,groupTipList:kA}=P;if(this._cookie=P?.cookie||"",E=P?.syncFlag,this._parseAndSaveUnreadMessageList(W),M.push(...iA),this._updateConversationUnreadOptions({unreadCountList:RA,overflowUnreadCountList:EA,conversationUpdateFieldList:m}),Array.isArray(kA)&&D.push(...kA),n){const{messages:xA}=this._handleNewMessageList(W);T.push(...xA)}}return n?{conversationUpdateFieldList:m,revokedMessageList:M,unreadMessageMap:this._unreadDBMessageMap,groupTipList:D,messages:T,isUnreadC2CMessage:!0}:{conversationUpdateFieldList:m,isInstantMessage:!u,isUnreadC2CMessage:!0,revokedMessageList:M,unreadMessageMap:this._unreadDBMessageMap,groupTipList:D}})}_syncUnreadDBMessageAfterLogin(){return pA(this,void 0,void 0,function*(){return this._cookie="",this._syncUnreadMessage({isAfterLogin:!0})})}_syncUnreadDBMessageAfterNewMessageReceived(s){return pA(this,void 0,void 0,function*(){if(s.data.Flag===1)return this._syncUnreadMessage({isAfterNewMessageReceived:!0})})}_updateConversationUnreadOptions(s){const{unreadCountList:n,overflowUnreadCountList:g,conversationUpdateFieldList:u}=s,{constants:{OuterConstant:{CONV_C2C:E,CONV_SYSTEM:m}}}=this._core;n?.forEach(D=>{const{From_Account:M,UnreadCount:T}=D;if(M!==m){const P=u.find(({conversationID:W})=>W===`${E}${M}`);P?P.unreadCount=T:u.push({conversationID:`${E}${M}`,unreadCount:T,type:E})}}),g?.forEach(D=>{const{From_Account:M,LastMsgTime:T}=D;M!==m&&(u.find(({conversationID:P})=>P===`${E}${M}`)||u.push({conversationID:`${E}${M}`,type:E,lastMsgTime:T}))})}_syncUnreadDBMessageAfterReOnline(){return pA(this,void 0,void 0,function*(){return this._syncUnreadMessage({isAfterReOnline:!0})})}_updateMessageProfile(s){var n;const{messageDataHandler:g}=this._core.message||{},u=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.userId,{from:E,nick:m,avatar:D,conversationID:M=""}=s;if(E!==u){const T=g.getLatestMsgSentByPeer(M);if(T){const{nick:P,avatar:W}=T;m&&D?m===P&&D===W||g.updateNickAndAvatarOfSentMessage({conversationID:M,latestNick:m,latestAvatar:D,isSentByMe:!1}):(s.nick=P,s.avatar=W)}}else{const T=g.getLatestMsgSentByMe(M);!T||m===T.nick&&D===T.avatar||g.updateNickAndAvatarOfSentMessage({conversationID:M,latestNick:m,latestAvatar:D,isSentByMe:!0})}}_handleNewMessageList(s){const{messageDataHandler:n}=this._core.message||{},g=new Map,u=[];return s.forEach(E=>{this._updateMessageProfile(E);let m=E.isModified===1;if(n.isMessageSentByCurrentInstance(E)?E.isModified=m:m=!1,E.isOnlineMessage())E._onlineOnlyFlag=!0,n.isMessageSentByCurrentInstance(E)||u.push(E);else if(this._shouldStoreUnreadMessage(E)){if(n.storeConversationMessage(E)){const{conversationID:D,conversationType:M,conversationSubType:T,flow:P,_isExcludedFromUnreadCount:W,_isExcludedFromLastMessage:iA}=E,EA=iA?"":E;g.has(D)?(g.get(D).lastMessage=EA,P==="in"&&(W||g.get(D).unreadCount++)):g.set(D,{conversationID:D,type:M,subType:T,unreadCount:W||P!=="in"?0:1,lastMessage:EA})}n.isMessageSentByCurrentInstance(E)&&!m||u.push(E)}}),{messages:u,conversationOptions:g}}_shouldStoreUnreadMessage(s){var n;const{conversationID:g}=s,{message:u,appStore:E,utils:{isEmpty:m}}=this._core||{},D=Array.from(((n=E.conversationStore.getConversationMap())===null||n===void 0?void 0:n.keys())||[]),M=this._getLocalLastMessageTime(g);return!u.messageDataHandler.isInMessageList(s)&&D.includes(g)&&this._localConversationIDListBeforeDisconnect.includes(g)&&!m(M)}_fetchUnreadDBMessage(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=this._core;try{n.debug("_fetchUnreadDBMessage",`unread-message-synchronizer._fetchUnreadDBMessage options:${g(s)}`);const E=yield el(s,this._core);if(!E)return null;const{syncFlag:m,unreadMessageList:D,revokedMessageList:M,cookie:T,unreadCountList:P,overflowUnreadCountList:W,groupTipList:iA}=E;return this._parseAndSaveUnreadMessageList(D),{syncFlag:m,cookie:T,unreadMessageList:D,revokedMessageList:M,unreadCountList:P,overflowUnreadCountList:W,groupTipList:iA}}catch(u){console.log(u)}})}_canContinueSync({cookie:s,syncFlag:n}){var g;return n===kg.START_SYNC||n===kg.SYNCING&&!(!((g=this._core)===null||g===void 0)&&g.helper.isEmpty(s))}_parseAndSaveUnreadMessageList(s){s.forEach(n=>{const{ID:g}=n;this._unreadDBMessageMap.set(g,n)})}_handleDisconnect(){var s;const{appStore:n}=this._core;this._localConversationIDListBeforeDisconnect=Array.from(((s=n.conversationStore.getConversationMap())===null||s===void 0?void 0:s.keys())||[])}_getLocalLastMessageTime(s){const{message:n}=this._core,g=n.messageDataHandler.getLocalMessageList(s),u=g[g.length-1];return u?.time}_reset(){this._cookie="",this._unreadDBMessageMap.clear()}_dispose(){var s,n;(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this),this._reset()}},TE=new class{init(s){var n;this._core=s,this._visibilityChangeHandler=this._handleVisibilityChange.bind(this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this),document?.addEventListener("visibilitychange",this._visibilityChangeHandler),(n=this._core)===null||n===void 0||n.store.set("activityMonitor",{isActive:!0})}_handleVisibilityChange(){var s,n;const g=document?.visibilityState==="visible";(s=this._core)===null||s===void 0||s.store.set("activityMonitor",{isActive:g}),(n=this._core)===null||n===void 0||n.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:g})}_reset(){var s;(s=this._core)===null||s===void 0||s.store.clear("activityMonitor")}_dispose(){document?.removeEventListener("visibilitychange",this._visibilityChangeHandler);const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this),this._reset()}},NE=new class{init(s){var n;this._core=s,this._bindAppActivityEvent(),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this),(n=this._core)===null||n===void 0||n.store.set("activityMonitor",{isActive:!0})}_bindAppActivityEvent(){var s,n,g,u,E;const{MINI_APP_NAMESPACE:m,IN_TT_MINI_GAME:D,IN_WX_MINI_GAME:M}=((s=this._core)===null||s===void 0?void 0:s.utils)||{};D||M?((n=m?.onShow)===null||n===void 0||n.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!0}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!0})}),(g=m?.onHide)===null||g===void 0||g.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!1}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!1})})):((u=m?.onAppShow)===null||u===void 0||u.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!0}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!0})}),(E=m?.onAppHide)===null||E===void 0||E.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!1}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!1})}))}_reset(){var s;(s=this._core)===null||s===void 0||s.store.clear("activityMonitor")}_dispose(){const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this),this._reset()}},hd=new class{init(s){const{IN_MINI_APP:n,IN_WX_MINI_PLUGIN:g}=s.helper;g||(n?NE.init(s):TE.init(s))}};const GE="none",tl="online";var dI=new class{init(s){this._core=s,this._activateNetworkMonitoring(),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this)}_activateNetworkMonitoring(){return pA(this,void 0,void 0,function*(){navigator.onLine?this._onOnline():this._onOffline(),this._onOnlineCallback=this._onOnline.bind(this),this._onOfflineCallback=this._onOffline.bind(this),window.addEventListener("online",this._onOnlineCallback),window.addEventListener("offline",this._onOfflineCallback)})}_deactivateNetworkMonitoring(){this._onOnlineCallback!==null&&(window.removeEventListener("online",this._onOnlineCallback),this._onOnlineCallback=null),this._onOfflineCallback!==null&&(window.removeEventListener("offline",this._onOfflineCallback),this._onOfflineCallback=null)}_onNetworkStatusChange(s){var n,g;const{isConnected:u,networkType:E}=s;(n=this._core)===null||n===void 0||n.store.set("netWorkMonitor",{isNetworkOnline:u,networkType:E}),(g=this._core)===null||g===void 0||g.notificationCenter.emitInnerEvent("networkStatusChange",{isNetworkOnline:u,networkType:E})}_onOnline(){this._onNetworkStatusChange({isConnected:!0,networkType:tl})}_onOffline(){this._onNetworkStatusChange({isConnected:!1,networkType:GE})}_reset(){var s;this._deactivateNetworkMonitoring(),(s=this._core)===null||s===void 0||s.store.clear("netWorkMonitor")}_dispose(){var s,n;(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeInnerEvent((n=this._core)===null||n===void 0?void 0:n.InnerEvent.DESTROY,this._dispose,this),this._reset()}},Lu=new class{init(s){this._core=s,this._activateNetworkMonitoring(),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this)}_activateNetworkMonitoring(){return pA(this,void 0,void 0,function*(){try{const{utils:{MINI_APP_NAMESPACE:s}}=this._core;this._mpNetworkStatusCallback=this._onNetworkStatusChange.bind(this),s.onNetworkStatusChange(this._onNetworkStatusChange.bind(this))}catch(s){console.error(s)}})}_deactivateNetworkMonitoring(){if(this._mpNetworkStatusCallback!==null){const{utils:{MINI_APP_NAMESPACE:s}}=this._core;s.offNetworkStatusChange&&s.offNetworkStatusChange(this._mpNetworkStatusCallback),this._mpNetworkStatusCallback=null}}_onNetworkStatusChange(s){var n,g;const{isConnected:u,networkType:E}=s;(n=this._core)===null||n===void 0||n.store.set("netWorkMonitor",{isNetworkOnline:u,networkType:E}),(g=this._core)===null||g===void 0||g.notificationCenter.emitInnerEvent("networkStatusChange",{isNetworkOnline:u,networkType:E})}_reset(){var s;this._deactivateNetworkMonitoring(),(s=this._core)===null||s===void 0||s.store.clear("netWorkMonitor")}_dispose(){var s,n;(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeInnerEvent((n=this._core)===null||n===void 0?void 0:n.InnerEvent.DESTROY,this._dispose,this),this._reset()}},Uu=new class{init(s){const{IN_MINI_APP:n}=s.utils;n?Lu.init(s):dI.init(s)}},EC=new class{constructor(){this.name="SystemStateMonitor"}install(s){hd.init(s),Uu.init(s)}};const Rr=new Set(["tui_room_svr.*","callkit_records_svr.*","room_engine_srv.*","room_engine_http_srv.*","room_engine_mic.*","live_engine_srv.*","live_engine_http_srv.*","live_engine_pk.*","trtc_ai_service.*","call_engine_srv.*"]),cg="tui_room_svr.*";var Rc=new class{constructor(){this.name="BusinessCommandTransfer",this._transferredCommands=Rr}install(s){this._core=s;const{notificationCenter:n,InnerEvent:g,helper:u}=s;n.subscribeInnerEvent(g.CLOUD_CONFIG_UPDATE,this._onCloudConfigUpdate,this),n.subscribeInnerEvent(g.LOGOUT,this._reset,this),n.subscribeInnerEvent(g.DESTROY,this._dispose,this),n.subscribeInnerEvent("im_open_push.msg_push",n.InnerEventSubType.BUSINESS_COMMAND,this._onServerPushBusinessCommand,this),u.registerExperimentalAPI("sendTRTCCustomData",this,"transferBusinessCommand"),u.registerExperimentalAPI("sendRoomCustomData",this,"transferBusinessCommand")}transferBusinessCommand(s){return pA(this,void 0,void 0,function*(){const n="transferBusinessCommand";try{const{serviceCommand:g=cg}=s||{};if(!this._isValidTransferredCommand(g))throw new this._core.helper.ChatError({code:2995,functionName:n});return{code:0,data:(yield function(E,m){return pA(this,void 0,void 0,function*(){const{helper:D,channel:M}=m,{serviceCommand:T=cg,data:P}=E||{};let W={};try{W=typeof P=="string"?JSON.parse(P):P}catch(RA){console.warn(RA)}const iA=D.generateProtocolData({servcmd:T,data:W}),EA=`${iA.head.seq}${T}`;return M.sendPacket(iA,{requestId:EA,shouldRejectOnError:!1})})}(s,this._core))||{}}}catch(g){throw console.warn(g),new this._core.helper.ChatError({code:g?.errorCode,message:g?.errorInfo,data:{},functionName:n})}})}_onCloudConfigUpdate(s={}){try{if(typeof s.rtc_cmd!="string")return;const n=JSON.parse(s.rtc_cmd);Array.isArray(n)&&(this._transferredCommands=new Set([...this._transferredCommands,...n]))}catch(n){console.log(n)}}_isValidTransferredCommand(s=""){const n=`${s?.split(".")[0]}.*`;return this._transferredCommands.has(n)}_onServerPushBusinessCommand(s){const{OuterEvent:n,notificationCenter:g}=this._core,{MsgContent:u}=s||{},{ROOM_CUSTOM_DATA_RECEIVED:E}=n;g.emitOuterEvent(E,{name:E,data:u})}_reset(){this._transferredCommands=Rr}_dispose(){const{notificationCenter:s,InnerEvent:n}=this._core;this._reset(),s.unSubscribeInnerEvent(n.CLOUD_CONFIG_UPDATE,this._onCloudConfigUpdate,this),s.unSubscribeInnerEvent(n.LOGOUT,this._reset,this),s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this),s.unSubscribeInnerEvent("im_open_push.msg_push",s.InnerEventSubType.BUSINESS_COMMAND,this._onServerPushBusinessCommand,this)}};const Fu=1,Tl=2,Bd=3,$r=4,CI=5,_n="TIMCustomElem",dC="C2C",il="GROUP",Qd="invite",hI="accept",Oa="cancel",CC="reject",Pa="modifyInvitation",ur="signaling",pd=8010,Ou="signaling-timeout";function Er(s){return s.filter(n=>{if(n.type===_n){const{cloudCustomData:g="",payload:{data:u=""}={}}=n,E=g.match(/"type":"tsignaling"/),m=u.match(/inviteID/),D=u.match(/actionType/);return E||m&&D}return!1})}function wc(s){const{data:n}=s.payload;try{return JSON.parse(n)}catch(g){return console.error(g),null}}function ol(s,n){return s.toString(16).padStart(n,"0")}function Lg(s){if(s<0||s>53)throw new Error("Number of digits must be between 0 and 53");if(s<=30)return Math.floor(Math.random()*(1<0;const M=this._core.common.getCurrentUserID();return D.includes(M)}return!0}updateSignaling(s){const n=`${ur}.updateSignaling`,{inviteID:g,inviter:u,inviteeList:E,groupID:m}=s;if(console.log(`${n} inviteID:${g} inviter:${u} groupID:${m}`),m&&this.hasSignaling(g)){const D=E[0],{inviteeList:M}=this._onlineSignalingMap.get(g);M.includes(D)&&(M.splice(M.indexOf(D),1),console.log(`${n} remove ${D}. localInviteeList.length:${M.length}`)),M.length===0&&this.removeSignaling(g)}else this.removeSignaling(g)}setSignalingListenStatus(s){this._isSignalingListening=s}getSignalingListenStatus(){return this._isSignalingListening}_dispose(){var s,n;this._reset(),(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),this._isSignalingListening=!1}_reset(){this._onlineSignalingMap.clear()}},$g=new class{init(s){this._core=s}createInviteSignaling(s){const n=this._generateInviteID(),g=this._createInviteSignalingData(Object.assign(Object.assign({},s),{inviteID:n})),{groupID:u,inviteeList:E}=g,m=u||E[0];return{signaling:this._createSignaling(g,m),signalingData:g,signalingExtensionOptions:this._createSignalingExtensionOptions(s)}}createAcceptSignaling(s){const n=this._createAcceptSignalingData(s),{groupID:g,inviter:u}=n,E=g||u;return{signaling:this._createSignaling(n,E),signalingData:n,signalingExtensionOptions:this._createSignalingExtensionOptions(s)}}createCancelSignaling(s){const n=this._createCancelSignalingData(s),{groupID:g,inviteeList:u}=n,E=g||u[0];return{signaling:this._createSignaling(n,E),signalingData:n,signalingExtensionOptions:this._createSignalingExtensionOptions(s)}}createRejectSignaling(s){const n=this._createRejectSignalingData(s),{groupID:g,inviter:u}=n,E=g||u;return{signaling:this._createSignaling(n,E),signalingData:n,signalingExtensionOptions:this._createSignalingExtensionOptions(s)}}createTimeoutSignaling(s){const{isInviter:n=!1}=s,g=this._createTimeoutSignalingData(s),{groupID:u,inviteeList:E,inviter:m}=g,D=u||(n?E[0]:m);return{signaling:this._createSignaling(g,D),signalingData:g,signalingExtensionOptions:this._createSignalingExtensionOptions(g)}}_createSignalingExtensionOptions(s){var n,g;const{data:u="",onlineUserOnly:E,inviteID:m="",offlinePushInfo:D,actionType:M}=s,T=((g=(n=Oo.getSignaling(m))===null||n===void 0?void 0:n.signaling)===null||g===void 0?void 0:g._onlineOnlyFlag)||!1;return{onlineUserOnly:E||T,offlinePushInfo:D,messageControlInfo:this._createMessageControlInfo(u,M)}}_createMessageControlInfo(s,n){const g=n===CI&&!!s.match(/excludeTimeoutSignalingFromHistoryMessage/),u=!!s.match(/excludeFromHistoryMessage/)||!!s.match(/excludeOriginalSignalingFromHistoryMessage/);return{excludedFromContentModeration:!0,excludedFromUnreadCount:g||u,excludedFromLastMessage:g||u}}_createInviteSignalingData(s){const n=`${ur}._createInviteSignalingData`,{userID:g,timeout:u=0,groupID:E="",inviteeList:m=[]}=s,D=this._core.common.getCurrentUserID(),M=Object.assign(Object.assign({},this._generateBaseSignalData(s)),{actionType:Fu,inviter:D,inviteeList:E?m:[g],timeout:u});return console.log(`${n} signalingData:`,M),M}_createAcceptSignalingData(s){const n=`${ur}._createAcceptSignalingData`,{inviteID:g}=s,u=this._core.common.getCurrentUserID(),{inviter:E,groupID:m}=Oo.getSignaling(g),D=Object.assign(Object.assign({},this._generateBaseSignalData(s)),{actionType:Bd,groupID:m,inviter:E,inviteeList:[u]});return console.log(`${n} signalingData:`,D),D}_createCancelSignalingData(s){const n=`${ur}._createCancelSignalingData`,{inviteID:g}=s,u=this._core.common.getCurrentUserID(),{inviteeList:E,groupID:m}=Oo.getSignaling(g),D=Object.assign(Object.assign({},this._generateBaseSignalData(s)),{actionType:Tl,groupID:m,inviter:u,inviteeList:E});return console.log(`${n} signalingData:`,D),D}_createRejectSignalingData(s){const n=`${ur}._createRejectSignalingData`,{inviteID:g}=s,u=this._core.common.getCurrentUserID(),{inviter:E,groupID:m}=Oo.getSignaling(g),D=Object.assign(Object.assign({},this._generateBaseSignalData(s)),{actionType:$r,groupID:m,inviter:E,inviteeList:[u]});return console.log(`${n} signalingData:`,D),D}_createTimeoutSignalingData(s){const n=`${ur}._createTimeoutSignalingData`,{isInviter:g=!1,inviteID:u}=s,{inviteeList:E,inviter:m}=Oo.getSignaling(u),D=this._core.common.getCurrentUserID(),M=Object.assign(Object.assign({},this._generateBaseSignalData(s)),{actionType:CI,inviter:m,inviteeList:g?E:[D]});return console.log(`${n} signalingData:`,M),M}_createSignaling(s,n){var g,u,E;const{groupID:m=""}=s,D={to:n,conversationType:m?il:dC,priority:"High",payload:{data:JSON.stringify(s)}};return(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageFactory)===null||E===void 0?void 0:E.createCustomMessage(D)}_generateInviteID(){return[ol(Lg(32),8),ol(Lg(16),4),ol(16384|Lg(12),4),ol(32768|Lg(14),4),ol(Lg(48),12)].join("-")}_generateBaseSignalData(s){const{data:n="",inviteID:g="",groupID:u=""}=s;return{businessID:1,timeout:0,data:n,inviteID:g,groupID:u}}},Za=new class{constructor(){this._isProcessingSignaling=!1}init(s){this._core=s,s.helper.registerApi({apiName:"invite",context:this}),s.helper.registerApi({apiName:"accept",context:this}),s.helper.registerApi({apiName:"cancel",context:this}),s.helper.registerApi({apiName:"reject",context:this}),s.helper.registerApi({apiName:"modifyInvitation",context:this}),s.helper.registerApi({apiName:"getSignalingInfo",context:this}),s.helper.registerApi({apiName:"addSignalingListener",context:this}),s.helper.registerApi({apiName:"removeSignalingListener",context:this}),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.LOGOUT,this._reset,this)}invite(s){return pA(this,void 0,void 0,function*(){var n;try{this._validateBeforeInvite(s);const{signaling:g,signalingData:u,signalingExtensionOptions:E}=$g.createInviteSignaling(s),m=yield this._sendSignaling(g,E);if(m?.code===0){const{inviteID:D,timeout:M}=u;return Oo.saveSignaling(D,Object.assign(Object.assign({},u),{signaling:g})),M>0&&((n=this._core)===null||n===void 0||n.helper.taskScheduler.addOnceTask({id:`${Ou}-${D}`,intervalMs:1e3*(M+5),callback:this.handleInvitationExpiryTimer.bind(this,D)})),Object.assign(Object.assign({},m),{inviteID:D})}return m}catch(g){throw g}})}accept(s){return pA(this,void 0,void 0,function*(){try{const{inviteID:n}=s;this._validateBeforeAccept(n),this._isProcessingSignaling=!0;const{signaling:g,signalingData:u,signalingExtensionOptions:E}=$g.createAcceptSignaling(s),m=yield this._sendSignaling(g,E);return m?.code===0?(Oo.updateSignaling(u),Object.assign(Object.assign({},m),{inviteID:n})):m}catch(n){throw n}finally{this._isProcessingSignaling=!1}})}cancel(s){return pA(this,void 0,void 0,function*(){try{const{inviteID:n}=s;this._validateBeforeCancel(n),this._isProcessingSignaling=!0;const{signaling:g,signalingExtensionOptions:u}=$g.createCancelSignaling(s),E=yield this._sendSignaling(g,u);return E?.code===0?(Oo.removeSignaling(n),Object.assign(Object.assign({},E),{inviteID:n})):E}catch(n){throw n}finally{this._isProcessingSignaling=!1}})}reject(s){return pA(this,void 0,void 0,function*(){try{const{inviteID:n}=s;this._validateBeforeReject(n),this._isProcessingSignaling=!0;const{signaling:g,signalingExtensionOptions:u}=$g.createRejectSignaling(s),E=yield this._sendSignaling(g,u);return E?.code===0?(Oo.removeSignaling(n),Object.assign(Object.assign({},E),{inviteID:n})):E}catch(n){throw n}finally{this._isProcessingSignaling=!1}})}modifyInvitation(s){return pA(this,void 0,void 0,function*(){var n,g;const{inviteID:u,data:E}=s;let m="";try{this._validateBeforeModifyInvitation(u);const D=Oo.getSignaling(u),{signaling:M}=D,T=Do(D,["signaling"]);m=M.payload.data,T.data=E,M.payload.data=JSON.stringify(T);const P=yield(g=(n=this._core)===null||n===void 0?void 0:n.message.messageAction)===null||g===void 0?void 0:g.modifyMessage(M);return Oo.hasSignaling(u)&&Oo.saveSignaling(u,Object.assign(Object.assign({},T),{signaling:M})),P}catch(D){if(m){const{signaling:M}=Oo.getSignaling(u);M.payload.data=m}throw D}})}getSignalingInfo(s){const{ssoLog:n,utils:{safeStringify:g}}=this._core;if(Er([s]).length===0)return;const u=wc(s),E={businessID:u.businessID||1,inviteID:u.inviteID,groupID:u.groupID||"",inviter:u.inviter||"",inviteeList:u.inviteeList||[],data:u.data||"",actionType:u.actionType||Fu,timeout:u.timeout||0};return n.debug(`${ur} getSignalingInfo ${g(E)}`),E}addSignalingListener(s,n,g){var u,E;s===((u=this._core)===null||u===void 0?void 0:u.SignalingEvent.NEW_INVITATION_RECEIVED)&&Oo.setSignalingListenStatus(!0),(E=this._core)===null||E===void 0||E.notificationCenter.subscribeOuterEvent(s,n,g)}removeSignalingListener(s,n,g){var u,E;s===((u=this._core)===null||u===void 0?void 0:u.SignalingEvent.NEW_INVITATION_RECEIVED)&&Oo.setSignalingListenStatus(!1),(E=this._core)===null||E===void 0||E.notificationCenter.unSubscribeOuterEvent(s,n,g)}handleInvitationExpiryTimer(s){const n=Oo.getOnlineSignalingMap(),g=this._core.common.getCurrentUserID();if(!n.has(s))return;const u=n.get(s).inviter===g;this._sendTimeoutNotice({inviteID:s,isInviter:u})}_sendSignaling(s,n){return pA(this,void 0,void 0,function*(){var g,u,E;return(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageSender)===null||E===void 0?void 0:E.sendMessage(s,n)})}_sendTimeoutNotice(s){return pA(this,void 0,void 0,function*(){var n,g,u;this._core.ssoLog.debug("_sendTimeoutNotice",`${ur}._sendTimeoutNotice params:${JSON.stringify(s)}`);const{isInviter:E,inviteID:m}=s,{signaling:D,signalingData:M,signalingExtensionOptions:T}=$g.createTimeoutSignaling(s),P=yield this._sendSignaling(D,T);if(P?.code===0){const{data:W,groupID:iA,inviteeList:EA,inviter:RA}=M;(n=this._core)===null||n===void 0||n.notificationCenter.emitOuterEvent((g=this._core)===null||g===void 0?void 0:g.SignalingEvent.INVITATION_TIMEOUT,{name:(u=this._core)===null||u===void 0?void 0:u.SignalingEvent.INVITATION_TIMEOUT,data:{data:W,groupID:iA,inviteID:m,inviteeList:EA,inviter:RA,isSelfTimeout:!0,message:D}}),E?Oo.removeSignaling(m):Oo.updateSignaling(M)}})}_validateInviteId(s,n){if(!Oo.hasSignaling(n))throw new this._core.helper.ChatError({functionName:s,code:pd})}_validateProcessStatus(s){if(this._isProcessingSignaling)throw new this._core.helper.ChatError({functionName:s,message:"processing other signaling operations"})}_validateBeforeInvite(s){const n=Qd,{userID:g}=s,u=this._core.common.getCurrentUserID();if(g===u)throw new this._core.helper.ChatError({functionName:n,message:`cannot invite yourself, currentUserId:${u}, inviteeId:${g}`})}_validateBeforeAccept(s){const n=hI;this._validateInviteId(n,s),this._validateProcessStatus(n);const g=this._core.common.getCurrentUserID(),{inviteeList:u}=Oo.getSignaling(s);if(!u.includes(g)){const E=`userID:${g} not in inviteeList. inviteID:${s}`;throw new this._core.helper.ChatError({functionName:n,message:E})}}_validateBeforeCancel(s){const n=Oa;this._validateInviteId(n,s),this._validateProcessStatus(n);const g=this._core.common.getCurrentUserID(),{inviter:u}=Oo.getSignaling(s);if(u!==g){const E=`unmatched inviter:${u} and my userID:${g}`;throw new this._core.helper.ChatError({functionName:n,message:E})}}_validateBeforeReject(s){const n=CC;this._validateInviteId(n,s),this._validateProcessStatus(n);const g=this._core.common.getCurrentUserID(),{inviteeList:u}=Oo.getSignaling(s);if(!u.includes(g)){const E=`userID:${g} not in inviteeList. inviteID:${s}`;throw new this._core.helper.ChatError({functionName:n,message:E})}}_validateBeforeModifyInvitation(s){const n=Pa;this._validateInviteId(n,s)}_dispose(){var s,n;this._reset(),(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this)}_reset(){this._isProcessingSignaling=!1}},Nl=new class{constructor(){this._actionProcessor=new Map([[Fu,this._onNewInvitationReceived.bind(this)],[$r,this._onInviteeRejected.bind(this)],[Bd,this._onInviteeAccepted.bind(this)],[Tl,this._onInvitationCancelled.bind(this)],[CI,this._onInvitationTimeout.bind(this)]])}init(s){this._core=s,s.notificationCenter.subscribeOuterEvent(s.OuterEvent.MESSAGE_RECEIVED,this._handleMessageReceived,this),s.notificationCenter.subscribeOuterEvent(s.OuterEvent.MESSAGE_MODIFIED,this._handleMessageModified,this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this._dispose,this)}handleActionSignaling(s){s.forEach(n=>{const g=wc(n);if(g){const u=this._actionProcessor.get(g.actionType);u?.(g,n)}})}_handleMessageReceived(s){if(!Oo.getSignalingListenStatus())return;const n=Er(s.data);n.length!==0&&this.handleActionSignaling(n)}_handleMessageModified(s){if(!Oo.getSignalingListenStatus())return;const n=Er(s.data);n.length>0&&n.forEach(g=>{const u=wc(g);u&&this._onInvitationModified(u,g)})}_onNewInvitationReceived(s,n){var g,u;const E=`${ur}._onNewInvitationReceived`,{inviteID:m,inviteeList:D,groupID:M}=s,T=this._core.common.getCurrentUserID();if(this._core.ssoLog.debug("_onNewInvitationReceived",`${E} signalingData:${JSON.stringify(s)}}`),M&&!D.includes(T))return;let{timeout:P}=s;const W=Date.now()/1e3-n.time;P>0&&W>0&&P>W&&(P-=W);const iA=Oo.getSignaling(m);iA!==s&&(iA||Oo.saveSignaling(m,Object.assign(Object.assign({},s),{signaling:n})),P>0&&((g=this._core)===null||g===void 0||g.helper.taskScheduler.addOnceTask({id:`${Ou}-${m}`,intervalMs:1e3*P,callback:Za.handleInvitationExpiryTimer.bind(Za,m)})),this._emitEvent({name:(u=this._core)===null||u===void 0?void 0:u.SignalingEvent.NEW_INVITATION_RECEIVED,data:Object.assign(Object.assign({},this._generateBaseEmitData(s)),{inviteeList:D})}))}_onInviteeRejected(s){var n;const g=`${ur}._onInviteeRejected`,{inviteID:u,inviter:E,groupID:m,inviteeList:D}=s,M=Oo.hasSignaling(u);this._core.ssoLog.debug("_onInviteeRejected",`${g} inviteID:${u} hasInviteID:${M} inviter:${E} groupID:${m}`),M&&(Oo.updateSignaling(s),this._emitEvent({name:(n=this._core)===null||n===void 0?void 0:n.SignalingEvent.INVITEE_REJECTED,data:Object.assign(Object.assign({},this._generateBaseEmitData(s)),{invitee:D[0]})}))}_onInviteeAccepted(s){var n;const g=`${ur}._onInviteeAccepted`,{inviteID:u,inviter:E,groupID:m,inviteeList:D}=s,M=Oo.hasSignaling(u);this._core.ssoLog.debug("_onInviteeAccepted",`${g} inviteID:${u} hasInviteID:${M} inviter:${E} groupID:${m}`),M&&(Oo.updateSignaling(s),this._emitEvent({name:(n=this._core)===null||n===void 0?void 0:n.SignalingEvent.INVITEE_ACCEPTED,data:Object.assign(Object.assign({},this._generateBaseEmitData(s)),{invitee:D[0]})}))}_onInvitationCancelled(s){var n;const g=`${ur}._onInvitationCancelled`,{inviteID:u,inviter:E,groupID:m}=s,D=Oo.hasSignaling(u);this._core.ssoLog.debug("_onInvitationCancelled",`${g} inviteID:${u} hasInviteID:${D} inviter:${E} groupID:${m}`),D&&(Oo.removeSignaling(u),this._emitEvent({name:(n=this._core)===null||n===void 0?void 0:n.SignalingEvent.INVITATION_CANCELLED,data:this._generateBaseEmitData(s)}))}_onInvitationTimeout(s){var n;const g=`${ur}._onInvitationTimeout`,{inviteID:u,inviteeList:E}=s,m=Oo.hasSignaling(u);this._core.ssoLog.debug("_onInvitationTimeout",`${g} inviteID:${u} hasInviteID:${m} data:${s.data}`),m&&(Oo.updateSignaling(s),this._emitEvent({name:(n=this._core)===null||n===void 0?void 0:n.SignalingEvent.INVITATION_TIMEOUT,data:Object.assign(Object.assign({},this._generateBaseEmitData(s)),{inviteeList:E,isSelfTimeout:!1})}))}_onInvitationModified(s,n){var g;const u=`${ur}._onInvitationModified`,{inviteID:E,data:m}=s,D=Oo.hasSignaling(E);this._core.ssoLog.debug("_onInvitationModified",`${u} inviteID:${E} data:${m}`),D&&(Oo.saveSignaling(E,Object.assign(Object.assign({},s),{signaling:n})),this._emitEvent({name:(g=this._core)===null||g===void 0?void 0:g.SignalingEvent.INVITATION_MODIFIED,data:{inviteID:E,data:m}}))}_emitEvent(s){var n;(n=this._core)===null||n===void 0||n.notificationCenter.emitOuterEvent(s.name,s)}_generateBaseEmitData(s){const{inviteID:n,inviter:g,groupID:u,data:E}=s;return{inviteID:n,inviter:g,groupID:u,data:E||""}}_dispose(){var s,n,g;(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeOuterEvent(this._core.OuterEvent.MESSAGE_RECEIVED,this._handleMessageReceived,this),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeOuterEvent(this._core.OuterEvent.MESSAGE_MODIFIED,this._handleMessageModified,this),(g=this._core)===null||g===void 0||g.notificationCenter.unSubscribeOuterEvent(this._core.InnerEvent.DESTROY,this._dispose,this)}},Aa=new class{constructor(){this._offlineSignalingMap=new Map}init(s){this._core=s;const{notificationCenter:n,helper:g,constants:{InnerEvent:u,WORKFLOW_STEP:E,WORKFLOW_NAME:m}}=s;n.subscribeInnerEvent(u.DESTROY,this._dispose,this),n.subscribeInnerEvent(u.LOGOUT,this._reset,this),g.registerWorkflowStep(m.SYNC_SERVER_INFO_AFTER_LOGIN,E.SIGNALING_MESSAGE_RECOVER,this._handleC2COfflineMessage,this)}_handleC2COfflineMessage(s){const{result:{unreadMessageMap:n}={}}=s||{};if(!(n?.size!==0&&Oo.getSignalingListenStatus()))return;const g=Er([...n.values()]);if(g.length!==0&&(g.forEach(u=>{this._handleC2CActionType(u)}),this._offlineSignalingMap.size>0)){const u=this._sortOfflineSignalingByTime();Nl.handleActionSignaling(u)}}_handleC2CActionType(s){const n=wc(s);if(!n)return;const{actionType:g}=n;g===Fu?this._saveValidOfflineInvite(n,s):this._removeOfflineInvite(n)}_saveValidOfflineInvite(s,n){const{inviteID:g,inviteeList:u=[],timeout:E=0}=s,m=this._core.common.getCurrentUserID();if(!u.includes(m))return;const D=Date.now()/1e3-n.time;E>0&&D>E&&E!==0||this._offlineSignalingMap.set(g,Object.assign(Object.assign({},s),{signalingList:[n]}))}_removeOfflineInvite(s){const{inviteID:n=""}=s;this._offlineSignalingMap.has(n)&&this._offlineSignalingMap.delete(n)}_sortOfflineSignalingByTime(){let s=[];return this._offlineSignalingMap.forEach(n=>{s=[...s,...n.signalingList]}),s.sort((n,g)=>n.time-g.time)}_dispose(){var s,n;this._reset(),(s=this._core)===null||s===void 0||s.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this)}_reset(){this._offlineSignalingMap.clear()}};const gh={invite:{userID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0},timeout:{required:!1,rules:["number"],allowEmpty:!1},onlineUserOnly:{required:!1,rules:["boolean"],allowEmpty:!1},offlinePushInfo:{required:!1,rules:["object"],allowEmpty:!1}},cancel:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}},accept:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}},reject:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}},modifyInvitation:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}}},js={invite:!0,cancel:!0,accept:!0,reject:!0,modifyInvitation:!0};var XI=new class{constructor(){this.name="Signaling"}install(s){Za.init(s),Nl.init(s),$g.init(s),Oo.init(s),Aa.init(s),s.helper.registerValidateConfig({auth:js,params:gh})}};const Us=new class{init(s){this.core=s}};function _c(s){let n;const{message:g}=Us.core,{conversationID:u,messageID:E}=s;return n=g.messageDataHandler.getLocalMessageList(u).find(m=>m.ID===E),!n&&(n=g.messageDataHandler.getSparseMessageList(u).find(m=>m.ID===E)),n}function Ac(s){return s.map(n=>{const{from:g,to:u,cloudCustomData:E,avatar:m,nick:D,ID:M,clientSequence:T,clientTime:P,messageRandom:W,messageSequence:iA,time:EA}=n;return{ClientSeq:T,CloudCustomData:E,From_Account:g,From_AccountHeadurl:m,From_AccountNick:D,Id:M,MsgBody:JSON.parse(JSON.stringify(n.transformElementsToServerFormat())),MsgClientTime:P,MsgRandom:W,Random:W,MsgSeq:iA,MsgTimeStamp:EA,ReceiverId:u,SenderId:g,To_Account:u}})}function dr(s){var n;const{From_Account:g,From_AccountHeadurl:u,From_AccountNick:E,GroupId:m,MsgClientTime:D,ClientSeq:M,To_Account:T,MsgTimeStamp:P,TinyId:W,MsgRandom:iA,MsgSeq:EA}=s;return{from:g,avatar:u,nick:E,clientTime:D,time:P,tinyID:W,random:iA,sequence:EA,to:T,groupID:m,clientSequence:M,_elements:(n=s.MsgBody)===null||n===void 0?void 0:n.map(RA=>{const{MsgType:kA}=RA;return Us.core.message.messageFactory.getElementClass(kA).parseServerPushElement(RA)})}}var Vr,Xa;(function(s){s.MSG_TEXT="TIMTextElem",s.MSG_CUSTOM="TIMCustomElem",s.MSG_LOCATION="TIMLocationElem",s.MSG_FACE="TIMFaceElem",s.MSG_STREAM="TIMStreamElem"})(Vr||(Vr={})),function(s){s[s.FORWARD=0]="FORWARD",s[s.BACKWARD=1]="BACKWARD"}(Xa||(Xa={}));const bE="MSG_REACTION",hC="MSG_EXT",ch=0,ao=1,Tc={ZH_CN:"zh (cmn-Hans-CN)",EN_US:"en-US",YUE_HK:"yue-Hant-HK",JA_JP:"ja-JP",ZH_PY:"zh-PY"},Gl="16k_zh",BC="16k_en",QC="16k_yue",bl="16k_ja",$I="16k_zh-PY",BI={[Tc.ZH_CN]:Gl,[Tc.EN_US]:BC,[Tc.YUE_HK]:QC,[Tc.JA_JP]:bl,[Tc.ZH_PY]:$I},QI=/\.(wav|pcm|ogg-opus|speex|silk|mp3|m4a|aac|amr)/,kE={READ:0,UNREAD:1},kl=1,Ll=2,Ug=3;var ec;(function(s){s.IN="in",s.OUT="out"})(ec||(ec={}));const md=16,LE=17;var Nc;(function(s){s[s.DATA=0]="DATA",s[s.REVOKED=1]="REVOKED"})(Nc||(Nc={}));var Au;(function(s){s[s.NORMAL=0]="NORMAL",s[s.TIMEOUT=1]="TIMEOUT"})(Au||(Au={}));const lo="StreamMsg.PushStreamHttp";var UE=new class{constructor(){this._reactionsMap=new Map}init(s){this._core=s;const{helper:n,notificationCenter:g,InnerEvent:{MESSAGE_PUSH:u},InnerEventSubType:{MESSAGE_REACTION_UPDATED:E,MESSAGE_REACTION_UPDATED_SYNC:m}}=s;n.registerApi({apiName:"addMessageReaction",context:this}),n.registerApi({apiName:"removeMessageReaction",context:this}),n.registerApi({apiName:"getMessageReactions",context:this}),n.registerApi({apiName:"getAllUserListOfMessageReaction",context:this}),g.subscribeInnerEvent(u,E,this._handleReactionUpdated,this),g.subscribeInnerEvent(u,m,this._handleReactionSync,this)}addMessageReaction(s,n){return pA(this,void 0,void 0,function*(){const{OuterConstant:g,ssoLog:u,helper:E}=this._core;this._validateMessageReactionBusinessCapability();const{conversationID:m,ID:D,conversationType:M,from:T,to:P,clientSequence:W,random:iA,time:EA,sequence:RA}=s,kA=`conversationID:${m} messageID:${D} reactionID:${n}`;try{return this._recordMessageReactedByMe(D,n),M===g.CONV_C2C?yield function(xA,LA){return pA(this,void 0,void 0,function*(){var SA;const{from:OA,to:JA,clientSequence:ae,random:ne,time:_i,reactionID:Ti}=xA,Lt={From_Account:OA,To_Account:JA,MsgKey:`${ae}_${ne}_${_i}`,Reaction:Ti,Add_Account:[(SA=LA.store.get("login"))===null||SA===void 0?void 0:SA.userId]};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_add",data:Lt})})}({from:T,to:P,clientSequence:W,random:iA,time:EA,reactionID:n},this._core):M===g.CONV_GROUP&&(yield function(xA,LA){return pA(this,void 0,void 0,function*(){var SA;const{to:OA,reactionID:JA,sequence:ae}=xA,ne={GroupId:OA,MsgSeq:ae,Reaction:JA,Add_Account:[(SA=LA.store.get("login"))===null||SA===void 0?void 0:SA.userId]};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_add",data:ne})})}({to:P,reactionID:n,sequence:RA},this._core)),{code:0,successLog:{message:kA}}}catch(xA){this._removeMyReactionRecord(D,n);const{errorCode:LA}=xA||{};throw new E.ChatError({functionName:"addMessageReaction",code:LA,moreMessage:kA})}})}removeMessageReaction(s,n){return pA(this,void 0,void 0,function*(){const{OuterConstant:g,helper:u}=this._core;this._validateMessageReactionBusinessCapability();const{conversationID:E,ID:m,conversationType:D,from:M,to:T,clientSequence:P,random:W,time:iA,sequence:EA}=s,RA=`conversationID:${E} messageID:${m} reactionID:${n}`;try{return this._removeMyReactionRecord(m,n),D===g.CONV_C2C?yield function(kA,xA){return pA(this,void 0,void 0,function*(){var LA;const{from:SA,to:OA,clientSequence:JA,random:ae,time:ne,reactionID:_i}=kA,Ti={From_Account:SA,To_Account:OA,MsgKey:`${JA}_${ae}_${ne}`,Reaction:_i,Del_Account:[(LA=xA.store.get("login"))===null||LA===void 0?void 0:LA.userId]};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_del",data:Ti})})}({from:M,to:T,clientSequence:P,random:W,time:iA,reactionID:n},this._core):D===g.CONV_GROUP&&(yield function(kA,xA){return pA(this,void 0,void 0,function*(){var LA;const{to:SA,reactionID:OA,sequence:JA}=kA,ae={GroupId:SA,MsgSeq:JA,Reaction:OA,Del_Account:[(LA=xA.store.get("login"))===null||LA===void 0?void 0:LA.userId]};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_del",data:ae},xA)})}({to:T,reactionID:n,sequence:EA},this._core)),{code:0,successLog:{message:RA}}}catch(kA){const{errorCode:xA}=kA||{};throw new u.ChatError({functionName:"removeMessageReaction",code:xA,moreMessage:RA})}})}getAllUserListOfMessageReaction(s){return pA(this,void 0,void 0,function*(){this._validateMessageReactionBusinessCapability();const{message:n,reactionID:g,nextSeq:u=0}=s,E=s.count>100?100:s.count,{conversationID:m}=n,{ssoLog:D,helper:M,constants:T}=this._core;try{let P=null;if(P=m.startsWith(T.OuterConstant.CONV_C2C)?yield function(W){return pA(this,void 0,void 0,function*(){const{message:iA,nextSeq:EA,reactionID:RA,count:kA}=W,{from:xA,to:LA,clientSequence:SA,random:OA,time:JA}=iA,ae={Reaction:RA,NextSeq:EA,Count:kA,From_Account:xA,To_Account:LA,MsgKey:`${SA}_${OA}_${JA}`};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_iterate",data:ae})})}({message:n,reactionID:g,nextSeq:u,count:E}):yield function(W){return pA(this,void 0,void 0,function*(){const{message:iA,nextSeq:EA,reactionID:RA,count:kA}=W,{sequence:xA,to:LA}=iA,SA={Reaction:RA,NextSeq:EA,GroupId:LA,Count:kA,MsgSeq:xA};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_iterate",data:SA})})}({message:n,reactionID:g,nextSeq:u,count:E}),P){const{Reaction_Account:W,NextSeq:iA}=P,EA=yield this._getUserProfileList(W);return{code:0,data:{nextSeq:iA,isCompleted:u===0,userList:EA}}}}catch(P){const{errorCode:W}=P||{};throw new M.ChatError({functionName:"getAllUserListOfMessageReaction",code:W})}})}getMessageReactions(s){return pA(this,void 0,void 0,function*(){const{constants:n}=this._core;this._validateMessageReactionBusinessCapability();const{messageList:g,maxUserCountPerReaction:u=10}=s,E=g[0];let m=null;const D=new Map,{from:M,to:T,conversationType:P}=E,W=this._generateMessageKeyList(g,D);P===n.OuterConstant.CONV_C2C?m=yield function(kA){return pA(this,void 0,void 0,function*(){const{from:xA,to:LA,messageKeyList:SA,maxUserCountPerReaction:OA}=kA,JA={From_Account:xA,To_Account:LA,MsgKeyList:SA,Count:OA};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_multi_stat",data:JA})})}({from:M,to:T,messageKeyList:W,maxUserCountPerReaction:u}):P===n.OuterConstant.CONV_GROUP&&(m=yield function(kA){return pA(this,void 0,void 0,function*(){const{groupId:xA,messageSequenceList:LA,maxUserCountPerReaction:SA}=kA,OA={GroupId:xA,MsgSeqList:LA,Count:SA};return Us.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_multi_stat",data:OA})})}({groupId:T,messageSequenceList:W,maxUserCountPerReaction:u}));const{Results:iA=[]}=m||{},EA=this._extractUserIDsFromReactionResults(iA),RA=yield this._getUserProfileMap(EA);return{code:0,data:{resultList:iA.map(kA=>{const{ReactionList:xA,MsgSeq:LA,MsgKey:SA}=kA;return{messageID:this._generateMessageID({messageSequence:LA,messageKey:SA,messageIDMap:D}),reactionList:xA.map(OA=>{const{Reaction:JA,Count:ae,Reaction_Account:ne,ReactedByMe:_i}=OA;return{reactionID:JA,totalUserCount:ae,partialUserList:this._generatePartialUserInfo({userIDList:ne,userProfileMap:RA}),reactedByMyself:_i===1}})}})}}})}dispose(){this._reactionsMap.clear()}_extractUserIDsFromReactionResults(s){const n=[];return s?.forEach(g=>{const{ReactionList:u=[]}=g;u.forEach(E=>{E.Reaction_Account&&n.push(...E.Reaction_Account)})}),n}_getUserProfileList(s){return pA(this,void 0,void 0,function*(){var n;try{const g=yield(n=this._core.user.userProfile)===null||n===void 0?void 0:n.getUserProfile({userIDList:s});return g?g.data:[]}catch{return[]}})}_getUserProfileMap(s){return pA(this,void 0,void 0,function*(){const n=new Map;return(yield this._getUserProfileList(s)).forEach(g=>{const{nick:u,avatar:E,userID:m}=g;n.set(m,{nick:u,avatar:E,userID:m})}),n})}_recordMessageReactedByMe(s,n){const g=`${s}-${n}`;this._reactionsMap.has(g)?this._reactionsMap.get(g).reactedByMe=!0:this._reactionsMap.set(g,{reactedByMe:!0})}_removeMyReactionRecord(s,n){const g=`${s}-${n}`;this._reactionsMap.has(g)&&(this._reactionsMap.get(g).reactedByMe=!1)}_recordMessageReactionInfo(s){const{messageID:n,reactionID:g,reactionInfo:u}=s,E=`${n}-${g}`,m=this._reactionsMap.get(E)||{};this._reactionsMap.set(E,Object.assign(Object.assign({},m),u))}_validateMessageReactionBusinessCapability(){const{helper:s,constants:n}=this._core;if(!s.checkBusinessCapabilityBits(bE))throw new s.ChatError({functionName:"addMessageReaction",code:n.ERROR_CODE.NO_USE,replacement1:"addMessageReaction"})}_handleReactionUpdated(s){const{MsgReactionNotifyList:n}=s,{notificationCenter:g,constants:u}=this._core;n.forEach(E=>pA(this,void 0,void 0,function*(){const{C2CMsgInfo:m,GroupMsgInfo:D,MsgReactionSummary:M}=E,{TinyId:T,MsgClientTime:P,MsgRandom:W}=Object.assign(Object.assign({},m),D),iA=`${T}-${P}-${W}`,EA=this._extractUserIDsFromReactionResults([{ReactionList:M}]),RA=yield this._getUserProfileMap(EA),kA=M.map(xA=>{var LA;const{Reaction:SA,Reaction_Account:OA}=xA,JA=this._generatePartialUserInfo({userIDList:OA,userProfileMap:RA}),ae=OA?xA.Count:0,ne=((LA=this._reactionsMap.get(`${iA}-${SA}`))===null||LA===void 0?void 0:LA.reactedByMe)||!1;return this._recordMessageReactionInfo({messageID:iA,reactionID:SA,reactionInfo:{reactionID:SA,totalUserCount:ae,partialUserList:JA}}),{reactionID:SA,totalUserCount:ae,partialUserList:JA,reactedByMyself:ne}});g.emitOuterEvent(u.OuterEvent.MESSAGE_REACTIONS_UPDATED,{name:u.OuterEvent.MESSAGE_REACTIONS_UPDATED,data:{messageID:iA,reactionList:kA}})}))}_handleReactionSync(s){var n;const{notificationCenter:g,constants:u}=this._core,{C2CMsgInfo:E={},GroupMsgInfo:m={},Reaction:D,OperateType:M}=s.MsgReactionNotify,{TinyId:T="",MsgClientTime:P=0,MsgRandom:W=0}=Object.assign(Object.assign({},E),m),iA=`${T}-${P}-${W}`,EA=`${iA}-${D}`;if(M===1?this._recordMessageReactedByMe(iA,D):this._removeMyReactionRecord(iA,D),(n=this._reactionsMap.get(EA))===null||n===void 0?void 0:n.reactionID){const RA=this._reactionsMap.get(EA);RA.reactedByMyself=M===1,g.emitOuterEvent(u.OuterEvent.MESSAGE_REACTIONS_UPDATED,{name:u.OuterEvent.MESSAGE_REACTIONS_UPDATED,data:{messageID:iA,reactionList:[RA]}})}}_generatePartialUserInfo({userIDList:s,userProfileMap:n}){const g=[];return s?.forEach(u=>{n.has(u)&&g.push(n.get(u))}),g}_generateMessageID(s){const{messageSequence:n,messageKey:g,messageIDMap:u}=s;return g?u.get(g):u.get(n)}_generateMessageKeyList(s,n){const{constants:g}=this._core,u=s[0],{conversationType:E}=u;let m=[];return E===g.OuterConstant.CONV_C2C?m=s.map(D=>{const{clientSequence:M,random:T,time:P,ID:W}=D,iA=`${M}_${T}_${P}`;return n.set(iA,W),iA}):E===g.OuterConstant.CONV_GROUP&&(m=s.map(D=>{const{ID:M,sequence:T}=D;return n.set(T,M),T})),m}},$a=new class{init(s){this._core=s;const{helper:n,InnerEvent:{MESSAGE_PUSH:g},InnerEventSubType:{C2C_MESSAGE_READ_RECEIPT:u,GROUP_MESSAGE_READ_RECEIPT:E},notificationCenter:m}=s;n.registerApi({apiName:"sendMessageReadReceipt",context:this}),n.registerApi({apiName:"getMessageReadReceiptList",context:this}),n.registerApi({apiName:"getGroupMessageReadMemberList",context:this}),m.subscribeInnerEvent(g,u,this._handleC2CMessageReadReceipt,this),m.subscribeInnerEvent(g,E,this._handleGroupMessageReadReceipt,this)}sendMessageReadReceipt(s){return pA(this,void 0,void 0,function*(){var n;const{common:g,constants:u}=this._core,E=this._filterValidMessageSendByOther(s);if(E.length===0)throw new g.ChatError({code:u.ERROR_CODE.READ_RECEIPT_MSG_LIST_EMPTY});try{const{conversationType:m}=E[0];return m===u.OuterConstant.CONV_C2C?yield function(D){return pA(this,void 0,void 0,function*(){const{common:M,constants:T}=Us.core,P=D[0].conversationID.replace(T.OuterConstant.CONV_C2C,""),W=D.map(EA=>{const{from:RA,to:kA,sequence:xA,random:LA,time:SA,clientTime:OA}=EA;return{From_Account:RA,To_Account:kA,MsgSeq:xA,MsgRandom:LA,MsgTime:SA,MsgClientTime:OA}}),iA={Peer_Account:P,C2CMsgInfo:W};return M.buildAndSendPacket({servcmd:"openim.c2c_msg_read_receipt",data:iA})})}(E):yield function(D){return pA(this,void 0,void 0,function*(){const{common:M,constants:T}=Us.core,P={GroupId:D[0].conversationID.replace(T.OuterConstant.CONV_GROUP,""),MsgSeqList:D.map(W=>({MsgSeq:W.sequence}))};return M.buildAndSendPacket({servcmd:"group_open_http_svc.group_msg_receipt",data:P})})}(E),{code:0,data:{}}}catch(m){const{errorCode:D,errorInfo:M}=m;throw new g.ChatError({code:D,message:M,moreMessage:`peerAccount:${(n=E?.[0])===null||n===void 0?void 0:n.conversationID}`})}})}getMessageReadReceiptList(s){return pA(this,void 0,void 0,function*(){const{common:n,constants:g}=this._core;try{const{conversationType:u}=s[0];if(u===g.OuterConstant.CONV_GROUP){const E=this._filterValidMessageSendByMe(s);if(E?.length>0){const m=yield function(M){return pA(this,void 0,void 0,function*(){const{common:T,constants:P}=Us.core,W={GroupId:M[0].conversationID.replace(P.OuterConstant.CONV_GROUP,""),MsgSeqList:M.map(iA=>({MsgSeq:iA.sequence}))};return T.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_msg_receipt",data:W})})}(E),{GroupMsgReceiptList:D}=m||{};this._updateGroupMessagesReadReceiptInfo({messageList:s,readReceiptList:D})}}return{code:0,data:{messageList:s}}}catch(u){const{errorCode:E,errorInfo:m}=u;throw new n.ChatError({code:E,message:m})}})}getGroupMessageReadMemberList(s){return pA(this,void 0,void 0,function*(){const{constants:n,common:g}=this._core,{message:u,filter:E=kE.READ,cursor:m=""}=s,{conversationID:D,sequence:M,ID:T}=u,P=D.replace(n.OuterConstant.CONV_GROUP,""),W=s.count>=100?100:s.count;try{const iA=yield function(EA){return pA(this,void 0,void 0,function*(){const{sequence:RA,groupID:kA,filter:xA,cursor:LA,count:SA}=EA,OA={MsgSeq:RA,GroupId:kA,Filter:xA,Cursor:LA,Num:SA};return Us.core.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_msg_receipt_detail",data:OA})})}({groupID:P,sequence:M,filter:E,cursor:m,count:W});if(iA){const{Cursor:EA,IsFinish:RA,UnreadList:kA,ReadList:xA}=iA,LA={cursor:EA,isCompleted:RA===1,messageID:T,unreadUserIDList:[],readUserIDList:[]};return E===kE.READ?LA.readUserIDList=xA.map(SA=>SA.Read_Account):E===kE.UNREAD&&(LA.unreadUserIDList=kA.map(SA=>SA.Unread_Account)),{code:0,data:LA}}}catch(iA){const{errorCode:EA,errorInfo:RA}=iA;throw new g.ChatError({code:EA,message:RA})}})}_handleC2CMessageReadReceipt(s){const n=[],{constants:g,helper:u}=this._core,{C2cMsgInfo:E,PeerReadTime:m,Peer_Account:D}=s;if(u.isEmpty(E))return;const M=`${g.OuterConstant.CONV_C2C}${D}`;E?.forEach(T=>{const{TinyId:P,MsgClientTime:W,MsgRandom:iA}=T,EA=`${P}-${W}-${iA}`,RA=_c({conversationID:M,messageID:EA});RA&&!RA.readReceiptInfo.isPeerRead&&(RA.readReceiptInfo.isPeerRead=!0,RA.readReceiptInfo.timestamp=m,n.push({userID:D,messageID:EA,isPeerRead:!0,timestamp:m}))}),this._emitReadReceiptEventIfNeed(n)}_updateGroupMessagesReadReceiptInfo(s){const{messageList:n,readReceiptList:g}=s,u=new Map;n.forEach(E=>{u.set(E.sequence,E)}),g?.forEach(E=>{if(E.Code===0){const{MsgSeq:m,ReadNum:D,UnreadNum:M}=E,T=u.get(m);T&&(T.readReceiptInfo.readCount=D,T.readReceiptInfo.unreadCount=M)}})}_handleGroupMessageReadReceipt(s){const n=[],{constants:g}=this._core,{GroupTips:u}=s;u.forEach(E=>{const{MsgBody:{GroupMsgReceiptList:m},GroupInfo:{GroupId:D}}=E,M=`${g.OuterConstant.CONV_GROUP}${D}`;m?.forEach(T=>{const{TinyId:P,MsgClientTime:W,MsgRandom:iA,ReadNum:EA,UnreadNum:RA}=T,kA=`${P}-${W}-${iA}`,xA=_c({conversationID:M,messageID:kA}),LA={groupID:D,messageID:kA,readCount:0,unreadCount:0};xA&&(typeof EA=="number"&&(xA.readReceiptInfo.readCount=EA,LA.readCount=EA),typeof RA=="number"&&(xA.readReceiptInfo.unreadCount=RA,LA.unreadCount=RA),n.push(LA))})}),this._emitReadReceiptEventIfNeed(n)}_emitReadReceiptEventIfNeed(s){const{notificationCenter:n,OuterEvent:g}=this._core;s.length>0&&n.emitOuterEvent(g.MESSAGE_READ_RECEIPT_RECEIVED,{name:g.MESSAGE_READ_RECEIPT_RECEIVED,data:s})}_filterValidMessageSendByOther(s){return this._filterNeedReadReceiptMessages(s).filter(n=>{const{from:g}=n;return g!==this._core.common.getCurrentUserID()})}_filterValidMessageSendByMe(s){const{OuterConstant:n}=this._core.constants;return this._filterNeedReadReceiptMessages(s).filter(g=>{const{from:u,status:E}=g;return u===this._core.common.getCurrentUserID()&&E===n.MessageStatus.SUCCESS})}_filterNeedReadReceiptMessages(s){return s.filter(n=>n.needReadReceipt===!0)}dispose(){const{InnerEvent:{MESSAGE_PUSH:s},InnerEventSubType:{C2C_MESSAGE_READ_RECEIPT:n,GROUP_MESSAGE_READ_RECEIPT:g},notificationCenter:u}=this._core;u.unSubscribeInnerEvent(s,n,this._handleC2CMessageReadReceipt,this),u.unSubscribeInnerEvent(s,g,this._handleGroupMessageReadReceipt,this)}};function eu(s,n,g){return pA(this,void 0,void 0,function*(){const{common:{buildAndSendPacket:u}}=Us.core,{from:E,to:m,clientSequence:D,random:M,time:T}=s;return u({servcmd:"openim_msg_ext_http_svc.set_key_values",data:{From_Account:E,To_Account:m,MsgKey:`${D}_${M}_${T}`,OperateType:g,ExtensionList:n}})})}function Pu(s,n,g){return pA(this,void 0,void 0,function*(){const{common:{buildAndSendPacket:u}}=Us.core,{to:E,sequence:m}=s;return u({servcmd:"openim_msg_ext_http_svc.group_set_key_values",data:{GroupId:E,MsgSeq:m,OperateType:g,ExtensionList:n}})})}var Gc=new class{constructor(){this._messageExtensionsMap=new Map,this._extensionsLatestSequenceMap=new Map,this._completedFetchExtensions=new Set}init(s){this._core=s;const{notificationCenter:n,helper:{registerApi:g},InnerEvent:{MESSAGE_PUSH:u,LOGOUT:E},InnerEventSubType:{MESSAGE_EXTENSIONS_UPDATED:m}}=s;g({apiName:"setMessageExtensions",context:this}),g({apiName:"getMessageExtensions",context:this}),g({apiName:"deleteMessageExtensions",context:this}),n.subscribeInnerEvent(u,m,this._handleMessageExtensionsNotify,this),n.subscribeInnerEvent(E,this.reset,this)}setMessageExtensions(s,n){return pA(this,void 0,void 0,function*(){this._validateMessageExtensionBusinessCapability("setMessageExtensions");const{constants:{OuterConstant:g},ssoLog:u}=this._core,{ID:E,conversationID:m,sequence:D,time:M,conversationType:T}=s;let P=n;n.length>20&&(P=n.slice(0,20),u.warn("setMessageExtensions","the length of extensions cannot exceed 20"));const W=this._generateServerExtensions(s,P),iA=`convID:${m} messageID:${E} sequence:${D} time:${M} count:${P.length}`;try{let EA;if(T===g.CONV_C2C?EA=yield eu(s,W,kl):T===g.CONV_GROUP&&(EA=yield Pu(s,W,kl)),EA){const{resultList:RA,successCount:kA,failureCount:xA}=this._handleModifyMessageExtensions(s,EA);return{code:0,data:{extensions:RA},successLog:{message:`${iA} successCount:${kA} failCount:${xA}`}}}return{code:0,data:{extensions:[]}}}catch(EA){const{errorCode:RA}=EA;throw new this._core.helper.ChatError({functionName:"setMessageExtensions",code:RA,moreMessage:iA})}})}getMessageExtensions(s){return pA(this,void 0,void 0,function*(){const{utils:{isUndefined:n}}=this._core;this._validateMessageExtensionBusinessCapability("getMessageExtensions");const{conversationID:g,ID:u,sequence:E,time:m}=s,D=`convID:${g} messageID:${u} sequence:${E} time:${m}`;try{let M;this._completedFetchExtensions.has(u)&&(M=this._extensionsLatestSequenceMap.get(u));const T=yield this._fetchMessageExtensions(s,M);return n(M)&&T.length>1&&this._completedFetchExtensions.add(u),{code:0,data:{extensions:T},successLog:{message:D}}}catch(M){const{errorCode:T,errorInfo:P=""}=M||{};throw new this._core.common.ChatError({code:T,message:P,moreMessage:D})}})}deleteMessageExtensions(s,n){return pA(this,void 0,void 0,function*(){this._validateMessageExtensionBusinessCapability("deleteMessageExtensions");const{utils:{isEmpty:g},constants:{OuterConstant:u}}=this._core,{conversationType:E,conversationID:m,sequence:D,ID:M,time:T}=s;let P=Ug;const W=[];g(n)||(P=Ll,n?.forEach(RA=>{W.push({key:RA,value:"",seq:0})}));const iA=`convID:${m} messageID:${M} sequence:${D} time:${T} operateType:${P}`,EA=this._generateServerExtensions(s,W);try{let RA;if(E===u.CONV_C2C?RA=yield eu(s,EA,P):E===u.CONV_GROUP&&(RA=yield Pu(s,EA,P)),RA){const{resultList:kA,successCount:xA,failureCount:LA}=this._handleModifyMessageExtensions(s,RA);return{code:0,data:{extensions:kA},successLog:{message:`${iA}successCount:${xA} failCount:${LA}`}}}return{code:0,data:{extensions:[]}}}catch(RA){const{errorCode:kA}=RA;throw new this._core.helper.ChatError({functionName:"deleteMessageExtensions",code:kA,moreMessage:iA})}})}reset(){this._messageExtensionsMap.clear(),this._extensionsLatestSequenceMap.clear(),this._completedFetchExtensions.clear()}dispose(){this.reset();const{notificationCenter:s,InnerEvent:{MESSAGE_PUSH:n,LOGOUT:g},InnerEventSubType:{MESSAGE_EXTENSIONS_UPDATED:u}}=this._core;s.unSubscribeInnerEvent(n,u,this._handleMessageExtensionsNotify,this),s.subscribeInnerEvent(g,this.reset,this)}_handleModifyMessageExtensions(s,n){const{ID:g}=s,{Seq:u}=n,E=n.ExtensionList||[],m=[];let D=0,M=0,T=[];return E.forEach(P=>{const{ErrorCode:W,Extension:iA}=P,{Key:EA,Value:RA,Seq:kA}=iA;m.push({code:W,key:EA,value:RA}),W===0?D++:M++,T.push({key:EA,value:RA,seq:kA})}),this._extensionsLatestSequenceMap.set(g,u),T.length>0&&this._updateLocalExtensions(s.ID,T),{resultList:m,successCount:D,failureCount:M}}_updateLocalExtensions(s,n){this._messageExtensionsMap.has(s)||this._messageExtensionsMap.set(s,new Map);const g=this._messageExtensionsMap.get(s);n?.forEach(u=>{const{key:E,seq:m,value:D=""}=u;g?.set(E,{value:D,seq:m})})}_fetchMessageExtensions(s,n){return pA(this,void 0,void 0,function*(){const{constants:{OuterConstant:g},utils:{isEmpty:u}}=this._core;try{let E;const{conversationType:m,ID:D}=s;if(m===g.CONV_C2C?E=yield function(M,T){const{common:{buildAndSendPacket:P}}=Us.core,{from:W,to:iA,clientSequence:EA,random:RA,time:kA}=M;return P({servcmd:"openim_msg_ext_http_svc.get_key_values",data:{From_Account:W,To_Account:iA,MsgKey:`${EA}_${RA}_${kA}`,StartSeq:T}})}(s,n):m===g.CONV_GROUP&&(E=yield function(M,T){const{common:{buildAndSendPacket:P}}=Us.core,{to:W,sequence:iA}=M;return P({servcmd:"openim_msg_ext_http_svc.group_get_key_values",data:{GroupId:W,MsgSeq:iA,StartSeq:T}})}(s,n)),E){const{LatestSeq:M,ClearSeq:T,CompleteFlag:P}=E,W=(E.ExtensionList||[]).map(EA=>({key:EA.Key,value:EA.Value,seq:EA.Seq}));if(this._updateLocalExtensions(D,W),this._clearLocationExtensions(D,T),this._extensionsLatestSequenceMap.set(D,M),P!==1){const EA=W[W.length-1].seq+1;return this._fetchMessageExtensions(s,EA)}const iA=[];if(this._messageExtensionsMap.has(D)){const EA=this._messageExtensionsMap.get(D);EA?.forEach((RA,kA)=>{const{value:xA}=RA;u(xA)||iA.push({key:kA,value:xA})})}return iA}}catch(E){throw E}})}_clearLocationExtensions(s,n){if(!(n<=0)&&this._messageExtensionsMap.has(s)){const g=this._messageExtensionsMap.get(s);g?.forEach((u,E)=>{u.seq<=n&&g.delete(E)})}}_generateServerExtensions(s,n){const{ID:g}=s;if(this._messageExtensionsMap.has(g)){const u=this._messageExtensionsMap.get(g);return n.map(E=>{var m;const{key:D,value:M}=E;let T=0;return u?.has(D)&&(T=(m=u.get(D))===null||m===void 0?void 0:m.seq),{Key:D,Value:M,Seq:T}})}return n.map(u=>({Key:u.key,Value:u.value,Seq:0}))}_validateMessageExtensionBusinessCapability(s){const{helper:n,constants:g}=this._core;if(!n.checkBusinessCapabilityBits(hC))throw new n.ChatError({functionName:s,code:g.ERROR_CODE.NO_USE,replacement1:s})}_handleMessageExtensionsNotify(s){const{SetKVInfo:n,DeleteKVInfo:g,ClearKVInfo:u,MsgOptType:E,TinyId:m,MsgLastSeq:D,ExtensionC2cMsgInfo:M,ExtensionGroupMsgInfo:T}=s?.MsgExtensionNotify||{},P=M||T||{},{MsgClientTime:W,MsgRandom:iA}=P,EA=`${m}-${W}-${iA}`;this._extensionsLatestSequenceMap.set(EA,D),E===kl?this._handleMessageExtensionsUpdated({messageID:EA,updateMessageExtensionsInfo:n}):E===Ll?this._handleMessageExtensionsDeleted({messageID:EA,deleteMessageExtensionsInfo:g}):E===Ug&&this._handleMessageExtensionsCleared({messageID:EA,clearMessageExtensionsInfo:u})}_handleMessageExtensionsUpdated(s){const{notificationCenter:n,OuterEvent:g}=this._core,{messageID:u,updateMessageExtensionsInfo:E=[]}=s,m=[];E.forEach(D=>{const{MsgKeyValue:M=[]}=D,T=M.map(P=>(m.push({key:P.Key,value:P.Value}),{key:P.Key,value:P.Value,seq:P.Seq}));this._updateLocalExtensions(u,T)}),n.emitOuterEvent(g.MESSAGE_EXTENSIONS_UPDATED,{name:g.MESSAGE_EXTENSIONS_UPDATED,data:{messageID:u,extensions:m}})}_handleMessageExtensionsDeleted(s){const{notificationCenter:n,OuterEvent:g}=this._core,{messageID:u,deleteMessageExtensionsInfo:E=[]}=s,m=[];E.forEach(D=>{const{MsgKeyValue:M=[]}=D,T=M.map(P=>(m.push(P.Key),{key:P.Key,seq:P.Seq}));this._updateLocalExtensions(u,T)}),n.emitOuterEvent(g.MESSAGE_EXTENSIONS_DELETED,{name:g.MESSAGE_EXTENSIONS_DELETED,data:{messageID:u,keyList:m}})}_handleMessageExtensionsCleared(s){const{notificationCenter:n,OuterEvent:{MESSAGE_EXTENSIONS_DELETED:g},utils:{isEmpty:u}}=this._core,{messageID:E,clearMessageExtensionsInfo:m=[]}=s,D=[];m.forEach(M=>{const{ClearMsgSeq:T}=M;this._messageExtensionsMap.has(E)&&(this._messageExtensionsMap.get(E)||[]).forEach((P,W)=>{P.seq<=T&&!u(P.value)&&D.push(W)}),this._clearLocationExtensions(E,T)}),n.emitOuterEvent(g,{name:g,data:{messageID:E,keyList:D}})}};const pI={key:"message",required:!0,rules:["object"],allowEmpty:!1,customValidator:s=>{const{constants:{OuterConstant:n}}=Us.core;return s.status!==n.MessageStatus.SUCCESS?"message is not success":s.isSupportExtension===!0||"message is not support extension"}},sl={setMessageExtensions:[pI,{key:"extensions",required:!0,rules:["array"],allowEmpty:!1}],getMessageExtensions:[pI],deleteMessageExtensions:[pI]},nl=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({deleteMessage:[{required:!0,rules:["array"],allowEmpty:!1}],revokeMessage:[{required:!0,rules:["object"],allowEmpty:!1}],resendMessage:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"options",required:!1,rules:["object"],allowEmpty:!1}],getMessageList:{conversationID:{required:!0,rules:["string"],allowEmpty:!1},nextReqMessageID:{required:!1,rules:["string"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0}},getMessageListHopping:{conversationID:{required:!0,rules:["string"],allowEmpty:!1},sequence:{required:!1,rules:["number"],allowEmpty:!0},direction:{required:!1,rules:["number"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0}},createTextAtMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1,customValidator:s=>{const n=function(g){var u;return typeof g?.text!="string"||typeof g.text=="string"&&((u=g?.text)===null||u===void 0?void 0:u.length)===0?"payload.text is invalid.":!0}(s);return n!==!0?n:!(s?.atUserList&&!Array.isArray(s.atUserList))||"atUserList should be an array or undefind."}}},findMessage:[{required:!0,rules:["string"],allowEmpty:!1}],translateText:{sourceTextList:{required:!0,rules:["array"],allowEmpty:!1},sourceLanguage:{required:!0,rules:["string"],allowEmpty:!1},targetLanguage:{required:!0,rules:["string"],allowEmpty:!1}},createForwardMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1,customValidator:s=>!(!s.startsWith("C2C")&&!s.startsWith("GROUP"))||"conversationType is invalid."},payload:{required:!0,rules:["object"],allowEmpty:!1}},createLocationMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1,customValidator:s=>{const{utils:{isString:n,isNumber:g}}=Us.core;return n(s?.description)?g(s?.longitude)?!!g(s?.latitude)||"payload.latitude must be a number.":"payload.longitude must be a number.":"payload.description must be a string."}}}},{addMessageReaction:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"reactionID",required:!0,rules:["string"],allowEmpty:!1}],removeMessageReaction:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"reactionID",required:!0,rules:["string"],allowEmpty:!1}],getMessageReactions:{messageList:{required:!0,rules:["array"],allowEmpty:!1},maxUserCountPerReaction:{required:!1,rules:["number"],allowEmpty:!0,customValidator:s=>typeof s!="number"?"maxUserCountPerReaction is invalid.":!(s<0||s>10)||"maxUserCountPerReaction should between [0, 10]."}},getAllUserListOfMessageReaction:{message:{required:!0,rules:["object"],allowEmpty:!1,customValidator:s=>s.status==="success"||"message is invalid."},reactionID:{required:!0,rules:["string"],allowEmpty:!1},nextSeq:{required:!1,rules:["number"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0}}}),{sendMessageReadReceipt:[{required:!0,rules:["array"],allowEmpty:!1}],getMessageReadReceiptList:[{required:!0,rules:["array"],allowEmpty:!1}],getGroupMessageReadMemberList:{message:{required:!0,rules:["object"],allowEmpty:!1},filter:{required:!1,rules:["number"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0},cursor:{required:!1,rules:["string"],allowEmpty:!0}}}),sl),{pinGroupMessage:{groupID:{required:!0,rules:["string"],allowEmpty:!1},message:{required:!0,rules:["object"],allowEmpty:!1},isPinned:{required:!0,rules:["boolean"],allowEmpty:!1}},getPinnedGroupMessageList:[{key:"groupID",required:!0,rules:["string"],allowEmpty:!1}]}),{createQuoteMessage:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"quotedMessage",required:!0,rules:["object"],allowEmpty:!1}]}),xa=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({deleteMessage:!0,revokeMessage:!0,resendMessage:!0,getMessageList:!0,getMessageListHopping:!0,createTextAtMessage:!0,findMessage:!0,translateText:!0,createForwardMessage:!0,createLocationMessage:!0},{addMessageReaction:!0,removeMessageReaction:!0,getMessageReactions:!0,getAllUserListOfMessageReaction:!0}),{sendMessageReadReceipt:!0,getMessageReadReceiptList:!0,getGroupMessageReadMemberList:!0}),{setMessageExtensions:!0,getMessageExtensions:!0,deleteMessageExtensions:!0}),{pinGroupMessage:!0,getPinnedGroupMessageList:!0}),{createQuoteMessage:!0});class FE{constructor(n){this._core=n}deleteMessage(n){return pA(this,void 0,void 0,function*(){const{to:g,messageIdentifiers:u}=n,E={From_Account:this._core.common.getCurrentUserID(),To_Account:g,MsgKeyList:u};return this._core.common.buildAndSendPacket({servcmd:"openim.delete_c2c_msg_ramble",data:E})})}revokeMessage(n){return pA(this,void 0,void 0,function*(){const{to:g,from:u,sequence:E,time:m,random:D}=n,M={MsgInfo:{From_Account:u,To_Account:g,MsgSeq:E,MsgRandom:D,MsgTimeStamp:m}};return this._core.common.buildAndSendPacket({servcmd:"openim.msgwithdraw",data:M})})}}class ra{constructor(n){this._core=n}deleteMessage(n){return pA(this,void 0,void 0,function*(){const{to:g,messageIdentifiers:u}=n,E={GroupId:g,Deleter_Account:this._core.common.getCurrentUserID(),Seqs:u};return this._core.common.buildAndSendPacket({servcmd:"group_open_http_svc.delete_group_ramble_msg_by_seq",data:E})})}revokeMessage(n){return pA(this,void 0,void 0,function*(){const{to:g,sequence:u}=n,E={GroupId:g,MsgSeqList:[{MsgSeq:u}]};return this._core.common.buildAndSendPacket({servcmd:"group_open_http_svc.group_msg_recall",data:E})})}}const Mn=2116;class kr{constructor(n){this._core=n}generateRevokeMessage(n){const{conversationID:g,sequence:u,random:E,tinyID:m,clientTime:D,revokeReason:M,revoker:T}=n;let P={};const{messageDataHandler:W}=this._core.message;return P=W.revokeMessage({conversationID:g,sequence:u,random:E,revoker:T}),P||(P={conversationID:g,sequence:u},m&&D&&E&&(P.ID=`${m}-${D}-${E}`)),P.revoker=T,P.revokeReason=M,P.revokerInfo={userID:T,nick:"",avatar:""},P}updateRevokerInfo(n){return pA(this,void 0,void 0,function*(){const g=n.map(u=>u.revoker);try{const u=yield this._fetchUserInfos(g);u&&n.forEach(E=>{const{revoker:m}=E;u[m]&&(E.revokerInfo.nick=u[m].nick||"",E.revokerInfo.avatar=u[m].avatar||"",E.revokerInfo.userID=m)})}catch(u){console.debug(u)}})}_fetchUserInfos(n){return pA(this,void 0,void 0,function*(){var g,u;const E=yield(g=this._core.user.userProfile)===null||g===void 0?void 0:g.getUserProfile({userIDList:n});return E?.data?(u=E.data)===null||u===void 0?void 0:u.reduce((m,{userID:D,nick:M,avatar:T})=>(m[D]={nick:M||"",avatar:T||""},m),{}):null})}}var rl=new class{constructor(){this._core=null,this._c2cMessageAction=null,this._groupMessageAction=null}init(s){this._core=s,this._groupMessageAction=new ra(s),this._c2cMessageAction=new FE(s),this._messageHelper=new kr(s);const{helper:n}=s;n.registerApi({apiName:"deleteMessage",context:this}),n.registerApi({apiName:"revokeMessage",context:this}),n.registerApi({apiName:"resendMessage",context:this}),n.registerApi({apiName:"findMessage",context:this}),n.registerApi({apiName:"createQuoteMessage",context:this})}deleteMessage(s){return pA(this,void 0,void 0,function*(){let n=[],g=[];const{conversationID:u,conversationType:E}=s[0],m=u.replace(E,"");if(E==="@TIM#SYSTEM")throw new this._core.helper.ChatError({code:Mn});if(s.forEach(D=>{const{conversationID:M,conversationType:T,status:P,_onlineOnlyFlag:W,sequence:iA,random:EA,time:RA}=D||{};if(P==="success"&&M===u&&T===E){if(!W){const kA=T==="C2C"?`${iA}_${EA}_${RA}`:String(iA);n.push(kA)}g.push(D)}}),n.length===0)return this._handleDeleteMessageSuccess(g),{code:0,data:{messageList:g}};n.length>30&&(n=n.slice(0,30),g=g.slice(0,30));try{return E==="C2C"?yield this._c2cMessageAction.deleteMessage({to:m,messageIdentifiers:n}):yield this._groupMessageAction.deleteMessage({to:m,messageIdentifiers:n}),this._handleDeleteMessageSuccess(g),{code:0,data:{messageList:g}}}catch(D){const{utils:{safeStringify:M}}=this._core,{errorCode:T,errorInfo:P}=D;throw new this._core.helper.ChatError({functionName:"deleteMessage",code:T,message:P,moreMessage:`messageIdentifiers: ${M(n)}`})}})}revokeMessage(s){return pA(this,void 0,void 0,function*(){var n;const{conversationType:g,isRevoked:u,ID:E,type:m,from:D,to:M}=s;let T=null;const P=`type:${m} from:${D} to:${M} ID:${E}`;if(g==="@TIM#SYSTEM")throw new this._core.helper.ChatError({message:"system message cannot be revoked"});if(u)throw new this._core.helper.ChatError({message:"message has been revoked",moreMessage:P});try{if(T=g==="C2C"?yield this._c2cMessageAction.revokeMessage(s):yield this._groupMessageAction.revokeMessage(s),T){const{RecallRetList:W}=T,iA=((n=W?.[0])===null||n===void 0?void 0:n.RetCode)||0;if(iA!==0)throw new this._core.helper.ChatError({code:iA,moreMessage:P});return s.isRevoked=!0,yield this._handleRevokeMessageSuccess(s),{code:0,data:{message:s},successLog:{message:P}}}}catch(W){const{errorCode:iA}=W;throw new this._core.helper.ChatError({functionName:"revokeMessage",code:iA,moreMessage:P})}})}resendMessage(s,n){return pA(this,void 0,void 0,function*(){var g,u;return s.isResend=!0,s.status="unSend",(u=(g=this._core)===null||g===void 0?void 0:g.apiMap)===null||u===void 0?void 0:u.sendMessage(s,n)})}findMessage(s){return this._core.message.messageDataHandler.findMessage(s)}createQuoteMessage(s,n){const{ID:g,time:u,sequence:E}=n;return s.quoteInfo={msgID:g,messageTime:u,messageSequence:E},s}_handleDeleteMessageSuccess(s){if(s.length===0)return;const{message:{messageDataHandler:n},common:{isTopic:g},notificationCenter:u,InnerEvent:E}=this._core;s.forEach(D=>{D.isDeleted=!0;const M=n.getLocalMessageList(D.conversationID);M?.forEach(T=>{T.ID===D.ID&&(T.isDeleted=!0)})});const{conversationID:m=""}=s[0];g(m)?u.emitInnerEvent(E.TOPIC_MESSAGE_DELETED,m):u.emitInnerEvent(E.MESSAGE_DELETED,m)}_handleRevokeMessageSuccess(s){return pA(this,void 0,void 0,function*(){var n;const g=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.userId,{conversationID:u,sequence:E,random:m}=s;this._core.message.messageDataHandler.revokeMessage({conversationID:u,sequence:E,random:m,revoker:g}),yield this._messageHelper.updateRevokerInfo([s])})}};class Ul{static parseServerPushElement(n){const{MsgContent:g={}}=n,{Index:u,Data:E}=g;return new Ul({index:u,data:E})}constructor(n){this.type=Vr.MSG_FACE;const{index:g,data:u}=n;this.content={index:g,data:u}}validateBeforeSend(){var n,g;return typeof((n=this.content)===null||n===void 0?void 0:n.index)=="number"&&typeof((g=this.content)===null||g===void 0?void 0:g.data)=="string"?{isValid:!0}:{isValid:!1,error:{message:"content is invalid"}}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{index:E,data:m}=u;return{MsgType:this.type,MsgContent:{Index:E,Data:m}}}}class bc{static parseServerPushElement(n){const{MsgContent:g={}}=n,{Desc:u,Longitude:E,Latitude:m}=g;return new bc({description:u,longitude:E,latitude:m})}constructor(n){this.type=Vr.MSG_LOCATION;const{description:g,longitude:u,latitude:E}=n;this.content={description:g,longitude:u,latitude:E}}validateBeforeSend(){return{isValid:!0}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{description:E,longitude:m,latitude:D}=u;return{MsgType:this.type,MsgContent:{Desc:E,Longitude:m,Latitude:D}}}}class OE{static parseServerPushElement(n){const{MsgContent:g={}}=n,{StreamMsgID:u,CompatibleText:E,Markdown:m,BinaryData:D,ErrorCode:M,ErrorMsg:T}=g;return new OE({streamMessageID:u,compatibleText:E,markdown:m,binaryData:D,errorCode:M,errorMessage:T})}constructor(n){this.type=Vr.MSG_STREAM,this.content={streamMessageID:"",compatibleText:"",errorCode:0,errorMessage:"",isStreamEnded:!1},this._chunks=[],this._latestIndex=0;const{streamMessageID:g,compatibleText:u,markdown:E,binaryData:m,errorCode:D=0,errorMessage:M="",isStreamEnded:T=!1,chunks:P=[],latestIndex:W=0}=n;this.content.streamMessageID=g,this.content.compatibleText=u,this.content.markdown=E,this.content.binaryData=m,this.content.errorCode=D,this.content.errorMessage=M,this.content.isStreamEnded=T,this.content.chunks=P,this.content.latestIndex=W}updateChunks(n){if(!n||n.length===0)return;const g=n.sort((m,D)=>m.index-D.index),u=this._getMaxRevokedChunkIndex(g);u>=0&&(this._chunks=[],this._latestIndex=u,this._updateContent());const E=this._getValidChunks(g);if(E.length!==0&&(this._mergeAndSortChunks(E),this._chunks.length>0)){const m=this._chunks[this._chunks.length-1];this._latestIndex=m.index,this._updateContent(),this.content.isStreamEnded=m.isLast}}getLatestIndex(){return this._latestIndex}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{streamMessageID:E,chunks:m}=u,D=m?.map(M=>({EventType:M.eventType||"data",Index:M.index,Markdown:M.markdown,IsLast:M.isLast}));return{MsgType:this.type,MsgContent:{StreamMsgID:E,Chunks:D}}}validateBeforeSend(){var n,g;return((g=(n=this.content)===null||n===void 0?void 0:n.chunks)===null||g===void 0?void 0:g.length)>0?{isValid:!0}:{isValid:!1,error:{message:"content is invalid"}}}_filterContinuousChunks(n,g){if(n.length===0)return[];const u=[];let E=g;for(const m of n){if(m.index>E)break;m.index===E&&(u.push(m),E++)}return u}_mergeAndSortChunks(n){const g=new Map;this._chunks.forEach(u=>{g.set(u.index,u)}),n.forEach(u=>{g.set(u.index,u)}),this._chunks=Array.from(g.values()).sort((u,E)=>u.index-E.index)}_updateContent(){this.content.markdown=this._chunks.map(g=>g.markdown).join("");const n=this._chunks.map(g=>g.binaryData).filter(g=>g?.length>0);if(n.length===0)this.content.binaryData=new Uint8Array(0);else if(n.length===1)this.content.binaryData=n[0];else{const g=n.reduce((m,D)=>m+D.length,0),u=new Uint8Array(g);let E=0;for(const m of n)u.set(m,E),E+=m.length;this.content.binaryData=u}}_getMaxRevokedChunkIndex(n){let g=-1;for(let u=0;ug&&(g=E.index)}return g}_getValidChunks(n){const g=n.filter(u=>u.eventType===Nc.DATA&&u.index>this._latestIndex);return this._filterContinuousChunks(g,this._latestIndex+1)}}var kc=new class{init(s){this._core=s,s.message.messageFactory.registerElementClass(Vr.MSG_FACE,Ul),s.message.messageFactory.registerElementClass(Vr.MSG_LOCATION,bc),s.message.messageFactory.registerElementClass(Vr.MSG_STREAM,OE),s.helper.registerApi({apiName:"createFaceMessage",context:this}),s.helper.registerApi({apiName:"createTextAtMessage",context:this}),s.helper.registerApi({apiName:"createForwardMessage",context:this}),s.helper.registerApi({apiName:"createLocationMessage",context:this})}createFaceMessage(s){if(!s)return null;const{index:n,data:g}=s?.payload||{},u=new Ul({index:n,data:g}),E=this._core.common.getCurrentUserID(),m=this._core.message.messageFactory.createMessage(Object.assign(Object.assign({},s),{from:E}));return m.setElement(u),m}createTextAtMessage(s){const{atUserList:n}=s?.payload||{},g=this._core.apiMap.createTextMessage(s),{OuterConstant:u}=this._core;if(!g)return null;if(Array.isArray(n)){const E=[],m=[];n.forEach(D=>{D!==u.MSG_AT_ALL?(E.push({GroupAtAllFlag:ch,GroupAt_Account:D}),m.push(D)):(E.push({GroupAtAllFlag:ao}),m.push(u.MSG_AT_ALL))}),g._groupAtInfoList=E,g.atUserList=m}return g}createForwardMessage(s){const{helper:n,OuterConstant:g}=this._core,{to:u,conversationType:E,priority:m,payload:D,needReadReceipt:M,receiverList:T,cloudCustomData:P="",isSupportExtension:W=!1}=s;if(!Array.isArray(D._elements))throw new n.ChatError({functionName:"createForwardMessage",code:2454});if(D.type===g.MSG_GRP_TIP)throw new n.ChatError({functionName:"createForwardMessage",code:2453});const iA=this._core.common.getCurrentUserID(),EA=this._core.message.messageFactory.createMessage({to:u,from:iA,conversationType:E,isPlaceMessage:0,priority:m,payload:D,needReadReceipt:M,isSupportExtension:W,cloudCustomData:P,receiverList:T});return EA.setRelayFlag(!0),EA.setElement(D._elements[0]),EA}createLocationMessage(s){if(!s)return null;const{description:n,longitude:g,latitude:u}=s?.payload||{},E=new bc({description:n,longitude:g,latitude:u}),m=this._core.common.getCurrentUserID(),D=this._core.message.messageFactory.createMessage(Object.assign(Object.assign({},s),{from:m}));return D.setElement(E),D}};let xu=class{init(s){this._messageHelper=new kr(s),this._core=s;const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:g},InnerEventSubType:{C2C_REVOKED_MESSAGE:u},helper:{registerWorkflowStep:E},constants:{WORKFLOW_NAME:m,WORKFLOW_STEP:D}}=s;n.subscribeInnerEvent(g,u,this._handleC2CNotifyMessage,this),E(m.SYNC_SERVER_INFO_AFTER_RE_ONLINE,D.HANDLE_C2C_REVOKED_MESSAGE_FROM_SYNC_UNREAD,this._handleC2CRevokeMessagesFromUnreadMessageSync,this)}_handleC2CNotifyMessage(s){const{C2cNotifyMsgArray:n}=s;n?.forEach(g=>{Object.keys(g).includes("WithdrawC2cMsgNotify")&&this._handleC2CRevokeMessage(g)})}_handleC2CRevokeMessage(s){return pA(this,void 0,void 0,function*(){try{const{WithdrawC2cMsgNotify:{C2cWithdrawInfoArray:n}}=s;yield this._parseAndEmitC2CRevokedMessages(n)}catch(n){console.debug(n)}})}_parseAndEmitC2CRevokedMessages(s){return pA(this,void 0,void 0,function*(){const n=[],{notificationCenter:g,OuterEvent:u,common:{getCurrentUserID:E}}=this._core;s.forEach(m=>{var D;const{MsgRand:M,MsgSeq:T,To_Account:P,From_Account:W,RevokerInfo:{Revoker_Account:iA,Revoke_Reason:EA}}=m,RA=E()===W?`C2C${P}`:`C2C${W}`,kA=((D=m?.RevokerInfo)===null||D===void 0?void 0:D.Reason)||EA,xA=this._messageHelper.generateRevokeMessage({conversationID:RA,sequence:T,random:M,revoker:iA,revokeReason:kA});n.push(xA)}),n.length>0&&(yield this._messageHelper.updateRevokerInfo(n),g.emitOuterEvent(u.MESSAGE_REVOKED,{name:u.MESSAGE_REVOKED,data:n}))})}_handleC2CRevokeMessagesFromUnreadMessageSync(s){return pA(this,void 0,void 0,function*(){const{revokedMessageList:n}=s.result;yield this._parseAndEmitC2CRevokedMessages(n)})}dispose(){const{notificationCenter:s,InnerEvent:{MESSAGE_PUSH:n},InnerEventSubType:{C2C_REVOKED_MESSAGE:g}}=this._core;s.unSubscribeInnerEvent(n,g,this._handleC2CNotifyMessage,this)}},pC=class{init(s){this._messageHelper=new kr(s),this._core=s;const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:g},InnerEventSubType:{GROUP_MESSAGE_REVOKED:u}}=s;n.subscribeInnerEvent(g,u,this._handleGroupNotifyMessage,this)}_handleGroupNotifyMessage(s){const{GroupTips:n}=s;n?.forEach(g=>{var u;Array.isArray((u=g?.MsgBody)===null||u===void 0?void 0:u.GroupWithdrawInfoArray)&&this._handleGroupRevokeMessage(g)})}_handleGroupRevokeMessage(s){return pA(this,void 0,void 0,function*(){try{const{RevokerInfo:n,MsgBody:{GroupWithdrawInfoArray:g},GroupInfo:u}=s,E=[],m=[],{notificationCenter:D,OuterEvent:M,utils:{isEmpty:T},common:{isCommunity:P}}=this._core;let W=!1;u&&(W=P({groupID:u.GroupId})||!T(u.TopicId)),g.forEach(iA=>{const{Random:EA,MsgSeq:RA,GroupId:kA,MsgClientTime:xA,TinyId:LA,TopicId:SA,RevokerInfo:{Revoker_Account:OA=n?.Revoker_Account||"",Reason:JA=n?.Reason||""}}=iA,ae=SA?`GROUP${SA}`:`GROUP${kA}`,ne=this._messageHelper.generateRevokeMessage({conversationID:ae,sequence:RA,random:EA,tinyID:LA,clientTime:xA,revoker:OA,revokeReason:JA});W?(ne.revokerInfo.nick=u.From_AccountNick,ne.revokerInfo.avatar=u.From_AccountHeadurl,E.push(ne)):m.push(ne)}),m.length>0&&(yield this._messageHelper.updateRevokerInfo(m),E.push(...m)),E.length!==0&&D.emitOuterEvent(M.MESSAGE_REVOKED,{name:M.MESSAGE_REVOKED,data:E})}catch(n){console.debug(n)}})}dispose(){const{notificationCenter:s,InnerEvent:{MESSAGE_PUSH:n},InnerEventSubType:{GROUP_MESSAGE_REVOKED:g}}=this._core;s.unSubscribeInnerEvent(n,g,this._handleGroupNotifyMessage,this)}};var tu=new class{constructor(){this._c2cMessageReceiver=new xu,this._groupMessageReceiver=new pC}init(s){this._c2cMessageReceiver.init(s),this._groupMessageReceiver.init(s)}dispose(){this._c2cMessageReceiver.dispose(),this._groupMessageReceiver.dispose()}},lh=new class{constructor(){this._core=null}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"translateText",context:this})}translateText(s){return pA(this,void 0,void 0,function*(){try{const{sourceLanguage:n,sourceTextList:g,targetLanguage:u}=s,E=yield function(m,D){return pA(this,void 0,void 0,function*(){var M,T;const{sourceTextList:P,sourceLanguage:W,targetLanguage:iA}=m,{store:EA,common:RA}=D,kA={SourceText:P,Source:W,Target:iA,FromAccount:(M=EA.get("login"))===null||M===void 0?void 0:M.tinyID,SDKAppID:(T=EA.get("instance"))===null||T===void 0?void 0:T.sdkAppId},xA=yield RA.buildAndSendPacket({servcmd:"im_open_translate.ws_batch_trans_text",data:kA});if(xA){const{CmdErrorCode:LA,TargetText:SA}=xA;return{cmdErrorCode:LA,translatedTextList:SA}}})}({sourceLanguage:n,sourceTextList:g,targetLanguage:u},this._core);if(E){const{cmdErrorCode:{ErrorCode:m,ErrorInfo:D},translatedTextList:M}=E;if(m===0)return{code:0,data:{translatedTextList:M}};throw{errorCode:m,errorInfo:D,message:D}}}catch(n){const{errorCode:g,errorInfo:u}=n||{};throw new this._core.helper.ChatError({functionName:"translateText",code:g,message:u})}})}},Yu=new class{init(s){this._core=s,s.helper.registerApi({apiName:"convertVoiceToText",context:this})}convertVoiceToText(s){return pA(this,void 0,void 0,function*(){var n;const{message:g,language:u=Tc.ZH_PY}=s;let{url:E}=g.payload||{};const m=this._core.common.getCurrentUserID();g.from===m&&g.flow==="out"&&(E=g.payload.remoteAudioUrl),this._validateVoiceFormat(E);const D=((n=QI.exec(E))===null||n===void 0?void 0:n[1])||"mp3",M=BI[u]||$I;try{const T=yield function(P){var W;const{store:iA,common:EA}=Us.core,{url:RA,format:kA,serverLanguageType:xA}=P,LA={BytesUrl:RA,BytesEngServiceType:xA,BytesVoiceFormat:kA,Uint32Sdkappid:(W=iA.get("instance"))===null||W===void 0?void 0:W.sdkAppId,Uint64SourceType:0};return EA.buildAndSendPacket({servcmd:"im_open_speech.ws_sentence_recognition",data:LA})}({url:E,format:D,serverLanguageType:M});if(T){const{CmdErrorCode:P,BytesResult:W}=T;if(P.ErrorCode===0)return{code:0,data:{result:W}};throw{code:P.ErrorCode,message:P.ErrorInfo}}}catch(T){const{code:P,message:W}=T||{};throw new this._core.common.ChatError({functionName:"convertVoiceToText",code:P,message:W})}})}_validateVoiceFormat(s){if(!QI.test(s))throw new this._core.common.ChatError({code:2119})}};class mI{constructor(n){const{constants:g,common:u,utils:E}=Us.core,{CONV_C2C:m,CONV_GROUP:D}=g.OuterConstant,{ID:M,tinyID:T,from:P,to:W,clientTime:iA=u.timeManager.getServerTimeSeconds()||0,random:EA,sequence:RA,cloudCustomData:kA="",nick:xA="",avatar:LA="",clientSequence:SA,conversationType:OA,groupID:JA,_elements:ae,time:ne}=n;this.ID=M||`${T}-${iA}-${EA}`,this.messageRandom=EA,this.from=P,this.messageSender=P,this.time=ne,this.messageSequence=RA,this.clientSequence=SA||RA,this.clientTime=iA,this.cloudCustomData=kA,this.messageReceiver=W,this.avatar=LA,this.nick=xA;const _i=E.deepCopyWithMethods(ae);_i.forEach(Ti=>{Ti.payload=Ti.content,delete Ti.content}),this.messageBody=_i,M?OA.startsWith(m)?this.receiverUserID=W:OA.startsWith(D)&&(this.receiverGroupID=W):JA?(this.receiverGroupID=JA,this.messageReceiver=JA):W&&(this.receiverUserID=W,this.messageReceiver=W)}transformElementsToServerFormat(){return this.messageBody?Array.isArray(this.messageBody)?this.messageBody.map(n=>n.transformToServerFormat({isMergerMessage:!0})):this.messageBody.transformToServerFormat({isMergerMessage:!0}):null}}class al{static parseServerPushElement(n){const{MsgContent:g}=n,{MsgList:u=[],CompatibleText:E,AbstractList:m,Title:D,PbMsgKey:M,JsonMsgKey:T}=g||{},P=u.map(W=>dr(W));return new al({messageList:P,title:D,abstractList:m,compatibleText:E,pbDownloadKey:M,downloadKey:T})}constructor(n){this.type=Us.core.constants.OuterConstant.MSG_MERGER;const{messageList:g,title:u,abstractList:E,compatibleText:m,pbDownloadKey:D="",downloadKey:M="",version:T=0,layersOverLimit:P=!1}=n,W=[];g.forEach(iA=>{if(iA){const EA=new mI(iA);W.push(EA)}}),this.content={messageList:W,title:u,abstractList:E,compatibleText:m,version:T,downloadKey:M,pbDownloadKey:D,layersOverLimit:P}}validateBeforeSend(){const{isEmpty:n}=Us.core.helper;return n(this.content.messageList)?{isValid:!1,error:{message:"content is invalid"}}:{isValid:!0}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{abstractList:E,compatibleText:m,downloadKey:D,layersOverLimit:M,pbDownloadKey:T,title:P,version:W,messageList:iA}=u;return{MsgType:this.type,MsgContent:{AbstractList:E,CompatibleText:m,JsonMsgKey:D,LayersOverLimit:M,PbMsgKey:T,Title:P,Version:W,MsgList:Ac(iA)}}}}var mC=new class{init(s){this._core=s;const{message:n,helper:g,constants:{OuterConstant:u}}=s;n.messageFactory.registerElementClass(u.MSG_MERGER,al),g.registerApi({apiName:"createMergerMessage",context:this}),g.registerApi({apiName:"sendMessage",context:this,matcher:E=>E[0].type===u.MSG_MERGER}),g.registerApi({apiName:"downloadMergerMessage",context:this})}createMergerMessage(s){const{common:n}=this._core;if(!s)return null;const g=new al(s.payload),u=n.getCurrentUserID(),E=this._core.message.messageFactory.createMessage(Object.assign(Object.assign({},s),{from:u}));return E.setRelayFlag(!0),E.setElement(g),E}sendMessage(s,n){return pA(this,void 0,void 0,function*(){var g,u,E;try{const m=function(P){let W="utf-8";Us.core.helper.IN_BROWSER&&document&&(W=document.charset.toLowerCase());let iA,EA=0,RA=0;if(RA=P.length,W==="utf-8"||W==="utf8")for(let kA=0;kA11264){D=this._core.utils.deepCopyWithMethods(s);try{const{JsonMsgKey:P,PbMsgKey:W}=yield function(EA){return pA(this,void 0,void 0,function*(){const{payload:{messageList:RA}}=EA,kA={MsgList:Ac(RA)};return Us.core.common.buildAndSendPacket({servcmd:"im_long_msg.save_relay_json_msg",data:kA})})}(D),{payload:iA}=D;M=new al(Object.assign(Object.assign({},iA),{messageList:[],downloadKey:P,pbDownloadKey:W})),D.setElement(M)}catch(P){console.error(P)}}const{data:{message:T}}=yield(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageSender)===null||E===void 0?void 0:E.sendMessage(D,n);return M&&T.setElement(s._elements),{code:0,data:{message:T}}}catch(m){const{errorCode:D}=m;throw new this._core.helper.ChatError({code:D})}})}downloadMergerMessage(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n}=this._core,g=s.payload,{downloadKey:u,pbDownload:E,type:m,messageList:D}=g,M=Do(g,["downloadKey","pbDownload","type","messageList"]);try{const T=yield function(iA){return pA(this,void 0,void 0,function*(){return Us.core.common.buildAndSendPacket({servcmd:"im_long_msg.get_relay_json_msg",data:{JsonMsgKey:iA}})})}(u),{MsgList:P}=T||{},W=P?.map(iA=>{const EA=dr(iA);return new mI(EA)});return typeof s.isOnlineMessage=="function"?s.setElement({type:s.type,content:Object.assign({messageList:W},M)}):(s.payload.messageList=W,s.payload.downloadKey="",s.payload.pbDownloadKey=""),n.info("downloadMergerMessage",` success downloadKey:${u}`),s}catch(T){const{errorCode:P}=T;throw new this._core.helper.ChatError({functionName:"downloadMergerMessage",code:P,moreMessage:u})}})}},aa=new class{init(s){this._core=s,this._core.helper.registerExperimentalAPI("sendComboMessage",this)}sendComboMessage(s){return pA(this,void 0,void 0,function*(){const{appStore:n,message:g,common:{getCurrentUserID:u},utils:{isArray:E}}=this._core,{GroupId:m,To_Account:D}=s;s.From_Account=s.From_Account||u();let M=null;if(m){M=this._generateGroupMessage(Object.assign(Object.assign({},s),{ToGroupId:m}));const T=n.userStore.getUserProfile(u());M.level=T?.level||0,E(D)&&D.length>0&&(M._receiverList=D)}else D&&(M=this._generateC2CMessage(s));return g.messageSender.sendMessage(M,s)})}_generateC2CMessage(s){const{message:n,OuterConstant:{CONV_C2C:g}}=this._core,u=g,E=n.messageHelper.parseServerPushMessage(s),m=n.messageFactory.createMessage(Object.assign(Object.assign({},E),{conversationType:u,flow:ec.OUT})),{elements:D}=E;return m.setElement(D),m}_generateGroupMessage(s){const{message:n,OuterConstant:{CONV_GROUP:g}}=this._core,u=g,E=n.messageHelper.parseServerGroupMessage(s),m=n.messageFactory.createMessage(Object.assign(Object.assign({},E),{conversationType:u,flow:ec.OUT})),{elements:D}=E;return m.setElement(D),m}},tc=new class{init(s){this._core=s;const{helper:n,notificationCenter:g,InnerEvent:{MESSAGE_PUSH:u},InnerEventSubType:{GROUP_MESSAGE_PINNED:E}}=s;g.subscribeInnerEvent(u,E,this._handleGroupMessagePinned,this),n.registerApi({apiName:"pinGroupMessage",context:this}),n.registerApi({apiName:"getPinnedGroupMessageList",context:this})}pinGroupMessage(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,common:{isTopic:g},OuterConstant:{GROUP_ID_PREFIX:u},helper:{ChatError:E}}=this._core;let{groupID:m,message:D,isPinned:M}=s;const{sequence:T}=D;try{return yield function(P){return pA(this,void 0,void 0,function*(){const{common:{buildAndSendPacket:W,getCurrentUserID:iA}}=Us.core,{groupID:EA,sequence:RA,isPinned:kA}=P,xA=iA(),LA=kA?"group_open_http_svc.pin_message":"group_open_http_svc.unpin_message",SA={GroupId:EA,MsgSeq:RA};return kA?SA.Pinner_Account=xA:SA.UnPinner_Account=xA,W({servcmd:LA,data:SA})})}({groupID:m,sequence:T,isPinned:M}),{code:0,data:{}}}catch(P){const{errorCode:W,errorInfo:iA}=P||{};throw new E({code:W,message:iA})}})}getPinnedGroupMessageList(s){return pA(this,void 0,void 0,function*(){let n=[];try{const g=yield function(u){return pA(this,void 0,void 0,function*(){const{groupID:E}=u,{common:{buildAndSendPacket:m}}=Us.core;return m({servcmd:"group_open_http_svc.get_pinned_messages",data:{GroupId:E}})})}({groupID:s});if(g){const{PinnedMsgList:u=[]}=g;n=yield this._updatePinnedMessageInfo({serverPinnedMessageList:u,groupID:s})}return{code:0,data:{messageList:n}}}catch(g){throw g}})}_handleGroupMessagePinned(s){const{message:{messageHelper:n,messageFactory:g},notificationCenter:u,OuterEvent:E,OuterConstant:m}=this._core;s.GroupTips.forEach(D=>{const{ToGroupId:M,MsgBody:{PinnedMsg:T,OpType:P,MsgOperatorMemberExtraInfo:W,SdkGroupMessageId:iA}}=D,{UserId:EA,NickName:RA="",ImageUrl:kA=""}=W;let xA=null,LA=!1;if(P===md){LA=!0;const SA=n.parseServerGroupMessage(T);xA=g.createMessage(Object.assign(Object.assign({},SA),{conversationType:m.CONV_GROUP,flow:"in"})),xA.setElement(SA.elements),xA.pinnerInfo={userID:EA,nick:RA,avatar:kA}}else if(P===LE){const{ClientTime:SA,Random:OA,SenderTinyId:JA,ServerTime:ae,MsgSeq:ne}=iA;xA={ID:`${JA}-${SA}-${OA}`,sequence:ne,random:OA,time:ae,clientTime:SA}}xA&&u.emitOuterEvent(E.PINNED_GROUP_MESSAGE_UPDATED,{name:E.PINNED_GROUP_MESSAGE_UPDATED,data:{groupID:M,message:xA,isPinned:LA,operatorInfo:{userID:EA,nick:RA,avatar:kA}}})})}_findMessageBySequence(s,n){const{message:{messageDataHandler:g}}=this._core;return[...g.getLocalMessageList(s),...g.getSparseMessageList(s)].find(u=>u.sequence===n)}_updatePinnedMessageInfo(s){return pA(this,arguments,void 0,function*({serverPinnedMessageList:n,groupID:g}){const{OuterConstant:{CONV_GROUP:u},utils:{isEmpty:E}}=this._core,m=[],D=[],M=[],T=new Map,P=`${u}${g}`;for(let iA=0;iA{const{sequence:kA}=RA,xA=T.get(kA),LA=iA[xA]||{userID:xA,nick:"",avatar:""};RA.pinnerInfo=LA}),m.sort((RA,kA)=>RA.sequence-kA.sequence),m}return[]})}_fetchPinnedMessageInfo(s){return pA(this,void 0,void 0,function*(){var n,g;const{message:{messageHistory:u},user:{userProfile:E},utils:{isArray:m}}=this._core,{conversationID:D,messageSequenceList:M,pinnerIDList:T}=s,P=yield Promise.all([this._fetchMessageBySequence({conversationID:D,messageSequenceList:M}),E?.getUserProfile({userIDList:T})]);if(m(P)){const W={};return(((n=P[1])===null||n===void 0?void 0:n.data)||[]).forEach(iA=>{const{userID:EA,nick:RA="",avatar:kA=""}=iA;W[EA]={userID:EA,nick:RA,avatar:kA}}),{messageList:((g=P[0])===null||g===void 0?void 0:g.messageList)||[],pinnerInfoMap:W}}})}_fetchMessageBySequence(s){return pA(this,void 0,void 0,function*(){const{utils:{isEmpty:n},message:{messageHistory:g}}=this._core,{conversationID:u,messageSequenceList:E}=s;return n(E)?[]:g.getGroupRoamingMessagesByAnchor({conversationID:u,messageSequenceList:E,getType:3})})}};class lg{constructor(n){this.eventType=Nc.DATA,this.index=0,this.markdown="",this.isLast=!1,this.binaryData=null;const{EventType:g,Index:u,Markdown:E,IsLast:m,BinaryData:D}=n;this.eventType=g,this.index=u,this.markdown=E,this.isLast=m,this.binaryData=D}}var fI=new class{constructor(){this._messageMap=new Map,this._retryCountMap=new Map}init(s){this._core=s;const{notificationCenter:n,OuterEvent:{MESSAGE_RECEIVED:g},InnerEvent:{HISTORY_MESSAGE_FETCHED:u},common:{workflowManager:E},constants:{WORKFLOW_NAME:m,WORKFLOW_STEP:D}}=s;n.subscribeInnerEvent(lo,this._handleStreamMessageChunkPush,this),n.subscribeOuterEvent(g,this._handleMessageReceived,this),n.subscribeInnerEvent(u,this.processHistoryMessage,this),E.registerWorkflowStep(m.SYNC_SERVER_INFO_AFTER_RE_ONLINE,D.STREAM_MESSAGE_RECOVER,this._recoverStreamMessage,this)}processHistoryMessage(s){const{utils:{isEmpty:n,safeStringify:g},ssoLog:u}=this._core;try{s?.forEach(E=>{var m;if(this._isValidStreamMessage(E)){const D=(m=E?._elements)===null||m===void 0?void 0:m[0],{streamMessageID:M,markdown:T,binaryData:P}=D?.content||{};n(T)&&n(P)?(this._messageMap.set(M,E),this._fetchStreamMessageChunks(E)):D.content.isStreamEnded=!0}})}catch(E){u.error("processHistoryMessage.error",g(E))}}_handleMessageReceived(s){const n=s.data;n?.forEach(g=>{var u,E;if(this._isValidStreamMessage(g)){const{streamMessageID:m}=((E=(u=g?._elements)===null||u===void 0?void 0:u[0])===null||E===void 0?void 0:E.content)||{};m&&(this._messageMap.set(m,g),this._fetchStreamMessageChunks(g))}})}_isValidStreamMessage(s){var n,g;const{utils:{isEmpty:u}}=this._core,{streamMessageID:E}=((g=(n=s?._elements)===null||n===void 0?void 0:n[0])===null||g===void 0?void 0:g.content)||{};return s.type===Vr.MSG_STREAM&&!u(E)}_fetchStreamMessageChunks(s){return pA(this,void 0,void 0,function*(){var n,g;const{constants:{ERROR_CODE:u},ssoLog:E,utils:{safeStringify:m}}=this._core,D=(n=s._elements)===null||n===void 0?void 0:n[0],M=(g=D?.content)===null||g===void 0?void 0:g.streamMessageID;try{const{from:T,to:P}=s,W=D.getLatestIndex();if(D.content.isStreamEnded)return;const iA=yield function(EA){return pA(this,void 0,void 0,function*(){const{from:RA,to:kA,streamMessageID:xA,index:LA}=EA,SA={From_Account:RA,To_Account:kA,StreamMsgID:xA,AckIndex:LA};return Us.core.common.buildAndSendPacket({servcmd:"StreamMsg.GetStreamHttp",data:SA,timeout:5e3})})}({from:T,to:P,streamMessageID:M,index:W});if(iA){const{ErrorCode:EA,ErrorInfo:RA}=iA;if(EA!==0)throw D.content.errorCode=EA,D.content.errorMessage=RA,{errorCode:EA,errorMessage:RA}}}catch(T){if(T.errorCode===u.NETWORK_TIMEOUT&&this._shouldRetryFetch(M)){const P=this._retryCountMap.get(M)||0;E.debug("_fetchStreamMessageChunks.timeout",`error: ${m(T)} retried: ${P}`),this._retryCountMap.set(M,P+1),this._fetchStreamMessageChunks(s)}else E.error("_fetchStreamMessageChunks.error",m(T))}})}_shouldRetryFetch(s){const{utils:{isNumber:n}}=this._core;if(!this._retryCountMap.has(s))return this._retryCountMap.set(s,1),!0;const g=this._retryCountMap.get(s);return!!(n(g)&&g<=3)}_onStreamEnded(s,n,g){const{ssoLog:u}=this._core;g.content.isStreamEnded=!0,g.stopReason=n,this._messageMap.delete(s),u.debug("_onStreamEnded",`streamMessage end, StopReason: ${n}`)}_handleStreamMessageChunkPush(s){var n;const{ssoLog:g}=this._core,{StopReason:u,Chunks:E,StreamID:m}=s?.body||{},D=this._messageMap.get(m);if(!D)return void g.warn(`_handleStreamMessageChunkPush, unfounded message: ${m}`);const M=(n=D._elements)===null||n===void 0?void 0:n[0];if(M&&this._validateExpectedChunk(M,E)){if(E.length>0){const T=E.map(P=>new lg(P));M.updateChunks(T)}this._emitMessageModify(D),function(T,P){pA(this,void 0,void 0,function*(){const{common:{generateProtocolData:W},utils:{safeStringify:iA},ssoLog:EA,channel:RA}=Us.core,kA={StreamMsgID:T,AckIndex:P};try{const xA=W({servcmd:"StreamMsg.AckHttp",data:kA});RA.sendPacket(xA)}catch(xA){EA.debug("sendStreamChunkAck",iA(xA))}})}(m,M.getLatestIndex()),M.content.isStreamEnded&&this._onStreamEnded(m,u,M)}}_emitMessageModify(s){const{notificationCenter:n,OuterEvent:{MESSAGE_MODIFIED:g}}=this._core;n.emitOuterEvent(g,{name:g,data:[s]})}_validateExpectedChunk(s,n){const g=s.getLatestIndex()+1;let u=!1;for(let E=0;Em.Index).join(", ")}]`),!1}return!0}_recoverStreamMessage(){this._retryCountMap.clear();const{ssoLog:s,utils:{safeStringify:n}}=this._core;try{const g=Array.from(this._messageMap.entries());for(let u=Math.max(0,g.length-300);u{const LA=this._getResponseBody(kA,E,iA&&EA),SA=this._buildResponse(kA,LA);if(kA.status===200)n(null,SA);else{if(EA&&!RA.includes(EA))return s.url=this._domainName2IP(RA,EA),s.uploadByIP=!0,this.request(s,n);n({code:kA.status,message:JSON.stringify(kA.responseText)},SA)}},kA.onerror=()=>{const LA=this._getResponseBody(kA,E,iA&&EA),SA=this._buildResponse(kA,LA),OA={code:kA.status,message:kA.status===0?"CORS blocked or network error":JSON.stringify(kA.responseText)};n(OA,SA)},s.onProgress&&kA.upload&&(kA.upload.onprogress=LA=>{const{total:SA,loaded:OA}=LA,JA=Math.min(Math.floor(100*OA/SA),100);s.onProgress({total:SA,loaded:OA,percent:JA/100})}),kA.send(P),kA})}_buildResponse(s,n){const g={};return s.getAllResponseHeaders().trim().split(`
-`).forEach(u=>{if(u){const[E,m]=u.split(":").map(D=>D.trim());g[E.toLowerCase()]=m}}),{statusCode:s.status,statusMessage:s.statusText,headers:g,data:n}}_getResponseBody(s,n,g){return s.status===200&&n?{location:n,uploadIP:g}:{response:s.responseText,uploadIP:g}}_queryString(s,n="&",g="="){var u;const{isEmpty:E,isPlainObject:m}=(u=this._core)===null||u===void 0?void 0:u.utils;return E(s)?"":m(s)?Object.keys(s).map(D=>{const M=encodeURIComponent(D)+g;return Array.isArray(s[D])?s[D].map(T=>M+encodeURIComponent(T)).join(n):M+encodeURIComponent(s[D])}).filter(Boolean).join(n):void 0}_domainName2IP(s,n){return s.replace(/^http(s)?:\/\/(.*?)\//,`https://${n}/`)}};const Ju=["unknown","image","video","audio","log"];var yI=new class{init(s){this._core=s}request(s,n){var g;const{MINI_APP_NAMESPACE:u,IN_ALIPAY_MINI_APP:E,isUniIOSApp:m}=(g=this._core)===null||g===void 0?void 0:g.utils,{resources:D="",headers:M={},url:T,downloadUrl:P=""}=s;let W=T,iA=null;const EA=P?P.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/):null;if(!EA)return void console.warn("message Invalid download URL format");const RA=decodeURIComponent(EA[3]),kA=RA.includes("?")?RA.split("?")[0]:RA||"",xA={key:s.fileKey||kA,success_action_status:200,"Content-Type":""},LA={};if(m()){const[OA,JA]=T.split("?sign=");JA&&(W=`${OA}?sign=${encodeURIComponent(JA)}`,LA.sign=decodeURIComponent(JA),LA.signature=decodeURIComponent(JA))}let SA={url:W,header:M,name:"file",filePath:D,formData:Object.assign(Object.assign({},xA),LA),timeout:s.timeout||3e5};if(E){const{name:OA}=SA,JA=Do(SA,["name"]);SA=Object.assign(Object.assign({},JA),{fileName:"file",fileType:s.fileType?Ju[s.fileType]:"image"})}return iA=u.uploadFile(Object.assign(Object.assign({},SA),{success:OA=>{this._handleResponse({response:OA,downloadUrl:P,callback:n})},fail:OA=>{this._handleResponse({response:OA,downloadUrl:P,callback:n})}})),iA.onProgressUpdate&&iA.onProgressUpdate(OA=>{s.onProgress&&s.onProgress({total:OA.totalBytesExpectedToSend||0,loaded:OA.totalBytesSent||0,percent:OA.progress?Math.floor(OA.progress)/100:0})}),iA}_handleResponse(s){const{downloadUrl:n,response:g,callback:u}=s,E={};if(g.header)for(const D in g.header)g.header.hasOwnProperty(D)&&(E[D.toLowerCase()]=g.header[D]);const m=+g.statusCode;m===200?u(null,{statusCode:m,headers:E,data:Object.assign(Object.assign({},g.data),{location:n})}):u({code:m,message:JSON.stringify(g.data)},{statusCode:m,headers:E,data:void 0})}};function gl(s){return function(n){return Object.prototype.toString.call(n).match(/^\[object (.*)\]$/)[1].toLowerCase()}(s)==="file"}function Lr(s){const n=s||99999999;return Math.round(Math.random()*n)}function Ur(s,n=!0,g=!0){const u=Date.now();return n?g?u-s+" ms":`${Math.round((u-s)/1e3)} s`:g?u-s:Math.round((u-s)/1e3)}function Ig(s){return`${Array.from({length:8},()=>Math.floor(65536*(1+Math.random())).toString(16).substring(1)).join("")}-${s}`}function ar(s,n){return Math.round(Number(s)*10**n)/10**n}function wr(s){return s<=1048576?`${ar(s/1024,1)}KB/s`:`${ar(s/1048576,1)}MB/s`}const ic="TIMImageElem",Fg="TIMSoundElem",Ya="TIMFileElem",Fl="TIMVideoFileElem",ha="RichMediaMessagePlugin",DI=["rich.my-imcloud.com","imrich.qcloud.com"],iu=1,Ba=2,cl=3,xE=255;var ou;(function(s){s.UNSENT="unSend",s.SUCCESS="success",s.FAIL="fail"})(ou||(ou={}));const YE={wechat:/^(wxfile:\/\/tmp_|http:\/\/temp\/|cloud:\/\/temp-)/,alipay:/^(https:\/\/resource\/|alipayfile:\/\/tmp\/)/,baidu:/^(http:\/\/tmp\/|swanfile:\/\/tmp_)/,bytedance:/^(ttfile:\/\/tmp_|\/(var|tmp)\/|tttemp:\/\/)/,qq:/^(qqfile:\/\/tmp_|http:\/\/qtemp\/)/},Jr=Symbol("isCustomUpload");var su,Ot=new class{init(s){this._core=s}addAuthToUrl(s=""){if(this._isMiniProgramTempFile(s))return s;const n=function(g){return g?g.startsWith("https://")?g:g.startsWith("http://")?g.replace("http://","https://"):g:""}(s);return this.processResourceUrl(n)}removeAuthToUrl(s){return function(n,g){const[u,E]=n.split("?");if(!E)return u;const m=E.split("&").reduce((M,T)=>{const[P,W]=T.split("=");return P&&P!==g&&(M[P]=W||""),M},{}),D=Object.keys(m).map(M=>`${M}${m[M]?`=${m[M]}`:""}`).join("&");return D?`${u}?${D}`:u}(s,"authKey")}_isMiniProgramTempFile(s){return!!this.getPlatformFlags().IN_MINI_APP&&Object.values(YE).some(n=>n.test(s))}extractFileFromInput(s){const{utils:{isArray:n}}=this._core;return gl(s)?s:function(g){if(typeof g!="object"||g===null)return!1;const u=Object.getPrototypeOf(g);if(u===null)return!0;let E=u;for(;Object.getPrototypeOf(E)!==null;)E=Object.getPrototypeOf(E);return u===E}(s)&&typeof uni<"u"?n(s.tempFiles)&&s.tempFiles.length>0?s.tempFiles[0]:n(s.files)?s.files[0]:s.tempFile?s.tempFile:null:s instanceof HTMLInputElement&&s.files&&s.files.length>0?s.files[0]:null}probeImageWidthHeight(s){return pA(this,void 0,void 0,function*(){var n;const{IN_MINI_APP:g,IN_BROWSER:u}=((n=this._core)===null||n===void 0?void 0:n.utils)||{};return this._shouldSkipProbing()?{width:0,height:0}:u?this._probeImageDimensionsWeb(s):g?this._probeImageDimensionsMiniApp(s):void 0})}isSimpleCos(){var s;const n=((s=this._core)===null||s===void 0?void 0:s.store.get("cloudConfig"))||{},{simple_cos:g}=n;return g!=="0"}getFileDNList(){var s;let n=DI;const g=((s=this._core)===null||s===void 0?void 0:s.store.get("cloudConfig"))||{},{file_dn_list:u}=g;if(u===void 0)return n;try{JSON.parse(u).forEach(E=>{n.includes(E)||n.push(E)})}catch(E){console.warn(E),n=DI}return n}getPlatform(){var s;return(s=this._core)===null||s===void 0?void 0:s.utils.platform}generateUUID(s,n){var g;let u=`${this.getSDKAppID()}-${this.getCurrentUserID()}-${(g=this._core)===null||g===void 0?void 0:g.utils.randomString()}`;if(n)return`${u}.${n}`;const E=s.name||s.value||s.url||s.tempFilePath,m=E&&E.slice(E.lastIndexOf(".")+1);return m&&(u=`${u}.${m}`),u}processResourceUrl(s){if(!s)return"";let n=s;const g=this.getFileDownloadProxy(),u=this.getAuthKey(),E=this.getFileDNList();return g&&(s.startsWith("http://")?n=s.replace(/^http:\/\/[^/]+/,g):s.startsWith("https://")&&(n=s.replace(/^https:\/\/[^/]+/,g))),u&&n.indexOf("authKey=")===-1&&function(D,M){let T=!1;if(D){const P=D.match(/:\/\/([0-9]?\.)?(.[^/:]+)/),W=P&&P[2]||"";if(W.includes("rich-dev"))return!0;for(let iA=0;iA-1?`${n}&authKey=${u}`:`${n}?authKey=${u}`),n}getCurrentUserID(){var s,n;return(n=(s=this._core)===null||s===void 0?void 0:s.store.get("login"))===null||n===void 0?void 0:n.userId}getSDKAppID(){var s,n;return(n=(s=this._core)===null||s===void 0?void 0:s.store.get("instance"))===null||n===void 0?void 0:n.sdkAppId}getFileDownloadProxy(){var s,n;return((n=(s=this._core)===null||s===void 0?void 0:s.store.get("instance"))===null||n===void 0?void 0:n.fileDownloadProxy)||""}getFileUploadProxy(){var s,n;return((n=(s=this._core)===null||s===void 0?void 0:s.store.get("instance"))===null||n===void 0?void 0:n.fileUploadProxy)||""}getAuthKey(){var s,n;return((n=(s=this._core)===null||s===void 0?void 0:s.store.get("login"))===null||n===void 0?void 0:n.authKey)||""}isPrivateNetWork(){var s,n;return(n=(s=this._core)===null||s===void 0?void 0:s.store.get("instance"))===null||n===void 0?void 0:n.proxyServer}getPlatformFlags(){var s;const{IN_BROWSER:n,IN_MINI_APP:g,IN_RN_APP:u,IN_UNI_NATIVE_APP:E}=(s=this._core)===null||s===void 0?void 0:s.utils;return{IN_BROWSER:n,IN_MINI_APP:g,IN_RN_APP:u,IN_UNI_NATIVE_APP:E}}isEmpty(s){var n;const{isEmpty:g}=(n=this._core)===null||n===void 0?void 0:n.utils;return g(s)}generateURL(s,n){const{needAddAuthToUrl:g=!0}=n||{};return g?this.addAuthToUrl(s):s}_probeImageDimensionsMiniApp(s){var n;const{MINI_APP_NAMESPACE:g}=((n=this._core)===null||n===void 0?void 0:n.utils)||{};return new Promise(u=>{g.getImageInfo({src:s,success:E=>u({width:E.width,height:E.height}),fail:()=>u({width:0,height:0})})})}_shouldSkipProbing(){var s;const{IN_RN_APP:n,IS_IE:g,IE_VERSION:u,IN_WX_MINI_GAME:E}=((s=this._core)===null||s===void 0?void 0:s.utils)||{};return n||g&&u===9||E}_probeImageDimensionsWeb(s){return new Promise(n=>{const g=new Image,u=()=>{g.onload=null,g.onerror=null,g.src=""};g.onload=()=>{n({width:g.width,height:g.height}),u()},g.onerror=()=>{n({width:0,height:0}),u()},g.src=s})}},Hu={exports:{}},qu=(su||(su=1,function(s){s.exports=function(n){var g=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function u(LA,SA){var OA=LA[0],JA=LA[1],ae=LA[2],ne=LA[3];JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ae|~JA&ne)+SA[0]-680876936|0)<<7|OA>>>25)+JA|0)&JA|~OA&ae)+SA[1]-389564586|0)<<12|ne>>>20)+OA|0)&OA|~ne&JA)+SA[2]+606105819|0)<<17|ae>>>15)+ne|0)&ne|~ae&OA)+SA[3]-1044525330|0)<<22|JA>>>10)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ae|~JA&ne)+SA[4]-176418897|0)<<7|OA>>>25)+JA|0)&JA|~OA&ae)+SA[5]+1200080426|0)<<12|ne>>>20)+OA|0)&OA|~ne&JA)+SA[6]-1473231341|0)<<17|ae>>>15)+ne|0)&ne|~ae&OA)+SA[7]-45705983|0)<<22|JA>>>10)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ae|~JA&ne)+SA[8]+1770035416|0)<<7|OA>>>25)+JA|0)&JA|~OA&ae)+SA[9]-1958414417|0)<<12|ne>>>20)+OA|0)&OA|~ne&JA)+SA[10]-42063|0)<<17|ae>>>15)+ne|0)&ne|~ae&OA)+SA[11]-1990404162|0)<<22|JA>>>10)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ae|~JA&ne)+SA[12]+1804603682|0)<<7|OA>>>25)+JA|0)&JA|~OA&ae)+SA[13]-40341101|0)<<12|ne>>>20)+OA|0)&OA|~ne&JA)+SA[14]-1502002290|0)<<17|ae>>>15)+ne|0)&ne|~ae&OA)+SA[15]+1236535329|0)<<22|JA>>>10)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ne|ae&~ne)+SA[1]-165796510|0)<<5|OA>>>27)+JA|0)&ae|JA&~ae)+SA[6]-1069501632|0)<<9|ne>>>23)+OA|0)&JA|OA&~JA)+SA[11]+643717713|0)<<14|ae>>>18)+ne|0)&OA|ne&~OA)+SA[0]-373897302|0)<<20|JA>>>12)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ne|ae&~ne)+SA[5]-701558691|0)<<5|OA>>>27)+JA|0)&ae|JA&~ae)+SA[10]+38016083|0)<<9|ne>>>23)+OA|0)&JA|OA&~JA)+SA[15]-660478335|0)<<14|ae>>>18)+ne|0)&OA|ne&~OA)+SA[4]-405537848|0)<<20|JA>>>12)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ne|ae&~ne)+SA[9]+568446438|0)<<5|OA>>>27)+JA|0)&ae|JA&~ae)+SA[14]-1019803690|0)<<9|ne>>>23)+OA|0)&JA|OA&~JA)+SA[3]-187363961|0)<<14|ae>>>18)+ne|0)&OA|ne&~OA)+SA[8]+1163531501|0)<<20|JA>>>12)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA&ne|ae&~ne)+SA[13]-1444681467|0)<<5|OA>>>27)+JA|0)&ae|JA&~ae)+SA[2]-51403784|0)<<9|ne>>>23)+OA|0)&JA|OA&~JA)+SA[7]+1735328473|0)<<14|ae>>>18)+ne|0)&OA|ne&~OA)+SA[12]-1926607734|0)<<20|JA>>>12)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA^ae^ne)+SA[5]-378558|0)<<4|OA>>>28)+JA|0)^JA^ae)+SA[8]-2022574463|0)<<11|ne>>>21)+OA|0)^OA^JA)+SA[11]+1839030562|0)<<16|ae>>>16)+ne|0)^ne^OA)+SA[14]-35309556|0)<<23|JA>>>9)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA^ae^ne)+SA[1]-1530992060|0)<<4|OA>>>28)+JA|0)^JA^ae)+SA[4]+1272893353|0)<<11|ne>>>21)+OA|0)^OA^JA)+SA[7]-155497632|0)<<16|ae>>>16)+ne|0)^ne^OA)+SA[10]-1094730640|0)<<23|JA>>>9)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA^ae^ne)+SA[13]+681279174|0)<<4|OA>>>28)+JA|0)^JA^ae)+SA[0]-358537222|0)<<11|ne>>>21)+OA|0)^OA^JA)+SA[3]-722521979|0)<<16|ae>>>16)+ne|0)^ne^OA)+SA[6]+76029189|0)<<23|JA>>>9)+ae|0,JA=((JA+=((ae=((ae+=((ne=((ne+=((OA=((OA+=(JA^ae^ne)+SA[9]-640364487|0)<<4|OA>>>28)+JA|0)^JA^ae)+SA[12]-421815835|0)<<11|ne>>>21)+OA|0)^OA^JA)+SA[15]+530742520|0)<<16|ae>>>16)+ne|0)^ne^OA)+SA[2]-995338651|0)<<23|JA>>>9)+ae|0,JA=((JA+=((ne=((ne+=(JA^((OA=((OA+=(ae^(JA|~ne))+SA[0]-198630844|0)<<6|OA>>>26)+JA|0)|~ae))+SA[7]+1126891415|0)<<10|ne>>>22)+OA|0)^((ae=((ae+=(OA^(ne|~JA))+SA[14]-1416354905|0)<<15|ae>>>17)+ne|0)|~OA))+SA[5]-57434055|0)<<21|JA>>>11)+ae|0,JA=((JA+=((ne=((ne+=(JA^((OA=((OA+=(ae^(JA|~ne))+SA[12]+1700485571|0)<<6|OA>>>26)+JA|0)|~ae))+SA[3]-1894986606|0)<<10|ne>>>22)+OA|0)^((ae=((ae+=(OA^(ne|~JA))+SA[10]-1051523|0)<<15|ae>>>17)+ne|0)|~OA))+SA[1]-2054922799|0)<<21|JA>>>11)+ae|0,JA=((JA+=((ne=((ne+=(JA^((OA=((OA+=(ae^(JA|~ne))+SA[8]+1873313359|0)<<6|OA>>>26)+JA|0)|~ae))+SA[15]-30611744|0)<<10|ne>>>22)+OA|0)^((ae=((ae+=(OA^(ne|~JA))+SA[6]-1560198380|0)<<15|ae>>>17)+ne|0)|~OA))+SA[13]+1309151649|0)<<21|JA>>>11)+ae|0,JA=((JA+=((ne=((ne+=(JA^((OA=((OA+=(ae^(JA|~ne))+SA[4]-145523070|0)<<6|OA>>>26)+JA|0)|~ae))+SA[11]-1120210379|0)<<10|ne>>>22)+OA|0)^((ae=((ae+=(OA^(ne|~JA))+SA[2]+718787259|0)<<15|ae>>>17)+ne|0)|~OA))+SA[9]-343485551|0)<<21|JA>>>11)+ae|0,LA[0]=OA+LA[0]|0,LA[1]=JA+LA[1]|0,LA[2]=ae+LA[2]|0,LA[3]=ne+LA[3]|0}function E(LA){var SA,OA=[];for(SA=0;SA<64;SA+=4)OA[SA>>2]=LA.charCodeAt(SA)+(LA.charCodeAt(SA+1)<<8)+(LA.charCodeAt(SA+2)<<16)+(LA.charCodeAt(SA+3)<<24);return OA}function m(LA){var SA,OA=[];for(SA=0;SA<64;SA+=4)OA[SA>>2]=LA[SA]+(LA[SA+1]<<8)+(LA[SA+2]<<16)+(LA[SA+3]<<24);return OA}function D(LA){var SA,OA,JA,ae,ne,_i,Ti=LA.length,Lt=[1732584193,-271733879,-1732584194,271733878];for(SA=64;SA<=Ti;SA+=64)u(Lt,E(LA.substring(SA-64,SA)));for(OA=(LA=LA.substring(SA-64)).length,JA=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],SA=0;SA>2]|=LA.charCodeAt(SA)<<(SA%4<<3);if(JA[SA>>2]|=128<<(SA%4<<3),SA>55)for(u(Lt,JA),SA=0;SA<16;SA+=1)JA[SA]=0;return ae=(ae=8*Ti).toString(16).match(/(.*?)(.{0,8})$/),ne=parseInt(ae[2],16),_i=parseInt(ae[1],16)||0,JA[14]=ne,JA[15]=_i,u(Lt,JA),Lt}function M(LA){var SA,OA,JA,ae,ne,_i,Ti=LA.length,Lt=[1732584193,-271733879,-1732584194,271733878];for(SA=64;SA<=Ti;SA+=64)u(Lt,m(LA.subarray(SA-64,SA)));for(OA=(LA=SA-64>2]|=LA[SA]<<(SA%4<<3);if(JA[SA>>2]|=128<<(SA%4<<3),SA>55)for(u(Lt,JA),SA=0;SA<16;SA+=1)JA[SA]=0;return ae=(ae=8*Ti).toString(16).match(/(.*?)(.{0,8})$/),ne=parseInt(ae[2],16),_i=parseInt(ae[1],16)||0,JA[14]=ne,JA[15]=_i,u(Lt,JA),Lt}function T(LA){var SA,OA="";for(SA=0;SA<4;SA+=1)OA+=g[LA>>8*SA+4&15]+g[LA>>8*SA&15];return OA}function P(LA){var SA;for(SA=0;SA"u"||ArrayBuffer.prototype.slice||function(){function LA(SA,OA){return(SA=0|SA||0)<0?Math.max(SA+OA,0):Math.min(SA,OA)}ArrayBuffer.prototype.slice=function(SA,OA){var JA,ae,ne,_i,Ti=this.byteLength,Lt=LA(SA,Ti),Ni=Ti;return OA!==n&&(Ni=LA(OA,Ti)),Lt>Ni?new ArrayBuffer(0):(JA=Ni-Lt,ae=new ArrayBuffer(JA),ne=new Uint8Array(ae),_i=new Uint8Array(this,Lt,JA),ne.set(_i),ae)}}(),xA.prototype.append=function(LA){return this.appendBinary(W(LA)),this},xA.prototype.appendBinary=function(LA){this._buff+=LA,this._length+=LA.length;var SA,OA=this._buff.length;for(SA=64;SA<=OA;SA+=64)u(this._hash,E(this._buff.substring(SA-64,SA)));return this._buff=this._buff.substring(SA-64),this},xA.prototype.end=function(LA){var SA,OA,JA=this._buff,ae=JA.length,ne=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(SA=0;SA>2]|=JA.charCodeAt(SA)<<(SA%4<<3);return this._finish(ne,ae),OA=P(this._hash),LA&&(OA=kA(OA)),this.reset(),OA},xA.prototype.reset=function(){return this._buff="",this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},xA.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash.slice()}},xA.prototype.setState=function(LA){return this._buff=LA.buff,this._length=LA.length,this._hash=LA.hash,this},xA.prototype.destroy=function(){delete this._hash,delete this._buff,delete this._length},xA.prototype._finish=function(LA,SA){var OA,JA,ae,ne=SA;if(LA[ne>>2]|=128<<(ne%4<<3),ne>55)for(u(this._hash,LA),ne=0;ne<16;ne+=1)LA[ne]=0;OA=(OA=8*this._length).toString(16).match(/(.*?)(.{0,8})$/),JA=parseInt(OA[2],16),ae=parseInt(OA[1],16)||0,LA[14]=JA,LA[15]=ae,u(this._hash,LA)},xA.hash=function(LA,SA){return xA.hashBinary(W(LA),SA)},xA.hashBinary=function(LA,SA){var OA=P(D(LA));return SA?kA(OA):OA},xA.ArrayBuffer=function(){this.reset()},xA.ArrayBuffer.prototype.append=function(LA){var SA,OA=RA(this._buff.buffer,LA),JA=OA.length;for(this._length+=LA.byteLength,SA=64;SA<=JA;SA+=64)u(this._hash,m(OA.subarray(SA-64,SA)));return this._buff=SA-64>2]|=JA[SA]<<(SA%4<<3);return this._finish(ne,ae),OA=P(this._hash),LA&&(OA=kA(OA)),this.reset(),OA},xA.ArrayBuffer.prototype.reset=function(){return this._buff=new Uint8Array(0),this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},xA.ArrayBuffer.prototype.getState=function(){var LA=xA.prototype.getState.call(this);return LA.buff=EA(LA.buff),LA},xA.ArrayBuffer.prototype.setState=function(LA){return LA.buff=iA(LA.buff,!0),xA.prototype.setState.call(this,LA)},xA.ArrayBuffer.prototype.destroy=xA.prototype.destroy,xA.ArrayBuffer.prototype._finish=xA.prototype._finish,xA.ArrayBuffer.hash=function(LA,SA){var OA=P(M(new Uint8Array(LA)));return SA?kA(OA):OA},xA}()}(Hu)),Hu.exports),fC=aI(qu),q=new class{constructor(){this.uploadFileTryCount=0,this.maxRetries=1,this.systemClockOffset=0,this.httpRequest=null,this.uploadFileType="",this.duration=900,this.fetchCosTryCount=0}init(s){var n;this._core=s;const{IN_MINI_APP:g}=s.utils;this.httpRequest=g?yI:Vu,(n=this.httpRequest)===null||n===void 0||n.init(s)}uploadToCOS(s){return pA(this,void 0,void 0,function*(){const n=`${ha} uploadToCOS`,{ssoLog:g,utils:{safeStringify:u}}=this._core,{file:E}=s;this.uploadFileType=s.uploadFileType,g.debug("uploadToCOS",`${n} options:${u(s)}`);try{const m=Date.now(),D=yield this._createCosOptions(s),M=D.fileExistsInCOS?{data:{location:D.downloadUrl}}:yield this._uploadFile(D);this._handleUploadError(M,s);const T=this._createUploadResult(E,M),P=Date.now()-m,W=function(EA){return EA<1024?`${EA}B`:EA<1048576?`${Math.floor(EA/1024)}KB`:`${Math.floor(EA/1048576)}MB`}(E.size),iA=`size:${W} time:${P}ms speed:${wr(1e3*E.size/P)}`;return g.debug("uploadToCOS",`${n} ok. name:${E.name} ${iA}`),{uploadOptions:D,response:T}}catch(m){throw g.warn("uploadToCOS",`${n} failed, error:${u(m)}`),m}})}_handleUploadError(s,n){var g,u;const{ChatError:E}=(g=this._core)===null||g===void 0?void 0:g.helper;if(s.statusCode===403)throw n.url,!((u=s?.data)===null||u===void 0)&&u.uploadIP&&s.data.uploadIP,new E({message:"Upload failed with status 403"})}_createUploadResult(s,n){return{fileName:s.name,fileSize:s.size,fileType:s.type.slice(s.type.indexOf("/")+1).toLowerCase(),location:n.data.location||"",uploadTime:Ur(Date.now(),!1),uploadSpeed:wr(1e3*s.size/Ur(Date.now(),!1))}}_createCosOptions(s){return pA(this,void 0,void 0,function*(){const{fileName:n,resources:g,uploadMethod:u}=yield this._prepareUploadParams(s),E=this._isC2CConversation(s.message.conversationID)?1:2;try{const m=yield this._fetchCosSignatureUrl({fileType:this.uploadFileType,fileName:n,uploadMethod:u,duration:this.duration,userID:s.message.from,conversationType:E}),{uploadUrl:D,downloadUrl:M,requestSnapshotUrl:T,thumbUrl:P,largeUrl:W,fileKey:iA,existFlag:EA}=m,RA=!Ot.isPrivateNetWork()&&m.uploadIP;return{url:this._getRawOrUploadProxyUrl(D),fileType:this.uploadFileType,fileName:n,resources:g,downloadUrl:M,requestSnapshotUrl:T,thumbUrl:P,largeUrl:W,fileKey:iA,uploadIP:RA||"",fileExistsInCOS:EA===1,onProgress:kA=>this._handleUploadProgress(kA,s)}}catch(m){throw console.error("Failed to create COS pre-signed URL options:",m),m}})}_prepareUploadParams(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g,isEmpty:u}}=this._core;n.debug("_prepareUploadParams",` prepareUploadParams:${g(s)}`);const{file:E}=s,{IN_MINI_APP:m,IN_RN_APP:D}=Ot.getPlatformFlags(),M=m||D,T=M&&s.message.type!==Ya,{name:P}=E,W=P.slice(P.lastIndexOf(".")),iA=`${Lr(999999)}${W}`,EA=T?E.name:iA,RA=yield this._generateHashFileName(E);return{fileName:u(RA)?Ig(EA):`${RA}${W}`,resources:M?E.url:E,uploadMethod:M?1:0}})}_generateHashFileName(s){return pA(this,void 0,void 0,function*(){const{utils:{IN_MINI_APP:n,IN_BROWSER:g,IN_UNI_NATIVE_APP:u,isArray:E},ssoLog:m}=this._core,D=Date.now();let M="";return g&&(M=yield this._generateHashFileNameInWeb(s)),n&&(E(s.tempFiles)&&(s=s.tempFiles[0]),u||(M=yield this._generateFileNameInMiniProgram(s)),u&&(M=yield this._generateFileNameInUNINativeApp(s))),m.info("_generateHashFileName",`hashFileName:${M} costTime:${Date.now()-D}`),M})}_generateHashFileNameInWeb(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=this._core;let u="";try{u=yield new Promise((E,m)=>{const D=File.prototype.slice||File.prototype.mozSlice||File.prototype.webkitSlice;D||(n.warn("_generateHashFileNameInWeb","Browser does not support file slicing"),E(""));const M=10485760,T=Math.ceil(s.size/M);let P=0;const W=new fC.ArrayBuffer,iA=new FileReader,EA=setTimeout(()=>{iA.abort(),n.warn("_generateHashFileNameInWeb","File hash generation timeout"),E("")},2e3);function RA(){const kA=P*M,xA=kA+M>=s.size?s.size:kA+M;iA.readAsArrayBuffer(D.call(s,kA,xA))}iA.onload=kA=>{n.debug("_generateHashFileNameInWeb",`read chunk nr ${P+1} of ${T}`),W.append(kA.target.result),P++,P{clearTimeout(EA),m(kA)},RA()})}catch(E){n.warn("_generateHashFileNameInWeb",g(E))}return u})}_generateFileNameInMiniProgram(s){return pA(this,void 0,void 0,function*(){const{utils:{MINI_APP_NAMESPACE:n,safeStringify:g,isEmpty:u},ssoLog:E}=this._core;let m="";if(u(s.url))return E.warn("_generateFileNameInMiniProgram","file.url is empty"),m;if(typeof n?.getFileSystemManager!="function")return E.warn("_generateFileNameInUNINativeApp","getFileSystemManager is not a function"),m;try{m=yield new Promise((D,M)=>{n.getFileSystemManager().getFileInfo({filePath:s.url,success:T=>{D(T.digest)},fail:T=>{M(T)}})})}catch(D){E.warn("_generateFileNameInMiniProgram",g(D))}return m})}_generateFileNameInUNINativeApp(s){return pA(this,void 0,void 0,function*(){var n;const{utils:{safeStringify:g,isEmpty:u},ssoLog:E}=this._core;let m="";if(u(s.url))return E.warn("_generateFileNameInUNINativeApp","file.url is empty"),m;if(typeof((n=plus==null?void 0:plus.io)===null||n===void 0?void 0:n.getFileInfo)!="function")return E.warn("_generateFileNameInUNINativeApp","plus.io.getFileInfo is not a function"),m;try{m=yield new Promise((D,M)=>{plus.io.getFileInfo({filePath:s.url,success:T=>{D(T.digest)},fail:T=>{M(T)}})})}catch(D){E.warn("_generateFileNameInMiniProgram",g(D))}return m})}_handleUploadProgress(s,n){if(typeof n.onProgress=="function")try{n.onProgress(s.percent)}catch(g){throw console.warn("Upload progress callback error:",g),g}}_fetchCosSignatureUrl(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=this._core,u=Ot.isSimpleCos(),E=this._prepareCosRequestData(s),m=u?"im_cos_msg.simple_sig":"im_cos_msg.pre_sig";try{const D=yield function(T,P,W){return pA(this,void 0,void 0,function*(){try{const{helper:iA,channel:EA}=W,RA=iA.generateCosSpecifiedData({servcmd:T,data:P}),kA=`${RA.head.seq}${T}`;return yield EA.sendPacket(RA,{requestId:kA})}catch(iA){throw console.warn("getCosSig error:",iA),iA}})}(m,E,this._core);this.fetchCosTryCount=0;const M=this._processResponse(D);return n.debug("_fetchCosSignatureUrl",` ok. isSimpleCos:${u} data:${g(M)}`),M||{}}catch(D){if(this.fetchCosTryCount<1)return this.fetchCosTryCount++,this._fetchCosSignatureUrl(s);throw this.fetchCosTryCount=0,D}})}_processResponse(s){var n;const g=Ot.isSimpleCos(),u=g?(n=s?.rpt_pre_sig)===null||n===void 0?void 0:n[0]:s;if(!u)return{};if(g){const{str_final_ip:W,rpt_pre_sig:iA,uint32_file_id:EA,uint32_exist_flag:RA,str_download_url:kA,str_upload_url:xA,str_snapshot_url:LA,str_file_key:SA}=u;return{uploadIP:W,preSig:iA,fileID:EA,existFlag:RA,downloadUrl:kA,uploadUrl:xA,requestSnapshotUrl:LA,fileKey:SA}}const{upload_url:E,download_url:m,snapshot_url:D,thumb_url:M,large_url:T,file_key:P}=u;return{uploadUrl:E,downloadUrl:m,requestSnapshotUrl:D,thumbUrl:M,largeUrl:T,fileKey:P}}_prepareCosRequestData(s){return Ot.isSimpleCos()?{uint32_upload_method:s.uploadMethod,uint32_platform:Ot.getPlatform(),uint32_sdkappid:Ot.getSDKAppID(),str_user_id:s.userID,uint32_scene:s.conversationType,rpt_upload_object:[{uint32_file_id:1,uint32_file_type:s.fileType,str_file_name:s.fileName}]}:{file_type:s.fileType,file_name:s.fileName,upload_method:s.uploadMethod,Duration:s.duration}}_uploadFile(s){return pA(this,void 0,void 0,function*(){return new Promise((n,g)=>{this.httpRequest.request(s,(u,E)=>{u&&this.uploadFileTryCount=3e4}_syncSystemClock(s){var n,g,u;const E=((n=s.headers)===null||n===void 0?void 0:n.date)||((g=s.headers)===null||g===void 0?void 0:g.Date)||((u=s.error)===null||u===void 0?void 0:u.ServerTime);if(E){const m=Date.now(),D=Date.parse(E);this.systemClockOffset=D-m}}_getRawOrUploadProxyUrl(s){const n=Ot.getFileUploadProxy();let g=s;return n&&(g=s.replace(/^https:\/\/[^/]+/,n)),g}_isC2CConversation(s){return s.slice(0,3)==="C2C"}};const L=2108,oA=2251,G=2252,x=2253,tA=["jpg","jpeg","gif","png","bmp","image","webp"],uA={JPG:1,JPEG:1,GIF:2,PNG:3,BMP:4,UNKNOWN:255},wA=1,$A=2;class me{constructor(n,g){this.instanceID=Lr(9999999),this.sizeType=n.type||0,this.type=0,this.size=n.size||0,this.width=n.width||0,this.height=n.height||0,this.imageUrl=Ot.addAuthToUrl(n.imageUrl||n.url||""),this.url=Ot.addAuthToUrl(n.url||g)}setSizeType(n){this.sizeType=n}setType(n){this.type=n}setImageUrl(n){n&&(this.imageUrl=Ot.addAuthToUrl(n))}getImageUrl(){return this.imageUrl}}function p(s){const{originUrl:n,originWidth:g,originHeight:u,min:E=198}=s,m=parseInt(g)||0,D=parseInt(u)||0,M={url:void 0,width:0,height:0};if((m<=D?m:D)<=E)M.url=n,M.width=m,M.height=D;else{D<=m?(M.width=Math.ceil(m*E/D),M.height=E):(M.width=E,M.height=Math.ceil(D*E/m));const T=n&&n.indexOf("?")>-1?`${n}&`:`${n}?`;M.url=E===198?`${T}imageView2/3/w/198/h/198`:`${T}imageView2/3/w/720/h/720`}if(n===void 0){const{url:T}=M;return Do(M,["url"])}return M}class B{constructor(n){this._imageMemoryURL="",this._percent=0,this.type=ic;const{uuid:g,file:u,imageFormat:E,imageInfoArray:m=[],isCustomUpload:D=!1}=n;this._imageMemoryURL=this.createImageDataAsURL(u),this.content={imageFormat:E,uuid:g,imageInfoArray:[]},this[Jr]=D,this.initImageInfoArray(m),this.autoFixUrl()}static parseServerPushElement(n){const{MsgContent:g}=n,{ImageFormat:u,ImageInfoArray:E,UUID:m}=g,D=function(M){return M.map(T=>({size:T.Size,type:T.Type,width:T.Width,height:T.Height,url:T.URL}))}(E);return new B({imageFormat:u,imageInfoArray:D,uuid:m})}createImageDataAsURL(n){let g="";const{IN_MINI_APP:u,IN_RN_APP:E,IN_BROWSER:m}=Ot.getPlatformFlags();return n&&((u||E)&&(g=n.url),m&&(g=window.URL.createObjectURL(n))),g}initImageInfoArray(n=[]){const g={type:0,size:0,width:0,height:0,url:""};for(let u=0;u<3;u++){const E=n[u]||Object.assign({},g),m=new me(E,this._imageMemoryURL);m.setSizeType(u+1),m.setType(u),this.addImageInfo(m)}this.updateAccessSideImageInfoArray()}autoFixUrl(){const n=["http","https"];this.content.imageInfoArray.forEach(g=>{if(!g.url||g.imageUrl==="")return;const[u,...E]=g.imageUrl.split("://"),m=E.join("://");n.includes(u)||g.setImageUrl(`https://${m}`)})}updatePercent(n){this._percent=Math.min(n,1)}updateImageFormat(n){this.content.imageFormat=uA[n.toUpperCase()]||uA.UNKNOWN}addImageInfo(n){this.content.imageInfoArray.length>=3||this.content.imageInfoArray.push(n)}updateImageInfoArray(n){const g=this.content.imageInfoArray.length;let u;for(let E=0;E({InstanceId:g.instanceID,Type:g.sizeType,MsgType:g.type,Size:g.size,Width:g.width,Height:g.height,URL:Ot.removeAuthToUrl(g.imageUrl)}))}}const v=new class{init(s){this.core=s}},N={[iu]:"i",[cl]:"a",[Ba]:"v",[xE]:"f"};let O=null,z=null;function X(s){var n;const{store:g,utils:{isNumber:u,safeStringify:E},ssoLog:m}=v.core;try{const D=((n=g.get("cloudConfig"))===null||n===void 0?void 0:n.upload_size_limit)||"";D!==z&&(z=D,O=JSON.parse(D)||{});const M=O?.[N[s]];if(u(M))return 1024*M*1024}catch(D){m.debug("getCloudControlUploadSizeLimit",E(D))}return null}var rA=new class{constructor(){this._messageOptionsMap=new Map}init(s){var n;this._core=s;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=s;u.registerApi({apiName:"createImageMessage",context:this}),u.registerExperimentalAPI("createImageMessage",this,"createCustomUploadImageMessage"),(n=m?.messageFactory)===null||n===void 0||n.registerElementClass(ic,B),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createImageMessage(s){var n,g,u;try{const E=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.userId,m=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:E})),D=this._processImage(s);s.payload.file=D;const M={imageFormat:uA.UNKNOWN,uuid:Ot.generateUUID(D),file:D,imageInfoArray:[]},T=new B(M);return m.setElement(T),this._messageOptionsMap.set(m.clientSequence,s),m}catch(E){throw E}}createCustomUploadImageMessage(s){var n,g,u,E;const{store:m,utils:{isEmpty:D}}=this._core,M=(n=m.get("login"))===null||n===void 0?void 0:n.userId,T=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:M})),{largeImageUuid:P,largeFileSize:W,largeImageWidth:iA,largeImageHeight:EA,largeImageUrl:RA,originImageUuid:kA,originFileSize:xA,originImageWidth:LA,originImageHeight:SA,originImageUrl:OA,thumbImageUuid:JA,thumbFileSize:ae,thumbImageWidth:ne,thumbImageHeight:_i,thumbImageUrl:Ti}=((E=s?.payload)===null||E===void 0?void 0:E.file)||{};if(D(OA)||D(kA))throw new Error("createImageMessageExperimental originImageUrl or originImageUuid is empty");const Lt=new B({imageFormat:uA.UNKNOWN,uuid:kA,imageInfoArray:[{instanceID:kA,size:xA,width:LA,height:SA,imageUrl:OA,url:OA},{instanceID:P,size:W,width:iA,height:EA,imageUrl:RA,url:RA},{instanceID:JA,size:ae,width:ne,height:_i,imageUrl:Ti,url:Ti}],isCustomUpload:!0});return T.setElement(Lt),this._messageOptionsMap.set(T.clientSequence,s),T._skipUpload=!0,T}upload(s){return pA(this,void 0,void 0,function*(){const n=s.getElements()[0],{file:g}=this._messageOptionsMap.get(s.clientSequence).payload;this._validateBeforeUploadImage(g);const u=yield this._performImageUpload(n,s,g),E=this._generateImageInfo(u);return n.updateImageFormat(u?.fileType),n.updateImageInfoArray(E),this._updateImageType(n.content.imageInfoArray),s})}_performImageUpload(s,n,g){return pA(this,void 0,void 0,function*(){const{to:u}=n,E={uploadFileType:iu,file:g,to:u,message:n,onProgress:M=>{var T,P;s.updatePercent(M),(P=(T=this._messageOptionsMap.get(n.clientSequence))===null||T===void 0?void 0:T.onProgress)===null||P===void 0||P.call(T,M)}},{uploadOptions:m,response:D}=yield q.uploadToCOS(E);return this._parseResponse(m,D)})}_generateImageInfo(s){const{location:n,fileSize:g,width:u,height:E,smallImageUrl:m,smallImageWidth:D,smallImageHeight:M,largeImageUrl:T,largeImageWidth:P,largeImageHeight:W,imageInfoArray:iA}=s,EA=Ot.addAuthToUrl(n),RA={size:g,url:EA,width:u,height:E};return iA?.length>0?this._processImageInfoArray(iA,g):m&&T?[Object.assign({},RA),{largeImageUrl:T,largeImageWidth:P,largeImageHeight:W},{smallImageUrl:m,smallImageWidth:D,smallImageHeight:M}]:[Object.assign({},RA),this._generateThumbInfo(EA,u,E,720),this._generateThumbInfo(EA,u,E,198)]}_generateThumbInfo(s,n,g,u){return p({originUrl:s,originWidth:n,originHeight:g,min:u})}_processImageInfoArray(s,n){let g,u,E;for(const m of s)m.type===1?(u=m,u.size=n):m.type===2?(E=m,E.size=n):(g=m,g.size=n);return[Object.assign({},g),Object.assign({},E),Object.assign({},u)]}_parseResponse(s,n){return pA(this,void 0,void 0,function*(){try{const{thumbUrl:g,largeUrl:u,downloadUrl:E}=s;if(g&&u&&(yield this._getImageInfoByUrl(g,n,"thumb"),yield this._getImageInfoByUrl(u,n,"large")),Ot.isSimpleCos()&&!Ot.isPrivateNetWork()&&(yield this._getImageInfoArray(E,n),n?.uploadIP)){const m=this._extractDomainFromUrl(E);m&&(yield this._getDownloadIP(m,n))}return n}catch(g){throw g}})}_extractDomainFromUrl(s){var n;try{const g=s.match(/:\/\/([^\/]+)/);return g?g[1]:null}catch(g){return(n=this._core)===null||n===void 0||n.ssoLog.warn("_extractDomainFromUrl",`Failed to extract domain from URL:${g.message}`),null}}_getImageInfoByUrl(s,n,g){return pA(this,void 0,void 0,function*(){var u;try{const E=Ot.addAuthToUrl(s),{width:m=0,height:D=0}=yield Ot.probeImageWidthHeight(E);n.width=m,n.height=D,g==="thumb"?(n.smallImageUrl=s,n.smallImageWidth=m,n.smallImageHeight=D):(n.largeImageUrl=s,n.largeImageWidth=m,n.largeImageHeight=D)}catch(E){(u=this._core)===null||u===void 0||u.ssoLog.warn("_getImageInfoByUrl",`Failed to get ${g} image info:${E.message}`)}})}_validateBeforeUploadImage(s){var n;const{ChatError:g}=(n=this._core)===null||n===void 0?void 0:n.helper;if(!s)throw new g({code:oA});this._checkImageType(s),this._checkImageSize(s)}_processImage(s){var n;try{const{IN_MINI_APP:g}=(n=this._core)===null||n===void 0?void 0:n.utils;let{file:u}=s.payload;return u=g?this._processMiniAppImageFile(u):this._processWebImageFile(u),u}catch(g){throw g}}_processMiniAppImageFile(s){gl(s)&&console.warn("FileUnsupportedInMiniApp","createImageMessage");const n=s.tempFiles[0].path||s.tempFiles[0].tempFilePath;return{url:n,name:n.slice(n.lastIndexOf("/")+1),size:s.tempFiles&&s.tempFiles[0].size||1,type:n.slice(n.lastIndexOf(".")+1).toLowerCase()}}_processWebImageFile(s){var n;const{ChatError:g}=(n=this._core)===null||n===void 0?void 0:n.helper,u=Ot.extractFileFromInput(s);if(!u)throw new g({message:"Invalid file. Pass either `e.target` (from file input) or a File object"});return u}_getDownloadIP(s,n){return pA(this,void 0,void 0,function*(){const g=`${ha} getDownloadIP domainName: ${s}`;try{const u=yield function(m,D){return pA(this,void 0,void 0,function*(){try{const{helper:M,channel:T}=D,P="im_cos_msg.get_final_ip",W={str_domain:m},iA=M.generateProtocolData({servcmd:P,data:W}),EA=`${iA.head.seq}${P}`;return yield T.sendPacket(iA,{requestId:EA})}catch(M){throw console.warn("getFinalIP error:",M),M}})}(s,this._core);if(!u||!u.str_final_ip)return;console.log(`${g} ok. downloadIP:${u}`);const E=n.location.split("/");E[0]=u.str_final_ip,n.location=E.join("/")}catch(u){console.warn(u)}})}_getImageInfoArray(s,n){return pA(this,void 0,void 0,function*(){try{const g=yield function(u,E){return pA(this,void 0,void 0,function*(){try{const{helper:m,channel:D}=E,M="im_cos_msg.get_imageinfo",T={str_image_url:u},P=m.generateProtocolData({servcmd:M,data:T}),W=`${P.head.seq}${M}`;return yield D.sendPacket(P,{requestId:W})}catch(m){throw console.warn("getImageInfo error:",m),m}})}(s,this._core);return n.imageInfoArray=this._processImageInfoResponse(g),n}catch(g){throw n.imageInfoArray=void 0,g}})}_processImageInfoResponse(s){if(!s)return[];const{rpt_msg_image_info:n}=s;return n.map(g=>({type:g.uint32_image_type,url:g.str_url,width:g.uint32_width,height:g.uint32_height,imageFormat:g.str_image_format}))}_checkImageType(s){const{utils:n,helper:g}=this._core;let u="";if(n.IN_MINI_APP&&(u=s.url.slice(s.url.lastIndexOf(".")+1)),n.IN_BROWSER&&(u=s.name.slice(s.name.lastIndexOf(".")+1)),tA.indexOf(u.toLowerCase())<0)throw new g.ChatError({code:G})}_checkImageSize(s){const{utils:n,helper:g,store:u}=this._core;let E=0;if(E=(n.IN_MINI_APP,s.size),E===0)throw new g.ChatError({code:L});if(E>=(X(iu)||20971520))throw new g.ChatError({code:x})}_updateImageType(s){s[1].type=$A,s[2].type=wA}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}};const DA=2108,GA=2401,VA=2402,te="2.5.0",Ce="1.18.0";function Ke(s,n){const g=s.split("."),u=n.split("."),E=Math.max(g.length,u.length);for(;g.lengthM)return 1;if(D0;return{isValid:n,error:n?null:{message:"content can not be empty"}}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{uuid:E,downloadFlag:m,fileUrl:D,fileName:M,fileSize:T}=u;return{MsgType:this.type,MsgContent:{Download_Flag:m,Url:Ot.removeAuthToUrl(D),FileName:M,FileSize:T,UUID:E}}}_getFileInfo(n){const{utils:{IN_UNI_NATIVE_APP:g}}=v.core;if(n.fileName&&n.fileSize)return{size:n.fileSize,name:n.fileName};const{file:u}=n;return u?(g&&this._processNativeAppFile(u),{size:u.size,name:u.name}):{size:0,name:""}}_processNativeAppFile(n){if(n.path&&n.path.includes(".")){const g=n.path.slice(n.path.lastIndexOf(".")+1).toLowerCase();n.type=g,n.name||(n.name=`${Lr(999999)}.${g}`)}n.name||(n.type="",n.name=n.path.slice(n.path.lastIndexOf("/")+1).toLowerCase()),n.suffix&&(n.type=n.suffix),n.url||(n.url=n.path)}}ot=Jr;var kt=new class{constructor(){this._messageOptionsMap=new Map}init(s){var n;this._core=s;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=s;u.registerApi({apiName:"createFileMessage",context:this}),u.registerExperimentalAPI("createFileMessage",this,"createCustomUploadFileMessage"),(n=m?.messageFactory)===null||n===void 0||n.registerElementClass(Ya,at),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createFileMessage(s){var n,g,u;try{this._checkVersion();const E=this._processFile(s.payload.file);s.payload.file=E;const m=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.userId,D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:m})),M={uuid:Ot.generateUUID(E),file:E},T=new at(M);return D.setElement(T),this._messageOptionsMap.set(D.clientSequence,s),D}catch(E){throw E}}createCustomUploadFileMessage(s){var n,g,u;try{const{store:E,message:m,utils:{isEmpty:D}}=this._core,M=(n=E.get("login"))===null||n===void 0?void 0:n.userId,{url:T,uuid:P,fileSize:W,fileName:iA=""}=((g=s?.payload)===null||g===void 0?void 0:g.file)||{};if(D(T))throw new Error("url is required");const EA=(u=m.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:M})),RA=new at({url:T,uuid:P,file:{size:W,name:iA},isCustomUpload:!0});return EA.setElement(RA),EA}catch(E){throw E}}upload(s){return pA(this,void 0,void 0,function*(){const{file:n}=this._messageOptionsMap.get(s.clientSequence).payload;this._validateBeforeUploadFile(n);const g=s.getElements()[0],u=yield this._performFileUpload(g,s,n),E=Ot.addAuthToUrl(u?.location);return g.updateFileUrl(E),s})}_validateBeforeUploadFile(s){const{helper:{ChatError:n}}=this._core;if(!s)throw new n({code:GA});const g=X(xE)||104857600;if(s.size>g)throw new n({code:VA});if(s.size===0)throw new n({code:DA})}_performFileUpload(s,n,g){return pA(this,void 0,void 0,function*(){const{to:u}=n,E={uploadFileType:xE,file:g,to:u,message:n,onProgress:D=>{var M,T;s.updatePercent(D),(T=(M=this._messageOptionsMap.get(n.clientSequence))===null||M===void 0?void 0:M.onProgress)===null||T===void 0||T.call(M,D)}},{response:m}=yield q.uploadToCOS(E);return m})}_processFile(s){var n,g;const{IN_BROWSER:u,IN_RN_APP:E,IN_WX_MINI_APP:m,IN_QQ_MINI_APP:D,IN_UNI_NATIVE_APP:M}=(n=this._core)===null||n===void 0?void 0:n.utils,{ChatError:T}=(g=this._core)===null||g===void 0?void 0:g.helper;if(u||M){const P=Ot.extractFileFromInput(s);if(!P)throw new T({message:"Invalid file. Pass either `e.target` (from file input) or a File object"});return P}if(m||D){const{tempFiles:P}=s;return Object.assign(Object.assign({},P[0]),{url:P[0].path})}return E?Object.assign(Object.assign({},s),{url:s.uri}):s}_checkVersion(){var s,n;const{MINI_APP_NAMESPACE:g,IN_MINI_APP:u,IN_WX_MINI_APP:E,IN_QQ_MINI_APP:m,IN_UNI_NATIVE_APP:D}=(s=this._core)===null||s===void 0?void 0:s.utils,{ChatError:M}=(n=this._core)===null||n===void 0?void 0:n.helper;if(u){if(!(E||m||D))throw new M({message:"Unsupported mini app environment"});const T=g.getSystemInfoSync().SDKVersion;if(E&&Ke(T,te)<0)throw new M({message:`WXChooseMessageFile requires SDK version ${te} or higher`});if(m&&Ke(T,Ce)<0)throw new M({message:`QQChooseMessageFile requires SDK version ${Ce} or higher`})}}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}};const Vt=2108,Ui=2351,go=2352,Xi=["mp4","quicktime","mov","video"];var Ei;class Po{constructor(n){this.type=Fl,this.uploadProgress=0,this[Ei]=!1;const g=typeof n?.videoSecond=="number"?n?.videoSecond:0;this[Jr]=n.isCustomUpload||!1,this.content={remoteVideoUrl:Ot.addAuthToUrl(n.remoteVideoUrl||n.videoUrl||""),videoFormat:n.videoFormat,videoSecond:parseInt(g?.toString(),10),videoSize:n.videoSize,videoUrl:Ot.addAuthToUrl(n.videoUrl),videoDownloadFlag:2,videoUUID:n.videoUUID,thumbUUID:n.thumbUUID,thumbFormat:n.thumbFormat,thumbWidth:n.thumbWidth,snapshotWidth:n.thumbWidth,thumbHeight:n.thumbHeight,snapshotHeight:n.thumbHeight,thumbSize:n.thumbSize,snapshotSize:n.thumbSize,thumbDownloadFlag:2,thumbUrl:Ot.addAuthToUrl(n.thumbUrl),snapshotUrl:Ot.addAuthToUrl(n.thumbUrl)}}static parseServerPushElement(n){const{MsgContent:g}=n,{VideoUrl:u,VideoFormat:E,VideoSecond:m,VideoSize:D,VideoDownloadFlag:M,VideoUUID:T,ThumbUUID:P,ThumbFormat:W,ThumbWidth:iA,SnapshotWidth:EA,ThumbHeight:RA,SnapshotHeight:kA,ThumbSize:xA,SnapshotSize:LA,ThumbDownloadFlag:SA,ThumbUrl:OA,SnapshotUrl:JA}=g;return new Po({videoUrl:u,videoFormat:E,videoSecond:m,videoSize:D,videoDownloadFlag:M,videoUUID:T,thumbUUID:P,thumbFormat:W,thumbWidth:iA,snapshotWidth:EA,thumbHeight:RA,snapshotHeight:kA,thumbSize:xA,snapshotSize:LA,thumbDownloadFlag:SA,thumbUrl:OA,snapshotUrl:JA})}updatePercent(n){this.uploadProgress=Math.min(n,1)}updateVideoUrl(n){n&&(this.content.remoteVideoUrl=n)}updateSnapshotInfo(n){const{snapshotUrl:g,snapshotWidth:u,snapshotHeight:E}=n;Ot.isEmpty(g)||(this.content.thumbUrl=this.content.snapshotUrl=g),Ot.isEmpty(u)||(this.content.thumbWidth=this.content.snapshotWidth=Number(u)),Ot.isEmpty(E)||(this.content.thumbHeight=this.content.snapshotHeight=Number(E))}validateBeforeSend(){if(this[Jr])return{isValid:!0};const n=this.content.remoteVideoUrl!=="";return{isValid:n,error:n?null:{message:"content can not be empty"}}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{remoteVideoUrl:E,videoFormat:m,videoSecond:D,videoSize:M,videoDownloadFlag:T,videoUUID:P,thumbUUID:W,thumbFormat:iA,thumbWidth:EA,snapshotWidth:RA,thumbHeight:kA,snapshotHeight:xA,thumbSize:LA,snapshotSize:SA,thumbDownloadFlag:OA,thumbUrl:JA,snapshotUrl:ae}=u;return{MsgType:this.type,MsgContent:{VideoUrl:Ot.removeAuthToUrl(E),VideoFormat:m,VideoSecond:D,VideoSize:M,VideoDownloadFlag:T,VideoUUID:P,ThumbUUID:W,ThumbFormat:iA,ThumbWidth:EA,SnapshotWidth:RA,ThumbHeight:kA,SnapshotHeight:xA,ThumbSize:LA,SnapshotSize:SA,ThumbDownloadFlag:OA,ThumbUrl:Ot.removeAuthToUrl(JA),SnapshotUrl:Ot.removeAuthToUrl(ae)}}}}Ei=Jr;var es,pi=new class{constructor(){this._messageOptionsMap=new Map}init(s){var n;this._core=s;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=s;u.registerApi({apiName:"createVideoMessage",context:this}),u.registerExperimentalAPI("createVideoMessage",this,"createCustomUploadVideoMessage"),(n=m?.messageFactory)===null||n===void 0||n.registerElementClass(Fl,Po),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createVideoMessage(s){var n,g,u;try{const E=this._processVideo(s);s.payload.file=E;const m=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.userId,D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:m})),M={videoFormat:E.videoFile.type,videoSecond:ar(E.videoFile.second,0),videoSize:E.videoFile.size,remoteVideoUrl:"",videoUrl:E.videoFile.url,videoUUID:Ot.generateUUID(E.videoFile),thumbUUID:Ot.generateUUID(E.videoFile,"jpg"),thumbWidth:E.width||200,thumbHeight:E.height||200,thumbUrl:E.thumbUrl,thumbSize:E.thumbSize,thumbFormat:"jpg"},T=new Po(M);return D.setElement(T),this._messageOptionsMap.set(D.clientSequence,s),D}catch(E){throw E}}createCustomUploadVideoMessage(s){var n,g,u;try{const{store:E,message:m}=this._core;this._validateCustomUploadVideoMessage(s);const D=(n=E.get("login"))===null||n===void 0?void 0:n.userId,{videoUrl:M,videoUuid:T,duration:P,snapshotUrl:W,snapshotUuid:iA,videoFileSize:EA,videoType:RA,snapshotWidth:kA,snapshotHeight:xA,snapshotFileSize:LA,snapshotType:SA="jpg"}=((g=s?.payload)===null||g===void 0?void 0:g.file)||{},OA=(u=m.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:D})),JA=new Po({videoFormat:RA,videoSecond:P||0,videoSize:EA,remoteVideoUrl:M,videoUrl:M,videoUUID:T,thumbUUID:iA,thumbWidth:kA||200,thumbHeight:xA||200,thumbUrl:W,thumbSize:LA,thumbFormat:SA,isCustomUpload:!0});return OA.setElement(JA),this._messageOptionsMap.set(OA.clientSequence,s),OA}catch(E){throw E}}upload(s){return pA(this,void 0,void 0,function*(){const n=s.getElements()[0],{file:g}=this._messageOptionsMap.get(s.clientSequence).payload;this._validateBeforeUploadVideo(g);const u=yield this._performVideoUpload(n,s,g),{location:E,snapshotInfo:m}=u,D=Ot.addAuthToUrl(E);return n.updateVideoUrl(D),Ot.isEmpty(m)||n.updateSnapshotInfo(m),s})}_validateBeforeUploadVideo(s){const{helper:{ChatError:n}}=this._core,g=X(Ba)||104857600;if(s.videoFile.size>g)throw new n({code:Ui});if(s.videoFile.size===0)throw new n({code:Vt});if(Xi.indexOf(s.videoFile.type)===-1)throw new n({code:go})}_validateCustomUploadVideoMessage(s){var n;const{utils:{isEmpty:g,isNumber:u}}=this._core,{videoUrl:E,videoUuid:m,duration:D,snapshotUrl:M,snapshotUuid:T}=((n=s?.payload)===null||n===void 0?void 0:n.file)||{};if(g(E)||g(m)||!u(D)||g(M)||g(T))throw new Error("Invalid video message options: missing required fields (videoUrl, videoUuid, duration, snapshotUrl, snapshotUuid)")}_performVideoUpload(s,n,g){return pA(this,void 0,void 0,function*(){const{to:u}=n,E={uploadFileType:Ba,file:g,to:u,message:n,onProgress:M=>{var T,P;s.updatePercent(M),(P=(T=this._messageOptionsMap.get(n.clientSequence))===null||T===void 0?void 0:T.onProgress)===null||P===void 0||P.call(T,M)}},{response:m,uploadOptions:D}=yield q.uploadToCOS(E);return{snapshotInfo:yield this._getSnapshotInfoByUrl(D.requestSnapshotUrl),location:m.location}})}_processVideo(s){var n,g;try{const{ChatError:u}=(n=this._core)===null||n===void 0?void 0:n.helper,{IN_MINI_APP:E,IN_BROWSER:m}=(g=this._core)===null||g===void 0?void 0:g.utils;let{file:D}=s.payload,M={};if(E&&(M=this._processMiniVideoFile(D),D.name=M.name,D.url=M.url,D.type=M.type),m){const T=Ot.extractFileFromInput(D);if(!T)throw new u({message:"Invalid file. Pass either `e.target` (from file input) or a File object"});D=T,M=this._processWebVideoFile(D)}return D.videoFile=M,D.thumbUrl="",D.thumbSize=0,D}catch(u){throw console.warn(`${ha} _processFile error:`,u),u}}_processMiniVideoFile(s){const{utils:{IN_UNI_NATIVE_APP:n},helper:{ChatError:g}}=this._core;if(gl(s))throw new g({message:"FileUnsupportedInMiniApp"});Array.isArray(s.tempFiles)&&(s=s.tempFiles[0]);let u=s.tempFilePath.slice(s.tempFilePath.lastIndexOf(".")+1).toLowerCase();return n&&(u=s.fileType||u),{url:s.tempFilePath,name:s.tempFilePath.slice(s.tempFilePath.lastIndexOf("/")+1),size:s.size||1,second:s.duration||0,type:u}}_processWebVideoFile(s){const{name:n,size:g=1,duration:u=0,type:E}=s,m=E.split("/")[1];return{url:window.URL.createObjectURL(s),name:n,size:g,second:u,type:m}}_getSnapshotInfoByUrl(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n}=this._core;try{n.debug("_getSnapshotInfoByUrl",`${ha} _getSnapshotInfoByUrl url:${s}`);const g={version:1,platform:Ot.getPlatform(),cover_name:Ig(Lr(99999)),snapshot_url:s},u=yield function(T,P){return pA(this,void 0,void 0,function*(){try{const W="im_cos_msg.video_cover",{helper:iA,channel:EA}=P,RA=iA.generateCosSpecifiedData({servcmd:W,data:T}),kA=`${RA.head.seq}${W}`;return yield EA.sendPacket(RA,{requestId:kA})}catch(W){throw console.warn("getSnapshotInfo error:",W),W}})}(g,this._core),{download_url:E}=u||{};if(n.debug("_getSnapshotInfoByUrl",`${ha} _getSnapshotInfoByUrl OK snapshotUrl:${E}`),Ot.isEmpty(E))return{};const m=Ot.addAuthToUrl(E),{width:D=0,height:M=0}=yield Ot.probeImageWidthHeight(m);return{snapshotUrl:m,snapshotWidth:D,snapshotHeight:M}}catch(g){throw g}})}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}};class ji{constructor(n){this.uploadProgress=0,this.type=Fg,this[es]=!1,this[Jr]=n.isCustomUpload||!1,this.content={downloadFlag:2,second:n.second,size:n.size,url:Ot.generateURL(n.url,{needAddAuthToUrl:!this[Jr]}),remoteAudioUrl:Ot.addAuthToUrl(n.url||""),uuid:n.uuid}}static parseServerPushElement(n){const{MsgContent:g}=n,{Url:u,Download_Flag:E,Second:m,Size:D,UUID:M}=g;return new ji({url:u,downloadFlag:E,second:m,size:D,uuid:M})}updatePercent(n){this.uploadProgress=Math.min(n,1)}updateAudioUrl(n){this.content.remoteAudioUrl=n}validateBeforeSend(){if(this[Jr])return{isValid:!0};const n=this.content.remoteAudioUrl!=="";return{isValid:n,error:n?null:{message:"content can not be empty"}}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{uuid:E,downloadFlag:m,remoteAudioUrl:D,size:M,second:T}=u;return{MsgType:this.type,MsgContent:{Url:Ot.removeAuthToUrl(D),Download_Flag:m,Second:T,Size:M,UUID:E}}}}es=Jr;const Ws=2108,Te=2300,Rt=2301;var FA=new class{constructor(){this._messageOptionsMap=new Map}init(s){var n;this._core=s;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=s;u.registerApi({apiName:"createAudioMessage",context:this}),u.registerExperimentalAPI("createAudioMessage",this,"createCustomUploadAudioMessage"),(n=m?.messageFactory)===null||n===void 0||n.registerElementClass(Fg,ji),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createAudioMessage(s){var n,g,u;try{let{file:E}=s.payload;E=this._processAudioFile(s.payload.file),s.payload.file=E;const m=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.userId,D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:m})),M={second:Math.max(1,Math.round((E.duration||E.second)/1e3)),size:E.fileSize||E.size||1,url:E.tempFilePath||E.uri||E.url,uuid:Ot.generateUUID(E)},T=new ji(M);return D.setElement(T),this._messageOptionsMap.set(D.clientSequence,s),D}catch(E){throw E}}createCustomUploadAudioMessage(s){var n,g,u;try{this._validateCustomUploadOptions(s);const{store:E,message:m}=this._core,D=(n=E.get("login"))===null||n===void 0?void 0:n.userId,{url:M,uuid:T,duration:P,fileSize:W}=((g=s?.payload)===null||g===void 0?void 0:g.file)||{},iA=(u=m.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},s),{from:D})),EA=new ji({second:P,size:W||1,url:M,uuid:T,isCustomUpload:!0});return iA.setElement(EA),this._messageOptionsMap.set(iA.clientSequence,s),iA}catch(E){throw E}}upload(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=this._core;n.debug("upload",`${ha} uploadAudio message:${g(s)}`);const{file:u}=this._messageOptionsMap.get(s.clientSequence).payload;this._validateBeforeUploadAudio(u);const E=s.getElements()[0],m=yield this._performAudioUpload(E,s,u),D=Ot.addAuthToUrl(m?.location);return E.updateAudioUrl(D),s})}_validateBeforeUploadAudio(s){const{helper:{ChatError:n},store:g}=this._core;if(!s)throw new n({code:Te});const u=X(cl)||20971520;if(s.size>u)throw new n({code:Rt});if(s.size===0)throw new n({code:Ws})}_performAudioUpload(s,n,g){return pA(this,void 0,void 0,function*(){const{to:u}=n,E={uploadFileType:cl,file:g,to:u,message:n,onProgress:D=>{var M,T;s.updatePercent(D),(T=(M=this._messageOptionsMap.get(n.clientSequence))===null||M===void 0?void 0:M.onProgress)===null||T===void 0||T.call(M,D)}},{response:m}=yield q.uploadToCOS(E);return m})}_processAudioFile(s){var n;const{IN_MINI_APP:g,IN_BROWSER:u}=(n=this._core)===null||n===void 0?void 0:n.utils;return g?this._processMiniFile(s):u?this._processWebFile(s):void 0}_processMiniFile(s){return{url:s.tempFilePath,name:s.tempFilePath.slice(s.tempFilePath.lastIndexOf("/")+1),size:s.fileSize,second:s.duration,type:s.tempFilePath.slice(s.tempFilePath.lastIndexOf(".")+1).toLowerCase()}}_processWebFile(s){if(s.tempFilePath||s.uri)return s;const n=URL.createObjectURL(s);return s.tempFilePath=n,s}_validateCustomUploadOptions(s){var n;const{utils:{isEmpty:g}}=this._core,{url:u,uuid:E,duration:m}=((n=s?.payload)===null||n===void 0?void 0:n.file)||{};if(g(u)||g(E)||g(m))throw new Error("Invalid audio message options")}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}};const Zt={to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1},cloudCustomData:{required:!1,rules:["string"],allowEmpty:!1},priority:{required:!1,rules:["string"],allowEmpty:!1},customModerationConfigurationID:{required:!1,rules:["string"],allowEmpty:!1},onProgress:{required:!1,rules:["function"],allowEmpty:!1}},En={createImageMessage:Zt,createAudioMessage:Zt,createVideoMessage:Zt,createFileMessage:Zt},$t={createImageMessage:!0,createAudioMessage:!0,createVideoMessage:!0,createFileMessage:!0},us={[ic]:rA,[Ya]:kt,[Fl]:pi,[Fg]:FA};var vi=new class{constructor(){this.name="RichMediaMessage"}install(s){this._core=s;const{constants:{OuterConstant:{MSG_AUDIO:n,MSG_FILE:g,MSG_IMAGE:u,MSG_VIDEO:E}}}=s;v.init(s),rA.init(s),kt.init(s),pi.init(s),FA.init(s),q.init(s),Ot.init(s),s.helper.registerApi({apiName:"sendMessage",context:this,matcher:m=>[n,g,u,E].includes(m[0].type)}),s.helper.registerValidateConfig({auth:$t,params:En})}sendMessage(s,n){return pA(this,void 0,void 0,function*(){var g,u,E;try{return this._isCustomUpload(s)||(yield this._upload(s)),yield(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageSender)===null||E===void 0?void 0:E.sendMessage(s,n)}catch(m){throw m}})}_upload(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=this._core;if(n.debug("_upload",` uploadFile message:${g(s)}`),s._relayFlag!==!0)try{const u=us[s.type];u&&(yield u.upload(s),n.info("_upload",` type:${s.type}`))}catch(u){throw s.status=ou.FAIL,u instanceof Error&&(u.data={message:s}),this._core.message.messageDataHandler.storeConversationMessage(s),u}})}_isCustomUpload(s){var n,g;return((g=(n=s._elements)===null||n===void 0?void 0:n[0])===null||g===void 0?void 0:g[Jr])===!0}};const ho=new class{init(s){this.core=s}};class Ct{constructor(n){this.conversationID=n.conversationID||"",this.unreadCount=n.unreadCount||0,this.type=n.type||"",this.lastMessage=ho.core.common.buildLastMessage(n.lastMessage),this.peerReadTime=n.peerReadTime||0,this.groupAtInfoList=[],this.remark=n.remark||"",this.isPinned=n.isPinned||!1,this.messageRemindType=n.messageRemindType,this.markList=n.markList||[],this.customData=n.customData||"",this.conversationGroupList=n.conversationGroupList||[],this.draftText=n.draftText||"",this.userProfile=n.userProfile,this.groupProfile=n.groupProfile,this.subType=n.subType||"",this._isInfoCompleted=!1,this._init()}_init(){var n;const{core:{OuterConstant:g,utils:{isUndefined:u}}}=ho;u(this.userProfile)&&this.type===g.CONV_C2C?this.userProfile={userID:this.conversationID.replace(g.CONV_C2C,"")}:this.type===g.CONV_GROUP&&(!this.subType&&(!((n=this.groupProfile)===null||n===void 0)&&n.type)&&(this.subType=this.groupProfile.type),u(this.groupProfile)&&(this.groupProfile={groupID:this.conversationID.replace(g.CONV_GROUP,""),selfInfo:{},lastMessage:{},type:this.subType}))}updateUnreadCount(n){var g;const{core:{OuterConstant:u,utils:{isUndefined:E},store:m}}=ho,{nextUnreadCount:D,isFromGetConversations:M,isUnreadC2CMessage:T}=n;if(E(D))return;if(this.subType===u.GRP_AVCHATROOM)return void(this.unreadCount=0);if(M&&this.type===u.CONV_GROUP)return void(this.unreadCount=D);if(T&&this.type===u.CONV_C2C)return void(this.unreadCount=D);const P=((g=m.get("cloudConfig"))===null||g===void 0?void 0:g.support_unread_count_for_meeting)==="1";this.subType!==u.GRP_MEETING||P?this.unreadCount+=D:this.unreadCount=0}updateLastMessage(n){this.lastMessage=ho.core.common.buildLastMessage(n)}reduceUnreadCount(){return this.unreadCount>=1&&(this.unreadCount-=1,!0)}isLastMessageRevoked(n){const{core:{OuterConstant:g}}=ho,{sequence:u,time:E}=n;return this.type===g.CONV_C2C&&u===this.lastMessage.lastSequence&&E===this.lastMessage.lastTime||this.type===g.CONV_GROUP&&u===this.lastMessage.lastSequence}setLastMessageRevoked(n){this.lastMessage.isRevoked=n}setLastMessageRevoker(n){this.lastMessage.revoker=n}setDraftText(n){this.draftText=n}updateGroupAtInfoList(n){const{core:{common:{updateGroupAtInfo:g}}}=ho;g(n,this.groupAtInfoList)}clearGroupAtInfoList(){this.groupAtInfoList.length=0}getProfileCompleted(){return this._isInfoCompleted}setProfileCompleted(){this._isInfoCompleted=!0}}const Bt=s=>{const{core:{OuterConstant:n,utils:{isString:g}}}=ho;return g(s)&&s.slice(0,3)===n.CONV_C2C},ug=s=>{const{core:{OuterConstant:n,utils:{isString:g}}}=ho;return g(s)&&s.slice(0,5)===n.CONV_GROUP},ks=s=>{const{core:{OuterConstant:n,utils:{isString:g}}}=ho;return g(s)&&s===n.CONV_SYSTEM};function Wi(s){const{OuterConstant:n}=ho.core;let g="";return s===0?g=n.MSG_REMIND_ACPT_AND_NOTE:s===1?g=n.MSG_REMIND_DISCARD:s===2?g=n.MSG_REMIND_ACPT_NOT_NOTE:s===3&&(g=n.NOT_RECEIVE_OFFLINE_PUSH_EXCEPT_AT),g}function Hr(s){const{OuterConstant:n}=ho.core;let g;return s.startsWith(n.CONV_C2C)&&(g=s.replace(n.CONV_C2C,"")),g==="@TLS#ERROR"||g==="@TLS#NOT_FOUND"}function oc(s,n){const{helper:g}=ho.core,u=new g.ChatError({functionName:s,code:n?.errorCode||n?.code,message:n?.errorInfo||n?.message});throw console.error(`${s} fail:`,u),u}var is,ga;(function(s){s[s.OFF=0]="OFF",s[s.ON=1]="ON"})(is||(is={})),function(s){s[s.ONLY_CONVERSATIONID=1]="ONLY_CONVERSATIONID"}(ga||(ga={}));var Qa;(function(s){s[s.CONV_NOT_FOUND=2500]="CONV_NOT_FOUND",s[s.USER_OR_GRP_NOT_FOUND=2501]="USER_OR_GRP_NOT_FOUND",s[s.CONV_UN_RECORDED_TYPE=2502]="CONV_UN_RECORDED_TYPE"})(Qa||(Qa={}));const ea=0,H=1;var BA=new class{constructor(){this._name="GetC2CMessageRemindType"}init(s){this._core=s}get(s){return pA(this,void 0,void 0,function*(){try{const{common:n}=this._core,g=yield function(E,m){return pA(this,void 0,void 0,function*(){const{toAccount:D,userIDList:M}=E,T={To_Account:D,Peer_Account:M};return m.common.buildAndSendPacket({servcmd:"openim.get_c2c_peer_mute_notifications",data:T})})}({toAccount:n.getCurrentUserID(),userIDList:s},this._core),{MuteNotificationsList:u=[]}=g||{};u.forEach(E=>{const{Peer_Account:m,MuteNotifications:D}=E,M=`${this._core.OuterConstant.CONV_C2C}${m}`,T=Wi(D);NA.patchMessageRemindType([M],T)})}catch(n){console.error(`${this._name}.get fail:`,n)}})}},yA=new class{constructor(){this._name="GetGroupMessageRemindType"}init(s){this._core=s}get(s){return pA(this,void 0,void 0,function*(){if(s.length!==0)try{const n=yield function(u,E){return pA(this,void 0,void 0,function*(){const{groupIDList:m,responseFilter:D}=u,M={GroupIdList:m,ResponseFilter:D};return E.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_self_member_info",data:M})})}({groupIDList:s,responseFilter:{MemberInfoFilter:["MsgFlag"]}},this._core),{GroupInfo:g=[]}=n||{};g.forEach(u=>{var E;const{GroupId:m,MemberList:D}=u,M=((E=D[0])===null||E===void 0?void 0:E.MsgFlag)||"",T=`${this._core.OuterConstant.CONV_GROUP}${m}`;NA.patchMessageRemindType([T],M)})}catch(n){console.error(`${this._name}.get fail:`,n)}})}},NA=new class{constructor(){this._name="ConversationDataHandler",this._totalUnreadCount=0,this._groupAtTipsList=[]}init(s){this._core=s;const{helper:n,notificationCenter:g,appStore:{conversationStore:u},constants:{WORKFLOW_NAME:E,WORKFLOW_STEP:m},InnerEvent:{SYNC_CONVERSATION_LIST:D,MESSAGE_PUSH:M,NEW_MESSAGE:T,MESSAGE_DELETED:P,MESSAGE_REVOKED:W,MESSAGE_MODIFIED:iA,CONVERSATION_UPDATED:EA,LOGOUT:RA,DESTROY:kA},InnerEventSubType:{C2C_MESSAGE_PEER_READ:xA}}=s;this._conversationStore=u,n.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_LOGIN,m.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,this._handleUnreadSyncFinished,this),n.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_LOGIN,m.CONVERSATION_UPDATE_AFTER_GROUP_LIST_SYNC_FINISHED,this._handleGroupListSyncFinished,this),n.registerWorkflowStep(E.RECEIVE_C2C_NEW_MESSAGE,m.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,this._handleNewMessage,this),n.registerWorkflowStep(E.RECEIVE_C2C_NEW_MESSAGE,m.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,this._handleUnreadSyncFinished,this),n.registerWorkflowStep(E.RECEIVE_GROUP_NEW_MESSAGE,m.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,this._handleNewMessage,this),n.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_RE_ONLINE,m.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,this._handleUnreadSyncFinished,this),n.registerWorkflowStep(E.RECEIVE_GROUP_TIPS_NOTIFICATION,m.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,this._handleNewMessage,this);const{InnerEventSubType:{GROUP_AT_TIPS:LA}}=g;g.subscribeInnerEvent(D,this._handleConversationSynced,this),g.subscribeInnerEvent(T,this._handleNewMessage,this),g.subscribeInnerEvent(M,LA,this._handleNewGroupAtTips,this),g.subscribeInnerEvent(P,this._handleMessageDeleted,this),g.subscribeInnerEvent(W,this._handleMessageRevoked,this),g.subscribeInnerEvent(iA,this._handleMessageModified,this),g.subscribeInnerEvent(EA,this._handleConversationUpdated,this),g.subscribeInnerEvent(M,xA,this._handleMessageRead,this),g.subscribeInnerEvent(RA,this._reset,this),g.subscribeInnerEvent(kA,this._dispose,this),s.ssoLog.debug(`${this._name}.init`)}_handleConversationSynced(s){this.updateLocalConversationList({conversationUpdateFieldList:s.conversationUpdateFieldList||[],isFromGetConversations:!0,updateUnreadCount:!0}),this.emitConversationListUpdate()}_handleUnreadSyncFinished(s){const{constants:{WORKFLOW_STEP:n}}=this._core,{conversationUpdateFieldList:g=[],groupTipList:u=[],isUnreadC2CMessage:E}=s.result[n.UNREAD_MESSAGE_SYNC]||{};let m=!1;g.forEach(D=>{const{conversationID:M,unreadCount:T}=D,P=this.getLocalConversation(M);P&&P.unreadCount!==T&&(P.updateUnreadCount({nextUnreadCount:T,isUnreadC2CMessage:E}),m=!0)}),m&&this.emitConversationListUpdate(),this._handleGroupAtTipsSynced(u)}_handleGroupAtTipsSynced(s){var n;for(let g=0;g0&&this._handleNewGroupAtTips({GroupTips:M._groupAtInfoList}),m=!0}m&&this.emitConversationListUpdate()}_handleNewMessage(s){const{conversationUpdateFieldList:n=[],isInstantMessage:g=!0,isUnreadC2CMessage:u=!1,updateUnreadCount:E=!0}=s.result||{};if(n.length===0)return;const{common:{isTopic:m}}=this._core;m(n[0].conversationID)||(this.updateLocalConversationList({conversationUpdateFieldList:n,isInstantMessage:g,isUnreadC2CMessage:u,isFromGetConversations:!1,updateUnreadCount:E}),n.filter(D=>this._isConversationNeedShow(D.conversationID)).length>0&&this.emitConversationListUpdate())}_handleNewGroupAtTips(s){const{GroupTips:n=[]}=s;n.forEach(g=>{const{GroupAtTips:u,MsgBody:E,MsgRandom:m,ClientSeq:D}=g;let M={};u?M=this._convertGroupAtTipsKey(u):E?M=Object.assign({},this._convertGroupAtTipsKey(E)):g.groupAtType&&(M=Object.assign({},g)),M.__random=m,M.__sequence=D,this._groupAtTipsList.push(M)}),console.log(`${this._name}._handleNewGroupAtTips groupAtTipsList: ${JSON.stringify(this._groupAtTipsList)}`),this._updateGroupAtInfoList()}_convertGroupAtTipsKey(s){const{From_Account:n,GroupId:g,MsgSeq:u,GroupAtType:E}=s;return{from:n,groupID:g,sequence:u,groupAtType:E}}_updateGroupAtInfoList(){if(this._groupAtTipsList.length===0)return;const{common:s,OuterConstant:n}=this._core,g=s.getCurrentUserID();let u=!1;this._groupAtTipsList.forEach(E=>{const{groupID:m,from:D}=E;if(D!==g){const M=this.getLocalConversation(`${n.CONV_GROUP}${m}`);M&&(M.updateGroupAtInfoList(E),u=!0)}}),u&&this.emitConversationListUpdate(),this._groupAtTipsList.length=0}_handleMessageDeleted(s){var n,g;console.log(`${this._name}._handleMessageDeleted, conversationID:`,s);const{message:{messageDataHandler:u},OuterConstant:E}=this._core,m=u?.getLocalMessageList(s)||[];let D={};for(let P=(m.length||0)-1;P>=0;P--)if(!m[P].isDeleted&&m[P]._isExcludedFromLastMessage!==!0){D=m[P];break}const M=this.getLocalConversation(s);if(!M)return;let T=!1;M.lastMessage.lastSequence===D.sequence&&M.lastMessage.lastTime===D.time||(!((g=(n=this._core)===null||n===void 0?void 0:n.helper)===null||g===void 0)&&g.isEmpty(D)&&(D=void 0),M.updateLastMessage(D),T=!0),s.startsWith(E.CONV_C2C)&&this.updateUnreadCount(s),T&&(this.emitConversationListUpdate(),console.log(`${this._name}._handleMessageDeleted. update conversationID:${s} with lastMessage:`,M.lastMessage))}_handleMessageRevoked(s){const{messageList:n=[],updateUnreadCount:g=!0}=s;if(console.log(`${this._name}._handleMessageRevoked messageList:${n.length}`),n.length===0)return;let u=null,E=!1;n.forEach(m=>{u=this.getLocalConversation(m.conversationID),u&&(g&&u.reduceUnreadCount()&&(E=!0),u.isLastMessageRevoked({sequence:m.sequence,time:m.time})&&(u.setLastMessageRevoked(!0),u.setLastMessageRevoker(m.revoker),E=!0))}),E&&this.emitConversationListUpdate()}_handleMessageModified(s){const{utils:{isEmpty:n},common:{getMessagePreviewText:g},ssoLog:u}=this._core;u.debug(`${this._name}._handleMessageModified`,JSON.stringify(s));const{conversationID:E,messageList:m}=s,D=this.getLocalConversation(E);if(n(D))return;const{lastMessage:M}=D;if(M){const T=m?.[0]||{};M.lastTime===T.time&&M.lastSequence===T.sequence&&M.version!==T.version&&(M.type=T.type,M.payload=T.payload,M.messageForShow=g(T.type,T.payload),M.cloudCustomData=T.cloudCustomData,M.version=T.version,this.emitConversationListUpdate(),console.log(`${this._name} conversationID:${E} lastMessage updated`))}}_handleConversationUpdated(s){this.emitConversationListUpdate(s?.needSort)}updateLocalConversationList(s){const{isFromGetConversations:n}=s,{newConversationList:g}=this._getTmpConversationListMapping(s);this._sortConversationList(),n||this._updateNewConversationProfile(g),this._core.ssoLog.debug("updateLocalConversationList",` newConversationList: ${g.length}`)}_getTmpConversationListMapping(s){const{OuterConstant:n}=this._core,{conversationUpdateFieldList:g,isFromGetConversations:u,isInstantMessage:E,isUnreadC2CMessage:m=!1,updateUnreadCount:D}=s,M=[],T=g?.length;for(let P=0;P{M[1].isPinned===!0?s(M[1].lastMessage.lastTime)?u.push(M):g.push(M):s(M[1].lastMessage.lastTime)?m.push(M):E.push(M)});const D=g.sort((M,T)=>T[1].lastMessage.lastTime-M[1].lastMessage.lastTime).concat(u).concat(E.sort((M,T)=>T[1].lastMessage.lastTime-M[1].lastMessage.lastTime)).concat(m);this._updateConversationMapFromList(D)}_updateNewConversationProfile(s){if(s.length===0)return;const n=[],g=[],{OuterConstant:{CONV_GROUP:u,CONV_C2C:E}}=this._core;s.forEach(m=>{const{conversationID:D,type:M}=m;if(M===E){const T=D.replace(E,"");n.push(T)}else if(M===u){const T=D.replace(u,"");g.push(T)}}),n.length>0&&this._updateC2CConversation(n),g.length>0&&this._updateGroupConversation(g)}_updateC2CConversation(s){var n;const{OuterConstant:{CONV_C2C:g},appStore:{userStore:u},user:E}=this._core;let m=!1;(n=E.userProfile)===null||n===void 0||n.getUserProfile({userIDList:s}).then(D=>{(D?.data||[]).forEach(M=>{var T;const{userID:P}=M,W=this.getLocalConversation(`${g}${P}`);if(W){const iA=((T=u.getFriend(P))===null||T===void 0?void 0:T.remark)||"";W.remark=iA,W.userProfile=M,m=!0}}),m&&this.emitConversationListUpdate()}).catch(D=>{}),BA.get(s)}_updateGroupConversation(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:{CONV_GROUP:n},appStore:{groupStore:g},utils:{safeStringify:u},ssoLog:E,apiMap:{getGroupProfile:m}}=this._core;let D=!1;try{yield Promise.all(s.map(M=>pA(this,void 0,void 0,function*(){const T=g.getGroup(M),P=this.getLocalConversation(`${n}${M}`);T&&P&&(P.groupProfile=T,D=!0),P&&!P.getProfileCompleted()&&typeof m=="function"&&(yield m({groupID:M}))}))),yA.get(s),D&&this.emitConversationListUpdate()}catch(M){E.debug("_updateGroupConversation",u(M))}})}_handleMessageRead(s){const{OuterConstant:{CONV_C2C:n}}=this._core,{C2cNotifyMsgArray:g=[]}=s||{};g.forEach(u=>{const{To_Account:E,UinPairReadArray:m=[]}=u?.C2cReadedReceipt||{};m?.forEach(D=>{const{LastReadTime:M}=D,T=`${n}${E}`;this._updateConversationReadInfo({conversationID:T,peerReadTime:M}),this._updateMessageListPeerRead({conversationID:T,peerReadTime:M})})})}_updateConversationReadInfo(s){const{appStore:n,utils:{isEmpty:g},common:{getCurrentUserID:u}}=this._core,{conversationID:E,peerReadTime:m}=s,D=n.conversationStore.getConversationMap();if(D.has(E)){const M=D.get(E);M.peerReadTime=m;const T=M?.lastMessage;g(T)||T.fromAccount===u()&&T.lastTime<=m&&!T.isPeerRead&&(T.isPeerRead=!0,n.conversationStore.updateConversation(E,{lastMessage:T}))}}_updateMessageListPeerRead(s){const{notificationCenter:n,OuterEvent:g,message:u}=this._core,{conversationID:E,peerReadTime:m}=s,D=u.messageDataHandler.getLocalMessageList(E),M=u.messageDataHandler.getSparseMessageList(E),T=[];D.forEach(P=>{P.time<=m&&!P.isPeerRead&&P.flow==="out"&&(P.isPeerRead=!0,T.push(P))}),M.forEach(P=>{P.time<=m&&!P.isPeerRead&&P.flow==="out"&&(P.isPeerRead=!0,T.push(P))}),n.emitOuterEvent(g.MESSAGE_READ_BY_PEER,{name:g.MESSAGE_READ_BY_PEER,data:T})}_isConversationNeedShow(s){var n,g;const{OuterConstant:{CONV_GROUP:u,GRP_ROOM:E,GRP_LIVE:m},utils:{isUndefined:D}}=this._core,M=this.getLocalConversation(s);if(D(M))return!0;const T=M.type===u&&((n=M.groupProfile)===null||n===void 0?void 0:n.type)===E,P=M.type===u&&((g=M.groupProfile)===null||g===void 0?void 0:g.type)===m;return!(T||P)}updateUnreadCount(s,n=!0){var g,u;let E=!1;const m=this.getLocalConversation(s),D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageDataHandler)===null||u===void 0?void 0:u.getLocalMessageList(s);if(!m)return E;const M=m.unreadCount,T=D?.filter(P=>!P.isRead&&!P._onlineOnlyFlag&&!P.isDeleted).length;return console.log(`${this._name}._updateUnreadCount conversationID:${s} currentUnreadCount:${M} newUnreadCount:${T}`),M!==T&&(m.unreadCount=T,E=!0,n===!0&&this.emitConversationListUpdate()),E}emitConversationListUpdate(s=!1){var n,g;s&&this._sortConversationList();const{OuterEvent:{CONVERSATION_LIST_UPDATED:u},conversation:E}=this._core,m=this.getLocalConversationList();this._emitEvent({name:u,data:m,isSyncCompleted:(g=(n=E?.syncConversationHandler)===null||n===void 0?void 0:n.isSyncCompleted)===null||g===void 0?void 0:g.call(n)}),this._emitTotalUnreadCountUpdate()}_emitTotalUnreadCountUpdate(){var s;const n=this.getTotalUnreadMessageCount();this._totalUnreadCount!==n&&(this._core.ssoLog.debug("_emitTotalUnreadCountUpdate",` from ${this._totalUnreadCount} to ${n}`),this._totalUnreadCount=n,this._emitEvent({name:(s=this._core)===null||s===void 0?void 0:s.OuterEvent.TOTAL_UNREAD_MESSAGE_COUNT_UPDATED,data:n}))}_emitEvent(s){var n;(n=this._core)===null||n===void 0||n.notificationCenter.emitOuterEvent(s.name,s)}getTotalUnreadMessageCount(){const{OuterConstant:s,utils:{isEmpty:n}}=this._core,g=this.getLocalConversationList();let u=0;return g.forEach(E=>{E.type!==s.CONV_SYSTEM&&(n(E.messageRemindType)||E.messageRemindType===s.MSG_REMIND_ACPT_AND_NOTE)&&(u+=E.unreadCount)}),u}getLocalConversationList(){return[...this._conversationStore.getConversationMap().values()].filter(s=>this._isConversationNeedShow(s.conversationID))}hasLocalConversation(s){return this._conversationStore.getConversationMap().has(s)}getLocalConversation(s){return this._conversationStore.getConversationMap().get(s)}setLocalConversation(s,n){return this._conversationStore.getConversationMap().set(s,n)}deleteLocalConversation(s){this._conversationStore.getConversationMap().delete(s)}_updateConversationMapFromList(s){this._clearConversationMap();for(const[n,g]of s)this.setLocalConversation(n,g)}_clearConversationMap(){this._conversationStore.getConversationMap().clear()}patchMessageRemindType(s,n){let g=!1;s.forEach(u=>{const E=this.getLocalConversation(u);E?.messageRemindType!==n&&(E.messageRemindType=n,g=!0)}),console.log(`${this._name}.patchMessageRemindType conversationIDList:${s} messageRemindType:${n} hasUpdated:${g}`),g&&this.emitConversationListUpdate()}markMessageAsRead(s){const{message:{messageDataHandler:n}}=this._core,{conversationID:g,lastReadTime:u=0,lastReadSequence:E=0}=s,m=n?.getLocalMessageList(g);if(m.length===0)return;const{length:D}=m;for(let M=D-1;M>=0;M--){const T=m[M],P=u&&T.time>u,W=E&&T.sequence>E;if(!P&&!W){if(T.flow==="in"&&T.isRead)break;T.setIsRead(!0)}}}appendToPinnedConversation(s){const n=[...this._conversationStore.getConversationMap().entries()],g=n.findIndex(u=>u[1].isPinned===!1);n.splice(g,0,[s.conversationID,s]),this._updateConversationMapFromList(n),this.emitConversationListUpdate()}_reset(){this._clearConversationMap(),this._totalUnreadCount=0,this._groupAtTipsList=[]}_dispose(){const{notificationCenter:s,InnerEvent:{NEW_MESSAGE:n,MESSAGE_DELETED:g,MESSAGE_REVOKED:u,MESSAGE_MODIFIED:E,CONVERSATION_UPDATED:m,LOGOUT:D,DESTROY:M,SYNC_CONVERSATION_LIST:T}}=this._core,{InnerEventSubType:{GROUP_AT_TIPS:P}}=s;s.unSubscribeInnerEvent(n,this._handleNewMessage,this),s.unSubscribeInnerEvent(n,P,this._handleNewGroupAtTips,this),s.unSubscribeInnerEvent(g,this._handleMessageDeleted,this),s.unSubscribeInnerEvent(u,this._handleMessageRevoked,this),s.unSubscribeInnerEvent(E,this._handleMessageModified,this),s.unSubscribeInnerEvent(m,this._handleConversationUpdated,this),s.unSubscribeInnerEvent(T,this._handleConversationSynced,this),s.unSubscribeInnerEvent(D,this._reset,this),s.unSubscribeInnerEvent(M,this._dispose,this)}},zA=new class{constructor(){this._name="GetConversationList"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"getConversationList",context:this})}getConversationList(s){return pA(this,void 0,void 0,function*(){return{code:0,data:{conversationList:this._getConversationList(s),isSyncCompleted:this._core.conversation.syncConversationHandler.isSyncCompleted()}}})}_getConversationList(s){const{utils:{isUndefined:n,isArray:g,isPlainObject:u}}=this._core;if(n(s))return NA.getLocalConversationList();if(g(s))return s.length===0?[]:NA.getLocalConversationList().filter(E=>s.includes(E.conversationID));if(u(s)){const{type:E,markType:m,groupName:D,hasUnreadCount:M,hasGroupAtInfo:T}=s;return NA.getLocalConversationList().filter(P=>this._filterType(P,E)&&this._filterMarkType(P,m)&&this._filterGroupName(P,D)&&this._filterUnreadCount(P,M)&&this._filterGroupAtInfo(P,T))}return[]}_filterType(s,n){const{OuterConstant:g}=this._core;return n!==g.CONV_C2C&&n!==g.CONV_GROUP||s.type===n}_filterGroupName(s,n){const{utils:{isString:g}}=this._core;return!g(n)||(n===""?s.conversationGroupList.length===0:s.conversationGroupList.includes(n))}_filterMarkType(s,n){const{utils:{isNumber:g}}=this._core;return!g(n)||(n===0?s.markList.length===0:s.markList.includes(n))}_filterUnreadCount(s,n){let g=!0;return n===!0?g=s.unreadCount>=1:n===!1&&(g=s.unreadCount===0),g}_filterGroupAtInfo(s,n){let g=!0;return n===!0?g=s.groupAtInfoList.length>=1:n===!1&&(g=s.groupAtInfoList.length===0),g}},we=new class{constructor(){this._name="GetConversationProfile"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"getConversationProfile",context:this})}getConversationProfile(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:{CONV_C2C:n,CONV_GROUP:g,GRP_AVCHATROOM:u},appStore:{groupStore:E},utils:{isEmpty:m}}=this._core,D={code:0,data:{}};let M=NA.getLocalConversation(s);if(ks(s))return D.data.conversation=M,D;let T=!1;const P=Bt(s)?n:g;if(m(M)&&(T=!0,M=new Ct({conversationID:s,type:P})),console.log(`${this._name}.getConversationProfile conversationID:${s} isNewConversation:${T}`),D.data.conversation=M,M?.getProfileCompleted())return D;if(P===n){const W=s.replace(n,"");yield this._handleC2CConversation(M,W),T&&(yield BA.get([W]))}if(P===g){const W=s.replace(g,"");if(!E.getGroup(W))return D;yield this._handleGroupConversation(M,W),T&&M.groupProfile.type!==u&&(yield yA.get([W]))}return D})}_handleC2CConversation(s,n){return pA(this,void 0,void 0,function*(){var g,u;const{user:E,helper:m,utils:{isEmpty:D},appStore:{conversationStore:M,userStore:T}}=this._core,{conversationID:P}=s,W=yield(g=E.userProfile)===null||g===void 0?void 0:g.getUserProfile({userIDList:[n]});if(W?.data.length===0)throw new m.ChatError({code:Qa.USER_OR_GRP_NOT_FOUND});s.userProfile=W?.data[0];const iA=(u=T.getFriend(n))===null||u===void 0?void 0:u.remark;D(iA)||s.remark===iA||(s.remark=iA),s.setProfileCompleted();const EA=NA.hasLocalConversation(P);console.log(`${this._name}._handleC2CConversation conversationID:${P} hasLocalConversation: ${EA}`),EA?M.updateConversation(P,s):NA.appendToPinnedConversation(s)})}_handleGroupConversation(s,n){return pA(this,void 0,void 0,function*(){const{apiMap:{getGroupProfile:g},appStore:{conversationStore:u}}=this._core,{conversationID:E}=s,m=yield g({groupID:n});s.groupProfile=m?.data.group,s.setProfileCompleted();const D=NA.hasLocalConversation(E);console.log(`${this._name}._handleGroupConversation conversationID:${E} hasLocalConversation: ${D}`),D?u.updateConversation(E,s):NA.appendToPinnedConversation(s)})}},Ie=new class{init(s){const{helper:n}=s;n.registerApi({apiName:"getTotalUnreadMessageCount",context:this})}getTotalUnreadMessageCount(){return NA.getTotalUnreadMessageCount()}},Ge=new class{constructor(){this._serverGroupConversationLastReadSeqMap=new Map,this._name="SetMessageRead"}init(s){this._core=s;const{helper:n,common:{isTopic:g},notificationCenter:u,InnerEvent:{MESSAGE_PUSH:E},InnerEventSubType:{ALL_MESSAGE_READ:m}}=s;n.registerApi({apiName:"setMessageRead",context:this,matcher:D=>!g(D[0].conversationID)}),n.registerApi({apiName:"setAllMessageRead",context:this}),u.subscribeInnerEvent(E,m,this._handleAllMessageRead,this)}handleC2CMessageReadSync(s){const{helper:{isEmpty:n},OuterConstant:g}=this._core;s.forEach(u=>{const{ReadC2cMsgNotify:E}=u;if(!n(E)){const{UinPairReadArray:m=[]}=E;m.forEach(D=>{const{From_Account:M,LastReadTime:T}=D,P=`${g.CONV_C2C}${M}`;console.log(`${this._name}.handleC2CMessageReadSync conversationID:${P} lastReadTime:${T}`),NA.markMessageAsRead({conversationID:P,lastReadTime:T}),NA.updateUnreadCount(P)})}})}handleGroupMessageReadSync(s){const{OuterConstant:n,utils:{isUndefined:g}}=this._core;s.forEach(u=>{const{GroupReadInfoArray:E}=u.MsgBody;g(E)||E.forEach(m=>{const{GroupId:D,LastReadMsgSeq:M}=m,T=`${n.CONV_GROUP}${D}`;console.log(`${this._name}.handleGroupMessageReadSync conversationID:${T} lastReadSequence:${M}`),NA.markMessageAsRead({conversationID:T,lastReadSequence:M}),NA.updateUnreadCount(T),this._clearGroupAtInfoList(T)})})}setMessageRead(s){return pA(this,void 0,void 0,function*(){var n,g;const{OuterConstant:u}=this._core,{conversationID:E}=s,m={code:0,data:{}},D=NA.getLocalConversation(E);let M=`${this._name}.setMessageRead conversationID:${E} unreadCount:${D?.unreadCount||0}`;if(m.successLog={message:M},!D)return m;const T=!(!((g=(n=this._core)===null||n===void 0?void 0:n.helper)===null||g===void 0)&&g.isEmpty(D.groupAtInfoList));if(D.type===u.CONV_GROUP&&T&&this._deleteGroupAtTips(E),D.unreadCount===0)return m;const{helper:{ChatError:P}}=this._core;try{if(D.type===u.CONV_C2C){const W=this._getLocalMessageMaxTime(D);M+=`lastMessageTime:${W}`,yield this._setC2CMessageRead(E,W)}if(D.type===u.CONV_GROUP){const W=this._getLocalMessageMaxSequence(D);M+=`lastMessageSequence:${W}`,yield this._setGroupMessageRead(E,W)}}catch(W){const{errorCode:iA,errorInfo:EA}=W;throw new P({functionName:"setMessageRead",code:iA,message:EA,moreMessage:M})}return D.type===u.CONV_SYSTEM&&(D.unreadCount=0),NA.emitConversationListUpdate(),Object.assign(Object.assign({},m),{successLog:{message:M}})})}setAllMessageRead(){return pA(this,arguments,void 0,function*(s={}){const{OuterConstant:{READ_ALL_MSG:n},utils:{safeStringify:g}}=this._core;let u=`scope:${s.scope}`;s.scope||(s.scope=n);const{scope:E}=s,m=this._generateSetAllMessageReadRequestData(E);if(m.allC2CMessageReadStatus===ea&&m.groupMessageReadInfoList.length===0)return{code:0};try{const D=yield function(M){return pA(this,void 0,void 0,function*(){const{allC2CMessageReadStatus:T,groupMessageReadInfoList:P}=M,W={C2CReadAllMsg:T,GroupReadInfo:P};return ho.core.common.buildAndSendPacket({servcmd:"openim.read_all_unread_msg",data:W})})}(m);if(D){const{GroupReadInfoArray:M,C2CReadAllMsg:T}=D,P=this._parseGroupReadInfo(M);this._updateAllConversationReadStatus({allC2CMessageReadStatus:T})>0&&NA.emitConversationListUpdate(),u+=`failureGroupInfoList:${g(P)}`}return{code:0,successLog:{message:u}}}catch(D){const{errorCode:M}=D;throw new this._core.helper.ChatError({functionName:"setAllMessageRead",code:M,moreMessage:u})}})}_handleAllMessageRead(s){const{GroupReadInfoArray:n,C2CReadAllMsg:g}=s;this._parseGroupReadInfo(n),this._updateAllConversationReadStatus({allC2CMessageReadStatus:g})>0&&NA.emitConversationListUpdate()}_updateAllConversationReadStatus(s){const{OuterConstant:{CONV_C2C:n,CONV_GROUP:g},appStore:u}=this._core,E=u.conversationStore.getConversationMap(),{allC2CMessageReadStatus:m}=s;let D=0;for(const[M,T]of E)if(T.unreadCount>=1){if(m===H&&T.type===n){const P=this._getLocalMessageMaxTime(T);NA.markMessageAsRead({conversationID:M,lastReadTime:P})}else if(T.type===g){const P=M.replace(g,"");if(this._serverGroupConversationLastReadSeqMap.has(P)){const W=this._serverGroupConversationLastReadSeqMap.get(P);NA.markMessageAsRead({conversationID:M,lastReadSequence:W})}}NA.updateUnreadCount(M,!1)&&(D+=1)}return D}_generateSetAllMessageReadRequestData(s){const{OuterConstant:{CONV_C2C:n,CONV_GROUP:g,READ_ALL_C2C_MSG:u},appStore:E}=this._core,m={allC2CMessageReadStatus:ea,groupMessageReadInfoList:[]},D=E.conversationStore.getConversationMap();for(const[,M]of D){const{type:T,unreadCount:P}=M;if(this._shouldSetAllMessageRead({scope:s,type:T,unreadCount:P})){if(T===n&&m.allC2CMessageReadStatus===ea){if(m.allC2CMessageReadStatus=H,s===u)break}else if(T===g){const W=this._getLocalMessageMaxSequence(M),{groupID:iA}=M.groupProfile;m.groupMessageReadInfoList.push({GroupId:iA,MsgSeq:W})}}}return m}_parseGroupReadInfo(s){const{utils:{isUndefined:n}}=this._core,g=[];return s?.forEach(u=>{const{GroupId:E,MsgSeq:m,RetCode:D,LastReadMsgSeq:M}=u;n(D)?this._serverGroupConversationLastReadSeqMap.set(E,M):(this._serverGroupConversationLastReadSeqMap.set(E,m),D!==0&&g.push(`${E}-${m}-${D}`))}),g}_deleteGroupAtTips(s){return pA(this,void 0,void 0,function*(){console.log(`${this._name}._deleteGroupAtTips conversationID:${s}`);const n=NA.getLocalConversation(s);if(!n)return;const g=n?.groupAtInfoList||[];if(g.length!==0)try{const{common:{getCurrentUserID:u,isCommunity:E},OuterConstant:{CONV_GROUP:m,CONV_AT_ALL:D}}=this._core;let M=[...g];if(E({groupID:s.replace(m,"")})&&(M=g.filter(P=>!P.atTypeArray.includes(D)),M.length===0))return void this._clearGroupAtInfoList(s,!1);const T=M.map(P=>({From_Account:P.from,To_Account:u(),MsgSeq:P.__sequence,MsgRandom:P.__random,GroupId:P.groupID}));yield function(P,W){return pA(this,void 0,void 0,function*(){const{messageListToDelete:iA}=P,EA={DelMsgList:iA};return W.common.buildAndSendPacket({servcmd:"openim.deletemsg",data:EA})})}({messageListToDelete:T},this._core),console.log(`${this._name}._deleteGroupAtTips ok. count:${g.length}`),this._clearGroupAtInfoList(s)}catch(u){console.error(`${this._name}._deleteGroupAtTips fail:`,u)}})}_clearGroupAtInfoList(s,n=!0){const g=NA.getLocalConversation(s);g&&(g.groupAtInfoList.length>0&&(g.clearGroupAtInfoList(),console.log(`${this._name}._clearGroupAtInfoList conversationID:${s} needEmitConversationUpdate:${n}`)),n&&NA.emitConversationListUpdate())}_getLocalMessageMaxTime(s){var n;const{conversationID:g}=s,u=this._core.message.messageDataHandler.getLocalMessageList(g),E=Math.max(...u.map(D=>D.time));let m=((n=s?.lastMessage)===null||n===void 0?void 0:n.lastTime)||0;return E>m&&(console.log(`${this._name}._getLocalMessageMaxTime update lastMessageTime from ${m} to ${E}`),m=E),m}_getLocalMessageMaxSequence(s){var n;const{conversationID:g}=s,u=this._core.message.messageDataHandler.getLocalMessageList(g),E=Math.max(...u.map(D=>D.sequence));let m=((n=s?.lastMessage)===null||n===void 0?void 0:n.lastSequence)||0;return E>m&&(console.log(`${this._name}._getLocalMessageMaxSequence update lastMessageSequence from ${m} to ${E}`),m=E),m}_setC2CMessageRead(s,n){return pA(this,void 0,void 0,function*(){try{yield function(g,u){return pA(this,void 0,void 0,function*(){return u.common.buildAndSendPacket({servcmd:"openim.msgreaded",data:g})})}({C2CMsgReaded:{Cookie:"",C2CMsgReadedItem:[{To_Account:s.replace("C2C",""),LastedMsgTime:n,Receipt:1}]}},this._core),console.log(`${this._name}._setC2CMessageRead ok, lastReadTime:${n}`),NA.markMessageAsRead({conversationID:s,lastReadTime:n}),NA.updateUnreadCount(s)}catch(g){throw console.warn(`${this._name}._setC2CMessageRead fail:`,g),g}})}_setGroupMessageRead(s,n){return pA(this,void 0,void 0,function*(){try{yield function(g,u){return pA(this,void 0,void 0,function*(){const{groupID:E,lastMessageSequence:m}=g,D={GroupId:E,MsgReadedSeq:m};return u.common.buildAndSendPacket({servcmd:"group_open_http_svc.msg_read_report",data:D})})}({groupID:s.replace("GROUP",""),lastMessageSequence:n},this._core),console.log(`${this._name}._setGroupMessageRead ok, lastReadSequence:${n}`),NA.markMessageAsRead({conversationID:s,lastReadSequence:n}),NA.updateUnreadCount(s)}catch(g){throw console.warn(`${this._name}._setGroupMessageRead fail:`,g),g}})}_shouldSetAllMessageRead(s){const{OuterConstant:{CONV_C2C:n,CONV_GROUP:g,READ_ALL_MSG:u,READ_ALL_C2C_MSG:E,READ_ALL_GROUP_MSG:m}}=this._core,{type:D,scope:M,unreadCount:T}=s;return!(T<=0)&&(!(D!==n||![u,E].includes(M))||!(D!==g||![u,m].includes(M)))}},ce=new class{constructor(){this._name="PinConversation"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"pinConversation",context:this})}handleConversationPinned(s,n){const{utils:{isArray:g}}=this._core;if(!g(s))return;const{OuterConstant:u}=this._core;let E=!1;s.forEach(m=>{const{Type:D,Peer_Account:M,GroupId:T}=m;let P;D===1?P=NA.getLocalConversation(`${u.CONV_C2C}${M}`):D===2&&(P=NA.getLocalConversation(`${u.CONV_GROUP}${T}`)),P&&(console.log(`${this._name}.handleConversationPinned conversationID:${P.conversationID} localPinned:${P.isPinned} remotePinned:${n}`),n&&!P.isPinned&&(P.isPinned=!0,E=!0),!n&&P.isPinned&&(P.isPinned=!1,E=!0))}),E&&NA.emitConversationListUpdate(!0)}pinConversation(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:n,common:g,helper:{ChatError:u}}=this._core,{conversationID:E,isPinned:m}=s,D={code:0,data:{conversationID:E}},M=NA.getLocalConversation(E);if(M&&M.isPinned===m)return D;if(ks(E))return M&&(M.isPinned=m),NA.emitConversationListUpdate(!0),D;const T=`conversationID:${E} isPinned:${m}`;try{let P=null;if(Bt(E)?P={Type:1,To_Account:E.replace(n.CONV_C2C,"")}:ug(E)&&(P={Type:2,GroupId:E.replace(n.CONV_GROUP,"")}),yield function(iA,EA){return pA(this,void 0,void 0,function*(){const{fromAccount:RA,operationType:kA,itemList:xA}=iA,LA={From_Account:RA,OperationType:kA,RecentContactItem:xA};return EA.common.buildAndSendPacket({servcmd:"recentcontact.top",data:LA})})}({fromAccount:g.getCurrentUserID(),operationType:m===!0?1:2,itemList:[P]},this._core)){if(M)M.isPinned!==m&&(M.isPinned=m);else{const iA=new Ct({conversationID:E,type:Bt(E)?n.CONV_C2C:n.CONV_GROUP,isPinned:m});NA.setLocalConversation(E,iA)}NA.emitConversationListUpdate(!0)}return Object.assign(Object.assign({},D),{successLog:{message:T}})}catch(P){const{errorCode:W,errorInfo:iA}=P;throw new u({functionName:"pinConversation",code:W,message:iA,moreMessage:T})}})}},Fe=new class{constructor(){this._name="DeleteConversation"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"deleteConversation",context:this})}handleConversationDeleted(s){const{utils:{isArray:n}}=this._core;if(!n(s))return;const{OuterConstant:g}=this._core,u=[];s.forEach(E=>{const{Type:m,Peer_Account:D,GroupId:M}=E;m===1&&u.push(`${g.CONV_C2C}${D}`),m===2&&u.push(`${g.CONV_GROUP}${M}`)}),console.log(`${this._name}.handleConversationDeleted conversationIDList:${u}`),this._deleteLocalConversationList(u)}deleteConversation(s){return pA(this,void 0,void 0,function*(){const{utils:{isString:n}}=this._core;if(n(s))return this._deleteConversation({conversationIDList:[s],flag:ga.ONLY_CONVERSATIONID});const g=Object.assign({},s);return g.conversationIDList.length>100&&(g.conversationIDList=g.conversationIDList.slice(0,100)),this._deleteConversation(g)})}_deleteConversation(s){return pA(this,void 0,void 0,function*(){const{conversationIDList:n,clearHistoryMessage:g=!0,flag:u=0}=s,{helper:{ChatError:E}}=this._core,m=`conversationIDList:${n} clearHistoryMessage:${g}`;try{const D=yield Promise.all([this._deleteConversationFromLocal(n),this._deleteConversationFromServer(n,g)]),M=[...D[0],...D[1]];if(M.length===0)throw new this._core.helper.ChatError({code:Qa.CONV_NOT_FOUND});return{code:0,data:u===ga.ONLY_CONVERSATIONID?{conversationID:M[0]}:{conversationIDList:M},successLog:{message:m}}}catch(D){const{errorCode:M,errorInfo:T}=D;throw new E({code:M,message:T,moreMessage:m})}})}_deleteConversationFromLocal(s){const{OuterConstant:n}=this._core;return s.filter(g=>{var u;if(!NA.hasLocalConversation(g))return!1;const E=(u=NA.getLocalConversation(g))===null||u===void 0?void 0:u.type;return E!==n.CONV_GROUP||this._hasLocalGroup(g)?E===n.CONV_SYSTEM&&(this._deleteLocalConversation(g),!0):(this._deleteLocalConversation(g),!0)})}_deleteConversationFromServer(s,n){return pA(this,void 0,void 0,function*(){const{OuterConstant:g,common:u}=this._core,E={fromAccount:u.getCurrentUserID(),conversationList:[],clearHistoryMessage:n?1:0};if(s.forEach(D=>{var M;if(NA.hasLocalConversation(D)){const T=((M=NA.getLocalConversation(D))===null||M===void 0?void 0:M.type)||"",P=D.replace(T,"");T===g.CONV_C2C?E.conversationList.push({To_Account:P,Type:1}):T===g.CONV_GROUP&&this._hasLocalGroup(D)&&E.conversationList.push({ToGroupid:P,Type:2})}}),E.conversationList.length===0)return[];const m=yield function(D,M){return pA(this,void 0,void 0,function*(){const{fromAccount:T,conversationList:P,clearHistoryMessage:W}=D,iA={From_Account:T,ContactItem:P,ClearRamble:W};return M.common.buildAndSendPacket({servcmd:"recentcontact.batch_delete",data:iA})})}(E,this._core);if(m){const{ResultItem:D=[]}=m,M=[];return D.length>0&&D.forEach(T=>{if(T.ResultCode===0){const P=T.Type===1?`${g.CONV_C2C}${T.To_Account}`:`${g.CONV_GROUP}${T.ToGroupid}`;M.push(P)}}),this._deleteLocalConversationList(M),M}return[]})}_deleteLocalConversationList(s){let n=!1;s.forEach(g=>{NA.hasLocalConversation(g)&&(this._deleteLocalConversation(g,!1),n=!0)}),console.log(`${this._name}._deleteLocalConversationList isUpdate:${n}`),n&&NA.emitConversationListUpdate()}_deleteLocalConversation(s,n=!0){const g=NA.hasLocalConversation(s);console.log(`${this._name}._deleteLocalConversation conversationID:${s} has:${g}`),g&&(NA.deleteLocalConversation(s),this._deleteConversationLocalMessage(s),n&&NA.emitConversationListUpdate())}_hasLocalGroup(s){const{OuterConstant:{CONV_GROUP:n},appStore:{groupStore:g}}=this._core,u=s.replace(n,"");return!!g.getGroup(u)}_deleteConversationLocalMessage(s){console.log(`${this._name}._deleteConversationLocalMessage conversationID:${s}`),this._core.message.messageDataHandler.deleteConversationMessageList(s),this._core.message.messageHistory.completedHistoryConversations.delete(s)}},St=new class{constructor(){this._name="SetConversationDraft"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setConversationDraft",context:this})}setConversationDraft(s){return pA(this,void 0,void 0,function*(){const{conversationID:n,draftText:g}=s;if(console.log(`${this._name} conversationID:${n} draftText:${g}`),!NA.hasLocalConversation(n))throw new this._core.helper.ChatError({code:Qa.CONV_NOT_FOUND});const u=NA.getLocalConversation(n);return u?.setDraftText(g),NA.emitConversationListUpdate(),{code:0,data:{conversation:u}}})}},jt=new class{constructor(){this._name="SetC2CMessageRemindType"}init(s){this._core=s}set(s,n){return pA(this,void 0,void 0,function*(){s.length>30&&(console.warn(`${this._name}.set userIDList length:${s.length} exceeds limit 30`),s.splice(30));const g=function(){const{MSG_REMIND_ACPT_AND_NOTE:P,MSG_REMIND_DISCARD:W,MSG_REMIND_ACPT_NOT_NOTE:iA}=ho.core.OuterConstant;return{[P]:0,[W]:1,[iA]:2}}()[n],u=yield function(P,W){return pA(this,void 0,void 0,function*(){const{userIDList:iA,receiveMessageOption:EA}=P,RA={Peer_Account:iA,Mute_Notifications:EA};return W.common.buildAndSendPacket({servcmd:"openim.set_c2c_peer_mute_notifications",data:RA})})}({userIDList:s,receiveMessageOption:g},this._core),{ErrorList:E=[]}=u||{},m=[];E.forEach(P=>{const{Peer_Account:W,ErrorCode:iA}=P;m.push({userID:W,code:iA});const EA=s.indexOf(W);EA>-1&&s.splice(EA,1)});const D=[],M=[],{OuterConstant:T}=this._core;return s.forEach(P=>{M.push(`${T.CONV_C2C}${P}`),D.push({userID:P})}),NA.patchMessageRemindType(M,n),{code:0,data:{successUserIDList:D,failureUserIDList:m}}})}},ci=new class{constructor(){this._name="SetGroupMessageRemindType"}init(s){this._core=s}set(s,n){return pA(this,void 0,void 0,function*(){const{common:{getCurrentUserID:g,isTopic:u},OuterConstant:E}=this._core;if(yield function(m,D){return pA(this,void 0,void 0,function*(){const{groupID:M,userID:T,receiveMessageOption:P}=m,W={GroupId:M,Member_Account:T,MsgFlag:P};return D.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_member_info",data:W})})}({groupID:s,userID:g(),receiveMessageOption:n},this._core),!u(s)){const m=`${E.CONV_GROUP}${s}`;NA.patchMessageRemindType([m],n)}return{code:0,data:{groupID:s,messageRemindType:n}}})}},ft=new class{constructor(){this._name="SetMessageRemindType"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setMessageRemindType",context:this})}handleC2CMessageRemindTypeSync(s){const{helper:{isEmpty:n},OuterConstant:g,ssoLog:u}=this._core;s.forEach(E=>{const{MuteNotificationsSync:m}=E;if(!n(m)){const{To_Account:D,MuteNotifications:M}=m,T=D.map(W=>`${g.CONV_C2C}${W}`),P=Wi(M);u.debug(`${this._name}.handleC2CMessageRemindTypeSync conversationIDList:${T} messageRemindType:${P}`),NA.patchMessageRemindType(T,P)}})}setMessageRemindType(s){return pA(this,void 0,void 0,function*(){const n="setMessageRemindType",{groupID:g,userIDList:u,messageRemindType:E}=s,{helper:m,utils:{isUndefined:D},ssoLog:M}=this._core;try{if(!D(g))return M.debug(`${this._name}.${n} groupID:${g} messageRemindType:${E}`),yield ci.set(g,E);if(!D(u))return M.debug(`${this._name}.${n} userIDList:${u} messageRemindType:${E}`),yield jt.set(u,E);throw new m.ChatError({functionName:n,message:"userIDList or groupID is required"})}catch(T){throw new m.ChatError({functionName:n,code:T?.errorCode,message:T?.errorInfo,moreMessage:`groupID:${g} userIDList:${u} messageRemindType:${E}`})}})}},Bi=new class{init(s){s.ssoLog.debug("ConversationAction.init"),this._core=s,zA.init(s),we.init(s),Ie.init(s),Ge.init(s),ce.init(s),Fe.init(s),St.init(s),ft.init(s);const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:g,DESTROY:u}}=this._core,{InnerEventSubType:{CONV_MODIFIED:E,C2C_MESSAGE_READ_SYNC:m,GROUP_MESSAGE_READ_SYNC:D,C2C_REMIND_TYPE_SYNC:M}}=n;n.subscribeInnerEvent(g,E,this._onConversationModified,this),n.subscribeInnerEvent(g,m,this._onC2CMessageReadSync,this),n.subscribeInnerEvent(g,M,this._onC2CMessageRemindTypeSync,this),n.subscribeInnerEvent(g,D,this._onGroupMessageReadSync,this),n.subscribeInnerEvent(u,this._dispose,this)}_onConversationModified(s){const{constants:{ConvModifyPushType:n}}=this._core,{RecentContactMod:g=[]}=s;g.forEach(u=>{const{PushType:E}=u;if(E===n.CONV_DELETED){const{RecentContactList:m}=u.RecentContactDeleteItem;Fe.handleConversationDeleted(m)}if(E===n.CONV_PINED){const{RecentContactList:m}=u.RecentContactTopItem;ce.handleConversationPinned(m,!0)}if(E===n.CONV_UNPINED){const{RecentContactList:m}=u.RecentContactTopItem;ce.handleConversationPinned(m,!1)}})}_onC2CMessageReadSync(s){const{C2cNotifyMsgArray:n=[]}=s;Ge.handleC2CMessageReadSync(n)}_onC2CMessageRemindTypeSync(s){const{C2cNotifyMsgArray:n=[]}=s;ft.handleC2CMessageRemindTypeSync(n)}_onGroupMessageReadSync(s){const{GroupTips:n=[]}=s;Ge.handleGroupMessageReadSync(n)}_dispose(){const{notificationCenter:s,InnerEvent:{MESSAGE_PUSH:n,DESTROY:g}}=this._core,{InnerEventSubType:{CONV_MODIFIED:u,C2C_MESSAGE_READ_SYNC:E,GROUP_MESSAGE_READ_SYNC:m,C2C_REMIND_TYPE_SYNC:D}}=s;s.unSubscribeInnerEvent(n,u,this._onConversationModified,this),s.unSubscribeInnerEvent(n,E,this._onC2CMessageReadSync,this),s.unSubscribeInnerEvent(n,D,this._onC2CMessageRemindTypeSync,this),s.unSubscribeInnerEvent(n,m,this._onGroupMessageReadSync,this),s.unSubscribeInnerEvent(g,this._dispose,this)}},eo=new class{init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setAllReceiveMessageOpt",context:this})}setAllReceiveMessageOpt(s){return pA(this,void 0,void 0,function*(){try{const{OuterConstant:{MSG_REMIND_ACPT_NOT_NOTE:n}}=this._core,{messageRemindType:g=n,isRepeated:u=!0}=s,{startTime:E=0,endTime:m=0}=this._calcStartAndEndTime(s),D=yield function(M){return pA(this,void 0,void 0,function*(){const{common:T}=ho.core,{startTime:P,endTime:W,isRepeated:iA,messageRemindType:EA}=M,RA={StartTime:P,EndTime:W,IsRepeated:iA,Level:EA};return T.buildAndSendPacket({servcmd:"im_msg_db_logic.ws_set_do_not_disturb",data:RA})})}({messageRemindType:this._getType(g),startTime:E,endTime:m,isRepeated:u?is.ON:is.OFF});return{code:0,data:{errorCode:D.ErrorCode,errorInfo:D.ErrorInfo}}}catch(n){oc("setAllReceiveMessageOpt",n)}})}_calcStartAndEndTime(s){const{startHour:n=0,startMinute:g=0,startSecond:u=0,duration:E=0,isRepeated:m=!0}=s,D=new Date,M=new Date(D.getFullYear(),D.getMonth(),D.getDate(),n,g,u),T=Math.round(M.getTime()/1e3);let P=T+E;return m&&E>=86400&&(P=T+86400),{startTime:T,endTime:P}}_getType(s){const{OuterConstant:n}=this._core;return{[n.MSG_REMIND_ACPT_AND_NOTE]:0,[n.MSG_REMIND_DISCARD]:1,[n.MSG_REMIND_ACPT_NOT_NOTE]:2}[s]}},Is=new class{init(s){this._core=s;const{helper:n,notificationCenter:g,InnerEvent:u}=s;n.registerApi({apiName:"getAllReceiveMessageOpt",context:this}),g.subscribeInnerEvent(u.MESSAGE_PUSH,g.InnerEventSubType.ALL_RECEIVE_MESSAGE_OPTION,this.onAllReceiveMsgOptionNotify,this)}onAllReceiveMsgOptionNotify(s){const n=this._handleResult(s),{notificationCenter:g,OuterEvent:{ALL_RECEIVE_MESSAGE_OPT_UPDATED:u}}=this._core;g.emitOuterEvent(u,{name:u,data:n})}getAllReceiveMessageOpt(){return pA(this,void 0,void 0,function*(){try{const s=yield function(){return pA(this,void 0,void 0,function*(){const{common:n}=ho.core,g={To_Account:n.getCurrentUserID()};return n.buildAndSendPacket({servcmd:"im_msg_db_logic.ws_get_do_not_disturb",data:g})})}();return{code:0,data:this._handleResult(s)}}catch(s){oc("getAllReceiveMessageOpt",s)}})}_handleResult(s){const{OuterConstant:n}=this._core,{MSG_REMIND_ACPT_AND_NOTE:g,MSG_REMIND_DISCARD:u,MSG_REMIND_ACPT_NOT_NOTE:E}=n,m={0:g,1:u,2:E},{Level:D,StartTime:M,EndTime:T,IsRepeated:P}=s;return{messageRemindType:m[D]||g,startTime:M,endTime:T,isRepeated:P===is.ON}}},Uo=new class{init(s){s.ssoLog.debug("ReceiveMessageOptions.init"),this._core=s,jt.init(s),ci.init(s),BA.init(s),yA.init(s),eo.init(s),Is.init(s)}};const oi=s=>!Bt(s)&&!ug(s)&&!ks(s),Fr={getConversationProfile:[{key:"conversationID",required:!0,rules:["string"],allowEmpty:!1,customValidator:s=>!oi(s)||"conversationID is invalid."}],setMessageRead:{conversationID:{required:!0,rules:["string"],allowEmpty:!1,customValidator:s=>!oi(s)||"conversationID is invalid."}},pinConversation:{conversationID:{required:!0,rules:["string"],allowEmpty:!1,customValidator:s=>!oi(s)||"conversationID is invalid."},isPinned:{required:!0,rules:["boolean"],allowEmpty:!1}},deleteConversation:[{key:"options",required:!0,rules:["string","object"],allowEmpty:!1,customValidator:s=>{const{core:{utils:{isArray:n,isObject:g,isString:u}}}=ho;if(!u(s)&&!g(s))return"options is String or Object.";if(u(s)&&oi(s))return"conversationID is invalid.";if(g(s)){if(!n(s.conversationIDList))return"conversationIDList is not Array.";if(s.conversationIDList.length===0)return"conversationIDList is empty.";if(s.conversationIDList.some(E=>{if(oi(E))return!0}))return"conversationIDList includes invalid conversationID.";if(s.clearHistoryMessage&&typeof s.clearHistoryMessage!="boolean")return"clearHistoryMessage is not Boolean."}return!0}}],setConversationDraft:{conversationID:{required:!0,rules:["string"],allowEmpty:!1,customValidator:s=>!(!Bt(s)&&!ug(s))||"conversationID is invalid."},draftText:{required:!0,rules:["string"],allowEmpty:!0}},setAllReceiveMessageOpt:{messageRemindType:{required:!1,rules:["string"],allowEmpty:!0},startHour:{required:!1,rules:["number"],allowEmpty:!0},startMinute:{required:!1,rules:["number"],allowEmpty:!0},startSecond:{required:!1,rules:["number"],allowEmpty:!0},duration:{required:!1,rules:["number"],allowEmpty:!0},isRepeated:{required:!1,rules:["boolean"],allowEmpty:!0}}},Zo={getConversationList:!0,getConversationProfile:!0,getTotalUnreadCount:!0,setMessageRead:!0,pinConversation:!0,deleteConversation:!0,setConversationDraft:!0,setMessageRemindType:!0,getAllReceiveMessageOpt:!0,setAllReceiveMessageOpt:!0};var jn=new class{constructor(){this.name="Conversation"}install(s){ho.init(s),Bi.init(s),Uo.init(s),NA.init(s),s.helper.registerValidateConfig({auth:Zo,params:Fr})}};const Wn=new class{init(s){this.core=s}},ta="AVChatRoom",qr="AV_HISTORY_MSG",sc="GRP_COUNTER",Ku="Set",mm="Increase",Ri="Decrease",si=0,yo=1,on=2,os=["Type","Name","Introduction","Notification","FaceUrl","Owner_Account","CreateTime","InfoSeq","LastInfoTime","LastMsgTime","MemberNum","MaxMemberNum","ApplyJoinOption","NextMsgSeq","ShutUpAllMember","InviteJoinOption","LastRecallTime"],Eg=["Type","Name","Introduction","Notification","FaceUrl","CreateTime","Owner_Account","LastInfoTime","LastMsgTime","NextMsgSeq","MemberNum","MaxMemberNum","ApplyJoinOption","InviteJoinOption"],Ol=["Role","JoinTime","MsgFlag","MsgSeq"],fd=["Role","JoinTime","MsgSeq","MsgFlag","NameCard"],Lc=0,Mr=1,SI="notStart",nu="resolved",Og="rejected",ru=10018,MI=11e3,Uc=2,ju=["Owner","Admin","Member"],fm=["Role","JoinTime","NameCard","ShutUpUntil","OnlineStatus"],ym=0,Dm=1,Sm=2,cD=4,lD=1,Fv=2,ID=3,uD=4,Ov=5,BT=1,yd=0,QT=4,ED=6,pT=400,dD=300,mT={from:!0,groupID:!0,groupName:!0,to:!0},Pv={from:!0,groupID:!0,groupName:!0,to:!0,type:!0},fT=2,xv=4,yT=5,DT=7,CD=8,hD=15,TQ=20,Mm=21,vm=2600,Dd=2602,ST=2603,MT=2620,Rm=2621,BD=2623,Ih=2660,vT=2661,RT=2681,wm=2683,Yv=2684,QD=2685,_m=2687,Vv=3122,wT=10018,_T={0:"DisableInvite",1:"NeedPermission",2:"FreeAccess"},Jv=s=>s===Wn.core.OuterConstant.GRP_PUBLIC,Sd=s=>s===Wn.core.OuterConstant.GRP_AVCHATROOM,Tm=(s,n)=>{const{isArray:g}=Wn.core.utils;if(!g(s)||!g(n))return!1;let u=!1;return n.forEach(({key:E,value:m})=>{const D=s.find(M=>M.key===E);D?D.value!==m&&(D.value=m,u=!0):(s.push({key:E,value:m}),u=!0)}),u},Md=s=>{const n=[];if(!s)return n;for(let g=0,u=s.length;g{const n=[];for(let g=0,u=s.length;g0&&M.members.forEach(T=>{T.userID===this.selfInfo.userID&&D(this.selfInfo,T,["sequence"])})}updateSelfInfo(n){const{nameCard:g,joinTime:u,role:E,messageRemindType:m,readedSequence:D,excludedUnreadSequenceList:M}=n,{common:{deepMerge:T}}=Wn.core;T(this.selfInfo,{nameCard:g,joinTime:u,role:E,messageRemindType:m,readedSequence:D,excludedUnreadSequenceList:M},[],["",null,void 0,0,NaN])}setSelfNameCard(n){this.selfInfo.nameCard=n}}var Yi=new class{constructor(){this._name="GroupDataHandler"}init(s){this._core=s;const{appStore:{groupStore:n}}=s;this._groupMap=n.getGroupMap()}hasLocalGroup(s){return this._groupMap.has(s)}getLocalGroup(s){return this._groupMap.get(s)}updateLocalGroup(s){const{common:{getCurrentUserID:n}}=this._core;let g;s.forEach(E=>{var m;g=E.groupID,this.hasLocalGroup(g)?(m=this.getLocalGroup(g))===null||m===void 0||m.updateGroup(E):(this._groupMap.set(g,new Wu(E)),this._clearGroupLocalMessage(g))});const u=n();for(const[,E]of this._groupMap)E.selfInfo.userID=u,E.selfInfo.role==="Owner"&&(E.ownerID=u)}deleteLocalGroup(s){this._groupMap.delete(s)}getLocalGroupList(){const{OuterConstant:{GRP_ROOM:s,GRP_LIVE:n}}=this._core;return[...this._groupMap.values()].filter(g=>{const{type:u}=g;return u!==s&&u!==n})}clearLocalGroup(){this._groupMap.clear()}emitGroupListUpdate(){const s=this.getLocalGroupList(),{OuterEvent:{GROUP_LIST_UPDATED:n},notificationCenter:g}=this._core;g.emitOuterEvent(n,{name:n,data:s})}updateConversationGroupProfile(s){const{appStore:{conversationStore:n},OuterConstant:{CONV_GROUP:g}}=this._core,u=`${g}${s}`,E=n.getConversation(u);if(E){const m=this.getLocalGroup(s);E.setProfileCompleted(),n.updateConversation(u,{groupProfile:m})}}reset(){this.clearLocalGroup()}_clearGroupLocalMessage(s){const{message:{messageHistory:n,messageDataHandler:g},OuterConstant:{CONV_GROUP:u},ssoLog:E}=this._core;E.debug("_clearGroupLocalMessage",`groupID:${s}`);const m=`${u}${s}`;n.completedHistoryConversations.delete(m),g.deleteConversationMessageList(m)}};function Gm(s,n){return pA(this,void 0,void 0,function*(){const{type:g,limit:u,offset:E,supportTopic:m=0,memberAccount:D,responseFilter:M}=s,T={Type:g,Limit:u,Offset:E,Member_Account:D,ResponseFilter:M,SupportTopic:m,NeedAppDefineData:1};return n.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_joined_group_list",data:T})})}const dn=function(s,n){return{code:0,data:s||{},successLog:n}};var Hv=new class{constructor(){this._name="GetGroupList",this._pagingStatus=SI,this.PAGING_GRP_COUNT_LIMIT=200}init(s){this._core=s;const{helper:n,constants:{WORKFLOW_NAME:g,WORKFLOW_STEP:u}}=s;n.registerApi({apiName:"getGroupList",context:this}),n.registerWorkflowStep(g.SYNC_SERVER_INFO_AFTER_LOGIN,u.GROUP_LIST_SYNC,this._syncGroupList,this)}getGroupList(){return pA(this,arguments,void 0,function*(s=!1){if(s){const g=[];return yield this._pagingGetJoinedCommunityList({limit:this.PAGING_GRP_COUNT_LIMIT,offset:0,groupList:g}),Yi.updateLocalGroup(g),Yi.getLocalGroupList()}if(this._core.ssoLog.debug("getGroupList",`${this._name}.getGroupList pagingStatus:${this._pagingStatus}`),this._pagingStatus===Og||this._pagingStatus===SI)return this._syncGroupList().then(()=>{const g=Yi.getLocalGroupList();return dn({groupList:g,isSyncCompleted:this._isSyncCompleted()})}).catch(g=>{throw g});const n=Yi.getLocalGroupList();return dn({groupList:n,isSyncCompleted:this._isSyncCompleted()},{message:`return group count:${n.length}`})})}_syncGroupList(){return pA(this,void 0,void 0,function*(){this._pagingStatus===SI&&Yi.clearLocalGroup();const s=this.PAGING_GRP_COUNT_LIMIT,n=[];try{yield this._pagingGetGroupList({limit:s,offset:0,groupList:n}),this._pagingStatus=nu,this._groupListTreeShaking(n),Yi.updateLocalGroup(n);const g=Yi.getLocalGroupList();return this._core.ssoLog.debug("_syncGroupList",`${this._name}._syncGroupList ok, count:${g.length}`),Yi.emitGroupListUpdate(),g}catch(g){throw this._pagingStatus=Og,g}})}_pagingGetGroupList(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n}=this._core,{isCommunityRelay:g=!1,groupList:u}=s;let E,{limit:m,offset:D}=s;const M=[...os];g&&(E=this._core.OuterConstant.GRP_COMMUNITY,M.push("AtInfoList"));try{const T=yield Gm({type:E,limit:m,offset:D,memberAccount:this._core.store.get("login").userId,responseFilter:{GroupBaseInfoFilter:M,SelfInfoFilter:[...Ol]}},this._core),{GroupIdList:P=[],TotalCount:W=0}=T||{},iA=this._convertGroupKey(P);u.push(...iA);const EA=D+m,RA=!(W>EA),kA=`offset:${D} limit:${m} total:${W} isCompleted:${RA} current:${u.length} isCommunityRelay:${g}`;return n.debug("_pagingGetGroupList",`${this._name}._pagingGetGroupList ok. ${kA}`),g?RA?u:(D=EA,this._pagingGetGroupList({isCommunityRelay:!0,limit:m,offset:D,groupList:u})):RA?(n.debug("_pagingGetGroupList",`${this._name}._pagingGetGroupList start to get community list`),D=0,this._pagingGetGroupList({isCommunityRelay:!0,limit:m,offset:D,groupList:u})):(D=EA,this._pagingGetGroupList({limit:m,offset:D,groupList:u}))}catch(T){if(T.ErrorCode===ru)return n.warn("_pagingGetGroupList",`${this._name}._pagingGetGroupList response size exceeds the limit, request count:${m}`),m=50,this._pagingGetGroupList({isCommunityRelay:g,limit:m,offset:D,groupList:u});if(g)return T.code===MI&&n.debug("_pagingGetGroupList",`${this._name}._pagingGetGroupList ok. community unavailable`),u;throw T}})}_pagingGetJoinedCommunityList(s){return pA(this,void 0,void 0,function*(){const{common:{getCurrentUserID:n},OuterConstant:g,ssoLog:u}=this._core,{groupList:E}=s;let{limit:m,offset:D}=s;try{const M=yield Gm({limit:m,offset:D,type:g.GRP_COMMUNITY,memberAccount:n(),supportTopic:1,responseFilter:{GroupBaseInfoFilter:[...os],SelfInfoFilter:[...Ol]}},this._core),{GroupIdList:T=[],TotalCount:P=0}=M||{},W=this._convertGroupKey(T);E.push(...W);const iA=D+m,EA=!(P>iA),RA=`offset:${D} limit:${m} total:${P} isCompleted:${EA} current:${E.length}`;return u.debug("_pagingGetJoinedCommunityList",`${this._name}._pagingGetJoinedCommunityList ok. ${RA}`),EA?E:(D=iA,this._pagingGetJoinedCommunityList({limit:m,offset:D,groupList:E}))}catch(M){if(M.code===wT)return u.warn("_pagingGetJoinedCommunityList",`${this._name}._pagingGetJoinedCommunityList response size exceeds the limit, request count:${m}`),m=50,this._pagingGetJoinedCommunityList({limit:m,offset:D,groupList:E});throw M}})}_groupListTreeShaking(s){const n=new Map([...Yi.getLocalGroupList()]);for(let u=0,E=s.length;u{const{AtFlagList:E,AtMsgSeq:m,From_Account:D}=u;g.push({groupID:s,groupAtType:E,sequence:m,from:D})}),g}},zu=new class{constructor(){this._name="CreateGroup"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"createGroup",context:this})}createGroup(s){return pA(this,void 0,void 0,function*(){var n;this._preCheckParams(s);const{helper:{ChatError:g}}=this._core;try{const{utils:{isEmpty:u},common:{getCurrentUserID:E},OuterConstant:{GRP_AVCHATROOM:m}}=this._core,D=yield function(iA,EA){return pA(this,void 0,void 0,function*(){const{name:RA,type:kA,groupID:xA,introduction:LA,notification:SA,avatar:OA,maxMemberNum:JA,joinOption:ae,inviteOption:ne,memberList:_i,groupCustomField:Ti,isSupportTopic:Lt}=iA;let Ni,cs;_i&&(Ni=_i.map(mt=>{const{userID:UA,memberCustomField:ni}=mt;return{Member_Account:UA,AppMemberDefinedData:ni?VE(ni):void 0}})),Ti&&(cs=VE(Ti));const Me={Name:RA,Type:kA,GroupId:xA,Introduction:LA,Notification:SA,FaceUrl:OA,MaxMemberCount:JA,ApplyJoinOption:ae,InviteJoinOption:ne,MemberList:Ni,AppDefinedData:cs,SupportTopic:Lt,webPushFlag:1};return EA.common.buildAndSendPacket({servcmd:"group_open_http_svc.create_group",data:Me})})}(Object.assign(Object.assign({},s),{ownerID:E()}),this._core),{GroupId:M,OverJoinedGroupLimit_Account:T=[]}=D||{},P=`${this._name}.createGroup ok, type:${s.type} groupID:${M} overLimitUserIDList:${T}`;if(u(s.memberList)||u(T)||(s.memberList=(n=s.memberList)===null||n===void 0?void 0:n.filter(iA=>T.includes(iA.userID))),s.type===m)return dn({group:new Wu(Object.assign(Object.assign({},s),{groupID:M}))},{message:P});Yi.updateLocalGroup([Object.assign(Object.assign({},s),{groupID:M})]);const W=Yi.getLocalGroup(M);return this._notNeedSendCustomMessage(s)||(this._sendCustomMessage(M,s.type),Yi.emitGroupListUpdate()),dn({group:W},{message:P})}catch(u){const{errorCode:E,errorInfo:m}=u;throw new g({functionName:"createGroup",code:E,message:m,moreMessage:` groupID:${s.groupID}`})}})}_preCheckParams(s){const{type:n,groupID:g}=s,{utils:{isEmpty:u,isUndefined:E},common:{isCommunity:m}}=this._core,D=!u(g);if(!(()=>{const{GRP_PUBLIC:M,GRP_WORK:T,GRP_MEETING:P,GRP_AVCHATROOM:W,GRP_COMMUNITY:iA}=Wn.core.OuterConstant;return[M,T,P,W,iA]})().includes(n))throw new this._core.helper.ChatError({code:vm});if(!m({type:n})){if(D&&m({groupID:g}))throw new this._core.helper.ChatError({code:Dd});E(s.isSupportTopic)||(s.isSupportTopic=void 0)}if(this._canIUseMemberList(n)||E(s.memberList)||(s.memberList=void 0),this._canIUseJoinOption(n)||E(s.joinOption)||(s.joinOption=void 0),m({type:n})){if(D&&!m({groupID:g}))throw new this._core.helper.ChatError({code:Dd});s.isSupportTopic=this._canIUseTopic(s)?1:0}}_canIUseMemberList(s){return!Sd(s)}_canIUseJoinOption(s){return Jv(s)||this._core.common.isCommunity({type:s})}_canIUseTopic(s){const{isSupportTopic:n}=s;return n===!0}_notNeedSendCustomMessage(s){const{type:n,isSupportTopic:g}=s,{OuterConstant:{GRP_AVCHATROOM:u,GRP_COMMUNITY:E}}=this._core;return n===u||n===E&&g===1}_sendCustomMessage(s,n){var g,u,E,m,D,M;const{OuterConstant:T,common:{t:P}}=this._core;let W=P("CREATE_GROUP"),iA=Lc;n===T.GRP_COMMUNITY&&(W=P("CREATE_COMMUNITY"),iA=Mr);const EA={to:s,conversationType:"GROUP",payload:{data:JSON.stringify({businessID:"group_create",content:W,cmd:iA,opUser:this._core.store.get("login").userId,version:4})}},RA=(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageFactory)===null||E===void 0?void 0:E.createCustomMessage(EA);(M=(D=(m=this._core)===null||m===void 0?void 0:m.message)===null||D===void 0?void 0:D.messageSender)===null||M===void 0||M.sendMessage(RA,{})}},zs=new class{constructor(){this._name="AttributesDataHandler",this._groupAttributesCache=new Map,this._groupAttributesCacheValuesCopy={}}init(s){this._core=s;const{helper:n,constants:g}=s;n.registerWorkflowStep(g.WORKFLOW_NAME.SYNC_SERVER_INFO_AFTER_RE_ONLINE,g.WORKFLOW_STEP.GROUP_ATTRIBUTE_CACHE_CLEAR,this.clearLocalMainSequence,this)}clearLocalMainSequence(){this._groupAttributesCache.forEach(s=>{s.localMainSequence=0})}isGroupAttributesUpdated(s){const{elements:{newGroupProfile:n}}=s,{utils:{isEmpty:g,isUndefined:u}}=this._core;return!u(n)&&!g(n.groupAttributeOption)}handleGroupAttributesUpdated(s){const{groupID:n,groupAttributeOption:g}=s,{serverMainSequence:u,groupAttributeList:E=[],operation:m}=g;this._core.ssoLog.debug("handleGroupAttributesUpdated",`${this._name}.handleGroupAttributesUpdated groupID:${n} operation:${m}`);const{utils:{isUndefined:D}}=this._core;D(m)||(this.refreshGroupAttributesCache({groupID:n,serverMainSequence:u,groupAttributeList:E,operation:m}),this.emitGroupAttributesUpdated(n))}initGroupAttributesCache(s){const{groupID:n,avChatRoomKey:g}=s;this._groupAttributesCache.set(n,{lastUpdateTime:0,localMainSequence:0,serverMainSequence:0,avChatRoomKey:g,values:new Map}),this._core.ssoLog.debug("initGroupAttributesCache",`${this._name}.initGroupAttributesCache. groupID:${n} avChatRoomKey:${g}`)}hasGroupAttributesCache(s){return this._groupAttributesCache.has(s)}getGroupAttributesCache(s){return this.hasGroupAttributesCache(s)||this.initGroupAttributesCache({groupID:s}),this._groupAttributesCache.get(s)}deleteGroupAttributesCache(s){this.hasGroupAttributesCache(s)&&this._groupAttributesCache.delete(s)}refreshGroupAttributesCache(s){const{groupID:n,serverMainSequence:g,groupAttributeList:u,operation:E}=s;if(this.hasGroupAttributesCache(n)){const m=this.getGroupAttributesCache(n),{localMainSequence:D}=m;E!==Ov&&g-D!==1||(m.serverMainSequence=g,m.localMainSequence=g,m.lastUpdateTime=Date.now(),this._updateGroupAttributesCacheValues({groupAttributes:m,groupAttributeList:u,operation:E})),g-D>1&&(m.serverMainSequence=g),this._groupAttributesCache.set(n,m),this._core.ssoLog.debug("refreshGroupAttributesCache",`${this._name}.refreshGroupAttributesCache. operation:${E} localMainSequence:${D} serverMainSequence:${g}`)}}_updateGroupAttributesCacheValues(s){const{groupAttributes:n,groupAttributeList:g=[],operation:u}=s;u!==ID?u!==uD?(u===lD&&n.values.clear(),g.forEach(E=>{const{key:m,value:D,sequence:M}=E;n.values.set(m,{value:D,sequence:M})})):g.forEach(E=>{n.values.delete(E.key)}):n.values.clear()}getGroupAttributesCacheValues(s){var n;const{groupID:g,keyList:u=[]}=s,E={};if(this.hasGroupAttributesCache(g)){const{values:m}=this.getGroupAttributesCache(g);if(u.length===0){for(const D of m.keys())E[D]=((n=m.get(D))===null||n===void 0?void 0:n.value)||"";return E}return u.forEach(D=>{var M;m.has(D)&&(E[D]=((M=m.get(D))===null||M===void 0?void 0:M.value)||"")}),E}return E}saveGroupAttributesCacheValuesCopy(s){this._groupAttributesCacheValuesCopy=this.getGroupAttributesCacheValues({groupID:s})}emitGroupAttributesUpdated(s){var n,g;const{OuterConstant:{GRP_ROOM:u,GRP_LIVE:E}}=this._core,m=this.getGroupAttributesCacheValues({groupID:s}),D=this._core.appStore.groupStore.getGroup(s),{updatedKeyList:M,deletedKeyList:T}=this._computeValuesChangedData(m);M.length===0&&T.length===0||([u,E].includes(D.type)?(this._core.ssoLog.debug("RICH_STATUS_CHANGED",`${this._name}.emitRichStatusChanged update count:${M.length}, delete count:${T.length}`),this._emitEvent({name:(n=this._core)===null||n===void 0?void 0:n.OuterEvent.RICH_STATUS_CHANGED,data:{groupID:s,richStatus:m,updatedKeyList:M,deletedKeyList:T}})):(this._core.ssoLog.debug("emitGroupAttributesUpdated",`${this._name}.emitGroupAttributesUpdated update count:${M.length}, delete count:${T.length}`),this._emitEvent({name:(g=this._core)===null||g===void 0?void 0:g.OuterEvent.GROUP_ATTRIBUTES_UPDATED,data:{groupID:s,groupAttributes:m,updatedKeyList:M,deletedKeyList:T}})))}_computeValuesChangedData(s){const{utils:{isUndefined:n}}=this._core,g=[],u=[];return Object.keys(s).forEach(E=>{s[E]!==this._groupAttributesCacheValuesCopy[E]&&g.push(E)}),Object.keys(this._groupAttributesCacheValuesCopy).forEach(E=>{n(s[E])&&u.push(E)}),this._groupAttributesCacheValuesCopy={},{updatedKeyList:g,deletedKeyList:u}}_emitEvent(s){var n;(n=this._core)===null||n===void 0||n.notificationCenter.emitOuterEvent(s.name,s)}convertKeyValueMapToList(s){const n=[];return Object.keys(s).forEach(g=>{n.push({key:g,value:s[g]})}),n}reset(){this._groupAttributesCache.clear(),this._groupAttributesCacheValuesCopy={}}},Eh=new class{constructor(){this._name="DismissGroup"}init(s,n){this._core=s;const{helper:g}=s;g.registerApi({apiName:"dismissGroup",context:this,matcher:()=>!n.getInstalledSubPlugins().includes(ta)})}dismissGroup(s){return pA(this,void 0,void 0,function*(){const{helper:{ChatError:n}}=this._core;try{yield function(u,E){return pA(this,void 0,void 0,function*(){const m={GroupId:u};return E.common.buildAndSendPacket({servcmd:"group_open_http_svc.destroy_group",data:m})})}(s,this._core);const{type:g}=Yi.getLocalGroup(s);return Yi.deleteLocalGroup(s),Yi.emitGroupListUpdate(),zs.deleteGroupAttributesCache(s),dn({groupID:s,type:g},{message:s})}catch(g){const{errorCode:u,errorInfo:E}=g;throw new n({functionName:"dismissGroup",code:u,message:E})}})}},Pl=new class{constructor(){this._name="GetGroupProfile"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"getGroupProfile",context:this})}getGroupProfile(s){return pA(this,void 0,void 0,function*(){const{groupID:n,groupCustomFieldFilter:g}=s,u={groupIDList:[n],responseFilter:{GroupBaseInfoFilter:[...os],AppDefinedDataFilter_Group:g,MemberInfoFilter:[...fd]}},{helper:{ChatError:E}}=this._core;try{const m=yield this.getGroupProfileAdvance(u),{successGroupList:D,failureGroupList:M}=m;if(M.length>0)throw M[0];let T;return!Yi.hasLocalGroup(n)&&Sd(D[0].type)?T=new Wu(D[0]):(Yi.updateLocalGroup(D),T=Yi.getLocalGroup(n)),T.isSupportTopic||Yi.updateConversationGroupProfile(n),dn({group:T},{message:`groupID:${n}`})}catch(m){const{code:D,message:M}=m;throw new E({functionName:"getGroupProfile",code:D,message:M})}})}getGroupProfileAdvance(s){return pA(this,void 0,void 0,function*(){const{groupIDList:n}=s,{common:{isCommunity:g}}=this._core,u=n.filter(T=>!g({groupID:T})),E=n.filter(T=>g({groupID:T}));u.length>50&&(u.length=50),E.length>50&&(E.length=50);const m=yield Promise.all([this._getGroupProfileAdvance(Object.assign(Object.assign({},s),{groupIDList:u})),this._getGroupProfileAdvance(Object.assign(Object.assign({},s),{groupIDList:E,isCommunityProfile:!0}))]),D=[],M=[];return m.forEach(T=>{D.push(...T.successGroupList),M.push(...T.failureGroupList)}),{successGroupList:D,failureGroupList:M}})}_getGroupProfileAdvance(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{isUndefined:g}}=this._core,{isCommunityProfile:u=!1}=s,E=Do(s,["isCommunityProfile"]);if(E.groupIDList.length===0)return{successGroupList:[],failureGroupList:[]};try{const m=yield function(W,iA){return pA(this,void 0,void 0,function*(){const{groupIDList:EA,responseFilter:RA}=W,kA={GroupIdList:EA,ResponseFilter:RA};return iA.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_self_member_info",data:kA})})}(E,this._core),{GroupInfo:D=[]}=m||{},M=this._convertGroupProfileKey(D),T=M.filter(W=>g(W.errorCode)||W.errorCode===0),P=M.filter(W=>W.errorCode&&W.errorCode!==0).map(W=>({code:W.errorCode,message:W.errorInfo,data:{groupID:W.groupID}}));return n.debug("_getGroupProfileAdvance",`${this._name}._getGroupProfileAdvance ok, groupID:${E.groupIDList.join(",")}`),{successGroupList:T,failureGroupList:P}}catch(m){if(u)return{successGroupList:[],failureGroupList:[]};throw m}})}_convertGroupProfileKey(s){const n=[];for(let g=0,u=s.length;g0&&u{const{Key:T,Value:P=0}=M;E.set(T,P)}),this._groupCountersMap.set(n,{lastUpdateTime:Date.now(),groupCounterSeq:u,counters:E,avChatRoomKey:m})}}initGroupCountersCache(s){const{groupID:n,avChatRoomKey:g}=s;this._groupCountersMap.set(n,{lastUpdateTime:0,groupCounterSeq:0,counters:new Map,avChatRoomKey:g})}getLocalCounters(s,n){const g={};if(!this._hasLocalGroupCounters(s))return g;const{counters:u}=this.getLocalGroupCounters(s);if(n.length>0)n.forEach(E=>{u.has(E)&&(g[E]=u.get(E))});else for(const E of u.keys())g[E]=u.get(E);return g}deleteLocalGroupCounters(s){const{groupID:n,counterList:g=[],groupCounterSeq:u}=s;if(this._hasLocalGroupCounters(n)){const{counters:E,avChatRoomKey:m}=this.getLocalGroupCounters(n);g.forEach(D=>{E.delete(D.key)}),this._groupCountersMap.set(n,{lastUpdateTime:Date.now(),groupCounterSeq:u,counters:E,avChatRoomKey:m})}}setGroupCounters(s,n){if(!this._hasLocalGroupCounters(s))return;const g=this.getLocalGroupCounters(s),{counters:u}=g;let E=!1;Object.entries(n).forEach(([m,D])=>{u.has(m)&&u.get(m)!==D&&(u.set(m,D),E=!0)}),E&&this._groupCountersMap.set(s,Object.assign(Object.assign({},g),{lastUpdateTime:Date.now(),counters:u}))}_hasLocalGroupCounters(s){return this._groupCountersMap.has(s)}reset(){this._groupCountersMap.clear()}},JE=new class{constructor(){this._name="JoinGroup"}init(s,n){this._core=s;const{helper:g}=s;g.registerApi({apiName:"joinGroup",context:this,matcher:()=>!n.getInstalledSubPlugins().includes(ta)})}joinGroup(s){return pA(this,void 0,void 0,function*(){const{groupID:n}=s,{helper:{ChatError:g},OuterConstant:u,ssoLog:E}=this._core;try{if(Yi.hasLocalGroup(n))try{return yield Pl.getGroupProfile({groupID:n}),dn({status:u.JOIN_STATUS_ALREADY_IN_GROUP,group:Yi.getLocalGroup(n)},{message:`groupID:${n} joinedStatus:${u.JOIN_STATUS_ALREADY_IN_GROUP}`})}catch{return E.warn("joinGroup",`${this._name}.joinGroup ${n} was unjoined, start to join!`),Yi.deleteLocalGroup(n),yield this._applyJoinGroup(s)}return yield this._applyJoinGroup(s)}catch(m){const{errorCode:D,errorInfo:M}=m;throw new g({functionName:"joinGroup",code:D,message:M,moreMessage:`groupID:${n}`})}})}_applyJoinGroup(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:n,helper:g,ssoLog:u}=this._core,{groupID:E}=s,m=Object.assign({},s),D=g.checkBusinessCapabilityBits(qr);D&&(m.historyMessageFlag=1);const M=yield function(SA,OA){return pA(this,void 0,void 0,function*(){const{groupID:JA,applyMessage:ae,historyMessageFlag:ne}=SA,_i={GroupId:JA,ApplyMsg:ae,HugeGroupHistoryMsgFlag:ne};return OA.common.buildAndSendPacket({servcmd:"group_open_http_svc.apply_join_group",data:_i})})}(m,this._core),{Type:T,JoinedStatus:P,LongPollingKey:W,StartSeq:iA,HugeGroupFlag:EA,AVChatRoomKey:RA,RspMsgList:kA=[]}=M||{},xA=`groupID:${E} joinedStatus:${P} longPollingKey:${W} startSeq:${iA} avChatRoomFlag:${EA} canGetAVChatRoomHistoryMsg:${D}, historyMessageCount:${kA.length}`;u.debug("_applyJoinGroup",`${this._name}._applyJoinGroup ok, ${xA}`);let LA=new Wu({groupID:E,type:T});if(P===n.JOIN_STATUS_WAIT_APPROVAL)return dn({status:n.JOIN_STATUS_WAIT_APPROVAL,group:LA});if(P===n.JOIN_STATUS_SUCCESS){try{LA=(yield Pl.getGroupProfile({groupID:E})).data.group}catch(SA){u.warn("_applyJoinGroup",`${this._name}._applyJoinGroup getGroupProfile failed, groupID: ${E}, errorCode:${SA?.code}`)}return this._handleJoinResult({group:LA,avChatRoomFlag:EA,longPollingKey:W,startSequence:iA,avChatRoomKey:RA,historyMessageList:kA})}throw new this._core.helper.ChatError({code:Ih})})}_handleJoinResult(s){const{group:n,avChatRoomFlag:g,avChatRoomKey:u}=s;return g===1?(zs.initGroupAttributesCache({groupID:n.groupID,avChatRoomKey:u}),nc.initGroupCountersCache({groupID:n.groupID,avChatRoomKey:u}),dn(s)):(Yi.updateLocalGroup([n]),Yi.emitGroupListUpdate(),dn({status:this._core.OuterConstant.JOIN_STATUS_SUCCESS,group:n},{message:`groupID:${n.groupID}`}))}},NQ=new class{constructor(){this._name="QuitGroup"}init(s,n){this._core=s;const{helper:g}=s;g.registerApi({apiName:"quitGroup",context:this,matcher:()=>!n.getInstalledSubPlugins().includes(ta)})}quitGroup(s){return pA(this,void 0,void 0,function*(){if(!Yi.hasLocalGroup(s))throw new this._core.helper.ChatError({code:BD});const{helper:{ChatError:n}}=this._core;try{yield function(u,E){return pA(this,void 0,void 0,function*(){const m={GroupId:u};return E.common.buildAndSendPacket({servcmd:"group_open_http_svc.quit_group",data:m})})}(s,this._core);const{type:g}=Yi.getLocalGroup(s);return Yi.deleteLocalGroup(s),Yi.emitGroupListUpdate(),zs.deleteGroupAttributesCache(s),dn({groupID:s,type:g},{message:`groupID:${s}`})}catch(g){const{errorCode:u,errorInfo:E}=g;throw new n({functionName:"quitGroup",code:u,message:E,moreMessage:`groupID:${s}`})}})}},cB=new class{constructor(){this._name="SearchGroup"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"searchGroupByID",context:this})}searchGroupByID(s){return pA(this,void 0,void 0,function*(){try{const n=yield function(OA,JA){return pA(this,void 0,void 0,function*(){const ae={GroupIdList:[OA],GroupBasePublicInfoFilter:[...Eg]};return JA.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_public_info",data:ae})})}(s,this._core),{GroupInfo:g=[]}=n||{},{AppDefinedData:u=[],ApplyJoinOption:E,CreateTime:m,FaceUrl:D,Introduction:M,InviteJoinOption:T,MaxMemberNum:P,MemberNum:W,Name:iA,Owner_Account:EA,Type:RA,ErrorCode:kA,ErrorInfo:xA}=g[0];if(kA!==0)throw new this._core.helper.ChatError({code:kA,message:xA});const LA=Md(u),SA=new Wu({groupID:s,name:iA,avatar:D,introduction:M,joinOption:E,inviteOption:T,maxMemberCount:P,memberCount:W,type:RA,ownerID:EA,createTime:m,groupCustomField:LA});return dn({group:SA})}catch(n){const{errorCode:g,errorInfo:u}=n;throw new this._core.helper.ChatError({functionName:"searchGroupByID",code:g,message:u})}})}},TT=new class{constructor(){this._name="UpdateGroupProfile"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"updateGroupProfile",context:this})}updateGroupProfile(s){return pA(this,void 0,void 0,function*(){const{groupID:n}=s,{utils:{isUndefined:g,safeStringify:u},ssoLog:E,helper:m}=this._core;let D=Yi.getLocalGroup(n);if(D){const{type:M}=D;this._canIUseJoinOption(M)||g(s.joinOption)||(E.warn("updateGroupProfile",`${this._name}.updateGroupProfile groupID:${n} joinOption is unavailable for Work/Meeting/AVChatRoom`),s.joinOption=void 0)}g(s.muteAllMembers)||(s.muteAllMembers=s.muteAllMembers===!0?"On":"Off");try{return yield function(M,T){return pA(this,void 0,void 0,function*(){const{groupID:P,name:W,avatar:iA,introduction:EA,notification:RA,muteAllMembers:kA,joinOption:xA,inviteOption:LA,groupCustomField:SA}=M,OA={GroupId:P,Name:W,FaceUrl:iA,Introduction:EA,Notification:RA,ShutUpAllMember:kA,ApplyJoinOption:xA,InviteJoinOption:LA,AppDefinedData:SA?VE(SA):void 0};return T.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_base_info",data:OA})})}(s,this._core),D?(D.updateGroup(s),Yi.emitGroupListUpdate()):D=new Wu(s),dn({group:D},{message:`groupID:${n}`})}catch(M){const{errorCode:T,errorInfo:P}=M;throw new m.ChatError({code:T,message:P,moreMessage:`options:${u(s)}`})}})}_canIUseJoinOption(s){return Jv(s)||this._core.common.isCommunity({type:s})}},NT=new class{constructor(){this._name="ChangeGroupOwner"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"changeGroupOwner",context:this})}changeGroupOwner(s){return pA(this,void 0,void 0,function*(){const n="changeGroupOwner",{groupID:g,newOwnerID:u}=s,E=Yi.getLocalGroup(g),{helper:m,OuterConstant:D,common:{getCurrentUserID:M}}=this._core;if(E?.type===D.GRP_AVCHATROOM)throw new m.ChatError({functionName:n,code:MT});if(u===M())throw new m.ChatError({functionName:n,code:Rm});try{return yield function(T,P){return pA(this,void 0,void 0,function*(){const{groupID:W,newOwnerID:iA}=T,EA={GroupId:W,NewOwner_Account:iA};return P.common.buildAndSendPacket({servcmd:"group_open_http_svc.change_group_owner",data:EA})})}(s,this._core),E.ownerID=u,Yi.emitGroupListUpdate(),dn({group:E})}catch(T){throw new m.ChatError({functionName:n,code:T?.errorCode,message:T?.errorInfo})}})}},GQ=new class{constructor(){this._name="GetGroupOnlineMemberCount",this._onlineMemberCountMap=new Map}init(s,n){this._core=s;const{helper:g}=s;g.registerApi({apiName:"getGroupOnlineMemberCount",context:this,matcher:()=>!n.getInstalledSubPlugins().includes(ta)})}getGroupOnlineMemberCount(s){return pA(this,void 0,void 0,function*(){const n="getGroupOnlineMemberCount";if(!Yi.hasLocalGroup(s))return dn({memberCount:0});const g=Date.now();if(this._onlineMemberCountMap.has(s)){const u=this._onlineMemberCountMap.get(s),{lastReqTime:E=0,memberCount:m=0}=u||{};if(g-E<=6e4)return dn({memberCount:m})}try{const u=yield function(D,M){return pA(this,void 0,void 0,function*(){const T={GroupId:D};return M.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_online_member_num",data:T})})}(s,this._core),{OnlineMemberNum:E=0}=u||{};this._onlineMemberCountMap.set(s,{lastReqTime:Date.now(),memberCount:E});const m=`${this._name}.${n} ok. groupID:${s} memberCount:${E}`;return dn({memberCount:E},{message:m})}catch(u){throw new this._core.helper.ChatError({functionName:n,code:u?.errorCode,message:u?.errorInfo})}})}},bQ=new class{init(s,n){s.ssoLog.debug("GroupAction.init"),Hv.init(s),zu.init(s),Eh.init(s,n),JE.init(s,n),NQ.init(s,n),cB.init(s),Pl.init(s),TT.init(s),NT.init(s),GQ.init(s,n)}dismissGroup(s){return Eh.dismissGroup(s)}joinGroup(s){return JE.joinGroup(s)}quitGroup(s){return NQ.quitGroup(s)}getGroupOnlineMemberCount(s){return GQ.getGroupOnlineMemberCount(s)}},qv=new class{constructor(){this._name="GetGroupApplicationList"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"getGroupApplicationList",context:this})}getGroupApplicationList(){return pA(this,void 0,void 0,function*(){const s="getGroupApplicationList";try{const n=yield Promise.all([this._getGroupApplicationList(),this._getGroupApplicationList({type:this._core.OuterConstant.GRP_COMMUNITY})]);this._core.ssoLog.debug("getGroupApplicationList",`${this._name}.${s} ok.`);const g=this._handleGroupApplicationResult([...n[0],...n[1]]);return dn({applicationList:g})}catch(n){throw new this._core.helper.ChatError({functionName:s,code:n?.errorCode,message:n?.errorInfo})}})}_getGroupApplicationList(s){return pA(this,void 0,void 0,function*(){const{type:n,startTime:g=0,limit:u=20}=s||{},{common:E}=this._core;let m;try{m=yield function(P,W){return pA(this,void 0,void 0,function*(){const{type:iA,startTime:EA,limit:RA,handleAccount:kA}=P,xA={Type:iA,StartTime:EA,Limit:RA,Handle_Account:kA};return W.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_pendency",data:xA})})}({type:n,startTime:g,limit:u,handleAccount:E.getCurrentUserID()},this._core)}catch(P){if(P?.errorCode!==11e3)throw P;m={}}const{NextStartTime:D=0,PendencyList:M=[]}=m||{};if(D===0)return M;const T=yield this._getGroupApplicationList(Object.assign(Object.assign({},s),{startTime:D}));return[...M,...T]})}_handleGroupApplicationResult(s){const n=[];return s.forEach(g=>{const u=this._convertApplicationData(g),{handled:E}=u,m=Do(u,["handled"]);E===0&&n.push(m)}),n}_convertApplicationData(s){const{Handled:n,AddTime:g,ApplyInviteMsg:u,Authentication:E,FromUserNickName:m,From_Account:D,GroupId:M,GroupName:T,PendencyType:P,To_Account:W}=s;return{handled:n,messageKey:g,applicant:D,applicantNick:m,groupID:M,groupName:T,authentication:E,applicationType:P,userID:W,note:u,addTime:g}}},Kv=new class{constructor(){this._name="HandleGroupApplication"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"handleGroupApplication",context:this})}handleGroupApplication(s){return pA(this,void 0,void 0,function*(){const{application:n}=s,g=this._handleParams(s);try{n?.applicationType===Uc?yield function(E,m){return pA(this,void 0,void 0,function*(){const{groupID:D,handleAction:M,handleMessage:T,applicant:P,authentication:W,invitee:iA}=E,EA={GroupId:D,HandleMsg:M,ApprovalMsg:T,Applicant_Account:P,Authentication:W,Invited_Account:iA};return m.common.buildAndSendPacket({servcmd:"group_open_http_svc.handle_invite_join_permission_group",data:EA})})}(g,this._core):yield function(E,m){return pA(this,void 0,void 0,function*(){const{groupID:D,handleAction:M,handleMessage:T,applicant:P,authentication:W,messageKey:iA}=E,EA={GroupId:D,HandleMsg:M,ApprovalMsg:T,Applicant_Account:P,Authentication:W,MsgKey:iA};return m.common.buildAndSendPacket({servcmd:"group_open_http_svc.handle_apply_join_group",data:EA})})}(g,this._core);const u=Yi.getLocalGroup(g.groupID);return dn({group:u})}catch(u){throw new this._core.helper.ChatError({functionName:"handleGroupApplication",code:u?.errorCode,message:u?.errorInfo})}})}_handleParams(s){var n;const{handleAction:g,handleMessage:u,message:E,application:m}=s;let D,M,T,P,W;if(E){const{payload:iA}=E||{};D=iA.operatorID,M=(n=iA.groupProfile)===null||n===void 0?void 0:n.groupID,T=iA.authentication,P=iA.messageKey}else D=m?.applicant||"",M=m?.groupID||"",T=m?.authentication||"",P=m?.messageKey||0;return m?.applicationType===Uc&&(W=m.userID),{handleAction:g,handleMessage:u,applicant:D,invitee:W,groupID:M,authentication:T,messageKey:P}}},pD=new class{init(s){s.ssoLog.debug("GroupApplication.init"),qv.init(s),Kv.init(s)}};let DC=class{constructor(s){this.userID="",this.avatar="",this.nick="",this.role="",this.joinTime="",this.nameCard="",this.muteUntil=0,this.memberCustomField=[],this.isOnline=!1,this.updateMember(s)}updateMember(s){const{core:{utils:{isUndefined:n},common:{deepMerge:g}}}=Wn;n(s.muteTime)||(this.muteUntil=Math.floor((Date.now()+1e3*s.muteTime)/1e3)),n(s.onlineStatus)||(this.isOnline=s.onlineStatus==="Online");const u=[null,void 0,"",0,NaN];s.memberCustomField&&Tm(this.memberCustomField,s.memberCustomField),g(this,s,["memberCustomField","marks","onlineStatus","muteTime"],u)}};function lB(s,n){return pA(this,void 0,void 0,function*(){const{groupID:g,userID:u,muteTime:E,role:m,nameCard:D,memberCustomField:M}=s;let T;M&&(T=VE(M));const P={GroupId:g,Member_Account:u,ShutUpTime:E,Role:m,NameCard:D,AppMemberDefinedData:T};return n.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_member_info",data:P})})}var mD=new class{constructor(){this._name="GetGroupMemberList"}init(s,n){this._core=s;const{helper:g}=s;g.registerApi({apiName:"getGroupMemberList",context:this,matcher:()=>!n.getInstalledSubPlugins().includes(ta)})}getGroupMemberList(s){return pA(this,void 0,void 0,function*(){const n="getGroupMemberList",{groupID:g,offset:u=0,count:E=100,role:m="",filter:D=""}=s,M=Yi.getLocalGroup(g),T=E>100?100:E,P={groupID:g,offset:u,limit:T,memberRoleFilter:ju.includes(m)?[m]:void 0,memberInfoFilter:fm};try{const W=yield function(ne,_i){return pA(this,void 0,void 0,function*(){const{isCommunity:Ti}=_i.common,{groupID:Lt,offset:Ni,limit:cs,memberRoleFilter:Me,memberInfoFilter:mt}=ne,UA={GroupId:Lt,Limit:cs,MemberRoleFilter:Me,MemberInfoFilter:mt};return Ti({groupID:Lt})?UA.Next=String(Ni):UA.Offset=Ni,_i.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_member_info",data:UA})})}(P,this._core),{MemberList:iA,MemberNum:EA,Next:RA}=W||{},kA=`${this._name}.${n} ok, totalMemberCount:${EA} next:${RA}`,{utils:{isArray:xA,isEmpty:LA},common:{isCommunity:SA}}=this._core;if(M&&(M.memberCount=EA),!xA(iA)||iA.length===0)return dn({memberList:[],offset:0},{message:kA});let OA=u+T;SA({groupID:g})&&(OA=LA(RA)?0:RA),iA.lengthD.userID),u=yield(n=this._core.user.userProfile)===null||n===void 0?void 0:n.getUserProfile({userIDList:g}),E=u?.data||[],m=new Map(E.map(D=>[D.userID,D]));return s.forEach(D=>{if(m.has(D.userID)){const{nick:M="",avatar:T=""}=m.get(D.userID);D.nick=M,D.avatar=T}}),s})}_generateGroupMember(s){const n=[];for(let g=0,u=s.length;g50&&(T.warn("getGroupMemberProfile",`${this._name}.${n} userIDList length:${u.length} exceeds limit 50`),u.splice(50));const P=`userIDList length:${u.length} groupID:${g}`;try{const W=yield function(kA,xA){return pA(this,void 0,void 0,function*(){const{groupID:LA,userIDList:SA,memberInfoFilter:OA,memberCustomFieldFilter:JA}=kA,ae={GroupId:LA,Member_List_Account:SA,MemberInfoFilter:OA,AppDefinedDataFilter_GroupMember:JA};return xA.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_specified_group_member_info",data:ae})})}({groupID:g,userIDList:u,memberCustomFieldFilter:E,memberInfoFilter:[...fm]},this._core),{MemberList:iA}=W||{};if(!M(iA)||iA.length===0)return dn({memberList:[]});let EA=this._convertMemberInfo(iA);EA=yield this._getMemberAvatarAndNick(EA);const RA=this._generateGroupMember(EA);return dn({memberList:RA},{message:P})}catch(W){throw new D.ChatError({functionName:n,code:W?.errorCode,message:W?.errorInfo,moreMessage:P})}})}_convertMemberInfo(s){const n=[];for(let g=0,u=s.length;gD.userID),u=yield(n=this._core.user.userProfile)===null||n===void 0?void 0:n.getUserProfile({userIDList:g}),E=u?.data||[],m=new Map(E.map(D=>[D.userID,D]));return s.forEach(D=>{if(m.has(D.userID)){const{nick:M="",avatar:T=""}=m.get(D.userID);D.nick=M,D.avatar=T}}),s})}_generateGroupMember(s){const n=[];for(let g=0,u=s.length;g({Member_Account:M}));try{const M=yield function(RA,kA){return pA(this,void 0,void 0,function*(){const{groupID:xA,userIDList:LA}=RA,SA={GroupId:xA,MemberList:LA};return kA.common.buildAndSendPacket({servcmd:"group_open_http_svc.add_group_member",data:SA})})}({groupID:g,userIDList:D},this._core),{MemberList:T=[]}=M||{},{failureUserIDList:P,successUserIDList:W,existedUserIDList:iA,overLimitUserIDList:EA}=this._handleResult(T);return dn({failureUserIDList:P,successUserIDList:W,existedUserIDList:iA,overLimitUserIDList:EA,group:E},{message:` groupID:${g} successUserIDList:${W} failureUserIDList:${P} existedUserIDList:${iA} overLimitUserIDList:${EA}`})}catch(M){throw new m.ChatError({functionName:n,code:M?.errorCode,message:M?.errorInfo})}})}_handleResult(s){const n=[],g=[],u=[],E=[];return s.forEach(m=>{const{Result:D,Member_Account:M}=m;D===ym?n.push(M):D===Dm?g.push(M):D===Sm?u.push(M):D===cD&&E.push(M)}),{failureUserIDList:n,successUserIDList:g,existedUserIDList:u,overLimitUserIDList:E}}},Rd=new class{constructor(){this._name="DeleteGroupMember"}init(s,n){this._core=s;const{helper:g}=s;g.registerApi({apiName:"deleteGroupMember",context:this,matcher:()=>!n.getInstalledSubPlugins().includes(ta)})}deleteGroupMember(s){return pA(this,void 0,void 0,function*(){const n="deleteGroupMember",{groupID:g,userIDList:u}=s,E=Yi.getLocalGroup(g),{helper:m,utils:{isUndefined:D},ssoLog:M}=this._core;if(D(E))throw new m.ChatError({functionName:n,code:ST});u.length>20&&(M.warn("deleteGroupMember",`${this._name}.${n} userIDList length:${u.length} exceeds limit 20`),u.splice(20));try{return yield function(T,P){return pA(this,void 0,void 0,function*(){const{groupID:W,userIDList:iA,reason:EA}=T,RA={GroupId:W,MemberToDel_Account:iA,Reason:EA};return P.common.buildAndSendPacket({servcmd:"group_open_http_svc.delete_group_member",data:RA})})}({groupID:g,userIDList:u},this._core),dn({group:E,userIDList:u},{message:`groupID:${g} userIDList length:${u.length}`})}catch(T){throw new m.ChatError({functionName:n,code:T?.errorCode,message:T?.errorInfo})}})}},jv=new class{constructor(){this._name="SetGroupMemberMuteTime"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setGroupMemberMuteTime",context:this})}setGroupMemberMuteTime(s){return pA(this,void 0,void 0,function*(){const{helper:n}=this._core,{groupID:g,userID:u,muteTime:E}=s,m=` groupID:${g} userID:${u} muteTime:${E}`;this._preCheckSettingMuteParams(s);try{yield lB(s,this._core);const D=Yi.getLocalGroup(g),M=new DC({userID:u,muteTime:E});return dn({group:D,member:M},{message:m})}catch(D){throw new n.ChatError({functionName:"setGroupMemberMuteTime",code:D?.errorCode,message:D?.errorInfo,moreMessage:m})}})}_preCheckSettingMuteParams(s){const{userID:n}=s,{store:g,helper:u}=this._core;if(n===g.get("login").userId)throw new u.ChatError({functionName:"setGroupMemberMuteTime",code:QD})}},LQ=new class{constructor(){this._name="SetGroupMemberRole"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setGroupMemberRole",context:this})}setGroupMemberRole(s){return pA(this,void 0,void 0,function*(){const n="setGroupMemberRole",{helper:g}=this._core,{groupID:u,userID:E,role:m}=s,D=`${this._name}.${n} ok, groupID:${u} userID:${E} role:${m}`;this._preCheckSettingRoleParams(s);try{yield lB(s,this._core);const M=Yi.getLocalGroup(u),T=new DC({userID:E,role:m});return dn({group:M,member:T},{message:D})}catch(M){throw new g.ChatError({functionName:n,code:M?.errorCode,message:M?.errorInfo,moreMessage:D})}})}_preCheckSettingRoleParams(s){var n;const{groupID:g,userID:u,role:E}=s,{store:m,helper:D,OuterConstant:M,common:{isCommunity:T}}=this._core,P=Yi.getLocalGroup(g);if(((n=P?.selfInfo)===null||n===void 0?void 0:n.role)!==M.GRP_MBR_ROLE_OWNER)throw new D.ChatError({functionName:"setGroupMemberRole",code:RT});if(u===m.get("login").userId)throw new D.ChatError({functionName:"setGroupMemberRole",code:Yv});const W=[...ju];if(T({groupID:g})&&W.push(M.GRP_MBR_ROLE_CUSTOM),!W.includes(E))throw new D.ChatError({functionName:"setGroupMemberRole",code:wm})}},fD=new class{constructor(){this._name="SetGroupMemberNameCard"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setGroupMemberNameCard",context:this})}setGroupMemberNameCard(s){return pA(this,void 0,void 0,function*(){var n;const g="setGroupMemberNameCard",{helper:u,common:{getCurrentUserID:E}}=this._core,{groupID:m,userID:D=E(),nameCard:M}=s,T=`${this._name}.${g} ok, groupID:${m} userID:${D} nameCard:${M}`;this._preCheckSettingNameCardParams(s);try{yield lB({groupID:m,userID:D,nameCard:M},this._core);const W=Yi.getLocalGroup(m);D===((n=W?.selfInfo)===null||n===void 0?void 0:n.userID)&&(W.updateSelfInfo({nameCard:M}),Yi.emitGroupListUpdate(),Yi.updateConversationGroupProfile(m));const iA=new DC({userID:D,nameCard:M});return dn({group:W,member:iA},{message:T})}catch(P){throw new u.ChatError({functionName:g,code:P?.errorCode,message:P?.errorInfo,moreMessage:T})}})}_preCheckSettingNameCardParams(s){const{groupID:n}=s,{helper:g}=this._core,u=Yi.getLocalGroup(n);if(Sd(u?.type))throw new g.ChatError({functionName:"setGroupMemberNameCard",code:_m})}},bm=new class{constructor(){this._name="SetGroupMemberCustomField"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setGroupMemberCustomField",context:this})}setGroupMemberCustomField(s){return pA(this,void 0,void 0,function*(){const n="setGroupMemberCustomField",{helper:g,common:{getCurrentUserID:u}}=this._core;this._preCheckSettingCustomFiledParams(s);const{groupID:E,userID:m=u(),memberCustomField:D}=s,M=`${this._name}.${n} ok, groupID:${E}userID:${m} memberCustomField:${JSON.stringify(D)}`;try{yield lB({groupID:E,userID:m,memberCustomField:D},this._core);const P=Yi.getLocalGroup(E),W=new DC({userID:m,memberCustomField:D});return dn({group:P,member:W},{message:M})}catch(T){throw new g.ChatError({functionName:n,code:T?.errorCode,message:T?.errorInfo,moreMessage:M})}})}_preCheckSettingCustomFiledParams(s){const{groupID:n}=s,{helper:g}=this._core,u=Yi.getLocalGroup(n);if(Sd(u?.type))throw new g.ChatError({functionName:"setGroupMemberCustomField",code:_m})}},Wv=new class{init(s,n){s.ssoLog.debug("GroupMember.init"),mD.init(s,n),kQ.init(s),vd.init(s),Rd.init(s,n),jv.init(s),LQ.init(s),fD.init(s),bm.init(s)}getGroupMemberList(s){return mD.getGroupMemberList(s)}deleteGroupMember(s){return Rd.deleteGroupMember(s)}},GT=new class{init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"getGroupCounters",context:this})}getGroupCounters(s){return pA(this,void 0,void 0,function*(){const n="getGroupCounters";try{Nm(n,sc);const{groupID:g,keyList:u=[]}=s,{avChatRoomKey:E,lastUpdateTime:m}=nc.getLocalGroupCounters(g);if(!(Date.now()-m>=this._getExpireTime()))return{code:0,data:{counters:nc.getLocalCounters(g,u)}};const D=yield function(P){return pA(this,void 0,void 0,function*(){const{groupID:W,GroupCounterKeys:iA,avChatRoomKey:EA}=P,{common:RA}=Wn.core,kA={GroupId:W,keyList:iA,BytesKey:EA};return RA.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_counter",data:kA})})}({groupID:g,keyList:u,avChatRoomKey:E}),{GroupCounter:M=[],GroupCounterSeq:T}=D;return nc.updateLocalGroupCounters({groupID:g,counterList:M,groupCounterSeq:T}),{code:0,data:{counters:nc.getLocalCounters(g,u)}}}catch(g){yC(n,g)}})}_getExpireTime(){const{store:s,utils:{isUndefined:n}}=this._core,g=s.get("cloudConfig")||{},{grp_counter_expire_time:u}=g;return n(u)?3e4:Number(u)}},km=new class{init(s){const{helper:n}=s;n.registerApi({apiName:"setGroupCounters",context:this}),n.registerApi({apiName:"increaseGroupCounter",context:this}),n.registerApi({apiName:"decreaseGroupCounter",context:this})}setGroupCounters(s){return pA(this,void 0,void 0,function*(){return this._handleCounterOperation(Ku,s)})}increaseGroupCounter(s){return pA(this,void 0,void 0,function*(){return this._handleCounterOperation(mm,s)})}decreaseGroupCounter(s){return pA(this,void 0,void 0,function*(){return this._handleCounterOperation(Ri,s)})}_handleCounterOperation(s,n){return pA(this,void 0,void 0,function*(){const g=`${s}GroupCounter`;try{Nm(g,sc);const{groupID:u,key:E,value:m=0}=n,{avChatRoomKey:D}=nc.getLocalGroupCounters(u),M=s===Ku?this._convertObjectToList(n.counters):[{Key:E,Value:m}],T=yield this._updateGroupCounters({groupID:u,counterList:M,avChatRoomKey:D,mode:s});return nc.setGroupCounters(u,T),{code:0,data:{counters:T}}}catch(u){yC(g,u)}})}_updateGroupCounters(s){return pA(this,void 0,void 0,function*(){const n=yield function(E){const{groupID:m,counterList:D,mode:M,avChatRoomKey:T}=E,{common:P}=Wn.core,W={GroupId:m,GroupCounter:D,Mode:M,BytesKey:T};return P.buildAndSendPacket({servcmd:"group_open_http_svc.update_group_counter",data:W})}(s),{GroupCounter:g=[]}=n,u={};return g.forEach(E=>{const{Key:m,Value:D=0}=E;u[m]=D}),u})}_convertObjectToList(s){return Object.entries(s).map(([n,g])=>({Key:n,Value:g||0}))}},IB=new class{init(s){this._core=s,GT.init(s),km.init(s)}isGroupCounterUpdated(s){const{elements:{groupCounterInfo:n}}=s,{utils:{isEmpty:g}}=this._core;return!g(n)}handleGroupCounterUpdated(s){const{to:n,elements:{groupCounterInfo:g}}=s;g.forEach(u=>{const{type:E,groupCounterSeq:m,counterList:D=[]}=u;E!==si&&E!==on||this._processAndNotifyCounterUpdate(n,m,D),E===yo&&nc.deleteLocalGroupCounters({groupID:n,groupCounterSeq:m,counterList:D})})}_processAndNotifyCounterUpdate(s,n,g){const{OuterEvent:u,notificationCenter:E}=this._core;nc.updateLocalGroupCounters({groupID:s,groupCounterSeq:n,counterList:g}),g.forEach(({Key:m,Value:D=0})=>{E.emitOuterEvent(u.GROUP_COUNTER_UPDATED,{name:u.GROUP_COUNTER_UPDATED,data:{groupID:s,key:m,value:D}})})}reset(){nc.reset()}},Lm=new class{constructor(){this._name="InitGroupAttributes"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"initGroupAttributes",context:this})}initGroupAttributes(s){return pA(this,void 0,void 0,function*(){const{groupID:n,groupAttributes:g}=s,{serverMainSequence:u,avChatRoomKey:E}=zs.getGroupAttributesCache(n),m=zs.convertKeyValueMapToList(g);try{const D=yield function(W,iA){return pA(this,void 0,void 0,function*(){const{groupID:EA,mainSequence:RA,groupAttributeList:kA,avChatRoomKey:xA}=W,LA={GroupId:EA,AttrMainSeq:RA,GroupAttr:kA,BytesKey:xA,AttrControl:["RaceConflict"]};return iA.common.buildAndSendPacket({servcmd:"group_open_http_svc.set_group_attr",data:LA})})}({groupID:n,avChatRoomKey:E,groupAttributeList:m,mainSequence:u},this._core),{AttrMainSeq:M,GroupAttr:T}=D||{},P=T.map(W=>{const{Key:iA,seq:EA}=W;return{key:iA,value:g[iA],sequence:EA}});return zs.saveGroupAttributesCacheValuesCopy(n),zs.refreshGroupAttributesCache({groupID:n,serverMainSequence:M,groupAttributeList:P,operation:lD}),zs.emitGroupAttributesUpdated(n),dn({groupAttributes:g},{message:` groupID:${n} serverMainSequence:${M}`})}catch(D){throw new this._core.helper.ChatError({functionName:"initGroupAttributes",code:D?.errorCode,message:D?.errorInfo})}})}},bT=new class{constructor(){this._name="SetGroupAttributes"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"setGroupAttributes",context:this}),n.registerExperimentalAPI("setRichStatus",this)}setGroupAttributes(s){return pA(this,void 0,void 0,function*(){const{groupID:n,groupAttributes:g,richStatusMode:u}=s,{serverMainSequence:E,avChatRoomKey:m,values:D}=zs.getGroupAttributesCache(n),M=zs.convertKeyValueMapToList(g).map(T=>{var P;const{key:W,value:iA}=T;return{key:W,value:iA,seq:((P=D.get(T.key))===null||P===void 0?void 0:P.sequence)||0}});try{const T=yield function(EA,RA){return pA(this,void 0,void 0,function*(){const{groupID:kA,mainSequence:xA,groupAttributeList:LA,avChatRoomKey:SA,richStatusMode:OA}=EA,JA={GroupId:kA,AttrMainSeq:xA,GroupAttr:LA,BytesKey:SA,AttrControl:["RaceConflict"],AllowRoomEngineOpt:OA};return RA.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_attr",data:JA})})}({groupID:n,avChatRoomKey:m,groupAttributeList:M,mainSequence:E,richStatusMode:u},this._core),{AttrMainSeq:P,GroupAttr:W}=T||{},iA=W.map(EA=>{const{Key:RA,seq:kA}=EA;return{key:RA,value:g[RA],sequence:kA}});return zs.saveGroupAttributesCacheValuesCopy(n),zs.refreshGroupAttributesCache({groupID:n,serverMainSequence:P,groupAttributeList:iA,operation:Fv}),zs.emitGroupAttributesUpdated(n),dn({groupAttributes:g},{message:` groupID:${n} serverMainSequence:${P}`})}catch(T){throw new this._core.helper.ChatError({functionName:"setGroupAttributes",code:T?.errorCode,message:T?.errorInfo})}})}setRichStatus(s){return pA(this,void 0,void 0,function*(){const{groupID:n,richStatus:g}=s;return this.setGroupAttributes({groupID:n,groupAttributes:g,richStatusMode:!0})})}},yD=new class{constructor(){this._name="DeleteGroupAttributes"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"deleteGroupAttributes",context:this}),n.registerExperimentalAPI("deleteRichStatus",this)}deleteGroupAttributes(s){return pA(this,void 0,void 0,function*(){const n="deleteGroupAttributes",{groupID:g,keyList:u=[],richStatusMode:E}=s;try{let m;m=u.length===0?yield this._clearGroupAttributes(g,{richStatusMode:E}):yield this._deleteGroupAttributes(g,{keyList:u,richStatusMode:E});const{resultList:D,serverMainSequence:M,operation:T,groupAttributeList:P}=m||{},W=`${this._name}.${n} ok. groupID:${g} operation: ${T}`;return zs.saveGroupAttributesCacheValuesCopy(g),zs.refreshGroupAttributesCache({groupID:g,serverMainSequence:M,groupAttributeList:P,operation:T}),zs.emitGroupAttributesUpdated(g),dn({keyList:D},{message:W})}catch(m){throw new this._core.helper.ChatError({functionName:n,code:m?.errorCode,message:m?.errorInfo})}})}deleteRichStatus(s){return pA(this,void 0,void 0,function*(){return this.deleteGroupAttributes(Object.assign(Object.assign({},s),{richStatusMode:!0}))})}_deleteGroupAttributes(s,n){return pA(this,void 0,void 0,function*(){const{serverMainSequence:g,avChatRoomKey:u,values:E}=zs.getGroupAttributesCache(s),{keyList:m,richStatusMode:D}=n,M=[],T=[];m.forEach(iA=>{if(E.has(iA)){const{sequence:EA=0}=E.get(iA)||{};T.push({key:iA,seq:EA}),M.push(iA)}});const P=yield function(iA,EA){return pA(this,void 0,void 0,function*(){const{groupID:RA,mainSequence:kA,groupAttributeList:xA,avChatRoomKey:LA,richStatusMode:SA}=iA,OA={GroupId:RA,AttrMainSeq:kA,GroupAttr:xA,BytesKey:LA,AttrControl:["RaceConflict"],AllowRoomEngineOpt:SA};return EA.common.buildAndSendPacket({servcmd:"group_open_http_svc.delete_group_attr",data:OA})})}({groupID:s,avChatRoomKey:u,groupAttributeList:T,mainSequence:g,richStatusMode:D},this._core),{AttrMainSeq:W}=P||{};return{resultList:M,serverMainSequence:W,groupAttributeList:T,operation:uD}})}_clearGroupAttributes(s,n){return pA(this,void 0,void 0,function*(){const{serverMainSequence:g,avChatRoomKey:u,values:E}=zs.getGroupAttributesCache(s),{richStatusMode:m}=n||{},D=[...E.keys()],M=yield function(P,W){return pA(this,void 0,void 0,function*(){const{groupID:iA,mainSequence:EA,avChatRoomKey:RA,richStatusMode:kA}=P,xA={GroupId:iA,AttrMainSeq:EA,BytesKey:RA,AttrControl:["RaceConflict"],AllowRoomEngineOpt:kA};return W.common.buildAndSendPacket({servcmd:"group_open_http_svc.clear_group_attr",data:xA})})}({groupID:s,avChatRoomKey:u,mainSequence:g,richStatusMode:m},this._core),{AttrMainSeq:T}=M||{};return{resultList:D,serverMainSequence:T,operation:ID}})}},DD=new class{constructor(){this._name="GetGroupAttributes"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"getGroupAttributes",context:this}),n.registerExperimentalAPI("getRichStatus",this,"getGroupAttributes")}getGroupAttributes(s){return pA(this,void 0,void 0,function*(){const{groupID:n}=s,{avChatRoomKey:g,lastUpdateTime:u,localMainSequence:E,serverMainSequence:m}=zs.getGroupAttributesCache(n),{helper:{ChatError:D}}=this._core,M=`groupID:${n} localMainSequence:${E} serverMainSequence:${m} keyList:${s.keyList}`;if(Date.now()-u>=3e4||E{const{key:iA,value:EA,seq:RA}=W;return{key:iA,value:EA,sequence:RA}});return zs.refreshGroupAttributesCache({groupID:u,serverMainSequence:M,groupAttributeList:P,operation:Ov}),{serverGroupAttributeList:T}})}},UQ=new class{init(s){s.ssoLog.debug("GroupAttribute.init"),Lm.init(s),bT.init(s),yD.init(s),DD.init(s),zs.init(s)}isGroupAttributesUpdated(s){return zs.isGroupAttributesUpdated(s)}handleGroupAttributesUpdated(s){const{to:n,elements:{newGroupProfile:g}}=s,{groupAttributeOption:u}=g,{serverMainSequence:E,withChangedAttributeInfo:m}=u,{localMainSequence:D}=zs.getGroupAttributesCache(n),M=E-D;if(console.log(`GroupAttribute.handleGroupAttributesUpdated groupID:${n} withChangedAttributeInfo:${m} diffSequence:${M}`),M!==0)if(zs.saveGroupAttributesCacheValuesCopy(n),m!==1||M!==1){if(zs.hasGroupAttributesCache(n)){const{avChatRoomKey:T}=zs.getGroupAttributesCache(n);DD.getGroupAttributesFromServer({groupID:n,avChatRoomKey:T}).then(()=>{zs.emitGroupAttributesUpdated(n)}).catch(()=>{})}}else zs.handleGroupAttributesUpdated({groupID:n,groupAttributeOption:u})}reset(){zs.reset()}};function HE(s,n="tips"){const{ClientSeq:g,From_Account:u,MsgClientTime:E,MsgPriority:m,MsgRandom:D,MsgSeq:M,MsgTimeStamp:T,TinyId:P,ToGroupId:W,GroupInfo:iA,MsgBody:EA}=s,RA=function(kA){const{GroupCode:xA,GroupId:LA,GroupName:SA,GroupType:OA,MsgFrom_AccountExtraInfo:JA,From_Account:ae,To_Account:ne}=kA;return{groupCode:xA,groupID:LA,groupName:SA,type:OA,messageFromAccountExtraInformation:JA,from:ae,to:ne}}(iA);return{clientSequence:g,from:u,clientTime:E,priority:m,random:D,sequence:M,time:T,tinyID:P,to:W,groupProfile:RA,elements:n==="tips"?Zu(EA):dh(EA)}}function Zu(s){const n={};return Object.keys(s).forEach(g=>{var u,E;switch(g){case"MemberNum":n.memberCount=s[g];break;case"OpType":n.operationType=s[g];break;case"Operator_Account":n.operatorID=s[g];break;case"List_Account":n.userIDList=s[g];break;case"MsgMemberExtraInfo":n.memberInfoList=(u=s[g])===null||u===void 0?void 0:u.map(m=>SD(m));break;case"MsgOperatorMemberExtraInfo":n.operatorInfo=SD(s[g]);break;case"MsgGroupNewInfo":n.newGroupProfile=function(m){const D={};return Object.keys(m).forEach(M=>{switch(M){case"GroupIntroduction":D.introduction=m[M];break;case"GroupName":D.groupName=m[M];break;case"GroupFaceUrl":D.avatar=m[M];break;case"GroupNotification":D.notification=m[M];break;case"ApplyJoinOption":D.joinOption=m[M];break;case"InviteJoinOption":D.inviteOption=m[M];break;case"ShutupAll":D.muteAllMembers=m[M];break;case"Owner_Account":D.ownerID=m[M];break;case"GroupAttrOption":D.groupAttributeOption=function(P){const{BytesChangedKeys:W,GroupAttrSeq:iA,OpType:EA,PushChangedAttrValFlag:RA,GroupAttrInfo:kA}=P,xA=kA.map(LA=>{const{Key:SA,Val:OA,SubKeySeq:JA}=LA;return{key:SA,value:OA,sequence:JA}});return{changedKeyList:W,groupAttributeList:xA,serverMainSequence:iA,operation:EA,withChangedAttributeInfo:RA}}(m[M]);break;case"MsgAppDefinedData":D.groupCustomField=(T=m[M])==null?void 0:T.map(P=>({key:P.Key,value:P.Value}));break;case"InviteOption":D.inviteOption=_T[m[M]]||m[M]}var T}),D}(s[g]);break;case"MsgMemberInfo":n.msgMemberInfo=(E=s[g])===null||E===void 0?void 0:E.map(m=>function(D){const{ShutupTime:M,User_Account:T}=D;return{muteTime:M,userID:T}}(m));break;case"OnlineMemberInfo":n.onlineMemberInfo=function(m){const{ExpireTime:D,OnlineMemberNum:M}=m;return{expireTime:D,onlineMemberNum:M}}(s[g]);break;case"GroupCounterInfo":n.groupCounterInfo=function(m){return m.map(D=>{const{GroupCounterSeq:M,GroupCounter:T,Type:P}=D;return{type:P,groupCounterSeq:M,counterList:T}})}(s[g])}}),n}function SD(s){const{ImageUrl:n,NickName:g,Role:u,UserId:E}=s;return{avatar:n,nick:g,role:u,userID:E}}function dh(s){const n={};return Object.keys(s).forEach(g=>{switch(g){case"MsgKey":n.messageKey=s[g];break;case"Operator_Account":n.operatorID=s[g];break;case"ReportType":n.operationType=s[g];break;case"Authentication":n.authentication=s[g];break;case"MsgFlag":n.messageRemindType=s[g];break;case"UserDefinedField":n.userDefinedField=s[g];break;case"RemarkInfo":n.remarkInfo=s[g];break;case"BanDuration":n.duration=s[g];break;case"MuteTime":n.muteTime=s[g];break;case"MsgMemberExtraInfoList":n.inviteeInfoList=(u=s[g]||[])==null?void 0:u.map(E=>{const{UserId:m,ImageUrl:D,NickName:M}=E;return{userID:m,avatar:D,nick:M}});break;case"MemberList_Account":n.inviteeList=s[g]}var u}),n}class Um{constructor(n){this.type=Wn.core.OuterConstant.MSG_GRP_TIP,this.content={},this._initContent(n)}static parseServerPushElement(n){const g=Zu(n);return new Um(g)}_initContent(n){Object.keys(n).forEach(g=>{switch(g){case"groupProfile":this._initGroupProfile(n[g]);break;case"operatorInfo":this._initOperatorInfo(n[g]);break;case"memberInfoList":case"msgMemberInfo":this._updateMemberList(n[g]);break;case"newGroupProfile":this._initNewGroupProfile(n[g]);break;case"memberExtraInfo":case"remarkInfo":case"onlineMemberInfo":break;default:this.content[g]=n[g]}}),this.content.userIDList||(this.content.userIDList=[this.content.operatorID])}_initGroupProfile(n){this.content.groupProfile={};const g=Object.keys(n);for(let u=0;u{n.forEach(u=>{g.userID===u.userID&&Object.assign(g,u)})}):this.content.memberList=n}_initNewGroupProfile(n){this.content.newGroupProfile={};const g=Object.keys(n);for(let u=0;u0&&this._handleGroupTipMessage(g),{conversationUpdateFieldList:u,messageList:g}}_emitGroupTipsEvent(s){var n;const{constants:{WORKFLOW_STEP:g}}=this._core,{messageList:u=[]}=((n=s?.result)===null||n===void 0?void 0:n[g.HANDLE_GROUP_TIPS_NOTIFICATION])||{};if(u.length>0){const{notificationCenter:E,OuterEvent:m}=this._core;E.emitOuterEvent(m.MESSAGE_RECEIVED,{name:m.MESSAGE_RECEIVED,data:u})}}_handleGroupTips(s,n=!0){const{Event:g,GroupTips:u}=s,E=new Map,m=[],D=[];for(let M=0,T=u.length;M{const{operationType:u}=g.payload;switch(u){case n.JOINED:this._handleNewMemberJoined(g);break;case n.QUITTED:this._handleMemberQuitted(g);break;case n.KICKED:this._handleMemberKicked(g);break;case n.GROUP_PROFILE_UPDATED:this._handleGroupProfileUpdated(g);break;case n.ADMIN_SET:this._handleMemberGrantAdmin(g);break;case n.ADMIN_CANCELED:this._handleMemberRevokeAdmin(g)}})}_handleNewMemberJoined(s){this._handleGroupMemberCountUpdated(s)}_handleMemberQuitted(s){this._handleGroupMemberCountUpdated(s)}_handleMemberKicked(s){this._handleGroupMemberCountUpdated(s)}_handleGroupProfileUpdated(s){var n;const{newGroupProfile:g,groupProfile:u,operatorInfo:E}=s.payload,{groupID:m}=u,D=Yi.getLocalGroup(m);Object.keys(g).forEach(T=>{switch(T){case"ownerID":this._handleGroupOwnerChanged(m,g);break;case"groupName":D.name=g[T];break;case"groupCustomField":Array.isArray(D[T])&&Array.isArray(g[T])?Tm(D[T],g[T]):D[T]=g[T];break;default:D[T]=g[T]}});const{utils:{isUndefined:M}}=this._core;M(E)||((n=D?.selfInfo)===null||n===void 0?void 0:n.userID)!==E.userID||Object.keys(E).forEach(T=>{T==="nameCard"&&D.updateSelfInfo({nameCard:E[T]}),T==="role"&&this._updateSelfRole(D,E[T])}),Yi.emitGroupListUpdate(),Yi.updateConversationGroupProfile(m)}_handleGroupOwnerChanged(s,n){const{common:g,OuterConstant:u}=this._core,E=Yi.getLocalGroup(s),m=g.getCurrentUserID(),{ownerID:D}=n;m===D&&E.updateGroup({ownerID:D,selfInfo:{role:u.GRP_MBR_ROLE_OWNER}})}_updateSelfRole(s,n){const{OuterConstant:g}=this._core;let u=g.GRP_MBR_ROLE_MEMBER;n===pT?u=g.GRP_MBR_ROLE_OWNER:n===dD&&(u=g.GRP_MBR_ROLE_ADMIN),s.updateSelfInfo({role:u})}_handleGroupMemberCountUpdated(s){const{memberCount:n,groupProfile:{groupID:g}}=s.payload,u=Yi.getLocalGroup(g),{utils:{isNumber:E}}=this._core;u&&E(n)&&u.memberCount!==n&&(u.memberCount=n,Yi.emitGroupListUpdate(),Yi.updateConversationGroupProfile(g))}_handleGroupTipsRecover(s){const{utils:{isArray:n}}=this._core,{groupTipList:g}=s?.result||{};n(g)&&g.forEach(u=>{const{messageList:E}=this._handleGroupTips({Event:u.Event,GroupTips:[u]},!1);this._handleGroupTipMessage(E)})}_handleMemberGrantAdmin(s){const{OuterConstant:n}=this._core,{groupProfile:g,userIDList:u}=s.payload,E=this._core.common.getCurrentUserID(),{groupID:m}=g,D=Yi.getLocalGroup(m);D&&u.includes(E)&&(D.updateSelfInfo({role:n.GRP_MBR_ROLE_ADMIN}),Yi.emitGroupListUpdate(),Yi.updateConversationGroupProfile(m))}_handleMemberRevokeAdmin(s){const{OuterConstant:n}=this._core,{groupProfile:g,userIDList:u}=s.payload,E=this._core.common.getCurrentUserID(),{groupID:m}=g,D=Yi.getLocalGroup(m);D&&u.includes(E)&&(D.updateSelfInfo({role:n.GRP_MBR_ROLE_MEMBER}),Yi.emitGroupListUpdate(),Yi.updateConversationGroupProfile(m))}};class FQ{constructor(n){this.type=Wn.core.OuterConstant.MSG_GRP_SYS_NOTICE,this.content={},this._initContent(n)}static parseServerPushElement(n){const g=dh(n);return new FQ(g)}_initContent(n){Object.keys(n).forEach(g=>{switch(g){case"remarkInfo":this.content.handleMessage=n[g];break;case"groupProfile":this._initGroupProfile(n[g]);break;case"memberInfoList":break;default:this.content[g]=n[g]}})}_initGroupProfile(n){this.content.groupProfile={};const g=Object.keys(n);for(let u=0;u0&&this._handleGroupSysTemMessage(g,E),g===!0&&E.length>0&&m.emitOuterEvent(D.MESSAGE_RECEIVED,{name:D.MESSAGE_RECEIVED,data:E})}_handleGroupSystemNotification(s,n){const g=[];let u={};for(let E=0;E0?[u]:[],messageList:g}}_assembleMessage(s){const{message:{messageFactory:n},OuterConstant:g,utils:{randomInt:u}}=this._core;s.flow="in",s.conversationType=g.CONV_SYSTEM,s.conversationSubType=s.groupProfile.type,s.conversationID=g.CONV_SYSTEM;const E=n.createMessage(s),m=new FQ(Object.assign(Object.assign({},s.elements),{groupProfile:Object.assign({},s.groupProfile)}));E.setElement(m),E.isSystemMessage=!0;const D=E.sequence===1&&E.random===1,M=E.sequence===2&&E.random===2;return(D||M)&&(E.sequence=u(),E.random=u(),E.generateMessageID()),E}_handleConversationOptions(s,n){const{OuterConstant:g}=this._core,u={conversationID:g.CONV_SYSTEM,unreadCount:0,type:g.CONV_SYSTEM,subType:s.conversationSubType,lastMessage:null};return n&&u.unreadCount++,u}_handleGroupSysTemMessage(s,n){s&&n.forEach(g=>{const{operationType:u}=g.payload;switch(u){case fT:this._handleGroupJoinResult(g);break;case xv:this._handleMemberKicked(g);break;case yT:this._handleGroupDismissed(g);break;case DT:this._handleGroupInvitedResult(g);break;case CD:this._handleGroupQuitResult(g);break;case TQ:this._handleMessageRemindTypeSynced(g);break;case Mm:this._handleAVChatRoomMemberBanned(g)}})}_handleGroupJoinResult(s){const{groupProfile:n}=s.payload,{groupID:g,type:u}=n,E=Yi.hasLocalGroup(g);this._core.ssoLog.debug("_handleGroupJoinResult",` groupID:${g} type:${u} hasLocalGroup:${E}`),E||Sd(u)||(Yi.updateLocalGroup([Object.assign({},n)]),Yi.emitGroupListUpdate())}_handleMemberKicked(s){const{groupProfile:{groupID:n,type:g}}=s.payload;Yi.hasLocalGroup(n)&&this._deleteLocalGroup(n,g),this._updateConversationProfile(n,{unreadCount:0})}_handleGroupDismissed(s){const{groupProfile:{groupID:n,type:g}}=s.payload;Yi.hasLocalGroup(n)&&this._deleteLocalGroup(n,g),this._updateConversationProfile(n,{unreadCount:0})}_handleGroupInvitedResult(s){const{groupProfile:n}=s.payload,{groupID:g}=n,u=Yi.hasLocalGroup(g);this._core.ssoLog.debug("_handleGroupInvitedResult",` groupID:${g} hasLocalGroup:${u}`),u||Pl.getGroupProfile({groupID:g}).then(E=>{const{data:{group:m}}=E;Yi.updateLocalGroup([Object.assign({},m)]),Yi.emitGroupListUpdate()})}_handleGroupQuitResult(s){const{groupProfile:{groupID:n,type:g}}=s.payload,u=Yi.hasLocalGroup(n);this._core.ssoLog.debug("_handleGroupQuitResult",` groupID:${n} type:${g} hasLocalGroup:${u}`),u&&this._deleteLocalGroup(n,g),this._updateConversationProfile(n,{unreadCount:0})}_handleMessageRemindTypeSynced(s){const{groupProfile:{groupID:n},messageRemindType:g}=s.payload;this._updateConversationProfile(n,{messageRemindType:g})}_handleAVChatRoomMemberBanned(s){const{groupProfile:{groupID:n,type:g}}=s.payload;this._deleteLocalGroup(n,g)}_deleteLocalGroup(s,n){if(Sd(n)){const{appStore:{conversationStore:g},OuterConstant:{CONV_GROUP:u}}=this._core;g.deleteConversation(`${u}${s}`)}Yi.deleteLocalGroup(s),Yi.emitGroupListUpdate()}_updateConversationProfile(s,n){const{appStore:{conversationStore:g},OuterConstant:{CONV_GROUP:u}}=this._core,E=`${u}${s}`;g.getConversation(E)&&g.updateConversation(E,n)}},MD=new class{init(s){this._core=s,s.ssoLog.debug("GroupNotificationHandler.init"),zv.init(s),Zv.init(s);const{notificationCenter:n,InnerEvent:g}=s,{InnerEventSubType:u}=n;n.subscribeInnerEvent(g.MESSAGE_PUSH,u.GROUP_TIPS_NOTIFICATION,this._onNewGroupTipsNotification,this),n.subscribeInnerEvent(g.MESSAGE_PUSH,u.GROUP_SYSTEM_NOTIFICATION,this._onNewGroupSystemNotification,this),n.subscribeInnerEvent(g.DESTROY,this._dispose,this)}_onNewGroupTipsNotification(s){const{common:{workflowManager:n},constants:{WORKFLOW_NAME:g}}=this._core;n.executeWorkflow(g.RECEIVE_GROUP_TIPS_NOTIFICATION,s)}_onNewGroupSystemNotification(s){Zv.onNewGroupSystemNotification(s)}_dispose(){const{notificationCenter:s,InnerEvent:n}=this._core,{InnerEventSubType:g}=s;s.unSubscribeInnerEvent(n.MESSAGE_PUSH,g.GROUP_TIPS_NOTIFICATION,this._onNewGroupTipsNotification,this),s.unSubscribeInnerEvent(n.MESSAGE_PUSH,g.GROUP_SYSTEM_NOTIFICATION,this._onNewGroupSystemNotification,this)}};const vn={required:!0,rules:["string"],allowEmpty:!1},OQ={required:!0,rules:["number"],allowEmpty:!1},wd={required:!0,rules:["array"],allowEmpty:!1},vD={required:!0,rules:["object"],allowEmpty:!1},kT={createGroup:{name:vn,type:vn},dismissGroup:[Object.assign({key:"groupID"},vn)],joinGroup:{groupID:vn,applyMessage:{required:!1,rules:["string"],allowEmpty:!0}},quitGroup:[Object.assign({key:"groupID"},vn)],searchGroupByID:[Object.assign({key:"groupID"},vn)],getGroupProfile:{groupID:vn,groupCustomFieldFilter:{required:!1,rules:["array"],allowEmpty:!0}},updateGroupProfile:{groupID:vn,muteAllMembers:{required:!1,rules:["boolean"],allowEmpty:!1}},changeGroupOwner:{groupID:vn,newOwnerID:vn},getGroupOnlineMemberCount:[Object.assign({key:"groupID"},vn)],handleGroupApplication:{handleAction:vn},getGroupMemberList:{groupID:vn},getGroupMemberProfile:{groupID:vn,userIDList:wd,memberCustomFieldFilter:{required:!1,rules:["array"],allowEmpty:!0}},addGroupMember:{groupID:vn,userIDList:wd},deleteGroupMember:{groupID:vn,userIDList:wd},setGroupMemberMuteTime:{groupID:vn,userID:vn,muteTime:Object.assign(Object.assign({},OQ),{customValidator:s=>!(s<0)||"muteTime must be a non-negative number."})},setGroupMemberRole:{groupID:vn,userID:vn,role:vn},setGroupMemberNameCard:{groupID:vn,userID:{required:!1,rules:["string"],allowEmpty:!1},nameCard:vn},setGroupMemberCustomField:{groupID:vn,userID:{required:!1,rules:["string"],allowEmpty:!1},memberCustomField:wd},markGroupMemberList:{groupID:vn,markType:Object.assign(Object.assign({},OQ),{customValidator:s=>!(s<1e3)||"markType must be greater than or equal to 1000."}),enableMark:{required:!0,rules:["boolean"],allowEmpty:!1},userIDList:wd},initGroupAttributes:{groupID:vn,groupAttributes:vD},setGroupAttributes:{groupID:vn,groupAttributes:vD},deleteGroupAttributes:{groupID:vn,keyList:Object.assign(Object.assign({},wd),{allowEmpty:!0})},getGroupAttributes:{groupID:vn,keyList:Object.assign(Object.assign({},wd),{allowEmpty:!0})},getGroupCounters:{groupID:vn,keyList:{required:!1,rules:["array"],allowEmpty:!0}},setGroupCounters:{groupID:vn,counters:vD},increaseGroupCounter:{groupID:vn,key:vn,value:OQ},decreaseGroupCounter:{groupID:vn,key:vn,value:OQ}},LT={getGroupList:!0,createGroup:!0,dismissGroup:!0,joinGroup:!0,quitGroup:!0,searchGroupByID:!0,getGroupProfile:!0,updateGroupProfile:!0,changeGroupOwner:!0,getGroupOnlineMemberCount:!0,getGroupApplicationList:!0,handleGroupApplication:!0,getGroupMemberList:!0,getGroupMemberProfile:!0,addGroupMember:!0,deleteGroupMember:!0,setGroupMemberMuteTime:!0,setGroupMemberRole:!0,setGroupMemberNameCard:!0,setGroupMemberCustomField:!0,markGroupMemberList:!0,initGroupAttributes:!0,setGroupAttributes:!0,getGroupAttributes:!0,deleteGroupAttributes:!0,getGroupCounters:!0,setGroupCounters:!0,increaseGroupCounter:!0,decreaseGroupCounter:!0};var UT=new class{constructor(){this._installedSubPlugins=[],this.groupDataHandler=Yi,this.groupAction=bQ,this.groupAttribute=UQ,this.groupMember=Wv,this.groupCounter=IB,this.name="Group"}install(s,n=[]){this._core=s,Wn.init(s),Yi.init(s),bQ.init(s,this),Wv.init(s,this),pD.init(s),IB.init(s),UQ.init(s),MD.init(s),s.helper.registerValidateConfig({auth:LT,params:kT}),this._installSubPlugins(n);const{notificationCenter:g,InnerEvent:u}=s;g.subscribeInnerEvent(u.LOGOUT,this._reset,this),g.subscribeInnerEvent(u.DESTROY,this._dispose,this)}getInstalledSubPlugins(){return this._installedSubPlugins}_installSubPlugins(s){const{utils:{isArray:n}}=this._core;s&&n(s)&&s.forEach(g=>{var u;this._installedSubPlugins.includes(g.name)||((u=g.install)===null||u===void 0||u.call(g,this._core,this),this._installedSubPlugins.push(g.name))})}_reset(){Yi.reset(),UQ.reset(),IB.reset()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.LOGOUT,this._reset,this),s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}};const uB=new class{init(s){this.core=s}},Xv="AV_MBR_LIST",FT="AV_BAN_MBR",qE={NORMAL_MESSAGE:3,GROUP_TIPS_HAS_ROAMING:4,GROUP_SYSTEM_MESSAGE:5,GROUP_TIPS_HAS_NO_ROAMING:6,BROADCAST_MESSAGE:17,MESSAGE_REVOKED:20,MESSAGE_REACTION:21,LIVE_CUSTOM_DATA:100},Ch={GROUP_DISMISSED:5,QUIT_GROUP:8,AVCHATROOM_MEMBER_BANNED:21},RD=60,wD=2603,OT=2686,PT=2688,PQ=3122;class $v{constructor(n){const{core:g,manager:u,groupID:E,getRequestParams:m,onSuccess:D,onFail:M}=n;this._name="Polling",this._core=g,this._manager=u,this._timeoutID=-1,this._isRunning=!1,this._groupID=E,this._getRequestParams=m,this._onSuccess=D,this._onFail=M}start(){this._isRunning=!0,this._request(),console.log(`${this._name}.start pollingInterval:${this._manager.getCurrentPollingInterval(this._groupID)}`)}isRunning(){return this._isRunning}_request(){return pA(this,void 0,void 0,function*(){try{const n=this._getRequestParams(this._groupID),g=yield function(E,m){return pA(this,void 0,void 0,function*(){const{longPollingKey:D,startSequence:M,startBroadcastSeq:T,simplifiedMessage:P}=E,W={Key:D,StartSeq:M,StartBroadcastSeq:T,DownsizeFlag:P,USP:1,HoldTime:90};return m.common.buildAndSendPacket({servcmd:"group_open_long_polling_http_svc.get_msg",data:W})})}(n,this._core);this._onSuccess(this._groupID,g);const u=this._manager.getCurrentPollingInterval(this._groupID);this._runNextPolling(u)}catch(n){this._onFail(this._groupID,n),this._runNextPolling(2e3)}})}_runNextPolling(n){this.isRunning()&&(this._timeoutID>-1&&clearTimeout(this._timeoutID),this._timeoutID=setTimeout(this._request.bind(this),n))}stop(){console.log(`${this._name}.stop timerID:${this._timeoutID}`),this._timeoutID>-1&&(clearTimeout(this._timeoutID),this._timeoutID=-1),this._isRunning=!1}}class hh{constructor(n){this._maxLength=n,this._map=new Map}set(n){var g;if(this._map.size>=this._maxLength){const u=((g=this._map.entries().next().value)===null||g===void 0?void 0:g[0])||"";this._map.delete(u)}this._map.set(n,1)}has(n){return this._map.has(n)}delete(n){this.has(n)&&this._map.delete(n)}clear(){this._map.clear()}}const Xu=s=>s===qE.GROUP_TIPS_HAS_NO_ROAMING||s===qE.GROUP_TIPS_HAS_ROAMING,xQ=s=>s===qE.GROUP_SYSTEM_MESSAGE;function Fm(s){const n=function(g){const{E:u,MCT:E,MR:m,MP:D,MTS:M,GId:T,MS:P,CCD:W,F_Account:iA,IsSys:EA,GInf:RA,MsgBody:kA}=g,xA=Do(g,["E","MCT","MR","MP","MTS","GId","MS","CCD","F_Account","IsSys","GInf","MsgBody"]);return Object.assign({Event:u,MsgClientTime:E,MsgRandom:m,MsgPriority:D,MsgTimeStamp:M,ToGroupId:T,MsgSeq:P,CloudCustomData:W,From_Account:iA,IsSystemMsg:EA,GroupInfo:_D(RA),MsgBody:xT(kA)},xA)}(s);return function(g){const{Event:u}=g;(Xu(u)||xQ(u))&&(g.From_Account=g.From_Account||"@TIM#SYSTEM"),E=u,(E===qE.BROADCAST_MESSAGE||(m=>m===qE.NORMAL_MESSAGE)(u))&&function(m){const{core:{OuterConstant:D}}=uB;m.CloudCustomData=m.CloudCustomData||"",m.MsgBody=m.MsgBody.map(M=>{if(M.MsgType===D.MSG_CUSTOM){const{content:T={}}=M;M.content=Object.assign({Data:"",Desc:"",Ext:""},T)}return M})}(g);var E;Xu(u)&&function(m){const{GroupJoinType:D,MsgOperatorMemberExtraInfo:M={},MsgMemberExtraInfo:T,Operator_Account:P,List_Account:W,OpType:iA}=m.MsgBody||{};typeof D=="number"||iA!==1&&iA!==2||(m.MsgBody.GroupJoinType=iA===2?0:1),T||(m.MsgBody.MsgMemberExtraInfo=W?.map(EA=>({UserId:EA}))),iA!==1||T||(m.MsgBody.MsgMemberExtraInfo=[{UserId:M.UserId}]),m.MsgBody.MsgOperatorMemberExtraInfo=Object.assign({Operator_Account:P,ImageUrl:"",NickName:""},M)}(g),xQ(u)&&function(m){const{MsgOperatorMemberExtraInfo:D={},Operator_Account:M}=m.MsgBody||{};m.MsgBody.MsgMemberExtraInfo=Object.assign({UserId:M,ImageUrl:"",NickName:""},D),m.MsgBody=Object.assign({Authentication:"",RemarkInfo:"",MsgKey:1e3*m.MsgTimeStamp},m.MsgBody),m.MsgBody=Object.keys(m.MsgBody).filter(T=>T!=="MsgOperatorMemberExtraInfo").reduce((T,P)=>Object.assign(Object.assign({},T),{[P]:m.MsgBody[P]}),{})}(g)}(n),n}function _D(s){const n=s||{},{GN:g,GT:u,F_Hd:E,F_NN:m,F_Ll:D}=n,M=Do(n,["GN","GT","F_Hd","F_NN","F_Ll"]),T=Object.assign({GroupName:g,GroupType:u},M);return E&&(T.From_AccountHeadurl=E),m&&(T.From_AccountNick=m),D&&(T.From_AccountLevel=D),T}function xT(s){let n=s;Array.isArray(s)||(n=[s]);const g=n.map(u=>{const{O_Account:E,Opt:m,L_Account:D,RT:M,UDF:T,OpInf:P,OnlineInf:W,MsgMemberExtraInfo:iA}=u,EA=Do(u,["O_Account","Opt","L_Account","RT","UDF","OpInf","OnlineInf","MsgMemberExtraInfo"]),RA=Object.assign({Operator_Account:E,OpType:m,List_Account:D,ReportType:M,UserDefinedField:T},EA);return P&&(RA.MsgOperatorMemberExtraInfo=function(kA){const{Img:xA,NN:LA}=kA,SA=Do(kA,["Img","NN"]);return Object.assign({ImageUrl:xA,NickName:LA},SA)}(P)),iA&&(RA.MsgMemberExtraInfo=function(kA){return kA?.map(xA=>{const{Img:LA,NN:SA}=xA,OA=Do(xA,["Img","NN"]);return Object.assign({ImageUrl:LA,NickName:SA},OA)})}(iA)),W&&(RA.OnlineMemberInfo=function(kA){const{ET:xA,Num:LA}=kA;return{ExpireTime:xA,OnlineMemberNum:LA}}(W)),RA});return Array.isArray(s)?g:g[0]}var Bh=new class{constructor(){this._name="MessageParser",this._sequenceList=new hh(200),this._messageIDList=new hh(100),this._broadcastMessageIDMap=new Map,this._reportMessageStackedCount=0}init(s,n){this._core=s,this._avChatRoomHandler=n}onMessageReceived(s,n,g=!1){this._sortServerMessageList({groupID:s,serverMessageList:n,isHistoryMessage:g});const u=this._handleMessageList(s,n);if(u.length===0)return;if(!g){const{appStore:{conversationStore:T},OuterConstant:{CONV_GROUP:P},common:{buildLastMessage:W}}=this._core,iA=W(u[u.length-1]);T.updateConversation(`${P}${s}`,{lastMessage:iA})}this._checkMessageStacked(u);const E=u.filter(T=>T.isModified===!0),m=u.filter(T=>T.isModified===!1),{OuterEvent:{MESSAGE_RECEIVED:D,MESSAGE_MODIFIED:M}}=this._core;E.length>0&&this._emitEvent({name:M,data:E}),m.length>0&&this._emitEvent({name:D,data:m})}_sortServerMessageList(s){const{groupID:n,serverMessageList:g,isHistoryMessage:u}=s;let E=[];this._avChatRoomHandler.isPollingSimplifiedMessage()&&!u?(g.sort((m,D)=>m.MS-D.MS),E=g.map(m=>m.MS)):(g.sort((m,D)=>m.MsgSeq-D.MsgSeq),E=g.map(m=>m.MsgSeq)),console.log(`${this._name}._sortServerMessageList groupID:${n} count:${E.length} sequenceList:${E}`),E.length=0}_handleMessageList(s,n){var g;const{message:{messageDataHandler:u,messageHelper:E}}=this._core,m=this._avChatRoomHandler.isPollingSimplifiedMessage(),D=[],M=n.length;for(let T=0;Tg===qE.MESSAGE_REVOKED)(n)?(this._handleMessageRevoked(s),null):(g=>g===qE.LIVE_CUSTOM_DATA)(n)?(this._onLiveCustomData(s),null):(g=>g===qE.MESSAGE_REACTION)(n)?null:s:(console.warn(`${this._name}.onMessageReceived unknown event:${n}`),null)}_createMessage(s){const{message:{messageFactory:n},OuterConstant:g}=this._core;let u=g.CONV_GROUP;s.elements.type===g.MSG_GRP_SYS_NOTICE&&(u=g.CONV_SYSTEM);const E=!!s.isSystemMessage,m=n.createMessage(Object.assign(Object.assign({},s),{conversationType:u,isSystemMessage:E,flow:"in"}));return m.setElement(s.elements),m}_filterDuplicateMessage(s){const{common:n}=this._core;if(!n.isUnlimitedAVChatRoom()){if(this._sequenceList.has(s.sequence))return null;this._sequenceList.set(s.sequence)}const g=this._messageIDList.has(s.ID);return g?(console.warn(`${this._name}_filterDuplicateMessageItem ID:${s.ID} has:${g}`),null):(this._messageIDList.set(s.ID),s)}_handleMessageRevoked(s){const{OuterConstant:n,OuterEvent:{MESSAGE_REVOKED:g}}=this._core,{ToGroupId:u,MsgBody:{RevokeMsgList:E},RevokerInfo:{Revoker_Account:m,Reason:D=""}}=s,M=[];E.forEach(T=>{const{TinyId:P,MsgClientTime:W,Random:iA,MsgSeq:EA}=T,RA={conversationID:`${n.CONV_GROUP}${u}`,ID:`${P}-${W}-${iA}`,revoker:m,revokeReason:D,revokerInfo:{userID:m,nick:"",avatar:""},sequence:EA};M.push(RA)}),M.length!==0&&this._emitEvent({name:g,data:M})}_onLiveCustomData(s){const{OuterEvent:{ROOM_CUSTOM_DATA_RECEIVED:n}}=this._core,{ToGroupId:g,MsgSeq:u,MsgTimeStamp:E,MsgBody:m}=s,D=m?.Content||m?.MsgContent||"";this._emitEvent({name:n,data:D}),console.log(`${this._name}._onLiveCustomData groupID:${g} sequence:${u} time:${E} data:${D}`)}_onGroupDismissed(s){this._avChatRoomHandler.reset(s)}_checkMessageStacked(s){const{length:n}=s;if(n>=100&&this._reportMessageStackedCount<5){const g=this._avChatRoomHandler.getJoinedGroups();this._core.ssoLog.info("MessageStacked",`count:${n} groupID:${g.join(",")}`),this._reportMessageStackedCount+=1}}_emitEvent(s){this._core.notificationCenter.emitOuterEvent(s.name,s)}onBroadcastMessageReceived(s){const{message:{messageHelper:n},OuterEvent:{MESSAGE_RECEIVED:g}}=this._core,u=this._avChatRoomHandler.isPollingSimplifiedMessage(),E=[],m=s.length;for(let D=0;D0&&this._emitEvent({name:g,data:E})}_updateLocalOnlineMemberCountFromTips(s){const{utils:{isEmpty:n}}=this._core,{ToGroupId:g,MsgBody:{OnlineMemberInfo:u}}=s;if(n(u))return;const{OnlineMemberNum:E=0,ExpireTime:m=RD}=u,D=Date.now();let M=this._avChatRoomHandler.getLocalOnlineMemberCount(g);n(M)?M={lastReqTime:0,lastSyncTime:0,latestUpdateTime:D,memberCount:E,expireTime:m}:(M.latestUpdateTime=D,M.memberCount=E),this._avChatRoomHandler.updateLocalOnlineMemberCount(g,M)}reset(){this._reportMessageStackedCount=0,this._sequenceList.clear(),this._messageIDList.clear(),this._broadcastMessageIDMap.clear()}};const EB=s=>{const{core:{store:n}}=uB;return(n.get("cloudConfig")||{})[s]},Qh=s=>{const{core:{utils:{isUndefined:n}}}=uB;return!n(s)},YQ=()=>{const s=EB("polling_interval");return Qh(s)?parseInt(s,10):300},dB=()=>{const s=EB("polling_simplified_msg");return Qh(s)?parseInt(s,10):0};var AR=new class{constructor(){this._name="GetAVChatRoomOnlineMemberCount"}init(s,n){this._core=s,this._parentPlugin=n;const{helper:g}=s;g.registerApi({apiName:"getGroupOnlineMemberCount",context:this,matcher:()=>n.getInstalledSubPlugins().length>0})}getGroupOnlineMemberCount(s){return pA(this,void 0,void 0,function*(){const{appStore:{groupStore:n},OuterConstant:g}=this._core,u=n.getGroup(s);return u?u.type===g.GRP_AVCHATROOM?this._getOnlineMemberCount(s):this._parentPlugin.groupAction.getGroupOnlineMemberCount(s):{code:0,data:{memberCount:0}}})}_getOnlineMemberCount(s){return pA(this,void 0,void 0,function*(){const n="_getOnlineMemberCount",{utils:{isEmpty:g}}=this._core,u=Pg.getLocalOnlineMemberCount(s);if(g(u)||this._isExpired(s)){const{memberCount:E=0}=yield this._getOnlineMemberCountFromServer(s);return console.log(`${this._name}.${n} ok, groupID:${s} memberCount:${E} from server.`),{code:0,data:{memberCount:E}}}return console.log(`${this._name}.${n} ok, groupID:${s} memberCount:${u.memberCount} from local.`),{code:0,data:{memberCount:u.memberCount}}})}_isExpired(s){const n=Pg.getLocalOnlineMemberCount(s),g=Date.now(),u=g-n.lastSyncTime>1e3*n.expireTime,E=g-n.latestUpdateTime>1e4,m=g-n.lastReqTime>3e3;return u&&E&&m}_getOnlineMemberCountFromServer(s){return pA(this,void 0,void 0,function*(){const n="_getOnlineMemberCountFromServer";try{const g=yield function(M,T){return pA(this,void 0,void 0,function*(){const P={GroupId:M};return T.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_online_member_num",data:P})})}(s,this._core),{OnlineMemberNum:u=0,ExpireTime:E=RD}=g||{},m=Date.now(),D={lastSyncTime:m,latestUpdateTime:m,lastReqTime:m,memberCount:u,expireTime:E};return Pg.updateLocalOnlineMemberCount(s,D),{memberCount:u}}catch(g){const u=new this._core.helper.ChatError({functionName:n,code:g?.errorCode,message:g?.errorInfo});throw console.error(`${this._name}.${n} fail:`,u),u}})}},Pg=new class{constructor(){this._name="AVChatRoomHandler",this._joinedGroupMap=new Map,this._pollingRequestInfoMap=new Map,this._pollingInstanceMap=new Map,this._onlineMemberCountMap=new Map,this._pollingIntervalMap=new Map,this._pollingNoMessageCountMap=new Map,this._membersReqInfoMap=new Map,this._startBroadcastSequence=1}init(s,n){this._core=s,this._parentPlugin=n,Bh.init(s,this),s.ssoLog.debug("AVChatRoomHandler.init")}onAVChatRoomSystemNotification(s){const{OuterConstant:{GRP_AVCHATROOM:n}}=this._core,{GroupTips:g=[]}=s;for(let u=0;u0&&(n=[...this._joinedGroupMap.values()].filter(g=>g.type===s)),n}handleJoinGroupResult(s){return pA(this,void 0,void 0,function*(){const{utils:{isUndefined:n},OuterConstant:{CONV_GROUP:g},apiMap:{getConversationProfile:u},OuterConstant:E}=this._core,{longPollingKey:m,group:D,historyMessageList:M=[]}=s,{groupID:T}=D;return yield this._preCheck(D),this._joinedGroupMap.set(T,D),this._parentPlugin.groupDataHandler.updateLocalGroup([D]),this._parentPlugin.groupDataHandler.emitGroupListUpdate(),u(`${g}${T}`),AR.getGroupOnlineMemberCount(T),M.length>0&&Bh.onMessageReceived(T,M,!0),n(m)?{code:0,data:{status:E.JOIN_STATUS_SUCCESS,group:D}}:{code:0,data:this.startMessageLongPolling(s)}})}isGroupCounterUpdated(s){return this._parentPlugin.groupCounter.isGroupCounterUpdated(s)}handleGroupCounterUpdated(s){this._parentPlugin.groupCounter.handleGroupCounterUpdated(s)}_preCheck(s){return pA(this,void 0,void 0,function*(){const{common:n,OuterConstant:g,helper:u,apiMap:{quitGroup:E},ssoLog:m}=this._core;if(n.isUnlimitedAVChatRoom()){if(this._pollingInstanceMap.size>(()=>{const T=EB("polling_count_limit");return Qh(T)&&T>0?parseInt(T,10):20})())throw new u.ChatError({code:PT,message:"the count of longPolling exceeds the max limit"});return}if(this._joinedAVChatRoomCount()===0||s.type===g.GRP_LIVE)return;const[D,M]=this._joinedGroupMap.entries().next().value;if(M.selfInfo.role===g.GRP_MBR_ROLE_OWNER)this._parentPlugin.groupDataHandler.deleteLocalGroup(D);else try{yield E(D)}catch(T){m.debug("quitGroup",`${this._name}._preCheck quitGroup failed, groupID:${D} info:`,T)}this.reset(D)})}startMessageLongPolling(s){const{OuterConstant:n}=this._core,{longPollingKey:g,startSequence:u=1,group:E}=s,{groupID:m}=E;return this._pollingRequestInfoMap.set(m,{longPollingKey:g,startSequence:u}),this._pollingIntervalMap.set(m,YQ()),this._startPolling(m),this._reportLongPollingCount(),{status:n.JOIN_STATUS_SUCCESS,group:E}}_startPolling(s){if(this._core.ssoLog.debug("_startPolling",`${this._name}._startPolling groupID:${s}`),this._pollingInstanceMap.has(s)){const g=this._pollingInstanceMap.get(s);return void(g?.isRunning()||g==null||g.start())}const n=new $v({core:this._core,manager:this,groupID:s,getRequestParams:this._handleRequestParams.bind(this),onSuccess:this._handleSuccess.bind(this),onFail:this._handleFailure.bind(this)});n.start(),this._pollingInstanceMap.set(s,n)}_handleRequestParams(s){const{longPollingKey:n,startSequence:g}=this._pollingRequestInfoMap.get(s)||{};return s===[...this._pollingInstanceMap.keys()][0]?{longPollingKey:n,startSequence:g,startBroadcastSeq:this._startBroadcastSequence,simplifiedMessage:dB()}:{longPollingKey:n,startSequence:g,simplifiedMessage:dB()}}_handleSuccess(s,n){const{ErrorCode:g}=n;if(g!==0){const{longPollingKey:u,startSequence:E}=this._pollingRequestInfoMap.get(s)||{};return void console.warn(`${this._name}._handleSuccess groupID:${s} key:${u} startSeq:${E} errorCode:${g}`)}this._hasJoinedAVChatRoom(s)&&this._handleResponseData(s,n)}_handleResponseData(s,n){const{Key:g,NextSeq:u,NextBroadcastSeq:E,RspMsgList:m=[],RspBroadcastMsgList:D=[]}=n;if(g&&u&&this._pollingRequestInfoMap.set(s,{longPollingKey:g,startSequence:u}),E&&E>this._startBroadcastSequence&&(this._startBroadcastSequence=E),m.length>0)this._getPollingNoMessageCount(s)!==0&&(this._updatePollingNoMessageCount(s,0),this._pollingIntervalMap.set(s,YQ())),Bh.onMessageReceived(s,m);else{let M=this._getPollingNoMessageCount(s);if(M+=1,this._updatePollingNoMessageCount(s,M),M===(()=>{const T=EB("polling_no_msg_count");return Qh(T)?parseInt(T,10):20})()){const T=YQ()+(()=>{const P=EB("polling_interval_plus");return Qh(P)?parseInt(P,10):2e3})();this._pollingIntervalMap.set(s,T)}}D.length>0&&Bh.onBroadcastMessageReceived(D)}_handleFailure(s,n){const{ssoLog:g,utils:{safeStringify:u}}=this._core;g.warn("polling",`${this._name}._handleFailure groupID:${s} error: ${u(n)}`)}_joinedAVChatRoomCount(){const{OuterConstant:s}=this._core;let n=[];return this._joinedGroupMap.size>0&&(n=this.getJoinedGroups().filter(g=>g.type===s.GRP_AVCHATROOM)),n.length}_hasJoinedAVChatRoom(s){return this._joinedGroupMap.has(s)}getJoinedGroups(){return[...this._joinedGroupMap.values()]}updateLocalLiveGroup(s,n){this._joinedGroupMap.set(s,n),this._parentPlugin.groupDataHandler.updateLocalGroup([n])}handleLiveHistoryMessages(s,n){Bh.onMessageReceived(s,n,!0)}isOverFrequencyLimit(s){if(!this._membersReqInfoMap.has(s))return this._membersReqInfoMap.set(s,{startTime:Date.now(),requestCount:1}),!1;let{startTime:n,requestCount:g}=this._membersReqInfoMap.get(s);const{interval:u,count:E}=(()=>{const m=EB("av_members_freq_limit");if(Qh(m)){const{interval:D,count:M}=JSON.parse(m);if(M>0&&D>0)return{interval:D,count:M}}return{interval:30,count:4}})();return Date.now()-n>1e3*u?(this._membersReqInfoMap.set(s,{startTime:Date.now(),requestCount:1}),!1):(g+=1,this._membersReqInfoMap.set(s,{startTime:n,requestCount:g}),g>E)}_stopPolling(s){if(this._core.ssoLog.debug("_stopPolling",`${this._name}._stopPolling groupID:${s}`),s){const{appStore:{conversationStore:n},OuterConstant:{CONV_GROUP:g}}=this._core;n.deleteConversation(`${g}${s}`);const u=this._pollingInstanceMap.get(s);return u?.stop(),this._parentPlugin.groupDataHandler.deleteLocalGroup(s),this._pollingInstanceMap.delete(s),this._pollingRequestInfoMap.delete(s),this._joinedGroupMap.delete(s),this._onlineMemberCountMap.delete(s),this._pollingIntervalMap.delete(s),this._pollingNoMessageCountMap.delete(s),void this._membersReqInfoMap.delete(s)}for(const n of this._pollingInstanceMap.values())n?.stop();this._pollingInstanceMap.clear(),this._pollingRequestInfoMap.clear(),this._joinedGroupMap.clear(),this._onlineMemberCountMap.clear(),this._pollingIntervalMap.clear(),this._pollingNoMessageCountMap.clear(),this._membersReqInfoMap.clear()}_updatePollingNoMessageCount(s,n){this._pollingNoMessageCountMap.set(s,n)}_getPollingNoMessageCount(s){return this._pollingNoMessageCountMap.get(s)||0}_reportLongPollingCount(){const s=this._joinedGroupMap.size;if(s>1){const{common:n,OuterConstant:g,ssoLog:u}=this._core,E=n.isUnlimitedAVChatRoom()?1:0,m=[],D=[];Array.from(this._joinedGroupMap.values()).forEach(({groupID:M,type:T})=>{T===g.GRP_LIVE?D.push(M):m.push(M)}),u.info("longPollingCount",String(s),{moreMessage:`av:${m.join(",")} live:${D.join(",")} code: ${E}`,eventType:29})}}reset(s){this._stopPolling(s),this._startBroadcastSequence=1,Bh.reset()}},eR=new class{init(s,n){this._core=s,this._parentPlugin=n;const{helper:g}=s;g.registerApi({apiName:"joinGroup",context:this,matcher:()=>n.getInstalledSubPlugins().length>0})}joinGroup(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:n}=this._core,g=yield this._parentPlugin.groupAction.joinGroup(s),{data:{status:u,group:{type:E}}}=g;return E===n.GRP_AVCHATROOM?u===n.JOIN_STATUS_ALREADY_IN_GROUP?g:Pg.handleJoinGroupResult(g.data):g})}},YT=new class{init(s,n){this._core=s,this._parentPlugin=n;const{helper:g}=s;g.registerApi({apiName:"quitGroup",context:this,matcher:()=>n.getInstalledSubPlugins().length>0})}quitGroup(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:n}=this._core,g=yield this._parentPlugin.groupAction.quitGroup(s),{data:{type:u}}=g;return u===n.GRP_AVCHATROOM&&Pg.reset(s),g})}},tR=new class{init(s,n){this._core=s,this._parentPlugin=n;const{helper:g}=s;g.registerApi({apiName:"dismissGroup",context:this,matcher:()=>n.getInstalledSubPlugins().length>0})}dismissGroup(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:n}=this._core,g=yield this._parentPlugin.groupAction.dismissGroup(s),{data:{type:u}}=g;return u===n.GRP_AVCHATROOM&&Pg.reset(s),g})}},Om=new class{constructor(){this._name="GetAVChatRoomMemberList"}init(s,n){this._core=s,this._parentPlugin=n;const{helper:g}=s;g.registerApi({apiName:"getGroupMemberList",context:this,matcher:()=>n.getInstalledSubPlugins().length>0})}getGroupMemberList(s){return pA(this,void 0,void 0,function*(){const{appStore:{groupStore:n},helper:g,OuterConstant:u}=this._core,{groupID:E}=s,m=n.getGroup(E);if(m?.type===u.GRP_AVCHATROOM&&g.checkBusinessCapabilityBits(Xv)){if(Pg.isOverFrequencyLimit(E))throw{code:2996,message:`Over frequency limit: get_members-${E}`};return this._getGroupMemberList(s)}return this._parentPlugin.groupMember.getGroupMemberList(s)})}_getGroupMemberList(s){return pA(this,void 0,void 0,function*(){const n="_getGroupMemberList",{helper:g}=this._core;try{const u=yield function(M,T){return pA(this,void 0,void 0,function*(){const{groupID:P,offset:W=0}=M,iA={GroupId:P,Timestamp:W};return T.common.buildAndSendPacket({servcmd:"group_open_avchatroom_http_svc.get_members",data:iA})})}(s,this._core),{MemberList:E=[],NextTimestamp:m=0}=u||{},D=this._handleMemberList(E);return console.log(`${this._name}.${n} ok, groupID:${s.groupID} count:${D.length} nextOffset:${m}`),{code:0,data:{memberList:D,offset:m}}}catch(u){const E=new g.ChatError({functionName:n,code:u?.errorCode,message:u?.errorInfo});throw console.error(`${this._name}.${n} fail:`,E),E}})}_handleMemberList(s){return s.map(n=>{const{Member_Account:g,NickName:u="",Avatar:E="",Remark:m="",JoinTime:D=0,Marks:M=[]}=n;return{userID:g,nick:u,avatar:E,remark:m,joinTime:D,marks:M,isOnline:!0}})}},Pm=new class{constructor(){this._name="DeleteAVChatRoomMember"}init(s,n){this._core=s,this._parentPlugin=n;const{helper:g}=s;g.registerApi({apiName:"deleteGroupMember",context:this,matcher:()=>n.getInstalledSubPlugins().length>0})}deleteGroupMember(s){return pA(this,void 0,void 0,function*(){const n="deleteGroupMember",{appStore:{groupStore:g},utils:{isUndefined:u},helper:E,OuterConstant:m}=this._core,{groupID:D}=s,M=g.getGroup(D);if(u(M))throw new E.ChatError({functionName:n,code:wD});if(M.type===m.GRP_AVCHATROOM){if(E.checkBusinessCapabilityBits(FT))return this._deleteGroupMember(s);throw new E.ChatError({functionName:n,code:PQ})}return this._parentPlugin.groupMember.deleteGroupMember(s)})}_deleteGroupMember(s){return pA(this,void 0,void 0,function*(){const n="_deleteGroupMember",{appStore:{groupStore:g},helper:u,ssoLog:E}=this._core,{groupID:m,duration:D=0,userIDList:M}=s;if(D===0)throw new u.ChatError({functionName:n,code:OT});try{return yield function(T,P){return pA(this,void 0,void 0,function*(){const{groupID:W,userIDList:iA,duration:EA,reason:RA}=T,kA={GroupId:W,Members_Account:iA,Duration:EA,Description:RA};return P.common.buildAndSendPacket({servcmd:"group_open_http_svc.ban_group_member",data:kA})})}(s,this._core),E.debug(n,`${this._name}.${n} ok, groupID:${m}`),{code:0,data:{group:g.getGroup(m),userIDList:M}}}catch(T){throw new u.ChatError({functionName:n,code:T?.errorCode,message:T?.errorInfo})}})}},_d=new class{constructor(){this._name="MarkAVChatRoomMember"}init(s){this._core=s;const{helper:n}=s;n.registerApi({apiName:"markGroupMemberList",context:this})}markGroupMemberList(s){return pA(this,void 0,void 0,function*(){const n="markGroupMemberList",{groupID:g,markType:u,enableMark:E,userIDList:m=[]}=s,D=this._generateRequestData(s);try{const M=yield function(iA,EA){return pA(this,void 0,void 0,function*(){const{groupID:RA,operationType:kA,memberList:xA}=iA,LA={GroupId:RA,CommandType:kA,MemberList:xA};return EA.common.buildAndSendPacket({servcmd:"group_open_avchatroom_http_svc.modify_user_info",data:LA})})}(D,this._core),{MemberList:T=[]}=M||{},{successUserIDList:P,failureUserIDList:W}=this._handleResult(T,m);return{code:0,data:{successUserIDList:P,failureUserIDList:W},successLog:{message:`${this._name}.${n} ok, groupID:${g} markType:${u} enableMark:${E} success:${P.length} fail:${W.length}`}}}catch(M){throw new this._core.helper.ChatError({functionName:n,code:M?.errorCode,message:M?.errorInfo})}})}_generateRequestData(s){const{groupID:n,markType:g,enableMark:u,userIDList:E=[]}=s,m=u===!0?1:2,D=[...E];return D.length>500&&console.warn(`${this._name}._generateRequestData, the length of userIDList cannot exceed 500`),{groupID:n,operationType:m,memberList:D.map(M=>({Member_Account:M,Marks:[g]}))}}_handleResult(s,n){const g=[],u=[];return s.length===n.length?(g.push(...n),{successUserIDList:g,failureUserIDList:u}):(n.forEach(E=>{s.find(m=>m.Member_Account===E)?g.push(E):u.push(E)}),{successUserIDList:g,failureUserIDList:u})}},iR=new class{init(s,n){s.ssoLog.debug("AVChatRoomAction.init"),eR.init(s,n),YT.init(s,n),tR.init(s,n),Om.init(s,n),AR.init(s,n),Pm.init(s,n),_d.init(s)}},oR=new class{constructor(){this._name="LiveHandler"}init(s){this._core=s;const{helper:n,ssoLog:g}=s;n.registerExperimentalAPI("startMessageLongPolling",this),n.registerExperimentalAPI("stopMessageLongPolling",this),g.debug("LiveHandler.init")}startMessageLongPolling(s){const{common:n,utils:{isEmpty:g},OuterConstant:u,ssoLog:E}=this._core,{groupID:m,longPollingKey:D,longPollingSequence:M=1}=s;if(g(D))return E.warn("startMessageLongPolling",`${this._name}.startMessageLongPolling longPollingKey is empty.`),Promise.resolve({});Pg.hasPollingInstance(m)&&this.stopMessageLongPolling({groupID:m});const T=Pg.getJoinedLiveList(),P=n.isUnlimitedAVChatRoom();!P&&T.length>0&&this.stopMessageLongPolling({groupID:T[0].groupID}),E.debug("startMessageLongPolling",`${this._name}.startMessageLongPolling isUnlimited:${P} groupID:${m} longPollingKey:${D} longPollingSequence:${M}`);const W={groupID:m,type:u.GRP_LIVE};return Pg.updateLocalLiveGroup(m,W),this._getLiveHistoryMessages({groupID:m,longPollingKey:D,startSequence:M}),Pg.startMessageLongPolling({group:W,longPollingKey:D,startSequence:M})}stopMessageLongPolling(s){const{groupID:n}=s;return Pg.reset(n),this._core.ssoLog.debug("stopMessageLongPolling",`${this._name}.stopMessageLongPolling ok, groupID:${n}`),Promise.resolve({groupID:n})}_getLiveHistoryMessages(s){return pA(this,void 0,void 0,function*(){const{ssoLog:n}=this._core,{groupID:g}=s;try{const u=yield function(m,D){return pA(this,void 0,void 0,function*(){const{groupID:M,longPollingKey:T,startSequence:P}=m,W={GroupId:M,LongPollingKey:T,PullPreSeq:P};return D.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_huge_group_msg",data:W})})}(s,this._core),{RspMsgList:E=[]}=u||{};n.debug("_getLiveHistoryMessages",`${this._name}._getLiveHistoryMessages ok, groupID:${g} count:${E.length}`),E.length>0&&Pg.handleLiveHistoryMessages(g,E)}catch(u){n.debug("_getLiveHistoryMessages",`${this._name}._getLiveHistoryMessages failed, groupID:${g} info:${u.message}`)}})}},xm=new class{constructor(){this.name="AVChatRoom"}install(s,n){this._core=s,uB.init(s),Pg.init(s,n),iR.init(s,n),oR.init(s);const{notificationCenter:g,InnerEvent:u}=s,{InnerEventSubType:E}=g;g.subscribeInnerEvent(u.MESSAGE_PUSH,E.GROUP_SYSTEM_NOTIFICATION,this._onAVChatRoomSystemNotification,this),g.subscribeInnerEvent(u.LOGOUT,this._reset,this),g.subscribeInnerEvent(u.DESTROY,this._dispose,this)}_onAVChatRoomSystemNotification(s){Pg.onAVChatRoomSystemNotification(s)}_reset(){Pg.reset()}_dispose(){this._reset();const{notificationCenter:s,InnerEvent:n}=this._core,{InnerEventSubType:g}=s;s.unSubscribeInnerEvent(n.MESSAGE_PUSH,g.GROUP_SYSTEM_NOTIFICATION,this._onAVChatRoomSystemNotification,this),s.unSubscribeInnerEvent(n.LOGOUT,this._reset,this),s.unSubscribeInnerEvent(n.DESTROY,this._dispose,this)}};const Ag=new class{init(s){this.core=s}},Ym="message",CB="user",hB={OR:"or",AND:"and"},vI=20,VT=20,sR=20,ph={required:!1,rules:["array"],allowEmpty:!0,customValidator:s=>!s||!!(Array.isArray(s)&&s.length<=5)||"keywordList should be an array and length <= 5"},Vm={required:!1,rules:["string"],allowEmpty:!0,customValidator:s=>!s||!![hB.OR,hB.AND].includes(s)||"keywordListMatchType should be OR or AND"},SC={required:!1,rules:["number"],allowEmpty:!0,customValidator:s=>typeof s=="number"&&s>=1&&s<=100||"count must be a number between 1 and 100"},VQ={required:!1,rules:["string"],allowEmpty:!0},nR={required:!1,rules:["array"],allowEmpty:!0,customValidator:s=>{const{OuterConstant:n}=Ag.core;if(!Array.isArray(s))return"groupTypeList should be an array";const g=[n.GRP_PUBLIC,n.GRP_COMMUNITY,n.GRP_WORK,n.GRP_MEETING];let u=!1;for(let E=0;E{const{OuterConstant:n}=Ag.core,g=[n.MSG_TEXT,n.MSG_IMAGE,n.MSG_AUDIO,n.MSG_FILE,n.MSG_VIDEO,n.MSG_LOCATION,n.MSG_CUSTOM,n.MSG_MERGER];let u=!1;for(let E=0;E{const{OuterConstant:n}=Ag.core;return!(!s?.startsWith(n.CONV_C2C)&&!s?.startsWith(n.CONV_GROUP)&&s!==n.CONV_SYSTEM)||"conversationID is invalid"}},Jm=s=>({required:!1,rules:["number"],allowEmpty:!0,customValidator:n=>typeof n=="number"&&n>=0||`${s} should be a number >= 0';`}),TD={required:!1,rules:["string"],allowEmpty:!0,customValidator:s=>{const{OuterConstant:n}=Ag.core;return!![n.GENDER_FEMALE,n.GENDER_MALE].includes(s)||"gender is invalid"}},Hm={searchCloudMessages:{keywordList:ph,keywordListMatchType:Vm,cursor:VQ,senderUserIDList:{required:!1,rules:["array"],allowEmpty:!0,customValidator:s=>!!(Array.isArray(s)&&s.length<=5)||"senderUserIDList should be an array and length <= 5"},messageTypeList:rR,conversationID:aR,timePosition:Jm("timePosition"),timePeriod:Jm("timePeriod")},searchCloudUsers:{keywordList:ph,keywordListMatchType:Vm,cursor:VQ,count:SC,miniBirthday:Jm("miniBirthday"),maxBirthday:Jm("maxBirthday"),gender:TD},searchCloudGroupMembers:{keywordList:ph,keywordListMatchType:Vm,cursor:VQ,count:SC,groupTypeList:nR,groupIDList:{required:!1,rules:["array"],allowEmpty:!0}},searchCloudGroups:{keywordList:ph,keywordListMatchType:Vm,cursor:VQ,count:SC,groupTypeList:nR}},ND={searchCloudMessages:!0,searchCloudUsers:!0,searchCloudGroupMembers:!0,searchCloudGroups:!0};var GD=new class{constructor(){this.name="CloudSearch"}install(s){this._core=s,Ag.init(s),s.helper.registerApi({apiName:"searchCloudMessages",context:this}),s.helper.registerApi({apiName:"searchCloudUsers",context:this}),s.helper.registerApi({apiName:"searchCloudGroupMembers",context:this}),s.helper.registerApi({apiName:"searchCloudGroups",context:this}),s.helper.registerValidateConfig({auth:ND,params:Hm})}searchCloudMessages(s){return pA(this,void 0,void 0,function*(){try{const{OuterConstant:n,helper:g}=this._core,{conversationID:u,timePeriod:E,timePosition:m}=s,D=Do(s,["conversationID","timePeriod","timePosition"]),M=Object.assign({count:100},D);u&&(u.startsWith(n.CONV_C2C)?M.account=u.replace(n.CONV_C2C,""):u.startsWith(n.CONV_GROUP)&&(M.groupID=u.replace(n.CONV_GROUP,""))),this._setTimeRangeParams(M,{timePeriod:E,timePosition:m});const T=yield function(LA){return pA(this,void 0,void 0,function*(){const{count:SA,keywordList:OA,keywordListMatchType:JA,senderUserIDList:ae,messageTypeList:ne,endTime:_i,startTime:Ti,cursor:Lt,account:Ni,groupID:cs}=LA,Me={Count:SA,KeywordList:OA,MatchType:JA,SendUserIDList:ae,MsgTypeList:ne,EndTime:_i,StartTime:Ti,Cursor:Lt,PeerAccount:Ni,GroupID:cs};return Ag.core.common.buildAndSendPacket({servcmd:"message_search.query",data:Me})})}(M);if(!T)return{code:0,data:{}};const{ErrorCode:P,ErrorInfo:W,TotalCount:iA,Cursor:EA="",ConversationMsgs:RA=[]}=T;if(P!==0)throw{errorCode:P,errorInfo:W};const kA=`keywordList:${s.keywordList} keywordListMatchType:${s.keywordListMatchType} cursor:${s.cursor} res: totalCount:${iA}`;return{code:0,data:{searchResultList:RA.map(LA=>{const{MsgList:SA,Count:OA,GroupID:JA,UserID:ae}=LA,ne=JA?`${n.CONV_GROUP}${JA}`:`${n.CONV_C2C}${ae}`;if(this._isSearchingAllConversations(s)&&OA>1)return{conversationID:ne,messageCount:OA,messageList:[]};const _i=SA.map(Ti=>g.isEmpty(JA)?function(Lt,Ni){const cs=Ni.OuterConstant.CONV_C2C,Me=Ni.message.messageHelper.parseServerPushMessage(Lt),mt=Ni.message.messageFactory.createMessage(Object.assign(Object.assign({},Me),{conversationType:cs,flow:"in"}));return mt.setElement(Me.elements),mt}(Ti,this._core):function(Lt,Ni){const cs=Ni.OuterConstant.CONV_GROUP,Me=Ni.message.messageHelper.parseServerGroupMessage(Lt),mt=Ni.message.messageFactory.createMessage(Object.assign(Object.assign({},Me),{conversationType:cs,flow:"in"}));return mt.setElement(Me.elements),mt}(Ti,this._core));return{conversationID:ne,messageCount:OA,messageList:_i}}),cursor:EA,totalCount:iA},successLog:{message:kA}}}catch(n){const{errorCode:g,errorInfo:u}=n||{};this._handleError({errorCode:g,errorInfo:u,searchType:Ym,functionName:"searchCloudMessages"})}})}searchCloudUsers(s){return pA(this,void 0,void 0,function*(){var n;try{const{keywordListMatchType:g,count:u=VT}=s,E=Do(s,["keywordListMatchType","count"]),m=Object.assign({count:u,keywordListMatchType:g===hB.AND?1:0},E);this._setBirthdayRangeParams(m,s);const D=yield function(kA){return pA(this,void 0,void 0,function*(){const{count:xA,keywordList:LA,keywordListMatchType:SA,miniBirthday:OA,maxBirthday:JA,cursor:ae,gender:ne}=kA,_i={Count:xA,Keywords:LA,KeywordMatchType:SA,Cursor:ae,UserBirthStart:OA,UserBirthEnd:JA,Gender:ne};return Ag.core.common.buildAndSendPacket({servcmd:"user_search.query",data:_i})})}(m);if(!D)return{error:0,data:{}};const{ErrorCode:M,ErrorInfo:T,TotalCount:P,Cursor:W="",Users:iA=[]}=D;if(M!==0)throw{errorCode:M,errorInfo:T};const EA=`keywordList:${s.keywordList} keywordListMatchType:${s.keywordListMatchType} cursor:${s.cursor} count:${s.count} res: totalCount:${P}`,RA=[];for(let kA=0,xA=iA.length;kA({tag:ae.Tag,value:ae.StrValue})),JA=(n=this._core.user.userProfile)===null||n===void 0?void 0:n.createProfile(LA,OA);RA.push(JA)}return{code:0,data:{searchResultList:RA,cursor:W,totalCount:P},successLog:{message:EA}}}catch(g){const{errorCode:u,errorInfo:E}=g||{};this._handleError({errorCode:u,errorInfo:E,searchType:CB,functionName:"searchCloudUsers"})}})}searchCloudGroupMembers(s){return pA(this,void 0,void 0,function*(){try{const{count:n=sR,keywordListMatchType:g}=s,u=Do(s,["count","keywordListMatchType"]),E=Object.assign({count:n,keywordListMatchType:g===hB.AND?1:0},u),m=yield function(RA){return pA(this,void 0,void 0,function*(){const{count:kA,keywordList:xA,keywordListMatchType:LA,groupTypeList:SA,cursor:OA,groupIDList:JA}=RA,ae={Count:kA,Keywords:xA,KeywordMatchType:LA,Cursor:OA,GroupType:SA,GroupIdList:JA};return Ag.core.common.buildAndSendPacket({servcmd:"group_member_search.query",data:ae})})}(E);if(!m)return{code:0,data:{}};const{ErrorCode:D,ErrorInfo:M,GroupMembers:T=[],Cursor:P,TotalCount:W}=m;if(D!==0)throw{errorCode:D,errorInfo:M};const iA=`keywordList:${s.keywordList} keywordListMatchType:${s.keywordListMatchType} cursor:${s.cursor} count:${s.count} res: totalCount:${W}`,EA=new Map;return T.forEach(RA=>{const{GroupID:kA,GroupName:xA,GroupType:LA,GroupFaceUrl:SA,GroupMemberUserName:OA,GroupMemberUserID:JA,GroupMemberNameCard:ae,GroupMemberAvatar:ne=""}=RA,_i={groupID:kA,name:xA,type:LA,avatar:SA},Ti={userID:JA,nick:OA,nameCard:ae,avatar:ne};if(EA.has(kA)){const Lt=EA.get(kA);Lt.memberList.push(Ti),EA.set(kA,Lt)}else EA.set(kA,{groupInfo:_i,memberList:[Ti]})}),{code:0,data:{searchResultList:[...EA.values()],cursor:P,totalCount:W},successLog:{message:iA}}}catch(n){const{errorCode:g,errorInfo:u}=n||{};this._handleError({errorCode:g,errorInfo:u,searchType:CB,functionName:"searchCloudGroupMembers"})}})}searchCloudGroups(s){return pA(this,void 0,void 0,function*(){try{const{count:n=vI,keywordListMatchType:g}=s,u=Do(s,["count","keywordListMatchType"]),E=Object.assign({count:n,keywordListMatchType:g===hB.AND?1:0},u),m=yield function(EA){return pA(this,void 0,void 0,function*(){const{count:RA,keywordList:kA,keywordListMatchType:xA,groupTypeList:LA,cursor:SA}=EA,OA={Count:RA,Keywords:kA,KeywordMatchType:xA,Cursor:SA,GroupType:LA};return Ag.core.common.buildAndSendPacket({servcmd:"group_search.query",data:OA})})}(E);if(!m)return{code:0,data:{}};const{ErrorCode:D,ErrorInfo:M,Groups:T,Cursor:P,TotalCount:W}=m;if(D!==0)throw{errorCode:D,errorInfo:M};const iA=`keywordList:${s.keywordList} keywordListMatchType:${s.keywordListMatchType} cursor:${s.cursor} count:${s.count} res: totalCount:${W}`;return{code:0,data:{searchResultList:T?.map(EA=>function(RA){const{GroupFaceUrl:kA,GroupID:xA,GroupIntroduction:LA,GroupMemberNum:SA,GroupName:OA,GroupOwnerTinyID:JA,GroupOwnerUserID:ae,GroupOwnerUserName:ne,GroupType:_i,GroupAddOption:Ti,GroupInviteOption:Lt}=RA;return{avatar:kA,groupID:xA,introduction:LA,memberCount:SA,name:OA,ownerTinyID:JA,ownerID:ae,ownerNick:ne,type:_i,joinOption:Ti,inviteOption:Lt}}(EA))||[],cursor:P,totalCount:W},successLog:{message:iA}}}catch(n){const{errorCode:g,errorInfo:u}=n||{};this._handleError({errorCode:g,errorInfo:u,searchType:CB,functionName:"searchCloudGroups"})}})}_setTimeRangeParams(s,{timePeriod:n,timePosition:g}){n&&n>0&&(s.startTime=g&&g>0?g-n:this._core.helper.timeManager.getServerTimeSeconds()-n),s.startTime&&s.startTime<0&&(s.startTime=void 0),g&&g>0&&(s.endTime=g)}_handleError({errorCode:s,errorMessage:n,searchType:g}){const{helper:u}=this._core;let E=s;throw s===60020?E="SearchUnable":g!==Ym&&s===27003?E="SearchParamsError":g!==Ym&&s===60018&&(E="SearchOverLimit"),new u.ChatError({code:E,message:n})}_isSearchingAllConversations(s){return this._core.helper.isEmpty(s.conversationID)}_setBirthdayRangeParams(s,n){const{miniBirthday:g,maxBirthday:u}=n;g!==void 0&&(s.miniBirthday=g,u===void 0&&(s.maxBirthday=4294967295)),u!==void 0&&(s.maxBirthday=u)}};function mh(s,n){return Math.round(Number(s)*Math.pow(10,n))/Math.pow(10,n)}const gR="qualityStat",bD="im-ssolog-quality-stat";var kD;(function(s){s[s.ONLINE=8]="ONLINE"})(kD||(kD={}));const qm="networkRTT",fh="messageE2EDelay",BB="sendMessageC2C",yh="sendMessageGroup",Dh="sendMessageGroupAV",QB="sendMessageRichMedia",pB="cosUpload",MC="messageReceivedGroup",JQ="messageReceivedGroupAVPush",HQ="messageReceivedGroupAVPull",JT={[qm]:2,[fh]:3,[BB]:4,[yh]:5,[Dh]:6,[QB]:7,[MC]:8,[JQ]:9,[HQ]:10,[pB]:11},cR=[BB,yh,Dh,QB,pB],Sh=[MC,JQ,HQ],mB=[qm,fh,BB,yh,Dh,QB,pB,MC,JQ,HQ],LD={ERR_SVR_COMM_SENSITIVE_TEXT:80001,ERR_SVR_COMM_BODY_SIZE_LIMIT:80002,OPEN_SERVICE_OVERLOAD_ERROR:60022,ERR_SVR_MSG_PKG_PARSE_FAILED:20001,ERR_SVR_MSG_INTERNAL_AUTH_FAILED:20002,ERR_SVR_MSG_INVALID_ID:20003,ERR_SVR_MSG_PUSH_DENY:20006,ERR_SVR_MSG_IN_PEER_BLACKLIST:20007,ERR_SVR_MSG_BOTH_NOT_FRIEND:20009,ERR_SVR_MSG_NOT_PEER_FRIEND:20010,ERR_SVR_MSG_NOT_SELF_FRIEND:20011,ERR_SVR_MSG_SHUTUP_DENY:20012,ERR_SVR_GROUP_INVALID_PARAMETERS:10004,ERR_SVR_GROUP_PERMISSION_DENY:10007,ERR_SVR_GROUP_NOT_FOUND:10010,ERR_SVR_GROUP_INVALID_GROUPID:10015,ERR_SVR_GROUP_REJECT_FROM_THIRDPARTY:10016,ERR_SVR_GROUP_SHUTUP_DENY:10017,MSG_SEND_FAIL:2100,OVER_FREQUENCY_LIMIT:2996},Km="quality_stat";var qQ=new class{constructor(){this._messageStatsMap=new Map,this._userSideErrorCodes=new Set(Object.values(LD))}init(s){this._core=s,Object.values(cR).forEach(n=>{this._messageStatsMap.set(n,{totalCount:0,successCount:0,failedCountOfUserSide:0,costSum:0,costCount:0,fileSizeSum:0})})}dispatchSendStats(s){const{name:n,message:g,error:u,startTs:E}=s,{SEND_MESSAGE_STAT:m}=this._core.constants;switch(n){case m.TOTAL_COUNT:this._handleTotalCount(g);break;case m.SUCCESS_COUNT:this._handleSuccessCount(g);break;case m.FAILED_COUNT:this._handleFailedCount(g,u);break;case m.SEND_COST:this._handleSendCost(g,E)}}getStatResult(s){const n=this._messageStatsMap.get(s);if(!n||n.totalCount===0)return null;const{totalCount:g,successCount:u,failedCountOfUserSide:E}=n,m=mh(u/g*100,2),D=u+E,M=mh(D/g*100,2),T=this._calcAverageValue(n,s);return this._resetStat(s),{total_count:g,success_count_business:u,percent_business:m,success_count_platform:D,percent_platform:M,average_value:T}}_handleTotalCount(s){const n=this._getSendMessageSpecifiedKey(s),g=n&&this._messageStatsMap.get(n);g&&g.totalCount++}_handleSuccessCount(s){const n=this._getSendMessageSpecifiedKey(s),g=n&&this._messageStatsMap.get(n);g&&g.successCount++}_handleFailedCount(s,n){var g;const u=(g=n?.code)!==null&&g!==void 0?g:n?.errorCode;if(this._isUserSideError(u)){const E=this._getSendMessageSpecifiedKey(s),m=E&&this._messageStatsMap.get(E);m&&m.failedCountOfUserSide++}}_handleSendCost(s,n){const g=this._getSendMessageSpecifiedKey(s),u=g&&this._messageStatsMap.get(g);u&&(u.costSum+=Date.now()-n,u.costCount++)}_isUserSideError(s){return this._userSideErrorCodes.has(s)||s>=120001&&s<=13e4||s>=10100&&s<=10200}_getSendMessageSpecifiedKey(s){const{MSG_IMAGE:n,MSG_AUDIO:g,MSG_VIDEO:u,MSG_FILE:E,CONV_C2C:m,CONV_GROUP:D,GRP_AVCHATROOM:M}=this._core.OuterConstant;if([n,g,u,E].includes(s.type))return QB;if(s.conversationType===m)return BB;if(s.conversationType===D){const{groupStore:T}=this._core.appStore,P=T.getGroup(s.to);if(!P)return;const{type:W}=P;return W===M?Dh:yh}}_calcAverageValue(s,n){return s.costCount===0?0:Math.round(n===pB?1e3*s.fileSizeSum/s.costSum:s.costSum/s.costCount)}_resetStat(s){const n=this._messageStatsMap.get(s);n&&(n.totalCount=0,n.successCount=0,n.failedCountOfUserSide=0,n.costSum=0,n.costCount=0,n.fileSizeSum=0)}},KQ=new class{constructor(){this._lastCycleStats=new Map,this._currentCycleStats=new Map}init(s){this._core=s;const{OuterEvent:n,notificationCenter:g}=s;this._initStatsMap(),g.subscribeOuterEvent(n.MESSAGE_RECEIVED,this._onMessageReceived,this)}addMessageSequence(s){const n=this._getReceivedMessageSpecifiedKey(s),{utils:{isUndefined:g},OuterConstant:{CONV_GROUP:u},ssoLog:E}=this._core;if(g(n)||!this._currentCycleStats.has(n))return void E.debug("addMessageSequence",`${gR}.addMessageSequence invalid key:${n}`);const{conversationID:m,sequence:D}=s,M=m.replace(u,""),T=this._lastCycleStats.get(n);if(T.size===0||!T.has(M))return void this._addToCurrentCycle(n,M,D);const P=T.get(M);D>P.minSeq&&D{const{sortedSequences:m,minSeq:D,maxSeq:M}=E;m.length>0&&(u+=m.length,g+=M-D+1)}),g===0?null:(this._transferCycleDataOptimized(s),{total_count:g,success_count_business:u,percent_business:mh(u/g*100,2)})}reset(){this._lastCycleStats.clear(),this._currentCycleStats.clear()}dispose(){const{notificationCenter:s,OuterEvent:{MESSAGE_RECEIVED:n}}=this._core;s.unSubscribeOuterEvent(n,this._onMessageReceived,this),this.reset()}_initStatsMap(){Object.values(Sh).forEach(s=>{this._lastCycleStats.set(s,new Map),this._currentCycleStats.set(s,new Map)})}_onMessageReceived(s){const{data:n=[]}=s;n.forEach(g=>{this.addMessageSequence(g)})}_transferCycleDataOptimized(s){const n=this._currentCycleStats.get(s);if(!n)return;const g=new Map;n.forEach((u,E)=>{const m=u.dirty?[...u.sortedSequences].sort((D,M)=>D-M):u.sortedSequences;g.set(E,{sortedSequences:m,minSeq:u.minSeq,maxSeq:u.maxSeq,dirty:!1})}),this._lastCycleStats.set(s,g),this._currentCycleStats.set(s,new Map)}_getReceivedMessageSpecifiedKey(s){const{OuterConstant:{CONV_GROUP:n,GRP_AVCHATROOM:g}}=this._core;if(s.conversationType===n&&s?._onlineOnlyFlag!==!0){const{groupStore:u}=this._core.appStore,E=u.getGroup(s.to);if(!E)return null;const{type:m}=E;return m===g?HQ:MC}}_insertToLastCycle(s,n){n.dirty&&(n.sortedSequences.sort((u,E)=>u-E),n.dirty=!1);const g=this._findInsertPos(n.sortedSequences,s);n.sortedSequences.splice(g,0,s),n.minSeq=Math.min(n.minSeq,s),n.maxSeq=Math.max(n.maxSeq,s)}_findInsertPos(s,n){let g=0,u=s.length-1;for(;g<=u;){const E=Math.floor((g+u)/2);if(s[E]===n)return E;s[E]0&&(this._totalDelay+=g,this._totalCount++,g<=1?this._countLessThan1s++:g<=3&&this._countLessThan3s++)}getStatResult(){if(this._totalCount===0)return null;const s={total_count:this._totalCount,success_count_business:this._countLessThan1s,success_count_platform:this._countLessThan3s,percent_business:this._calculatePercentage(this._countLessThan1s,this._totalCount),percent_platform:this._calculatePercentage(this._countLessThan3s,this._totalCount),average_value:this._calculateAverageDelay(this._totalCount)};return this.reset(),s}reset(){this._totalDelay=0,this._totalCount=0,this._countLessThan1s=0,this._countLessThan3s=0}dispose(){const{notificationCenter:s,OuterEvent:{MESSAGE_RECEIVED:n}}=this._core;s.unSubscribeOuterEvent(n,this._onMessageReceived,this),this.reset()}_onMessageReceived(s){const{data:n=[]}=s,{OuterConstant:{MSG_GRP_TIP:g,MSG_GRP_SYS_NOTICE:u}}=this._core,E=[g,u];n.forEach(m=>{!E.includes(m.type)&&m.clientTime>0&&this.addMessageDelay(m.clientTime)})}_calculateAverageDelay(s){return s===0?0:mh(this._totalDelay/s,1)}_calculatePercentage(s,n){return mh(s/n*100,2)}},lR=new class{init(s){this.core=s}},HT=new class{constructor(){this.name="MessageQualityStat",this._reportIndex=0,this._wholePeriod=!1,this._pendingReports=[],this._failedLogsCache=new Map}install(s){this._core=s;const{helper:n,notificationCenter:g,InnerEvent:{QUALITY_STAT:u,LOGOUT:E,DESTROY:m},constants:{WORKFLOW_NAME:D,WORKFLOW_STEP:M}}=s;lR.init(s),qQ.init(s),KQ.init(s),jQ.init(s),n.registerWorkflowStep(D.SYNC_SERVER_INFO_AFTER_LOGIN,M.QUALITY_REPORT,this.handleLoginSuccess,this),g.subscribeInnerEvent(u,this._handleQualityStat,this),g.subscribeInnerEvent(E,this._reset,this),g.subscribeInnerEvent(m,this._dispose,this)}handleLoginSuccess(){const{store:s,helper:n,utils:{isUndefined:g}}=this._core,u=s.get("cloudConfig")||{},{q_rpt_interval:E}=u,m=g(E)?12e4:Number(E);n.taskScheduler.addTask({id:Km,intervalMs:m,callback:this.report,context:this})}report(){this._wholePeriod=!0;const s=[...mB.map(n=>{const g=this._buildQualityReportItem(n);return g?Object.assign(Object.assign({},g),{report_index:this._reportIndex,whole_period:this._wholePeriod}):null}).filter(Boolean),...this._pendingReports];this._pendingReports=[],this._needSkipReport()||this._uploadQualityReports(s)}_handleQualityStat(s){const{constants:{QUALITY_METRICS:n}}=this._core,{label:g,data:u}=s;g===n.MESSAGE_SEND_SUCCESS_RATE&&qQ.dispatchSendStats(u)}_needSkipReport(){return this._isSDKAppIDInBlacklist()&&!this._isTinyIDInWhitelist()}_isSDKAppIDInBlacklist(){const{store:s,utils:n}=this._core,g=s.get("cloudConfig")||{},u=s.get("instance")||{},{sdkAppId:E}=u,{q_rpt_sdkappid_bl:m=[]}=g;if(!n.isEmpty(m))return m.split(",").map(D=>Number(D)).includes(E)}_isTinyIDInWhitelist(){const{store:s,utils:n}=this._core,g=s.get("cloudConfig")||{},u=s.get("login")||{},E=Number(u.tinyID),{q_rpt_tinyid_wl:m=[]}=g;if(!n.isEmpty(m))return m.split(",").includes(E)}_buildQualityReportItem(s){const n=this._getStatResultByKey(s);if(n===null)return null;const g={quality_type:JT[s],timestamp:Date.now(),network_type:kD.ONLINE,extension:""};return Object.assign(Object.assign({},g),n)}_getStatResultByKey(s){switch(s){case fh:return jQ.getStatResult();case BB:case yh:case Dh:case QB:case pB:return qQ.getStatResult(s);case MC:case JQ:case HQ:return KQ.getStatResult(s);default:return null}}_uploadQualityReports(s){return pA(this,void 0,void 0,function*(){try{const n={header:this._core.common.getCommonHead(),quality:s};yield function(g){const{common:u,channel:E}=lR.core,m="imopenstat.tim_web_report_v2",D=u.generateSSOLogProtocolData({servcmd:m,data:g}),M=`${D.head.seq}${m}`;return E.sendPacket(D,{requestId:M})}(n),this._reportIndex++,this._wholePeriod=!1}catch(n){console.warn("doReport failed. error:",n),this._pendingReports=this._pendingReports.concat(s),this._cacheFailedLogs()}})}_cacheFailedLogs(){const s=this._pendingReports,n=`${gR}._cacheFailedLogs`;let g=[...this._failedLogsCache.get(bD)||[],...s];g.length>10&&(g=g.slice(g.length-10),console.log(`${n} logs overflow, keeping last 10 items`)),this._failedLogsCache.set(bD,g),console.log(`${n} count: ${g.length}`),this._pendingReports=[]}_reset(){const{helper:s}=this._core;s.taskScheduler.removeTask(Km)}_dispose(){const{notificationCenter:s,InnerEvent:{QUALITY_STAT:n,LOGOUT:g,DESTROY:u}}=this._core;s.unSubscribeInnerEvent(n,this._handleQualityStat,this),s.unSubscribeInnerEvent(g,this._reset,this),s.unSubscribeInnerEvent(u,this._dispose,this),this._reset(),jQ.dispose(),KQ.dispose()}};const ll=new class{init(s){this.core=s}};function IR(s){return pA(this,void 0,void 0,function*(){var n;const{message:g,user:u,appStore:E,constants:{OuterConstant:m}}=ll.core,D=E.conversationStore.getConversationMap();if(D.has(s)){const T=(n=D.get(s))===null||n===void 0?void 0:n.userProfile;if(T&&s.startsWith(m.CONV_C2C)){const{avatar:P,nick:W}=T;ll.core.message.messageDataHandler.updateNickAndAvatarOfSentMessage({conversationID:s,latestAvatar:P,latestNick:W,isSentByMe:!1})}}const{data:M}=(yield u.userProfile.getMyProfile())||{};if(M){const{avatar:T,nick:P}=M;g.messageDataHandler.updateNickAndAvatarOfSentMessage({conversationID:s,latestAvatar:T,latestNick:P,isSentByMe:!0})}})}function uR(s){return pA(this,void 0,void 0,function*(){const n=s.map(g=>g.revoker);try{const g=yield function(u){return pA(this,void 0,void 0,function*(){var E,m;const D=yield(E=ll.core.user.userProfile)===null||E===void 0?void 0:E.getUserProfile({userIDList:u});return D?.data?(m=D.data)===null||m===void 0?void 0:m.reduce((M,{userID:T,nick:P,avatar:W})=>(M[T]={nick:P||"",avatar:W||""},M),{}):null})}(n);g&&s.forEach(u=>{const{revoker:E}=u;g[E]&&(u.revokerInfo.nick=g[E].nick||"",u.revokerInfo.avatar=g[E].avatar||"",u.revokerInfo.userID=E)})}catch(g){console.debug(g)}})}const UD=1,ER=2,Mh=20,WQ=2500,dR=1,vh=300;function zQ(s){return pA(this,void 0,void 0,function*(){var n,g;const{appStore:u,utils:{isEmpty:E},common:{getCurrentUserID:m},notificationCenter:D,OuterEvent:M,OuterConstant:{CONV_C2C:T}}=ll.core,{messageList:P,conversationID:W}=s,iA=u.conversationStore.getConversationMap();let EA=(n=iA.get(W))===null||n===void 0?void 0:n.peerReadTime;if(!EA){const kA=W.replace(T,""),xA=yield function(LA){return pA(this,void 0,void 0,function*(){const SA={To_Account:LA};return ll.core.common.buildAndSendPacket({servcmd:"openim.get_peer_read_time",data:SA})})}([kA]);if(xA){const{ReadTime:LA}=xA;EA=LA?.[0],iA.has(W)&&(iA.get(W).peerReadTime=EA)}}if(iA.has(W)){const kA=(g=iA.get(W))===null||g===void 0?void 0:g.lastMessage;E(kA)||kA.fromAccount===m()&&kA.lastTime<=EA&&!kA.isPeerRead&&(kA.isPeerRead=!0,u.conversationStore.updateConversation(W,{lastMessage:kA}))}const RA=[];P.forEach(kA=>{kA.time<=EA&&!kA.isPeerRead&&kA.flow==="out"&&(kA.isPeerRead=!0,RA.push(kA))}),RA.length>0&&D.emitOuterEvent(M.MESSAGE_READ_BY_PEER,{name:M.MESSAGE_READ_BY_PEER,data:RA})})}var CR=new class{init(s){this._core=s,s.helper.registerApi({apiName:"getMessageList",context:this}),s.helper.registerApi({apiName:"getMessageListHopping",context:this}),s.helper.registerApi({apiName:"clearHistoryMessage",context:this})}getMessageList(s){return pA(this,void 0,void 0,function*(){try{const{message:n,OuterConstant:{Direction:g,CONV_C2C:u,CONV_GROUP:E},InnerEvent:{HISTORY_MESSAGE_FETCHED:m},notificationCenter:D}=this._core,{conversationID:M,nextReqMessageID:T}=s,P=Mh;if(M==="@TIM#SYSTEM")return{code:0,data:{messageList:[],isCompleted:!1,nextMessageSeq:""}};const W=this._getAvailableLocalMessagesCount({conversationID:M,nextReqMessageID:T});if(this._needFetchHistoryMessageList({conversationID:M,availableLocalMessagesCount:W,targetCount:P})){let iA=null;if(M.startsWith(E)?iA=yield n.messageHistory.getGroupRoamingMessagesByAnchor({conversationID:M,sequence:Number(T),count:P,direction:g.FORWARD,shouldMarkCompleted:!0}):M.startsWith(u)&&(iA=yield n.messageHistory.getC2CRoamingMessagesByAnchor({conversationID:M,messageID:T,count:P,direction:g.FORWARD,shouldMarkCompleted:!0})),iA){const{nextReqMessageIDFromServer:EA,hasNoMoreHistoryMessage:RA,messageList:kA}=iA,xA=n.messageDataHandler.prependLocalMessageList({messageList:kA,conversationID:M});(function(ae){const{appStore:ne,message:_i,OuterConstant:Ti}=ll.core,Lt=ne.conversationStore.getConversation(ae),Ni=_i.messageDataHandler.getLocalMessageList(ae);if(!Lt||Ni.length===0||ae===Ti.CONV_SYSTEM)return;const cs=[];for(let mt=0;mtUA.isRevoked).length;Me=cs.length-Lt.unreadCount-mt}else Me=cs.length-Lt.unreadCount;for(let mt=0;mtae.isRevoked);yield uR(SA),D.emitInnerEvent(m,xA);const OA={nextReqMessageID:RA?"":String(EA),messageList:LA,isCompleted:RA},JA=LA.map(ae=>ae.sequence);return{code:0,data:OA,successLog:{message:`conversationID: ${M} nextReqMessageID: ${T} availableLocalMessagesCount: ${W} sequenceList: ${JSON.stringify(JA)}`}}}return{code:0,data:{messageList:[],isCompleted:!1,nextReqMessageID:""}}}return{code:0,data:yield this._getMessageListFromMemory({conversationID:M,nextReqMessageID:T,count:P}),successLog:{message:`conversationID: ${M} nextReqMessageID: ${T} availableLocalMessagesCount: ${W}}`}}}catch(n){const{code:g,message:u}=n||{};throw new this._core.helper.ChatError({code:g,message:u,moreMessage:`options: ${this._core.utils.safeStringify(s)}`})}})}getMessageListHopping(s){return pA(this,void 0,void 0,function*(){var n,g;const{OuterConstant:{Direction:u,CONV_C2C:E,CONV_GROUP:m},utils:{safeStringify:D}}=this._core,{conversationID:M,sequence:T,time:P,direction:W=u.FORWARD}=s,{utils:{isEmpty:iA},message:EA,notificationCenter:RA,InnerEvent:{HISTORY_MESSAGE_FETCHED:kA}}=this._core;if(![u.BACKWARD,u.FORWARD].includes(W))throw new this._core.helper.ChatError({message:"direction must be 0 or 1",moreMessage:`options: ${D(s)}`});let{count:xA=Mh}=s;xA=xA>Mh?Mh:xA;let LA=null;if(M.startsWith(m)){if(LA=yield EA.messageHistory.getGroupRoamingMessagesByAnchor({conversationID:M,sequence:T,count:xA,direction:W}),LA){const{nextReqMessageIDFromServer:SA,hasNoMoreHistoryMessage:OA,messageList:JA,invisibleSequenceList:ae}=LA;if(this._core.message.messageDataHandler.storeSparseMessageList(JA),RA.emitInnerEvent(kA,JA),W===u.FORWARD){const ne=OA&&SA<1;return{code:0,data:{messageList:JA,isCompleted:ne,nextMessageSeq:ne?"":SA}}}if(W===u.BACKWARD){if(iA(JA)&&iA(ae))return{code:0,data:{messageList:[],isCompleted:!0,nextMessageSeq:""}};const ne=((n=JA?.[JA.length-1])===null||n===void 0?void 0:n.sequence)||0,_i=((g=ae?.[ae.length-1])===null||g===void 0?void 0:g.sequence)||0;return{code:0,data:{messageList:JA.filter(Ti=>Ti.sequence>=T),isCompleted:!OA,nextMessageSeq:OA?Math.max(ne,_i)+1:""}}}return{code:0,data:LA}}}else if(M.startsWith(E)&&(LA=yield EA.messageHistory.getC2CRoamingMessagesByAnchor({conversationID:M,count:xA+1,time:P,direction:W}),LA)){const{messageList:SA,lastMessageTime:OA,hasNoMoreHistoryMessage:JA}=LA;return RA.emitInnerEvent(kA,SA),JA||(W===u.FORWARD?SA.shift():SA.pop()),EA.messageDataHandler.storeSparseMessageList(SA),yield zQ({messageList:SA,conversationID:M}),{code:0,data:{messageList:SA,isCompleted:JA,nextMessageTime:JA?"":OA}}}})}clearHistoryMessage(s){return pA(this,void 0,void 0,function*(){var n;const{appStore:g,common:{ChatError:u,getCurrentUserID:E},OuterConstant:{CONV_C2C:m,CONV_GROUP:D},apiMap:M,message:T}=this._core,P=g.conversationStore.getConversation(s);if(!P)throw new u({code:WQ});const W={fromAccount:E()},{type:iA}=P;iA===m?(W.type=UD,W.toAccount=s.replace(m,"")):iA===D&&(W.type=ER,W.toGroupID=s.replace(D,""));try{return yield(n=M?.setMessageRead)===null||n===void 0?void 0:n.call(M,{conversationID:s}),(yield function(RA){return pA(this,void 0,void 0,function*(){const{fromAccount:kA,type:xA,toAccount:LA,toGroupID:SA}=RA,OA={From_Account:kA,Type:xA,To_Account:LA,ToGroupid:SA};return ll.core.common.buildAndSendPacket({servcmd:"recentcontact.clear_msg",data:OA})})}(W))&&(T.messageDataHandler.deleteConversationMessageList(s),T.messageHistory.completedHistoryConversations.delete(s),T.messageHistory.clearHistoryMessageListFetchAnchors(s),this._updateConversationLastMessage(s)),{code:0,data:{conversationID:s},successLog:{message:`convID:${s}`}}}catch(EA){const{errorCode:RA}=EA;throw new this._core.helper.ChatError({functionName:"clearHistoryMessage",code:RA,moreMessage:`convID:${s}`})}})}_updateConversationLastMessage(s){const{appStore:n}=this._core;n.conversationStore.updateConversation(s,{lastMessage:this._generateLastMessage()},{needSort:!0})}_getAvailableLocalMessagesCount({conversationID:s,nextReqMessageID:n}){const{OuterConstant:{CONV_C2C:g,CONV_GROUP:u}}=this._core,E=this._core.message.messageDataHandler.getLocalMessageList(s),{length:m}=E;if(!n)return m;let D=-1;return s?.startsWith(g)?D=E.findIndex(M=>M.ID===n):s?.startsWith(u)&&(D=E.findIndex(M=>n.includes("-")?M.ID===n:String(M.sequence)===n)),D===-1?0:D}_needFetchHistoryMessageList({conversationID:s,availableLocalMessagesCount:n,targetCount:g}){const{message:u}=this._core;return nn.startsWith(E)?EA.ID===g:String(EA.sequence)===g),W=iA>u?iA-u:0,T=iA):W=M>u?M-u:0,P.messageList=D.slice(W,iA),P.isCompleted=T<=u&&m.messageHistory.completedHistoryConversations.has(n),P.isCompleted?P.nextReqMessageID="":P.nextReqMessageID=this._generateNextReqMessageID({conversationID:n,targetIndex:W}),n.startsWith(E)&&(yield IR(n),yield zQ({messageList:P.messageList,conversationID:n})),P})}_generateNextReqMessageID({conversationID:s,targetIndex:n}){const g=this._core.message.messageDataHandler.getLocalMessageList(s);return s.startsWith("C2C")?g[n].ID:String(g[n].sequence)}_generateLastMessage(){return{lastTime:0,lastSequence:0,fromAccount:"",messageForShow:"",payload:null,type:"",isRevoked:!1,cloudCustomData:"",onlineOnlyFlag:!1,nick:"",nameCard:"",version:0,isPeerRead:!1,revoker:null}}},fB=new class{constructor(){this._lastMessageSequenceMapOnDisconnect=new Map,this._lastMessageTimeMapOnDisconnect=new Map}init(s){this._core=s;const{common:{workflowManager:n},constants:{WORKFLOW_NAME:g,WORKFLOW_STEP:u,InnerEvent:E}}=s;n.registerWorkflowStep(g.SYNC_SERVER_INFO_AFTER_RE_ONLINE,u.HISTORY_MESSAGE_RECOVER,this._syncGroupOfflineMessage,this),n.registerWorkflowStep(g.SYNC_SERVER_INFO_AFTER_RE_ONLINE,u.C2C_HISTORY_MESSAGE_RECOVER,this._syncC2COfflineMessage,this),s.notificationCenter.subscribeInnerEvent(E.SOCKET_DISCONNECTED,this._updateLastMessageSequenceMapOnDisconnect,this)}_syncGroupOfflineMessage(s){const{conversationList:n}=s?.result||{},{OuterConstant:g,utils:{isArray:u}}=this._core;if(u(n)){const E=n.filter(m=>m.type===g.CONV_GROUP&&m.groupProfile.type!==g.GRP_AVCHATROOM);return this._recoverGroupHistoryMessage(E)}}_recoverGroupHistoryMessage(s){return pA(this,void 0,void 0,function*(){const{OuterConstant:n}=this._core,g=[],u=[];return yield Promise.all(s?.map(E=>pA(this,void 0,void 0,function*(){const{groupProfile:{groupID:m}={},lastMessage:{lastSequence:D}={}}=E,M=`${n.CONV_GROUP}${m}`;let T=this._getLocalLastMessageSequence(M);this._shouldRecoverHistory({localLastMessageSequence:T,serverLastMessageSequence:D})&&(yield this._recoverGroupHistoryForConversation({conversationID:M,localLastMessageSequence:T,serverLastMessageSequence:D,groupTipList:u})),g.push(M.replace(n.CONV_GROUP,""))}))),{recoverRevokeNoticeGroupIDList:g,groupTipList:u}})}_recoverGroupHistoryForConversation(s){return pA(this,arguments,void 0,function*({conversationID:n,localLastMessageSequence:g,serverLastMessageSequence:u,groupTipList:E}){try{const{utils:{isArray:m,isObject:D,isEmpty:M},OuterEvent:T,OuterConstant:P,notificationCenter:W,message:iA,appStore:EA,common:{getMessagePreviewText:RA,buildLastMessage:kA}}=this._core,xA=u-g,LA=Math.min(20,xA),SA={},OA=yield iA.messageHistory.getGroupRoamingMessagesByAnchor({conversationID:n,sequence:g+LA,direction:P.Direction.FORWARD,count:LA}),{nextReqMessageIDFromServer:JA,hasNoMoreHistoryMessage:ae,messageList:ne,serverGroupTipList:_i}=OA;m(_i)&&E.push(..._i);const Ti=ae&&JA<0,Lt=[];if(m(ne)&&(ne.forEach(Ni=>{iA.messageReceiver.groupMessageReceiver.updateMessageProfile(Ni),Ni.from===P.CONV_SYSTEM&&(Ni.isSystemMessage=!1),iA.messageDataHandler.storeConversationMessage(Ni)&&!M(Ni.payload)&&(Lt.push(Ni),Ni._isExcludedFromLastMessage||(SA.lastMessage=kA(Ni)))}),Lt.length>0&&W.emitOuterEvent(T.MESSAGE_RECEIVED,{name:T.MESSAGE_RECEIVED,data:Lt})),!Ti&&ne.length>0){const Ni=ne[ne.length-1].sequence;yield this._recoverGroupHistoryForConversation({conversationID:n,localLastMessageSequence:Ni,serverLastMessageSequence:u,groupTipList:E})}D(SA.lastMessage)&&(SA.lastMessage.messageForShow=RA(SA.lastMessage.type,SA.lastMessage.payload),EA.conversationStore.updateConversation(n,SA))}catch(m){this._core.ssoLog.error("_recoverGroupHistoryForConversation",`Recovery failed for conversation:${n}`,{error:m})}})}_updateLastMessageSequenceMapOnDisconnect(){const{message:s}=this._core,n=s.messageDataHandler.getContinuousMessagesByConversation();for(const[g,u]of n){const E=Array.from(u.values());if(E?.length>0){const m=E[E.length-1];g.startsWith("C2C")?this._lastMessageTimeMapOnDisconnect.set(g,m.time):g.startsWith("GROUP")&&this._lastMessageSequenceMapOnDisconnect.set(g,m.sequence)}}}_getLocalLastMessageSequence(s){const{message:n}=this._core;if(this._lastMessageSequenceMapOnDisconnect.has(s))return this._lastMessageSequenceMapOnDisconnect.get(s);const g=n.messageDataHandler.getLocalMessageList(s),u=g[g.length-1];return u?.sequence}_shouldRecoverHistory(s){const{localLastMessageSequence:n,serverLastMessageSequence:g}=s;if(typeof n!="number"||typeof g!="number")return!1;const u=g-n;return g!==0&&n>0&&u>=dR&&u{m.type===g.CONV_C2C&&E.push(m)}),this._recoverC2CHistoryMessage(E)}}_recoverC2CHistoryMessage(s){return pA(this,void 0,void 0,function*(){yield Promise.all(s?.map(n=>pA(this,void 0,void 0,function*(){const{conversationID:g,lastMessage:{lastTime:u}={}}=n,E=this._getLocalLastMessageTime(g);this._shouldRecoverC2CHistory({localLastMessageTime:E,serverLastMessageTime:u})&&(yield this._recoverHistoryForC2CConversation({conversationID:g,localLastMessageTime:E,serverLastMessageTime:u}))})))})}_shouldRecoverC2CHistory(s){const{localLastMessageTime:n,serverLastMessageTime:g}=s,u=g-n;return n>0&&u>=1&&u<=600}_recoverHistoryForC2CConversation(s){return pA(this,void 0,void 0,function*(){var n;const{conversationID:g,localLastMessageTime:u,serverLastMessageTime:E}=s,{utils:{isArray:m,isObject:D,isEmpty:M,safeStringify:T},OuterEvent:P,OuterConstant:W,notificationCenter:iA,message:EA,appStore:RA,common:{getMessagePreviewText:kA,buildLastMessage:xA}}=this._core;try{const LA={},SA=yield EA.messageHistory.getC2CRoamingMessagesByAnchor({conversationID:g,direction:W.Direction.BACKWARD,time:u,count:20});if(M(SA))return;const{hasNoMoreHistoryMessage:OA,messageList:JA}=SA,ae=[];m(JA)&&(JA.forEach(_i=>{EA.messageDataHandler.storeConversationMessage(_i)&&!M(_i.payload)&&(ae.push(_i),_i._isExcludedFromLastMessage||(LA.lastMessage=xA(_i)))}),ae.length>0&&iA.emitOuterEvent(P.MESSAGE_RECEIVED,{name:P.MESSAGE_RECEIVED,data:ae}));const ne=(n=JA[JA.length-1])===null||n===void 0?void 0:n.time;!OA&&ne>E&&(yield this._recoverHistoryForC2CConversation({conversationID:g,localLastMessageTime:ne,serverLastMessageTime:E})),D(LA.lastMessage)&&(LA.lastMessage.messageForShow=kA(LA.lastMessage.type,LA.lastMessage.payload),RA.conversationStore.updateConversation(g,LA))}catch(LA){this._core.ssoLog.error("_recoverHistoryForC2CConversation",`Recovery failed for conversation:${g} error: ${T(LA)}`)}})}_getLocalLastMessageTime(s){const{message:n}=this._core;if(this._lastMessageTimeMapOnDisconnect.has(s))return this._lastMessageTimeMapOnDisconnect.get(s);const g=n.messageDataHandler.getLocalMessageList(s),u=g[g.length-1];return u?.time}reset(){this._lastMessageSequenceMapOnDisconnect.clear(),this._lastMessageTimeMapOnDisconnect.clear()}dispose(){this.reset()}},yB=new class{constructor(){this.name="HistoryMessage"}install(s){this._core=s,ll.init(s),CR.init(s),fB.init(s),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.LOGOUT,this._reset,this),s.notificationCenter.subscribeInnerEvent(s.InnerEvent.DESTROY,this.dispose,this)}dispose(){const{notificationCenter:s,InnerEvent:n}=this._core;s.unSubscribeInnerEvent(n.LOGOUT,this._reset,this),s.unSubscribeInnerEvent(n.DESTROY,this.dispose,this),fB.dispose()}_reset(){fB.reset()}},FD=new class{init(s){this.core=s}},vC=new class{constructor(){this._reportedAtomicStoreIDs=new Set}init(s){const{helper:{registerExperimentalAPI:n}}=s;this._core=s,n("reportModalView",this),n("reportTUIFeatureUsage",this),n("reportRoomEngineEvent",this)}reportModalView(s){const{ssoLog:n,utils:{safeStringify:g,isString:u}}=this._core;try{if(!u(s))throw new Error("reportModalView data is not a string");n.createSSOLogData({method:"reportModalView",message:s,eventType:30}).end(!0)}catch(E){n.debug(`reportModalView Report failed: ${g(E)}`)}}reportTUIFeatureUsage(s){const{ssoLog:n,utils:{safeStringify:g,isEmpty:u}}=this._core,{atomicStoreID:E}=s;try{u(E)||this._reportedAtomicStoreIDs.has(E)||(this._core.ssoLog.info("reportTUIFeatureUsage",`atomicStoreID: ${s.atomicStoreID}`,{method:"reportTUIFeatureUsage",eventType:31,code:E}),this._reportedAtomicStoreIDs.add(E))}catch(m){n.debug(`reportTUIFeatureUsage Report failed: ${g(m)}`)}}reportRoomEngineEvent(s){const{utils:{safeStringify:n},ssoLog:g}=this._core;try{g.debug(`reportRoomEngineEvent Report: ${n(s)}`);const{eventId:u,eventCode:E,eventResult:m,eventMessage:D,moreMessage:M,extensionMessage:T}=s;g.createSSOLogData({method:T,code:u,message:D,eventType:30,costTime:E,uiPlatform:m,moreMessage:M}).end(!0)}catch(u){g.debug(`reportRoomEngineEvent Report failed: ${n(u)}`)}}reset(){this._reportedAtomicStoreIDs.clear()}dispose(){this.reset()}},ZQ=new class{constructor(){this.name="DataReport"}install(s){this._core=s;const{notificationCenter:n,InnerEvent:{LOGOUT:g,DESTROY:u}}=s;FD.init(s),vC.init(s),n.subscribeInnerEvent(g,this._reset,this),n.subscribeInnerEvent(u,this._dispose,this)}_reset(){vC.reset()}_dispose(){const{notificationCenter:s,InnerEvent:{LOGOUT:n,DESTROY:g}}=this._core;s.unSubscribeInnerEvent(n,this._reset,this),s.unSubscribeInnerEvent(g,this._dispose,this),vC.dispose()}};let jm=nr.STANDARD,DB=[];jm=nr.STANDARD,DB=[ah,IC,uC,EC,Rc,HT,yB,ZQ,PE,vi,jn,UT,xm,GD,XI];function SB(s,n){const{operationType:g,memberInfoList:u,operatorInfo:E}=s||{};let m={};if(Rs(u)?Rs(E)||(m=E):g!==Tg.JOINED&&g!==Tg.KICKED&&g!==Tg.ADMIN_SET&&g!==Tg.ADMIN_CANCELED||(m=Object.assign({},u[0])),!Rs(m)){const{nick:D="",avatar:M=""}=m;n.nick=D,n.avatar=M}}const XQ=s=>({lastTime:s?.time||s?.lastTime||0,lastSequence:s?.sequence||s?.lastSequence||0,fromAccount:s?.from||s?.fromAccount||"",messageForShow:Zc(s?.type,s?.payload),payload:s?.payload||null,type:s?.type||"",isRevoked:s?.isRevoked||!1,cloudCustomData:s?.cloudCustomData||"",onlineOnlyFlag:s?._onlineOnlyFlag||!1,nick:s?.nick||"",nameCard:s?.nameCard||"",version:s?.version||0,isPeerRead:s?.isPeerRead||!1,revoker:s?.revoker||null});var $Q=Object.freeze({__proto__:null,ChatError:gs,WorkflowManager:ws,buildAndSendPacket:gg,buildLastMessage:XQ,get builtInPlugins(){return DB},checkBusinessCapabilityBits:tn,deepMerge:Cd,getCurrentUserID:Ar,getErrorMessage:rs,getMessagePreviewText:Zc,isC2CConv:s=>l(s)&&s.slice(0,3)===ka.CONV_C2C,isCommunity:Xr,isGroupConv:s=>l(s)&&s.slice(0,5)===ka.CONV_GROUP,isInternational:wl,isTopic:zc,isUnlimitedAVChatRoom:function(){var s;return!!(!((s=ye.store.get("instance"))===null||s===void 0)&&s.unlimitedAVChatRoom)},liteChatInstanceMap:Ca,registerInterceptor:Mc,registerValidateConfig:Wc,requireAuth:ud,get sdkEdition(){return jm},setGroupTipsUserInfo:SB,t:ku,updateGroupAtInfo:(s,n)=>{const{CONV_AT_ME:g,CONV_AT_ALL:u,CONV_AT_ALL_AT_ME:E}=Lo;if(function(M,T){const{CONV_AT_ME:P,CONV_AT_ALL:W,CONV_AT_ALL_AT_ME:iA}=Lo,{groupID:EA,sequence:RA}=M;let kA=!1;return Xr({groupID:EA})&&T.forEach(xA=>{xA.messageSequence===RA&&(xA.atTypeArray.includes(P)&&M.groupAtType.includes(W)&&(xA.atTypeArray=[iA]),xA.atTypeArray.includes(W)&&M.groupAtType.includes(P)&&(xA.atTypeArray=[iA],xA.__random=M.__random,xA.__sequence=M.__sequence),kA=!0)}),kA}(s,n))return;let m=[...s.groupAtType];m.includes(g)&&m.includes(u)&&(m=[E]);const D={from:s.from,groupID:s.groupID,topicID:s.topicID,messageSequence:s.sequence,atTypeArray:m,__random:s.__random,__sequence:s.__sequence};n.push(D)},validateAndExecute:Sr,validateParameters:II});class au{constructor(){this._builtInPlugins=new Set,this._externalPlugins=new Set}static getInstance(){return au._instance||(au._instance=new au),au._instance}static setInstance(n){au._instance=n}installBuiltInPlugin(n){n&&this._installPlugin(n,this._builtInPlugins)}installExternalPlugin(n){n&&this._installPlugin(n,this._externalPlugins)}clear(){this._builtInPlugins=new Set,this._externalPlugins=new Set}_installPlugin(n,g){let u=[];u=h(n)?n:[n];const E=u.findIndex(D=>D?.name==="AVChatRoom"),m=E>-1?u.splice(E,1):[];u.forEach(D=>{this._isPluginInstalled(D.name)||(D&&vg(D.install)?(g.add(D.name),vg(D.getInstalledSubPlugins)?(m?.forEach(M=>g.add(M?.name)),D.install(Cr.getInstance().exposeApiForPlugin(),m)):D.install(Cr.getInstance().exposeApiForPlugin()),vg(D.handleLoginSuccess)&&this._isLoggedIn()&&D.handleLoginSuccess()):vg(D)?(g.add(D.name),D(Cr.getInstance().exposeApiForPlugin()),vg(D.handleLoginSuccess)&&this._isLoggedIn()&&D.handleLoginSuccess()):console.warn('A plugin must either be a function or an object with an "install" function.'))})}_isPluginInstalled(n){return this._builtInPlugins.has(n)||this._externalPlugins.has(n)}_isLoggedIn(){var n;return((n=ye.store.get("login"))===null||n===void 0?void 0:n.isLoggedIn)===!0}}var MB=new class{constructor(){this._conversationMap=new Map}getConversationMap(){return this._conversationMap}getConversation(s){return this._conversationMap.get(s)}updateConversation(s,n,g){const{emit:u=!0,needSort:E=!1}=g||{},m=this._conversationMap.get(s);m&&!Rs(n)&&(Object.keys(n).forEach(D=>{m[D]=n[D]}),u&&ye.notificationCenter.emitInnerEvent(no.CONVERSATION_UPDATED,{needSort:E}))}deleteConversation(s){this._conversationMap.has(s)&&(this._conversationMap.delete(s),ye.notificationCenter.emitInnerEvent(no.CONVERSATION_UPDATED))}},Ap=new class{constructor(){this._groupMap=new Map}getGroupMap(){return this._groupMap}getGroup(s){return this._groupMap.get(s)}updateGroup(s,n){const g=this._groupMap.get(s);g&&!Rs(n)&&Object.keys(n).forEach(u=>{g[u]=n[u]})}},ep=new class{constructor(){this._messagesByConversation=new Map}updateMessage(s,n,g){var u;const{operation:E,updateUnreadCount:m=!0}=g,D=Do(g,["operation","updateUnreadCount"]),M=[];for(const T of n){const P=(u=this._messagesByConversation.get(s))===null||u===void 0?void 0:u.get(T);if(!P)return!1;Object.keys(D).forEach(W=>{P[W]=D[W]}),M.push(P)}return this._emitMessageStoreOperationEvent(E,{conversationID:s,messageList:M,updateUnreadCount:m}),M}getMessagesByConversation(s){var n;return[...((n=this._messagesByConversation.get(s))===null||n===void 0?void 0:n.values())||[]]}getMessages(){return this._messagesByConversation}_emitMessageStoreOperationEvent(s,n){const{conversationID:g}=n;zc(g)?ye.notificationCenter.emitInnerEvent(_u[s],n):ye.notificationCenter.emitInnerEvent(s,n)}},rc=new class{constructor(){this.userProfileMap=new Map,this.friendMap=new Map}getUserProfileMap(){return this.userProfileMap}getFriendMap(){return this.friendMap}getUserProfile(s){return this.userProfileMap.get(s)}getFriend(s){return this.friendMap.get(s)}},OD=Object.freeze({__proto__:null,conversationStore:MB,groupStore:Ap,messageStore:ep,userStore:rc});class Cr{static getInstance(){return Cr._instance||(Cr._instance=new Cr),Cr._instance}static setInstance(n){Cr._instance=n}constructor(){this._experimentalApiMap={statTUIKeyFeatures:this.statKeyFeatureUsage.bind(this),setApplicationID:this.setApplicationID.bind(this)},this._apiHandlersMap={},this._apiMap={on:ye.notificationCenter.subscribeOuterEvent.bind(ye.notificationCenter),off:ye.notificationCenter.unSubscribeOuterEvent.bind(ye.notificationCenter),destroy:this.destroy.bind(this),callExperimentalAPI:this.callExperimentalAPI.bind(this),use:au.getInstance().installExternalPlugin.bind(au.getInstance()),registerPlugin:this.registerPlugin.bind(this),setLogLevel:this.setLogLevel.bind(this)}}registerPlugin(n){ye.ssoLog.debug("registerPlugin",n)}statKeyFeatureUsage(n){ye.ssoLog.debug("statTUIKeyFeatures",n)}setLogLevel(n){ye.ssoLog.debug("setLogLevel",n),ye.ssoLog.setLogLevel(n)}setApplicationID(n){ye.store.set("instance",{applicationID:n})}getApiMap(){return this._apiMap}setApiMap(n){this._apiMap=n}registerApi(n){const{common:{timeManager:g},utils:{safeStringify:u}}=ye,{apiName:E,context:m,methodName:D=E,matcher:M}=n;this._apiHandlersMap[E]||(this._apiHandlersMap[E]=[]),this._apiHandlersMap[E].push({context:m,methodName:D,matcher:M}),this._apiMap[E]&&this._apiHandlersMap[E].length!==1||(this._apiMap[E]=(...T)=>{const P=g.getServerTimeMs();let W=0;E==="login"&&(W=4),qI.includes(E)&&ye.ssoLog.debug(E,`${E} start params: ${u(T)}`),Sr(D,T);const iA=this._apiHandlersMap[E];for(const EA of iA)if(!EA.matcher||EA.matcher(T))try{const RA=EA.context[EA.methodName].bind(EA.context)(...T);return this._isPromiseLike(RA)?this._handleAsyncResult(RA,E,W,P):(this._reportApiSuccessLog({result:RA,apiName:E,eventType:W,startTime:P}),RA)}catch(RA){throw ye.ssoLog.error(E,`${E} fail ${RA?.message||RA?.errorMessage})`,{error:RA,costTime:g.getServerTimeMs()-P,eventType:W,method:E}),RA}})}registerExperimentalAPI(n,g,u){const E=u||n;this._experimentalApiMap[n]=g[E].bind(g)}destroy(){return pA(this,void 0,void 0,function*(){var n,g;try{!((n=ye.store.get("login"))===null||n===void 0)&&n.isLogin&&(yield this._apiMap.logout()),ye.notificationCenter.emitInnerEvent(no.DESTROY)}catch(u){console.debug("destroy error: ",u)}finally{ye.notificationCenter.emitOuterEvent(Dr.SDK_DESTROY,{SDKAppID:(g=ye.store.get("instance"))===null||g===void 0?void 0:g.sdkAppId}),Ca.clear(),au.getInstance().clear(),ws.getInstance().destroy(),ye.destroy()}})}exposeApiForClient(){return this._apiMap}exposeApiForPlugin(){return Object.assign(Object.assign({InnerEvent:no,InnerEventSubType:ye.notificationCenter.InnerEventSubType,OuterEvent:Dr,OuterConstant:Lo,SignalingEvent:qc,helper:Object.assign(Object.assign(Object.assign({},ye.utils),ye.common),{registerApi:this.registerApi.bind(this),registerExperimentalAPI:this.registerExperimentalAPI.bind(this),registerInterceptor:Mc,registerValidateConfig:Wc,checkBusinessCapabilityBits:tn,registerWorkflowStep:ws.getInstance().registerWorkflowStep.bind(ws.getInstance()),ChatError:gs}),apiMap:this._apiMap},ye),{constants:Object.assign(Object.assign({},za),ye.constants),common:Object.assign(Object.assign(Object.assign({},$Q),ye.common),{workflowManager:ws.getInstance()}),utils:ye.utils,appStore:OD})}callExperimentalAPI(n,g){return ye.ssoLog.debug(`callExperimentalAPI.${n} start params: ${ye.utils.safeStringify(g)}`),this._experimentalApiMap[n]?this._experimentalApiMap[n](g):(ye.ssoLog.error("callExperimentalAPI",`callExperimentalAPI.${n} not found, params: ${ye.utils.safeStringify(g)}`),Promise.reject(new gs({code:da.INVALID_OPERATION})))}_isPromiseLike(n){return n!==null&&typeof n=="object"&&typeof n.then=="function"}_handleAsyncResult(n,g,u,E){return n.then(m=>(this._reportApiSuccessLog({result:m,apiName:g,eventType:u,startTime:E}),m)).catch(m=>{throw ye.ssoLog.error(g,`${g} fail ${m?.message||m?.errorMessage})`,{error:m,costTime:ye.common.timeManager.getServerTimeMs()-E,eventType:u,method:g,startTime:E}),m})}_reportApiSuccessLog(n){let{result:g,apiName:u,startTime:E,eventType:m}=n;const{timeManager:D}=ye.common,{successLog:{message:M,moreMessage:T}={message:"",moreMessage:""}}=g||{},P=D.getServerTimeMs();u==="login"&&(E+=D.getTimeOffsetWithServer()),qI.includes(u)&&ye.ssoLog.info(u,`${u} success ${M} ${T}`,{costTime:P-E,eventType:m,message:M,moreMessage:T,startTime:E}),g?.successLog&&delete g.successLog}}class hR{constructor(){this._latestLoginAt=0,this._latestSendOnlinePresenceRequestTime=0,this._helloInterval=120,this._customLoginInfo=""}init(){const{notificationCenter:n,store:g}=ye;g.set("login",{isReady:!1}),Cr.getInstance().registerApi({apiName:"login",context:this}),Cr.getInstance().registerApi({apiName:"logout",context:this}),Cr.getInstance().registerApi({apiName:"getLoginUser",context:this}),Cr.getInstance().registerApi({apiName:"isReady",context:this}),Cr.getInstance().registerApi({apiName:"getServerTime",context:this}),Cr.getInstance().registerExperimentalAPI("setCustomLoginInfo",this),n.subscribeInnerEvent(no.RECONNECTED,this._reLogin,this),ye.notificationCenter.subscribeInnerEvent(no.DESTROY,this._dispose,this)}login(n){return pA(this,void 0,void 0,function*(){var g;const{sdkEdition:u}=ye.store.get("instance")||{};try{if(this._isLoginIn())return this._createRepeatLoginResponse();if(this._isLoginFrequencyExceeded())throw new gs({functionName:"login",code:da.REPEAT_LOGIN});const E=yield this._performLogin(n);this._validateAfterLogin(E),this._handleLoginSuccess(E),yield this._ensureAsyncComplete(),this._updateAndEmitSDKReady(),this._latestLoginAt=0;const m=(g=ye.channel.getSocketAdapter())===null||g===void 0?void 0:g.getId(),{appId:D,href:M}=ye.store.get("instance")||{},{instanceID:T,customStatus:P}=E||{};return{code:0,data:E,successLog:{message:u,moreMessage:`socketID:${m} instanceID:${T} customStatus:${P} href: ${M} appId: ${D}`}}}catch(E){const{errorCode:m}=E;m!==da.REPEAT_LOGIN&&(this._latestLoginAt=0);const D=new gs({functionName:"login",code:m});throw console.error(D),D}})}_reLogin(){return pA(this,void 0,void 0,function*(){var n;try{if(!this._isLoginIn())return;const g=yield bu(this._customLoginInfo);if(g){const{instanceID:u,customStatus:E}=g;ye.store.set("login",{statusInstanceId:u}),ws.getInstance().executeWorkflow(Yt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,{customStatus:E,statusType:SE.USER_STATUS_ONLINE});const m=(n=ye.channel.getSocketAdapter())===null||n===void 0?void 0:n.getId();ye.ssoLog.info("reLogin",`socketId:${m} instanceId:${u}`)}}catch(g){console.warn(g)}})}logout(){return pA(this,arguments,void 0,function*(n=na.USER_INITIATED){const{ssoLog:g}=ye;g.debug("logout",`logout start logoutReason: ${n}`);try{yield this._performLogout(n),g.info("logout","logout success"),ye.ssoLog.uploadSSOLogData()}catch(u){const{errorCode:E}=u;throw new gs({functionName:"logout",code:E})}finally{this.handleLogoutCompleted()}return{code:0,data:{}}})}getLoginUser(){return this._isLoginIn()?Ar():""}isReady(){var n;return(n=ye.store.get("login"))===null||n===void 0?void 0:n.isReady}setCustomLoginInfo(n=""){this._customLoginInfo=n}handleLogoutCompleted(){this._updateAndEmitSDKNotReady(),this._reset(),ws.getInstance().reset(),ye.notificationCenter.emitInnerEvent("logout")}getServerTime(){const{timeManager:n}=ye.common;return n.getServerTimeMs()}_updateAndEmitSDKReady(){ye.store.set("login",{isReady:!0}),setTimeout(()=>{ye.notificationCenter.emitOuterEvent(Dr.SDK_READY,{name:Dr.SDK_READY})},1)}_updateAndEmitSDKNotReady(){ye.store.set("login",{isReady:!1}),ye.notificationCenter.emitOuterEvent(Dr.SDK_NOT_READY,{name:Dr.SDK_NOT_READY})}_validateAfterLogin(n){const g="login";if(!n)throw new gs({functionName:g,message:"login response is empty"});const{tinyID:u,a2Key:E}=n||{};if(!u)throw new gs({functionName:g,code:da.NO_TINYID});if(!E)throw new gs({functionName:g,code:da.NO_A2KEY})}_createRepeatLoginResponse(){var n;return{code:0,data:{actionStatus:"OK",errorCode:0,errorInfo:rs({code:"RepeatLogin",replacement1:(n=ye.store.get("login"))===null||n===void 0?void 0:n.userId}),repeatLogin:!0}}}_performLogin(n){return pA(this,void 0,void 0,function*(){const{userID:g,userSig:u}=n;return ye.store.set("login",{userId:g,userSig:u}),this._latestLoginAt=Date.now(),bu(this._customLoginInfo)})}_ensureAsyncComplete(){return pA(this,void 0,void 0,function*(){yield new Promise(n=>{setTimeout(()=>n(null),1)})})}_handleLoginSuccess(n){const{timeManager:g}=ye.common,{helloInterval:u,timeStamp:E,customStatus:m,purchaseBits:D}=n,M=1e3*E;g.calculateTimeOffsetWithServer(this._latestLoginAt,M),this._helloInterval=u||120,this._updateLoginStore(n),ye.user.userStatus.setCustomStatus(m),ws.getInstance().executeWorkflow(Yt.SYNC_SERVER_INFO_AFTER_LOGIN,{purchaseBits:D}),ye.common.taskScheduler.addTask({id:Gg,intervalMs:1e3*this._helloInterval,callback:this._sendOnlinePresenceRequest,context:this})}_performLogout(n){return function(g){return pA(this,void 0,void 0,function*(){const{logoutReason:u}=g,E="im_open_status.wslogout",m=ye.common.generateProtocolData({servcmd:E,data:{wslogout_type:u,isWebUniapp:0}}),D=`${m.head.seq}${E}`;return yield ye.channel.sendPacket(m,{requestId:D})})}({logoutReason:n})}_updateLoginStore(n){const{a2Key:g,tinyID:u,instanceID:E,authKey:m}=n;ye.store.set("login",{a2Key:g,tinyID:u,statusInstanceId:E,authKey:m,isLoggedIn:!0})}_sendOnlinePresenceRequest(){return pA(this,void 0,void 0,function*(){this._latestSendOnlinePresenceRequestTime=Date.now();try{yield function(){const n="im_open_status.wshello",g=ye.common.generateProtocolData({servcmd:n,data:{isWebUniapp:0}}),u=`${g.head.seq}${n}`;return ye.channel.sendPacket(g,{requestId:u})}()}catch(n){ye.ssoLog.warn("_sendOnlinePresenceRequest",` error:${n.message}`)}})}_isLoginIn(){var n;return((n=ye.store.get("login"))===null||n===void 0?void 0:n.isLoggedIn)===!0}_isLoginFrequencyExceeded(){return Date.now()-this._latestLoginAt<=15e3}_reset(){ye.common.taskScheduler.removeTask(Gg),this._helloInterval=120,this._latestSendOnlinePresenceRequestTime=0,this._latestLoginAt=0,this._customLoginInfo="",ye.store.clear("login"),ye.store.set("login",{isReady:!1}),ye.store.set("instance",{applicationID:0})}_dispose(){this._reset();const{notificationCenter:n}=ye;n.unSubscribeInnerEvent(no.RECONNECTED,this._reLogin,this),n.unSubscribeInnerEvent(no.DESTROY,this._dispose,this)}}const BR={login:{userID:{required:!0,rules:["string"],allowEmpty:!1},userSig:{required:!0,rules:["string"],allowEmpty:!1}}},qT={logout:!0};class Rh{constructor(){this.loginAction=new hR,this.kickedOutHandler=new Gu,this.loginAction.init(),this.kickedOutHandler.init(),Wc({auth:qT,params:BR})}}var Kr,$u,KE;(function(s){s.CONV_C2C="C2C",s.CONV_GROUP="GROUP",s.CONV_TOPIC="TOPIC",s.CONV_SYSTEM="@TIM#SYSTEM"})(Kr||(Kr={})),function(s){s.MSG_PRIORITY_HIGH="High",s.MSG_PRIORITY_NORMAL="Normal",s.MSG_PRIORITY_LOW="Low",s.MSG_PRIORITY_LOWEST="Lowest"}($u||($u={})),function(s){s.MSG_TEXT="TIMTextElem",s.MSG_CUSTOM="TIMCustomElem",s.MSG_LOCATION="TIMLocationElem",s.MSG_FACE="TIMFaceElem",s.MSG_IMAGE="TIMImageElem",s.MSG_AUDIO="TIMSoundElem",s.MSG_FILE="TIMFileElem",s.MSG_VIDEO="TIMVideoFileElem",s.MSG_GRP_TIP="TIMGroupTipElem",s.MSG_GRP_SYS_NOTICE="TIMGroupSystemNoticeElem",s.MSG_MERGER="TIMRelayElem"}(KE||(KE={}));const PD={1:$u.MSG_PRIORITY_HIGH,2:$u.MSG_PRIORITY_NORMAL,3:$u.MSG_PRIORITY_LOW,4:$u.MSG_PRIORITY_LOWEST},xD=0,QR=1;var AE;(function(s){s.IN="in",s.OUT="out"})(AE||(AE={}));const pR=2,tp={};function gu(s){if(!s)return 0;if(tp[s]===void 0){const n=new Date,g=`3${n.getHours()}`.slice(-2),u=`0${n.getMinutes()}`.slice(-2),E=`0${n.getSeconds()}`.slice(-2);tp[s]=parseInt([g,u,E,"0001"].join(""),10),console.log(`autoIncrementIndex start index:${tp[s]}`)}else tp[s]+=1;return tp[s]}class jE{constructor(n){this.ID="",this.random=0,this.sequence=0,this.nameCard="",this.isRead=!1,this.isPeerRead=!1,this.isDeleted=!1,this.isResend=!1,this.hasRiskContent=!1,this._onlineOnlyFlag=!1,this.atUserList=[],this._groupAtInfoList=[],this.isBroadcastMessage=!1,this.priority=$u.MSG_PRIORITY_NORMAL,this._relayFlag=!1;const{clientTime:g=ye.common.timeManager.getServerTimeSeconds()||0,senderTinyID:u,currentUser:E,needReadReceipt:m,isSupportExtension:D,customModerationConfigurationId:M,to:T,from:P,nick:W="",avatar:iA="",time:EA,messageControlInfo:RA,tinyID:kA,cloudCustomData:xA="",messageLifeTime:LA,messageVersion:SA=0,conversationType:OA,sequence:JA,checkResult:ae=0,isPlaceMessage:ne=0,messageFlagBits:_i,receiverList:Ti,isSystemMessage:Lt=!1,status:Ni=Yr.SUCCESS,revokeReason:cs="",conversationSubType:Me,clientSequence:mt,protocol:UA="JSON",revokerInfo:ni={userID:"",nick:"",avatar:""},readReceiptInfo:_s={readCount:void 0,unreadCount:void 0,isPeerRead:void 0,timestamp:0},random:Gi,groupProfile:Or,atUserList:xi,flow:gr,isRead:Tt=!1,priority:Nt=$u.MSG_PRIORITY_NORMAL,onlineOnlyFlag:tE=!1,nameCard:ln="",quoteInfo:Bo}=n;var Il;this.clientTime=g,this.senderTinyID=u||kA,this.needReadReceipt=m===!0||m===1,this.isSupportExtension=D===!0||D===1,this._cmConfigID=M,this.to=T,this.nick=W,this.avatar=iA,this.protocol=UA,this.random=Gi===void 0?(Il=Il||99999999,Math.round(Math.random()*Il)):Gi,this.time=EA||Math.ceil(Date.now()/1e3),this._isExcludedFromLastMessage=!!RA?.excludedFromLastMessage,this._isExcludedFromUnreadCount=!!RA?.excludedFromUnreadCount,this.isModified=!!SA,this.cloudCustomData=xA,this.messageLifeTime=LA,this.from=P||null,this.sequence=JA||0,this.conversationType=OA||Kr.CONV_C2C,this.hasRiskContent=ae>1,this.version=SA,this.isPlaceMessage=ne,this.isRevoked=ne===2||_i===8,this.isSystemMessage=Lt,this.readReceiptInfo=_s,this.revokeReason=cs,this.revokerInfo=ni,this._receiverList=Ti,this.conversationSubType=Me,this.revoker=ni?.revoker||"",this.clientSequence=mt||JA||0,this.status=Ni,this.atUserList=xi||[],this.flow=gr,this.isRead=Tt,this.priority=Nt,this._onlineOnlyFlag=tE,this.nameCard=ln,this.quoteInfo=Bo,this.reInitialize(E),this._initC2CReadReceiptInfo(n),this._extractGroupInfo(Or)}getElements(){return this._elements}isOnlineMessage(){return this.messageLifeTime===0}setElement(n){Array.isArray(n)?this._elements=n:this._elements=[n],this._updatePayloadAndType()}transformElementsToServerFormat(){return this._elements?Array.isArray(this._elements)?this._elements.map(n=>n.transformToServerFormat()):this._elements.transformToServerFormat():null}setRelayFlag(n){this._relayFlag=n}validateBeforeSend(){var n,g,u;return this._relayFlag?{isValid:!0}:((n=this._elements)===null||n===void 0?void 0:n.length)>0?(u=(g=this._elements[0])===null||g===void 0?void 0:g.validateBeforeSend)===null||u===void 0?void 0:u.call(g):{isValid:!1}}_updatePayloadAndType(){this._elements[0]&&(this.payload=this._elements[0].content,this.type=this._elements[0].type)}_initC2CReadReceiptInfo(n){const{readReceiptSentByPeer:g,timestamp:u=0}=n;this.conversationType===Kr.CONV_C2C&&this.needReadReceipt===!0&&(this.readReceiptInfo.isPeerRead=g===1,this.readReceiptInfo.timestamp=u)}_extractGroupInfo(n){if(!n)return;const{From_AccountNick:g,From_AccountHeadurl:u,MsgFrom_AccountExtraInfo:E,GroupType:m}=n,{NameCard:D}=E||{};typeof g=="string"&&(this.nick=g),typeof u=="string"&&(this.avatar=u),typeof D=="string"&&(this.nameCard=D),this.conversationSubType=m}reInitialize(n){n===this.from&&(this.isRead=!0),this._initSequence(n),this._concatConversationID(n),this.generateMessageID()}_concatConversationID(n){let g="";const u=this.conversationType;u!==Kr.CONV_SYSTEM?(g=u===Kr.CONV_C2C?n===this.from?this.to:this.from:this.to,this.conversationID=g?`${u}${g}`:null):this.conversationID=Kr.CONV_SYSTEM}_initSequence(n){this.clientSequence===0&&n&&(this.clientSequence=gu(n)),this.sequence===0&&this.conversationType===Kr.CONV_C2C&&(this.sequence=this.clientSequence)}generateMessageID(){this.from===Kr.CONV_SYSTEM&&(this.senderTinyID="144115198244471703"),this.ID=`${this.senderTinyID}-${this.clientTime}-${this.random}`}setIsRead(n){this.isRead=n}}class Td{static parseServerPushElement(n){const{MsgContent:g={}}=n,{Data:u,Ext:E,Desc:m}=g;return new Td({data:u,description:m,extension:E})}constructor(n){this.type=KE.MSG_CUSTOM;const{data:g="",description:u="",extension:E=""}=n;this.content={data:g,description:u,extension:E}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{data:E,description:m,extension:D}=u;return{MsgType:this.type,MsgContent:{Data:E,Ext:D,Desc:m}}}validateBeforeSend(){const{isEmpty:n}=ye.utils,g=[this.content.data,this.content.description,this.content.extension].some(u=>!n(u));return{isValid:g,error:g?null:{message:"content can not be empty"}}}}class Nd{static parseServerPushElement(n){const{MsgContent:g={Text:""}}=n,{Text:u}=g;return new Nd({text:u})}constructor(n){this.type=wg.MSG_TEXT,this.content={text:n.text||""}}validateBeforeSend(){var n,g;return((g=(n=this.content)===null||n===void 0?void 0:n.text)===null||g===void 0?void 0:g.length)>0?{isValid:!0}:{isValid:!1,error:{message:"content can not be empty"}}}transformToServerFormat(n){const{isMergerMessage:g=!1}=n||{},u=g?this.payload:this.content,{text:E}=u;return{MsgType:this.type,MsgContent:{Text:E}}}}var Wm=new class{constructor(){this._elementClassMap={[KE.MSG_CUSTOM]:Td,[KE.MSG_TEXT]:Nd}}init(){Cr.getInstance().registerApi({apiName:"createCustomMessage",context:this}),Cr.getInstance().registerApi({apiName:"createTextMessage",context:this})}registerElementClass(s,n){var g;(g=n).prototype!==void 0&&"constructor"in g.prototype&&(this._elementClassMap[s]=n)}getElementClass(s){return this._elementClassMap[s]}createMessage(s){const{from:n,flow:g=AE.OUT}=s,{userId:u}=ye.store.get("login")||{};this._isSendByCurrentInstance({from:n,flow:g,currentUser:u})?this._updateWithSenderInfo(s):this._isMultiEndpointSyncMessage({from:n,flow:g,currentUser:u})&&(s.flow=AE.OUT);const E=Object.assign(Object.assign({},s),{currentUser:u});return new jE(E)}createCustomMessage(s){const n=Ar(),g=this.createMessage(Object.assign(Object.assign({},s),{from:n})),u=this._elementClassMap[KE.MSG_CUSTOM];if(!g)return null;if(u){const E=new u(s.payload);g.setElement(E)}return g}createTextMessage(s){var n;if(!s)return null;const g=typeof s.payload=="string"?s.payload:((n=s?.payload)===null||n===void 0?void 0:n.text)||"",u=new Nd({text:g}),E=Ar(),m=ye.message.messageFactory.createMessage(Object.assign(Object.assign({},s),{from:E}));return m.setElement(u),m}_updateWithSenderInfo(s){var n,g;const{nick:u,avatar:E,conversationType:m,to:D}=s,{userId:M,tinyID:T}=ye.store.get("login")||{},P=rc.getUserProfile(M);return s.nick=u||P?.nick||"",s.avatar=E||P?.avatar||"",s.tinyID=s.tinyID||T||"",s.from=M,s.status=Yr.UNSENT,s.flow=AE.OUT,m===ka.CONV_GROUP&&(s.nameCard=(g=(n=Ap.getGroup(D))===null||n===void 0?void 0:n.selfInfo)===null||g===void 0?void 0:g.nameCard),s}_isMultiEndpointSyncMessage(s){const{from:n,flow:g,currentUser:u}=s;return n===u&&g===AE.IN}_isSendByCurrentInstance(s){const{from:n,flow:g,currentUser:u}=s;return n===u&&g===AE.OUT}};const mR={PushFlag:0,Title:"",Desc:"",Ext:"",ApnsInfo:{Sound:"",BadgeMode:0,IsVoipPush:void 0,Image:"",InterruptionLevel:"active",ContentAvailable:0},AndroidInfo:{Sound:"",XiaoMiChannelID:"",OPPOChannelID:"",GoogleChannelID:"",VIVOClassification:1,VIVOCategory:"",HuaWeiCategory:"",OPPOCategory:"",HuaWeiImage:"",HonorImage:"",GoogleImage:"",HonorImportance:"",MeizuNotifyType:void 0}},Gd={HonorImportance:{range:["LOW","NORMAL"],defaultValue:void 0},MeizuNotifyType:{range:[0,1],defaultValue:void 0}},YD={enableIOSBackgroundNotification:{range:[!0,!1],defaultValue:!1},interruptionLevel:{range:["passive","active","time-sensitive","critical"],defaultValue:"active"}};function fR(s,n){return Object.keys(n).forEach(g=>{const{range:u,defaultValue:E}=n[g];s[g]=u.includes(s[g])?s[g]:E}),s}function ip(s){const n=s.lastIndexOf(".");return n===-1?s:s.slice(0,n)}function yR(s){const{androidInfo:n={},androidOPPOChannelID:g=""}=s,u=n.OPPOChannelID||g,E=fR(n,Gd),{sound:m="",FCMChannelID:D=""}=E,M=Do(E,["sound","FCMChannelID"]);return Object.assign(Object.assign({},M),{Sound:ip(m),OPPOChannelID:u,GoogleChannelID:D})}function DR(s){const{apnsInfo:n={},ignoreIOSBadge:g=!1,disableVoipPush:u}=s,E=fR(n,YD),{ignoreIOSBadge:m,disableVoipPush:D,enableIOSBackgroundNotification:M}=E,T=Do(E,["ignoreIOSBadge","disableVoipPush","enableIOSBackgroundNotification"]),P=m===!0||g===!0?1:0;let W;return r(u)||(W=u===!1?1:0),r(D)||(W=D===!1?1:0),Object.assign(Object.assign({},T),{BadgeMode:P,IsVoipPush:W,ContentAvailable:M?1:0})}function VD(s){return ye.utils.isPlainObject(s)?{PushFlag:s.disablePush===!0?1:0,Title:s.title||"",Desc:s.description||"",Ext:s.extension||"",ApnsInfo:DR(s),AndroidInfo:yR(s)}:mR}function zm(s){const{From_AccountHeadurl:n,From_AccountNick:g,IsNeedReadReceipt:u,IsPeerRead:E,IsSyncMsg:m,MsgBody:D,MsgClientTime:M,MsgLifeTime:T,MsgRandom:P,MsgSeq:W,MsgTimeStamp:iA,SendMsgControl:EA,SupportMessageExtension:RA,TinyId:kA,MsgCheckResult:xA,CloudCustomData:LA,MsgVersion:SA,MsgFlagBits:OA,RevokerInfo:JA,InnerSdkCustomData:ae}=s;let ne,{From_Account:_i,To_Account:Ti}=s;if(m===1){const Lt=Ti;Ti=_i,_i=Lt}if(JA){const{Reason:Lt,Revoker_Account:Ni,Revoker_FromUin:cs}=JA;ne={reason:Lt,revoker:Ni,revokerFromUin:cs,userID:Ni}}return{from:_i,avatar:n,nick:g,needReadReceipt:u===1,isSyncMessage:m,clientTime:M,messageLifeTime:T,random:P,sequence:W,time:iA,messageControlInfo:{excludedFromLastMessage:EA?.NoLastMsg===1,excludedFromUnreadCount:EA?.NoUnread===1},isSupportExtension:RA,to:Ti,tinyID:kA,checkResult:xA,cloudCustomData:LA,revokerInfo:ne,messageVersion:SA,messageFlagBits:OA,readReceiptSentByPeer:E,elements:RC(D),onlineOnlyFlag:T===0,quoteInfo:op(ae)}}function Zm(s){const{From_Account:n,MsgBody:g,MsgClientTime:u,MsgRandom:E,MsgSeq:m,MsgTimeStamp:D,To_Account:M,MsgVersion:T,CloudCustomData:P,MsgCheckResult:W}=s;return{from:n,clientTime:u,random:E,sequence:m,time:D,to:M,elements:RC(g),messageVersion:T,cloudCustomData:P,checkResult:W}}function JD(s){const{ClientSeq:n,From_Account:g,GroupInfo:u,MsgBody:E,MsgClientTime:m,MsgRandom:D,MsgSeq:M,MsgTimeStamp:T,SendMsgControl:P,SupportMessageExtension:W,TinyId:iA,CloudCustomData:EA,MsgVersion:RA,MsgCheckResult:kA,NeedReadReceipt:xA,IsPlaceMsg:LA,RevokerInfo:SA,GroupAtInfo:OA,OnlineOnlyFlag:JA,InnerSdkCustomData:ae}=s;let ne,_i=$u.MSG_PRIORITY_NORMAL;if(Object.keys(PD).includes(String(s.MsgPriority))&&(_i=PD[s.MsgPriority]),SA){const{Reason:Lt,Revoker_Account:Ni,Revoker_FromUin:cs}=SA;ne={reason:Lt,revoker:Ni,revokerFromUin:cs,userID:Ni}}const Ti=function(Lt){const Ni=[];return Array.isArray(Lt)&&Lt.forEach(cs=>{cs.GroupAtAllFlag===xD?Ni.push(cs.GroupAt_Account):cs.GroupAtAllFlag===QR&&Ni.push(Lo.MSG_AT_ALL)}),Ni}(OA);return{clientSequence:n,from:g,groupProfile:u,clientTime:m,priority:_i,random:D,sequence:M,time:T,messageControlInfo:{excludedFromLastMessage:P?.NoLastMsg===1,excludedFromUnreadCount:P?.NoUnread===1},isSupportExtension:W,tinyID:iA,cloudCustomData:EA,messageVersion:RA,checkResult:kA,needReadReceipt:xA,isPlaceMessage:LA,revokerInfo:ne,atUserList:Ti,elements:RC(E),to:KT(s),onlineOnlyFlag:JA===1,quoteInfo:op(ae)}}function KT(s){const{utils:{isEmpty:n},constants:{IS_TOPIC_MESSAGE:g}}=ye,{ToGroupId:u,GroupInfo:{MillionGroupFlag:E=0,TopicId:m}={}}=s;return E!==g||n(m)?u:m}function RC(s){if(!s)return null;if(Array.isArray(s))return s.map(g=>{const u=ye.message.messageFactory.getElementClass(g.MsgType);return u?.parseServerPushElement(g)});const n=ye.message.messageFactory.getElementClass(s.MsgType);return n?.parseServerPushElement(s)}function HD(s){const{From_Account:n,MsgBody:g,MsgClientTime:u,MsgRandom:E,MsgSeq:m,MsgTimeStamp:D,GroupId:M,TopicId:T,MsgVersion:P,CloudCustomData:W,MsgCheckResult:iA}=s;return{from:n,clientTime:u,random:E,sequence:m,time:D,groupID:M,topicID:T,elements:RC(g),messageVersion:P,cloudCustomData:W,checkResult:iA}}function op(s){const{utils:{isString:n,safeStringify:g},ssoLog:u}=ye;if(!n(s))return null;try{const{messageID:E,messageTime:m,messageSequence:D}=JSON.parse(s).businessQuote;return{msgID:E,messageTime:m,messageSequence:D}}catch(E){return u.debug("_parseServerQuoteInfo",g(E)),null}}function sp({conversationUpdateFields:s,message:n}){const{conversationID:g,conversationType:u,conversationSubType:E,flow:m,_isExcludedFromUnreadCount:D,_isExcludedFromLastMessage:M}=n,T=M?"":XQ(n),P=!D&&m===AE.IN;s.has(g)?(s.get(g).lastMessage=T,P&&s.get(g).unreadCount++):s.set(g,{conversationID:g,type:u,subType:E,unreadCount:P?1:0,lastMessage:T})}function vB(s){return s.filter(n=>{const g=!Rs(n?._elements),u=n?.isPlaceMessage===1;return g||ye.ssoLog.error("emptyMessageBody",`from:${n.from} to:${n.to} sequence:${n.sequence}`),g&&!u})}function RB(s){const{messageDataHandler:n}=ye.message;return!n.isInMessageList(s)&&!n.isMessageSentByCurrentInstance(s)}var SR=Object.freeze({__proto__:null,autoIncrementIndex:gu,createAndroidPushInfo:yR,createApnsPushInfo:DR,createOfflinePushInfo:VD,filterValidMessages:vB,getAndroidSoundName:ip,parseServerGroupMessage:JD,parseServerPushC2CModifyMessage:Zm,parseServerPushGroupModifyMessage:HD,parseServerPushMessage:zm,parseServerPushMessageElement:RC,shouldStoreMessage:RB,updateConversationFields:sp});const{isPlainObject:MR}=ye.utils;function np(s,n={}){const{onlineUserOnly:g,messageControlInfo:u}=n;let{offlinePushInfo:E}=n;s.conversationType===Kr.CONV_C2C&&g===!0&&(E?E.disablePush=!0:E={disablePush:!0});let m="";typeof s.cloudCustomData=="string"&&s.cloudCustomData.length>0&&(m=s.cloudCustomData);const D=[];if(u&&MR(u)){const{excludedFromUnreadCount:M,excludedFromLastMessage:T,excludedFromContentModeration:P}=u;M===!0&&D.push("NoUnread"),T===!0&&D.push("NoLastMsg"),P===!0&&D.push("NoMsgCheck")}return{onlineUserOnly:g,cloudCustomData:m,messageControlInfo:D,offlinePushInfo:E}}function qD(s){const{webhookInfo:{disableCloudMessagePreHook:n=!1,disableCloudMessagePostHook:g=!1}={}}=s||{};if(!n&&!g)return;const u=[];return n&&u.push("ForbidBeforeSendMsgCallback"),g&&u.push("ForbidAfterSendMsgCallback"),u}function wh(s,n){return pA(this,void 0,void 0,function*(){const g=s.conversationType===Kr.CONV_GROUP?function(E,m){var D;const M=np(E,m),{onlineUserOnly:T,cloudCustomData:P,messageControlInfo:W,offlinePushInfo:iA}=M,EA=JSON.parse(JSON.stringify(E.transformElementsToServerFormat()));let RA;return h(E._receiverList)&&E._receiverList.length>0&&(RA=E._receiverList,E._receiverList.length>50&&(RA=E._receiverList.slice(0,50),console.warn("ReceiverListLimit"))),{servcmd:"group_open_http_svc.send_group_msg",data:{From_Account:(D=ye.store.get("login"))===null||D===void 0?void 0:D.userId,GroupId:E.to,MsgBody:EA,CloudCustomData:P,Random:E.random,MsgPriority:E.priority,ClientSeq:E.clientSequence,GroupAtInfo:E._groupAtInfoList,OnlineOnlyFlag:T?1:0,MsgClientTime:E.clientTime,OfflinePushInfo:VD(iA),SendMsgControl:T?void 0:W,NeedReadReceipt:E.needReadReceipt===!0?1:0,To_Account:RA,SupportMessageExtension:E.isSupportExtension===!0?1:0,IsRelayMsg:E._relayFlag===!0?1:0,CustomModerationConfigID:E._cmConfigID,ForbidCallbackControl:qD(m),InnerSdkCustomData:_B(E)}}}(s,n):function(E,m){var D;const M=np(E,m),{onlineUserOnly:T,cloudCustomData:P,messageControlInfo:W,offlinePushInfo:iA}=M,EA=T===!0?0:void 0,RA=JSON.parse(JSON.stringify(E.transformElementsToServerFormat()));return{servcmd:"openim.sendmsg",data:{From_Account:(D=ye.store.get("login"))===null||D===void 0?void 0:D.userId,To_Account:E.to,MsgBody:RA,CloudCustomData:P,MsgSeq:E.sequence,MsgRandom:E.random,MsgLifeTime:EA,From_AccountNick:E.nick,From_AccountHeadurl:E.avatar,SendMsgControl:EA!==0?W:void 0,MsgClientTime:E.clientTime,IsNeedReadReceipt:E.needReadReceipt===!0?1:0,SupportMessageExtension:E.isSupportExtension===!0?1:0,IsRelayMsg:E._relayFlag===!0?1:0,CustomModerationConfigID:E._cmConfigID,OfflinePushInfo:VD(iA),ForbidCallbackControl:qD(m),InnerSdkCustomData:_B(E)}}}(s,n),u=yield gg(g);return u?{time:u.MsgTime,messageDropReason:u.MsgDropReason,sequence:u.MsgSeq}:null})}function _h(s){return pA(this,void 0,void 0,function*(){const{from:n,to:g,version:u=0,sequence:E,random:m,time:D,type:M,cloudCustomData:T}=s,P={From_Account:n,To_Account:g,MsgVersion:u,MsgSeq:E,MsgRandom:m,MsgTime:D,MsgType:M,MsgBody:s.transformElementsToServerFormat(),CloudCustomData:T},W=yield gg({servcmd:"openim.modify_c2c_msg",data:P});if(W){const{MsgBody:iA,MsgVersion:EA,CloudCustomData:RA}=W;return{elements:RC(iA),messageVersion:EA,cloudCustomData:RA}}})}function wB(s){return pA(this,void 0,void 0,function*(){const{to:n,version:g=0,sequence:u,cloudCustomData:E}=s,m={GroupId:n,MsgVersion:g,MsgSeq:u,MsgBody:s.transformElementsToServerFormat(),CloudCustomData:E},D=yield gg({servcmd:"openim.modify_group_msg",data:m});if(D){const{MsgBody:M,MsgVersion:T,CloudCustomData:P}=D;return{elements:RC(M),messageVersion:T,cloudCustomData:P}}})}function Th(s){return pA(this,void 0,void 0,function*(){const{groupID:n,count:g,messageSequence:u,messageSequenceList:E,getType:m}=s,D={GroupId:n,ReqMsgNumber:g,WithRecalledMsg:1,Version:1,GetType:m};return u&&(D.ReqMsgSeq=u),h(E)&&E.length>0&&(D.ReqMsgSeqList=E),yield gg({servcmd:"group_open_http_svc.group_msg_get",data:D})})}function Xm(s){return pA(this,void 0,void 0,function*(){const{peerAccount:n,count:g,lastMessageTime:u,messageKey:E,direction:m}=s;return gg({servcmd:"openim.getroammsg",data:{Peer_Account:n,MaxCnt:g,WithRecalledMsg:1,LastMsgTime:u,MsgKey:E,GetDirection:m}})})}function _B(s){if(ye.utils.isObject(s.quoteInfo)){const{msgID:n,messageSequence:g,messageTime:u}=s.quoteInfo;return JSON.stringify({businessQuote:{messageID:n,messageSequence:g,messageTime:u}})}}var KD=Object.freeze({__proto__:null,createMessagePackOptions:np,generateForbidCallbackControl:qD,getC2CRoamingMessagesByAnchor:Xm,getGroupRoamingMessagesByAnchor:Th,getRoamingMessages:function(s){return pA(this,void 0,void 0,function*(){const{peerAccount:n,count:g,lastMessageTime:u,messageKey:E}=s;return(yield gg({servcmd:"openim.getroammsg",data:{Peer_Account:n,MaxCnt:g||15,LastMsgTime:u||0,MsgKey:E,GetDirection:0,WithRecalledMsg:1}}))||[]})},modifyC2CMessage:_h,modifyGroupMessage:wB,sendMessage:wh});const{isPlainObject:jT}=ye.utils,{MSG_AUDIO:jD,MSG_FILE:WD,MSG_IMAGE:vR,MSG_VIDEO:RR,MSG_MERGER:wR}=Lo;class $m{constructor(){this._sendProtocolMap=new Map}init(){Cr.getInstance().registerApi({apiName:"sendMessage",context:this,matcher:n=>![jD,WD,vR,RR,wR].includes(n[0].type)})}registerSendProtocol(n,g,u){this._sendProtocolMap.set(n,g.bind(u))}sendMessage(n,g){return pA(this,void 0,void 0,function*(){const{TOTAL_COUNT:u,SEND_COST:E,SUCCESS_COUNT:m,FAILED_COUNT:D}=rr;if(!(n instanceof jE))throw new gs({code:da.MSG_INSTANCE_REQUIRED});const M=n.validateBeforeSend();if(!M.isValid){const{code:W,message:iA=""}=M.error||{};throw new gs({code:W,message:iA})}this._reportMessageSendQuality({name:u,message:n});let T=!1;const{messageDataHandler:P}=ye.message||{};try{const{messageControlInfo:W}=g||{};let iA=null;P.addRandomOfSentMessage(n.random);const EA=Date.now(),RA=this._getSendProtocol(n);if(n.conversationType===Kr.CONV_C2C?(T=g?.onlineUserOnly===!0,iA=yield RA(n,g)):n.conversationType===Kr.CONV_GROUP&&(yield this._validateBeforeSendGroupMessage(n),iA=yield RA(n,g)),iA){const{messageDropReason:kA,sequence:xA,time:LA}=iA;if(this._updateNickAndAvatarOfSentMessageByMe(n),kA&&this._logRateLimitInfo(n,xA,kA),this._reportMessageSendQuality({name:m,message:n}),this._reportMessageSendQuality({name:E,message:n,startTs:EA}),n.isResend===!0){const SA=P.findMessage(n.ID);SA&&(ye.ssoLog.debug("sendMessage",`sendMessage resend ok. ID:${SA.ID}`),P.deleteConversationMessage(SA))}return n.status=Yr.SUCCESS,n.time=LA,n.conversationType===Kr.CONV_GROUP&&(n.sequence=xA),T?n._onlineOnlyFlag=!0:(P.storeConversationMessage(n),this._applySentMessageControlInfo(n,W),this._emitOnlineMessageSent(n)),n.type===wg.MSG_STREAM?{code:0,data:{message:n,streamMessageID:iA.streamMessageID}}:{code:0,data:{message:n}}}}catch(W){n.status=Yr.FAIL,P.removeRandomOfSentMessage(n.random);let{errorCode:iA}=W||{},EA=W?.errorInfo||W?.message||"";throw this._hasRiskContent(iA)&&(n.hasRiskContent=!0),T||this._isRejectedByRestApi(iA)||P.storeConversationMessage(n),this._reportMessageSendQuality({name:D,message:n,error:W}),new gs({code:iA,message:EA,data:{message:n},moreMessage:`type:${n.type} from:${n.from} to:${n.to}`})}})}_hasRiskContent(n){return n===80001||n===80004}_isRejectedByRestApi(n){return n>=10100&&n<=10200||n>=120001&&n<=13e4}_emitOnlineMessageSent(n){const g=n._isExcludedFromLastMessage?"":n,{conversationID:u,conversationType:E}=n,m=zc(u)?no.TOPIC_NEW_MESSAGE:no.NEW_MESSAGE;ye.notificationCenter.emitInnerEvent(m,{result:{conversationUpdateFieldList:[{conversationID:u,type:E,message:n,lastMessage:g,unreadCount:0}]}})}_applySentMessageControlInfo(n,g){g&&jT(g)&&(g.excludedFromLastMessage===!0&&(n._isExcludedFromLastMessage=!0),g.excludedFromUnreadCount===!0&&(n._isExcludedFromUnreadCount=!0))}_logRateLimitInfo(n,g,u){const E=`from:${n.from} to:${n.to} sequence:${g} messageDropReason:${u}`;ye.ssoLog.warn("messageDropReason",E)}_updateNickAndAvatarOfSentMessageByMe(n){const{messageDataHandler:g}=ye.message||{};let u=!1;const{conversationID:E}=n,m=g.getLatestMsgSentByMe(E);if(m){const{nick:D,avatar:M}=m;D===n.nick&&M===n.avatar||(u=!0),u&&g.updateNickAndAvatarOfSentMessage({conversationID:E,latestNick:n.nick,latestAvatar:n.avatar,isSentByMe:!0})}}_validateBeforeSendGroupMessage(n){return pA(this,void 0,void 0,function*(){var g,u,E;const{to:m,from:D}=n;let M=m,T=Ap.getGroup(M);if(Xr({groupID:M})&&T?.isSupportTopic)throw new gs({code:da.MSG_SEND_GRP_WITH_TOPIC_FAIL});if(zc(m)&&([M]=m.split(sa.TOPIC),T=Ap.getGroup(M)),!T&&typeof((g=Cr.getInstance().getApiMap())===null||g===void 0?void 0:g.getGroupProfile)=="function"){const P=yield Cr.getInstance().getApiMap().getGroupProfile({groupID:M});if(((E=(u=P?.data)===null||u===void 0?void 0:u.group)===null||E===void 0?void 0:E.type)===Lo.GRP_AVCHATROOM){const W=rs({code:da.MSG_SEND_FAIL_NOT_IN_AV,replacement1:D,replacement2:M});throw new gs({code:da.MSG_SEND_FAIL_NOT_IN_AV,message:W})}}return!0})}_reportMessageSendQuality(n){ye.notificationCenter.emitInnerEvent(no.QUALITY_STAT,{label:cI.MESSAGE_SEND_SUCCESS_RATE,data:n})}_getSendProtocol(n){return this._sendProtocolMap.get(n.type)||wh}}var WT=new class{constructor(){this._sparseMessagesByConversation=new Map,this._latestMessageSentByPeerMap=new Map,this._latestMessageSentByMeMap=new Map,this._randomOfSentMessageList=new Set}init(){ye.notificationCenter.subscribeInnerEvent(no.LOGOUT,this._reset,this),ye.notificationCenter.subscribeInnerEvent(no.DESTROY,this._dispose,this)}get _messagesByConversation(){return ep.getMessages()}storeConversationMessage(s,n=!1){if(an)return!0;const{conversationID:g}=s;if(!g||(this._messagesByConversation.has(g)||this._messagesByConversation.set(g,new Map),this._shouldSkipStoreMessage(s,n)))return!1;const u=this._getUniqueIdOfMessage(s);return this._messagesByConversation.get(g).set(u,s),this._updateLatestMessageMap(s),!0}_updateLatestMessageMap(s){const{conversationID:n}=s;s.flow==="out"?this._setLatestMsgSentByMe(n,s):n.startsWith("C2C")&&this._setLatestMsgSentByPeer(n,s)}_shouldSkipStoreMessage(s,n){const g=this._getUniqueIdOfMessage(s),u=this._messagesByConversation.get(s.conversationID);if(u?.has(g)){const E=u?.get(g);if(!n||E?.isModified===!0)return!0}return!1}deleteConversationMessage(s){var n;const{conversationID:g=""}=s,u=this._getUniqueIdOfMessage(s);this._messagesByConversation.has(g)&&((n=this._messagesByConversation.get(g))===null||n===void 0||n.delete(u))}modifyConversationMessage(s,n){var g;if(!this._messagesByConversation.has(s)&&!this._sparseMessagesByConversation.has(s))return{isUpdated:!1,message:null};const u=this._getUniqueIdOfMessage(n),E=this._getMessageFromLocalMessage(s,u);if(E){const{messageVersion:m,elements:D,cloudCustomData:M,checkResult:T=0}=n,P=T>1;if(ye.ssoLog.debug("modifyConversationMessage",`conversationToMessageMap modifyConversationMessage localVersion:${E.version} remoteVersion:${m}`),E.versionE.ID===s)||null,n)break;if(!n){const u=Array.from(this._sparseMessagesByConversation.values());for(const E of u)if(n=E.get(s)||null,n)break}return n}deleteConversationMessageList(s){this._messagesByConversation.has(s)&&(this._messagesByConversation.delete(s),this._latestMessageSentByMeMap.delete(s),this._latestMessageSentByPeerMap.delete(s)),this._sparseMessagesByConversation.has(s)&&this._sparseMessagesByConversation.delete(s)}revokeMessage({conversationID:s,sequence:n,random:g,revoker:u}){const E=this._messagesByConversation.get(s);let m=null;if(E){const D=Array.from(E.values());if(m=this._findMessageBySequenceAndRandom({messageList:D,random:g,sequence:n}),m){const M=this._getUniqueIdOfMessage(m);return ep.updateMessage(s,[M],{isRevoked:!0,revoker:u,operation:yc.revoke}),m}}if(this._sparseMessagesByConversation.has(s)){const D=Array.from(this._sparseMessagesByConversation.get(s).values());if(m=this._findMessageBySequenceAndRandom({messageList:D,random:g,sequence:n}),m)return m.isRevoked=!0,m.revoker=u,m}}_findMessageBySequenceAndRandom({messageList:s,sequence:n,random:g}){for(let u=0;u0){const D=new Map([...E,...m.entries()]);this._messagesByConversation.set(g,D),this._updateLatestMessageSentByMe(g),this._updateLatestMessageSentByPeer(g)}return u}storeSparseMessageList(s){if(s.length===0)return;const{conversationID:n}=s[0],g=s.length;this._sparseMessagesByConversation.has(n)||this._sparseMessagesByConversation.set(n,new Map);const u=this._sparseMessagesByConversation.get(n);for(let E=0;E=0;u--)if(g[u].flow==="out"){this._setLatestMsgSentByMe(s,g[u]);break}}}_updateLatestMessageSentByPeer(s){var n;const g=Array.from(((n=this._messagesByConversation.get(s))===null||n===void 0?void 0:n.values())||[]);if(g.length!==0&&s.startsWith("C2C")){for(let u=g.length-1;u>=0;u--)if(g[u].flow==="in"){this._setLatestMsgSentByPeer(s,g[u]);break}}}_getUniqueIdOfMessage(s){const{from:n,to:g,random:u,sequence:E,time:m}=s;return`${n}-${g}-${u}-${E}-${m}`}_setLatestMsgSentByPeer(s,n){this._latestMessageSentByPeerMap.set(s,n)}_setLatestMsgSentByMe(s,n){this._latestMessageSentByMeMap.set(s,n)}getLatestMsgSentByPeer(s){return this._latestMessageSentByPeerMap.get(s)}getLatestMsgSentByMe(s){return this._latestMessageSentByMeMap.get(s)}addRandomOfSentMessage(s){this._randomOfSentMessageList.add(s)}removeRandomOfSentMessage(s){this._randomOfSentMessageList.delete(s)}updateNickAndAvatarOfSentMessage(s){const{conversationID:n="",latestAvatar:g,latestNick:u,isSentByMe:E=!0}=s,m=this._messagesByConversation.get(n);if(!m)return;const D=Array.from(m.values()),M=E?"out":"in";D.forEach(T=>{const{nick:P,avatar:W,flow:iA}=T;iA===M&&(P!==u&&(T.nick=u),W!==g&&(T.avatar=g))})}isInMessageList(s){var n;const{conversationID:g}=s;if(!g||!this._messagesByConversation.has(g))return!1;const u=this._getUniqueIdOfMessage(s);return(n=this._messagesByConversation.get(g))===null||n===void 0?void 0:n.has(u)}isMessageSentByCurrentInstance(s){const{random:n}=s;return this._randomOfSentMessageList.has(n)}getContinuousMessagesByConversation(){return this._messagesByConversation}getLocalMessageList(s){const n=this._messagesByConversation.get(s);return n?[...n.values()]:[]}getSparseMessageList(s){const n=this._sparseMessagesByConversation.get(s);return n?[...n.values()]:[]}_reset(){this._messagesByConversation.clear(),this._latestMessageSentByPeerMap.clear(),this._latestMessageSentByMeMap.clear(),this._randomOfSentMessageList.clear()}_dispose(){this._reset(),ye.notificationCenter.unSubscribeInnerEvent(no.LOGOUT,this._reset,this),ye.notificationCenter.unSubscribeInnerEvent(no.DESTROY,this._dispose,this)}};function Af(s,n){const g=MB.getConversation(s);if(g?.lastMessage){const{lastMessage:u}=g,{lastTime:E,lastSequence:m,version:D}=u,{time:M,sequence:T,messageVersion:P,elements:W,cloudCustomData:iA}=n;E===M&&m===T&&D!==P&&(u.type=W[0].type,u.payload=W[0].content,u.messageForShow=Zc(u.type,u.payload),u.cloudCustomData=iA,u.version=P,MB.updateConversation(s,{lastMessage:u}))}}class _R{init(){Cr.getInstance().registerApi({apiName:"modifyMessage",context:this})}modifyMessage(n){return pA(this,void 0,void 0,function*(){const{to:g,payload:u,sequence:E,conversationType:m,random:D,time:M,from:T,type:P}=n;if(this._canModifyMessageElement(P)){const W=n?._elements||[];W.length>=1&&(W[0].type=P,W[0].content=u)}try{let W=null,iA=null;if(m===Kr.CONV_C2C?W=yield _h(n):m===Kr.CONV_GROUP&&(W=yield wB(n)),W){let EA=`${m}${g}`;return g===Ar()&&m===Kr.CONV_C2C&&(EA=`${m}${T}`),iA={conversationType:m,from:T,to:g,time:M,random:D,sequence:E,elements:W?.elements,cloudCustomData:W?.cloudCustomData,messageVersion:W?.messageVersion,conversationID:EA},this._handleModifyMessageSuccess(iA),{code:0,data:{message:n},successLog:{message:`to:${g}`}}}}catch(W){const{errorCode:iA}=W||{};throw new gs({functionName:"modifyMessage",code:iA,moreMessage:`to:${g}`})}})}_handleModifyMessageSuccess(n){const{conversationID:g}=n,{isUpdated:u,message:E}=ye.message.messageDataHandler.modifyConversationMessage(g,n);u===!0&&ye.notificationCenter.emitOuterEvent(Dr.MESSAGE_MODIFIED,{name:Dr.MESSAGE_MODIFIED,data:[E]}),ye.notificationCenter.emitInnerEvent(no.MESSAGE_MODIFIED,{conversationID:g,message:E}),Af(g,n)}_canModifyMessageElement(n){return[KE.MSG_TEXT,KE.MSG_CUSTOM,KE.MSG_LOCATION,KE.MSG_FACE].includes(n)}}class Nh{init(){const{notificationCenter:n}=ye,{InnerEventSubType:g}=n;ws.getInstance().registerWorkflowStep(Yt.RECEIVE_C2C_NEW_MESSAGE,qt.HANDLE_C2C_NEW_MESSAGE,this._handleC2CMessagePush,this),ws.getInstance().registerWorkflowStep(Yt.RECEIVE_C2C_NEW_MESSAGE,qt.EMIT_C2C_MESSAGE_EVENT,this._emitMessageEventsAfterReceiveNewMessage,this),ws.getInstance().registerWorkflowStep(Yt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,qt.EMIT_C2C_MESSAGE_EVENT,this._emitMessageEventsAfterSyncUnreadMessage,this),n.subscribeInnerEvent(no.MESSAGE_PUSH,g.C2C_REALTIME_MESSAGE,this._executeReceiverNewMessageWorkFlow,this),n.subscribeInnerEvent(no.MESSAGE_PUSH,g.C2C_MESSAGE_MODIFIED,this._handleC2CMessageModify,this),n.subscribeInnerEvent(no.DESTROY,this._dispose,this)}_executeReceiverNewMessageWorkFlow(n){ws.getInstance().executeWorkflow(Yt.RECEIVE_C2C_NEW_MESSAGE,n)}_handleC2CMessagePush(n){const g=n.data||{},{messageDataHandler:u}=ye.message||{},E=[],m=new Map;return g.C2cMsgArray.forEach(D=>{const M=this._generateC2CMessage(D);this._updateMessageProfile(M);let T=M.isModified===1;u.isMessageSentByCurrentInstance(M)?M.isModified=T:T=!1,M._onlineOnlyFlag?u.isMessageSentByCurrentInstance(M)||E.push(M):RB(M)&&(u.storeConversationMessage(M)&&sp({conversationUpdateFields:m,message:M}),u.isMessageSentByCurrentInstance(M)&&!T||E.push(M))}),{conversationUpdateFieldList:[...m.values()],messages:E}}_emitMessageEventsAfterReceiveNewMessage(n){var g;const{messages:u=[]}=((g=n.result)===null||g===void 0?void 0:g[qt.HANDLE_C2C_NEW_MESSAGE])||{};this._emitMessageEvents(u)}_emitMessageEventsAfterSyncUnreadMessage(n){var g;const{messages:u=[]}=((g=n.result)===null||g===void 0?void 0:g[qt.UNREAD_MESSAGE_SYNC])||{};this._emitMessageEvents(u)}_emitMessageEvents(n){const g=n?.filter(E=>E?.isModified===!0)||[];g.length>0&&ye.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:g});const u=n?.filter(E=>!E?.isModified);u.length>0&&ye.notificationCenter.emitOuterEvent("onMessageReceived",{name:"onMessageReceived",data:u})}_generateC2CMessage(n){const g=Kr.CONV_C2C,u=zm(n),E=ye.message.messageFactory.createMessage(Object.assign(Object.assign({},u),{conversationType:g,flow:AE.IN})),{elements:m}=u;return E.setElement(m),E}_updateMessageProfile(n){var g;const{messageDataHandler:u}=ye.message||{},E=(g=ye.store.get("login"))===null||g===void 0?void 0:g.userId,{from:m,nick:D,avatar:M,conversationID:T=""}=n;if(m!==E){const P=u.getLatestMsgSentByPeer(T);if(P){const{nick:W,avatar:iA}=P;r(D)||r(M)?(n.nick=l(W)?W:n.nick,n.avatar=l(iA)?iA:n.avatar):D===W&&M===iA||(u.updateNickAndAvatarOfSentMessage({conversationID:T,latestNick:D,latestAvatar:M,isSentByMe:!1}),this._updateConversationUserProfile({conversationID:T,nick:D,avatar:M}))}}else{const P=u.getLatestMsgSentByMe(T);!P||D===P.nick&&M===P.avatar||u.updateNickAndAvatarOfSentMessage({conversationID:T,latestNick:D,latestAvatar:M,isSentByMe:!0})}}_updateConversationUserProfile(n){const{conversationID:g,nick:u,avatar:E}=n,m=MB.getConversation(g),{userProfile:D={}}=m||{};D.avatar===E&&D.nick===u||MB.updateConversation(g,{userProfile:Object.assign(Object.assign({},D),{nick:u,avatar:E})})}_updateMessageListDueToModify(n){const{conversationID:g}=n,{isUpdated:u,message:E}=ye.message.messageDataHandler.modifyConversationMessage(g,n);u===!0&&ye.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:[E]}),ye.notificationCenter.emitInnerEvent("ModifyMessageSuccess",n),Af(g,n)}_handleC2CMessageModify(n){n.C2cMsgModNotifys.forEach(g=>{var u;const E=Kr.CONV_C2C;let m=Zm(g);const{to:D,from:M}=m;let T=`${E}${D}`;D===((u=ye.store.get("login"))===null||u===void 0?void 0:u.userId)&&(T=`${E}${M}`),m=Object.assign({conversationType:E,conversationID:T},m),this._updateMessageListDueToModify(m)})}_dispose(){const{notificationCenter:n}=ye,{InnerEventSubType:g}=n;ye.notificationCenter.unSubscribeInnerEvent(no.MESSAGE_PUSH,g.C2C_REALTIME_MESSAGE,this._handleC2CMessagePush,this),ye.notificationCenter.unSubscribeInnerEvent(no.MESSAGE_PUSH,g.C2C_MESSAGE_MODIFIED,this._handleC2CMessageModify,this),ye.notificationCenter.unSubscribeInnerEvent(no.DESTROY,this._dispose,this)}}class Gh{init(){const{notificationCenter:n}=ye,{InnerEventSubType:g}=n;ws.getInstance().registerWorkflowStep(Yt.RECEIVE_GROUP_NEW_MESSAGE,qt.HANDLE_GROUP_NEW_MESSAGE,this._handleGroupMessagePush,this),ws.getInstance().registerWorkflowStep(Yt.RECEIVE_GROUP_NEW_MESSAGE,qt.EMIT_GROUP_MESSAGE_EVENT,this._emitMessageEvents,this),n.subscribeInnerEvent(no.MESSAGE_PUSH,g.GROUP_REALTIME_MESSAGE,this._executeReceiverNewMessageWorkFlow,this),n.subscribeInnerEvent(no.MESSAGE_PUSH,g.GROUP_MESSAGE_MODIFIED,this._handleGroupMessageModify,this),n.subscribeInnerEvent(no.DESTROY,this._dispose,this)}_executeReceiverNewMessageWorkFlow(n){this._canExecuteReceiverNewMessageWorkFlow(n)&&ws.getInstance().executeWorkflow(Yt.RECEIVE_GROUP_NEW_MESSAGE,n)}_handleGroupMessagePush(n){const g=n.data||{},{messageDataHandler:u}=ye.message,E=[],m=new Map,D=g?.GroupMsgArray;return D?.forEach(M=>{if(M.GroupInfo.NotVisible===1)return;const T=this._generateGroupMessage(M);this.updateMessageProfile(T);let P=T.isModified===1;u.isMessageSentByCurrentInstance(T)?T.isModified=P:P=!1,T._onlineOnlyFlag?u.isMessageSentByCurrentInstance(T)||E.push(T):RB(T)&&u.storeConversationMessage(T)&&(E.push(T),sp({conversationUpdateFields:m,message:T}))}),{conversationUpdateFieldList:[...m.values()],messages:E}}_emitMessageEvents(n){var g;const{messages:u}=((g=n.result)===null||g===void 0?void 0:g[qt.HANDLE_GROUP_NEW_MESSAGE])||{},E=u?.filter(D=>D?.isModified===!0)||[];E.length>0&&ye.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:E});const m=u?.filter(D=>!D?.isModified)||[];m.length>0&&ye.notificationCenter.emitOuterEvent("onMessageReceived",{name:"onMessageReceived",data:m})}_generateGroupMessage(n){const g=Kr.CONV_GROUP,u=JD(n),E=ye.message.messageFactory.createMessage(Object.assign(Object.assign({},u),{conversationType:g,flow:AE.IN})),{elements:m}=u;return E.setElement(m),E}updateMessageProfile(n){var g;const{messageDataHandler:u}=ye.message||{},E=(g=ye.store.get("login"))===null||g===void 0?void 0:g.userId,{from:m,nick:D,avatar:M,conversationID:T="",_elements:P}=n;if(m===E){const W=u.getLatestMsgSentByMe(T);!W||D===W.nick&&M===W.avatar||u.updateNickAndAvatarOfSentMessage({conversationID:T,latestNick:D,latestAvatar:M,isSentByMe:!0})}else if(m===Lo.CONV_SYSTEM){const{operationType:W,memberInfoList:iA,operatorInfo:EA}=P;let RA={};if(Rs(iA)?Rs(EA)||(RA=EA):[Tg.JOINED,Tg.KICKED,Tg.ADMIN_SET,Tg.ADMIN_CANCELED].includes(W)&&(RA=Object.assign({},iA[0])),!Rs(RA)){const{nick:kA="",avatar:xA=""}=RA;n.nick=kA,n.avatar=xA}}}_updateMessageListDueToModify(n){const{conversationID:g}=n,{isUpdated:u,message:E}=ye.message.messageDataHandler.modifyConversationMessage(g,n);u===!0&&ye.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:[E]}),Af(g,n)}_handleGroupMessageModify(n){n.GroupMsgModNotifys.forEach(g=>{const u=Kr.CONV_GROUP;let E=HD(g);const{topicID:m,groupID:D}=E,M=m||D,T=`${u}${M}`;E=Object.assign({conversationType:u,conversationID:T,to:M},E),this._updateMessageListDueToModify(E)})}_dispose(){const{notificationCenter:n}=ye,{InnerEventSubType:{GROUP_REALTIME_MESSAGE:g,GROUP_MESSAGE_MODIFIED:u}}=n;n.unSubscribeInnerEvent(no.MESSAGE_PUSH,g,this._handleGroupMessagePush,this),n.unSubscribeInnerEvent(no.MESSAGE_PUSH,u,this._handleGroupMessageModify,this),n.unSubscribeInnerEvent(no.DESTROY,this._dispose,this)}_canExecuteReceiverNewMessageWorkFlow(n){var g,u;const{GroupId:E,GroupType:m}=((u=(g=n?.GroupMsgArray)===null||g===void 0?void 0:g[0])===null||u===void 0?void 0:u.GroupInfo)||{},D=m===La.GRP_AVCHATROOM;return!(!Ap.getGroup(E)&&D)}}var zD=new class{constructor(){this.c2cMessageReceiver=new Nh,this.groupMessageReceiver=new Gh}init(){this.c2cMessageReceiver.init(),this.groupMessageReceiver.init()}};const TR={createCustomMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1},cloudCustomData:{required:!1,rules:["string"],allowEmpty:!1},priority:{required:!1,rules:["string"],allowEmpty:!1},customModerationConfigurationID:{required:!1,rules:["string"],allowEmpty:!1}},sendMessage:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"options",required:!1,rules:["object"],allowEmpty:!1}],createTextMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1,customValidator:s=>!(!s.startsWith("C2C")&&!s.startsWith("GROUP"))||"conversationType is invalid."},payload:{required:!0,rules:["object"],allowEmpty:!1,customValidator:s=>function(n){var g;return typeof n?.text!="string"||typeof n.text=="string"&&((g=n?.text)===null||g===void 0?void 0:g.length)===0?"payload.text must be a string":!0}(s)}}},zT={createCustomMessage:!0,sendMessage:!0,modifyMessage:!0};var ZT=new class{constructor(){this._historyMessageListFetchAnchors=new Map,this.completedHistoryConversations=new Set}getGroupRoamingMessagesByAnchor(s){return pA(this,void 0,void 0,function*(){try{const{conversationID:n,count:g,direction:u,sequence:E,messageSequenceList:m,shouldMarkCompleted:D=!1,getType:M}=s,T=n.replace(ka.CONV_GROUP,""),P=[];let W=E;if(u===Kc.BACKWARD){if(typeof E!="number")return{messageList:[],hasNoMoreHistoryMessage:!1,nextReqMessageIDFromServer:""};W=E+g-1}const iA=yield Th({groupID:T,count:g,messageSequence:W,messageSequenceList:m,getType:M});if(iA){const{RspMsgList:EA=[],NextReqMsgSeq:RA=0,IsFinished:kA,InvisibleMsgSeq:xA}=iA,LA=`groupID:${T} sequence:${E} reqSeq:${W} direction:${u} complete:${kA} nextSequence:${RA} remoteMsgCount:${EA.length} invisibleSequenceList:${xA}`,SA=[];for(let ae=0;ae=E),OA&&D&&this.completedHistoryConversations.add(n);const JA=vB(SA);return ye.ssoLog.info("getGroupRoamingMessagesByAnchor",LA),{messageList:JA,invisibleSequenceList:xA,nextReqMessageIDFromServer:RA,hasNoMoreHistoryMessage:OA,serverGroupTipList:P}}}catch(n){const{errorCode:g,errorInfo:u}=n||{};throw new gs({code:g,message:u})}})}clearHistoryMessageListFetchAnchors(s){this._historyMessageListFetchAnchors.delete(s)}isHistoryMessageFetchCompleted(s){return this.completedHistoryConversations.has(s)}_parseMessage(s){var n;const g=ka.CONV_GROUP;s.Event===4&&(s.MsgBody.MsgType=Lo.MSG_GRP_TIP);const u=JD(s),E=Wm.createMessage(Object.assign(Object.assign({},u),{conversationType:g,flow:"in"}));return SB(((n=u.elements)===null||n===void 0?void 0:n.content)||{},E),E.setElement(u.elements),E}getC2CRoamingMessagesByAnchor(s){return pA(this,void 0,void 0,function*(){var n;try{const{conversationID:g,count:u,messageID:E,time:m,direction:D,shouldMarkCompleted:M=!1}=s;let T=m,P="";if(!m){const EA=E?ye.message.messageDataHandler.findMessage(E):null;if(T=EA?.time||0,E&&this._historyMessageListFetchAnchors.has(g)){const RA=this._historyMessageListFetchAnchors.get(g);T=RA.lastMessageTime,P=RA.messageKey}}const W=g.replace(ka.CONV_C2C,""),iA=yield Xm({count:u,lastMessageTime:T,messageKey:P,peerAccount:W,direction:D});if(iA){const{MsgList:EA=[],Complete:RA,MsgKey:kA,LastMsgTime:xA}=iA;this._historyMessageListFetchAnchors.set(g,{messageKey:kA,lastMessageTime:xA});const LA=[];for(let ae=0;ae{const{tag:E,value:m}=u;E&&E.indexOf(XD)>-1?g.profileCustomField.push({key:E,value:m}):bd.has(E)&&(g[bd.get(E)]=m)}),Object.assign(Object.assign({},ef),g)}parseProfileItem(s=[]){const n=[];return s.forEach(g=>{n.push({tag:g.Tag,value:g.Value})}),n}parseProfileList(s=[]){const n=[];return s.forEach(g=>{n.push({tag:g.Tag,value:g.ValueBytes})}),n}convertParamsToProfile(s){const n=[];return Object.keys(s).forEach(g=>{g!==$D&&n.push({tag:xl[g.toUpperCase()],value:s[g]})}),s.profileCustomField&&h(s.profileCustomField)&&s.profileCustomField.forEach(g=>{n.push({tag:g.key,value:g.value})}),n}normalizeProfileFields(s){const n={},g=[];return s.forEach(u=>{const{tag:E,value:m}=u;if(E&&E.indexOf(XD)>-1&&g.push({key:E,value:m}),bd.has(E)&&m!==void 0){const D=bd.get(E);n[D]=m}}),g.length>0&&(n.profileCustomField=g),n}};const{generateProtocolData:GR}=ye.common;function bR(s){return pA(this,void 0,void 0,function*(){const n="profile.portrait_get_all",g={From_Account:Ar(),UserItem:[]};s.forEach(D=>{g.UserItem.push({CustomSequence:0,StandardSequence:0,To_Account:D})});const u=GR({servcmd:n,data:g}),E=`${u.head.seq}${n}`,m=yield ye.channel.sendPacket(u,{requestId:E});if(m)return function(D){const{ActionStatus:M,ErrorCode:T,ErrorDisplay:P,ErrorInfo:W,UserProfileItem:iA}=D,EA=[];return iA.map(RA=>{const{To_Account:kA,CustomSequence:xA,ResultCode:LA,ResultInfo:SA,StandardSequence:OA,ProfileItem:JA}=RA,ae=eE.parseProfileItem(JA);EA.push({userId:kA,customSequence:xA,resultCode:LA,resultInfo:SA,standardSequence:OA,profileItem:ae})}),{actionStatus:M,errorCode:T,errorDisplay:P,errorInfo:W,userProfile:EA}}(m)})}function WE(s){return rc.getFriendMap().has(s)}const{isEmpty:AS}=ye.utils;class tf{constructor(){this._strangerProfileMap=new Map}init(){Cr.getInstance().registerApi({apiName:"getMyProfile",context:this}),Cr.getInstance().registerApi({apiName:"getUserProfile",context:this}),Cr.getInstance().registerApi({apiName:"updateMyProfile",context:this}),this.createProfile=eE.createProfile.bind(eE);const{notificationCenter:n}=ye;ws.getInstance().registerWorkflowStep(Yt.SYNC_SERVER_INFO_AFTER_LOGIN,qt.USER_PROFILE_SYNC,this.getMyProfileCacheThenServer,this),n.subscribeInnerEvent(no.MESSAGE_PUSH,n.InnerEventSubType.PROFILE_MODIFIED,this._onProfileDataModify,this),n.subscribeInnerEvent(no.LOGOUT,this._reset,this),n.subscribeInnerEvent(no.DESTROY,this._dispose,this)}getMyProfile(){return pA(this,void 0,void 0,function*(){try{const n=Ar(),g=yield bR([n]);if(g){const u=this._handleProfileFormResponse(g)[0];return rc.getUserProfileMap().set(n,u),{code:0,data:u}}}catch(n){const{errorCode:g,errorInfo:u}=n;throw new gs({functionName:"getMyProfile",code:g,message:u})}})}getUserProfile(n){return pA(this,void 0,void 0,function*(){try{let{userIDList:g}=n;const{userIdListToRequest:u,profileFromCache:E}=this._filterRequestAndCacheUsers(g);if(u.length===0)return{code:0,data:E,successLog:{message:`userIDList.length:${g.length}`}};u.length>NR&&(ye.ssoLog.warn("getUserProfile","userIdListToRequest.length > 1000"),u.length=NR);const{data:m,error:D}=yield this._batchFetchUserProfiles(u),M=u.length,T=m.length,P=M-T;if(E.length===0&&M===P&&!AS(D))throw D;if(h(m))return m.forEach(iA=>{WE(iA.userID)?rc.getUserProfileMap().set(iA.userID,iA):this._strangerProfileMap.set(iA.userID,iA)}),{code:0,data:m.concat(E),successLog:{message:`getUserProfile query:${M} success:${T} fail:${P} from cache:${E.length}`}}}catch(g){throw new gs(g)}})}getMyProfileCacheThenServer(){return pA(this,void 0,void 0,function*(){const n=Ar(),g=rc.getUserProfileMap().has(n);return g?{code:0,data:g}:this.getMyProfile()})}updateMyProfile(n){return pA(this,void 0,void 0,function*(){const g=Ar(),u={};for(const m in n)n[m]!==void 0&&(u[m]=n[m]);const E=eE.convertParamsToProfile(u);try{yield function(P){return pA(this,void 0,void 0,function*(){const W="profile.portrait_set",iA=GR({servcmd:W,data:P}),EA=`${iA.head.seq}${W}`,RA=yield ye.channel.sendPacket(iA,{requestId:EA});if(RA){const{ActionStatus:kA,ErrorCode:xA,ErrorDisplay:LA,ErrorInfo:SA}=RA;return{actionStatus:kA,errorCode:xA,errorDisplay:LA,errorInfo:SA}}})}({From_Account:g,ProfileItem:E});const D=rc.getUserProfile(g);let M;M=D?Object.assign(Object.assign({},D),u):eE.createProfile(g,E);const T=!rg(D,M,["lastUpdatedTime"]);return M.lastUpdatedTime=Date.now(),rc.getUserProfileMap().set(g,M),T&&this._emitProfileUpdated(M),{code:0,data:M,successLog:{message:`profileArray: ${ye.utils.safeStringify(E)}`}}}catch(m){const{errorCode:D,errorInfo:M}=m;throw new gs({functionName:"updateMyProfile",code:D,message:M,moreMessage:`params: ${ye.utils.safeStringify(n)}`})}})}updateMyNickAndAvatar(n){return pA(this,void 0,void 0,function*(){const g=Ar(),u=Date.now(),E=rc.getUserProfile(g);let m={};m=E?Object.assign(E,n):eE.createProfile(g,n),m.lastUpdatedTime=u,rc.getUserProfileMap().set(g,m)})}_onProfileDataModify(n){const g=function(m){const{Profile_Account:D,PushType:M,ProfileList:T}=m;return{userId:D,pushType:M,profileList:eE.parseProfileList(T)}}(n.ProfileDataMod[0]);if(AS(g))return;const{isProfileUpdated:u,profile:E}=this._handleProfileModified(g);u&&this._emitProfileUpdated(E)}_emitProfileUpdated(n){ye.notificationCenter.emitInnerEvent(no.PROFILE_UPDATE,{name:no.PROFILE_UPDATE,data:[n]}),ye.notificationCenter.emitOuterEvent(Dr.PROFILE_UPDATED,{name:Dr.PROFILE_UPDATED,data:[n]}),MB.updateConversation(`C2C${n?.userID}`,{userProfile:n})}_dispose(){const{notificationCenter:n}=ye;n.unSubscribeInnerEvent(no.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(no.MESSAGE_PUSH,n.InnerEventSubType.PROFILE_MODIFIED,this._onProfileDataModify,this),n.unSubscribeInnerEvent(no.DESTROY,this._dispose,this),this._reset()}_handleProfileModified(n){const{userId:g,profileList:u}=n,E=rc.getUserProfile(g);if(!(Ar()===g||WE(g)&&E))return{isProfileUpdated:!1,profile:null};const m=eE.normalizeProfileFields(u),D=Object.keys(m).some(W=>W===$D?this._isCustomFieldChanged(E.profileCustomField,m.profileCustomField):E[W]!==m[W]);if(!D)return{isProfileUpdated:!1,profile:E};const M=Date.now(),T=Object.prototype.hasOwnProperty.call(m,$D)?this._mergeProfileCustomField(E.profileCustomField,m.profileCustomField):E.profileCustomField,P=Object.assign(Object.assign(Object.assign({},E),m),{profileCustomField:T,lastUpdatedTime:M});return rc.getUserProfileMap().set(g,P),{isProfileUpdated:D,profile:P}}_filterRequestAndCacheUsers(n){const g=[],u=[];return n.forEach(E=>{const m=rc.getUserProfileMap().has(E);WE(E)&&m?u.push(rc.getUserProfile(E)):this._isStrangerAndProfileValid(E)?u.push(this._strangerProfileMap.get(E)):g.push(E)}),{userIdListToRequest:g,profileFromCache:u}}_handleProfileFormResponse(n){const{userProfile:g}=n;if(!Array.isArray(g))return[];const u=g.filter(m=>m.userId!=="@TLS#NOT_FOUND"&&m.userId!==""&&!AS(m.profileItem)),E=Date.now();return u.map(m=>{const D=eE.createProfile(m.userId,m.profileItem);return D.lastUpdatedTime=E,D})}_isStrangerAndProfileValid(n){var g;if(!WE(n)){const{lastUpdatedTime:u=0}=this._strangerProfileMap.get(n)||{},E=((g=ye.store.get("cloudConfig"))===null||g===void 0?void 0:g.stranger_profile_expiration_time)||6e5;return Date.now()-u<=E}return!1}_chunkUserIDList(n,g){return Array.from({length:Math.ceil(n.length/g)},(u,E)=>n.slice(E*g,(E+1)*g))}_batchFetchUserProfiles(n){return pA(this,void 0,void 0,function*(){const g=[],u=[];let E={};return this._chunkUserIDList(n,100).forEach(m=>{g.push(bR(m))}),(yield Promise.allSettled(g)).forEach(m=>{if(m.status==="fulfilled"){const D=m.value,M=this._handleProfileFormResponse(D);h(M)&&u.push(...M)}else if(m.status==="rejected"){const{code:D,message:M}=m.reason||{};E={errorCode:D,message:M}}}),{data:u,error:E}})}_isCustomFieldChanged(n=[],g=[]){if(!h(g)||g.length===0)return!1;if(!h(n)||n.length===0)return!0;const u=new Map(n.map(E=>[E.key,E.value]));return g.some(E=>u.get(E.key)!==E.value)}_mergeProfileCustomField(n=[],g=[]){const u=h(n)?n.map(E=>Object.assign({},E)):[];return h(g)&&g.length!==0&&g.forEach(({key:E,value:m})=>{const D=u.find(M=>M.key===E);D?D.value=m:u.push({key:E,value:m})}),u}_reset(){rc.getUserProfileMap().clear(),this._strangerProfileMap.clear()}}const of=new Map,eS=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];for(let s=0,n=eS.length;s>(-2*m&6)):0)E="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(E);try{return decodeURIComponent(escape(g))}catch(u){return console.warn(u),""}}const{isEmpty:$T}=ye.utils,{generateProtocolData:sf}=ye.common;function kR(s){return pA(this,void 0,void 0,function*(){const n="im_open_status.ws_get_user_status",g=sf({servcmd:n,data:{To_Account:s}}),u=`${g.head.seq}${n}`,E=yield ye.channel.sendPacket(g,{requestId:u});if(E)return function(m){const{ErrorCode:D,ErrorInfo:M,ErrorList:T=[],UserStatusList:P=[]}=m,W=P.map(EA=>{const{To_Account:RA,Status:kA,CustomStatus:xA,Detail:LA=[]}=EA;return{userID:RA,statusType:kA,customStatus:rp(xA),onlineDevices:AN(LA)}}),iA=T.map(EA=>{const{To_Account:RA,Invalid_Account:kA,ErrorCode:xA,ErrorInfo:LA}=EA;return{userID:$T(kA)?RA:kA,code:xA,message:LA}});return{errorCode:D,errorInfo:M,successUserList:W,failureUserList:iA}}(E)})}function AN(s){const n=[];return s?.forEach(g=>{const{Platform:u,Status:E}=g;E==="Online"&&n.push(u)}),n}class eN{constructor(){this._customStatus=""}init(){const{notificationCenter:n}=ye;Cr.getInstance().registerApi({apiName:"getUserStatus",context:this}),Cr.getInstance().registerApi({apiName:"setSelfStatus",context:this}),Cr.getInstance().registerApi({apiName:"subscribeUserStatus",context:this}),Cr.getInstance().registerApi({apiName:"unsubscribeUserStatus",context:this}),ws.getInstance().registerWorkflowStep(Yt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,qt.USER_STATUS_UPDATE,this._onReOnline,this),n.subscribeInnerEvent(no.MESSAGE_PUSH,n.InnerEventSubType.USER_STATUS_UPDATE,this._onUserStatusUpdate,this),n.subscribeInnerEvent(no.LOGOUT,this._reset,this),n.subscribeInnerEvent(no.DESTROY,this._dispose,this)}setSelfStatus(n){return pA(this,void 0,void 0,function*(){const g=Ar(),{customStatus:u}=n;try{return yield function(E){return pA(this,void 0,void 0,function*(){const m="im_open_status.ws_set_custom_status",D=sf({servcmd:m,data:{CustomStatus:E}}),M=`${D.head.seq}${m}`,T=yield ye.channel.sendPacket(D,{requestId:M});if(T){const{ErrorCode:P,ErrorInfo:W}=T;return{errorCode:P,errorInfo:W}}})}(u),this._customStatus=u,{code:0,data:{userID:g,statusType:bh,customStatus:u},successLog:{message:`customStatus: ${u}`}}}catch(E){const{errorCode:m,errorInfo:D}=E;throw new gs({functionName:"setSelfStatus",code:m,message:D})}})}getUserStatus(n){return pA(this,void 0,void 0,function*(){const{userIDList:g=[]}=n;if(this._isOnlyMeInArray(g))return this._getMyStatus();const u=yield this._getUserStatus(g);return Object.assign(Object.assign({},u),{successLog:{message:`userIDList length: ${g.length}`}})})}setCustomStatus(n){const g=rp(n);this._customStatus=g}subscribeUserStatus(n){return pA(this,void 0,void 0,function*(){try{const{userIDList:g=[]}=n;this._checkBusinessCapabilityBits("subscribeUserStatus");const u=this._getMaxUserCount("subscribe"),E=this._sliceUserIDList(g,u),m=yield function(M){return pA(this,void 0,void 0,function*(){const{channel:T}=ye,P="im_open_status.ws_status_subscribe",W=sf({servcmd:P,data:{To_Account:M}}),iA=`${W.head.seq}${P}`;return yield T.sendPacket(W,{requestId:iA})})}(E),D=this._parseResponse(m);return{code:0,data:{failureUserList:D},successLog:{message:`userID length:${g.length} failCount: ${D.length}`}}}catch(g){const{errorCode:u}=g;throw new gs({functionName:"subscribeUserStatus",code:u})}})}unsubscribeUserStatus(n){return pA(this,void 0,void 0,function*(){try{this._checkBusinessCapabilityBits("unsubscribeUserStatus");const{userIDList:g=[]}=n,u=this._getMaxUserCount("unsubscribe"),E=this._sliceUserIDList(g,u),m=yield function(M){return pA(this,void 0,void 0,function*(){const{channel:T}=ye,P="im_open_status.ws_status_unsubscribe";let W={};W=M.length===0?{UnsubscribeAll:1}:{To_Account:M};const iA=sf({servcmd:P,data:W}),EA=`${iA.head.seq}${P}`;return yield T.sendPacket(iA,{requestId:EA})})}(E),D=this._parseResponse(m);return{code:0,data:{failureUserList:D},successLog:{message:`userID length:${g.length} failCount: ${D.length}`}}}catch(g){const{errorCode:u}=g;throw new gs({functionName:"unsubscribeUserStatus",code:u})}})}_onUserStatusUpdate(n){const{UserStatusList:g=[]}=n||{},u=g.map(E=>{const{To_Account:m,Status:D,CustomStatus:M,Platform:T}=E,P={userID:m,statusType:D,customStatus:rp(M)};return T&&(P.onlineDevices=T),P});this._emitUserStatusUpdatedEvent(u)}_onReOnline(n){const g=rp(n.data.customStatus);if(this._customStatus===g)return;this._customStatus=g;const u={userID:Ar(),statusType:bh,customStatus:g};this._emitUserStatusUpdatedEvent(u)}_emitUserStatusUpdatedEvent(n){ye.notificationCenter.emitOuterEvent(Dr.USER_STATUS_UPDATED,{name:Dr.USER_STATUS_UPDATED,data:n})}_sliceUserIDList(n,g){return n.slice(0,g)}_parseResponse(n){const{ErrorList:g=[]}=n;return g.map(u=>{const{To_Account:E,Invalid_Account:m,ErrorCode:D,ErrorInfo:M}=u;return{userID:ye.utils.isEmpty(m)?E:m,code:D,message:M}})}_checkBusinessCapabilityBits(n){if(!ye.store.get("commercialConfig").get(XT))throw new gs({functionName:n,code:da.NO_USE,replacement1:n})}_getMaxUserCount(n){const g=ye.store.get("cloudConfig")||{},u={query:{key:"status_query_count",default:500},subscribe:{key:"status_sub_count",default:100},unsubscribe:{key:"status_unsub_count",default:100}},{key:E,default:m}=u[n],D=g[E]||m;return parseInt(D,10)}_getMyStatus(){return{code:0,data:{successUserList:[{userID:Ar(),statusType:bh,customStatus:this._customStatus}],failureUserList:[]}}}_getUserStatus(n){return pA(this,void 0,void 0,function*(){try{this._checkBusinessCapabilityBits("getUserStatus");const g=this._getMaxUserCount("query"),u=this._sliceUserIDList(n,g),E=yield kR(u),{successUserList:m,failureUserList:D}=E||{};return{code:0,data:{successUserList:m,failureUserList:D}}}catch(g){const{errorCode:u}=g;throw new gs({functionName:"getUserStatus",code:u})}})}_isOnlyMeInArray(n){const g=Ar();return n.length===1&&n.indexOf(g)>-1}_dispose(){const{notificationCenter:n}=ye;n.unSubscribeInnerEvent(no.MESSAGE_PUSH,n.InnerEventSubType.USER_STATUS_UPDATE,this._onUserStatusUpdate,this),n.unSubscribeInnerEvent(no.DESTROY,this._dispose,this),n.unSubscribeInnerEvent(no.LOGOUT,this._reset,this),this._reset()}_reset(){this._customStatus=""}}const tS={getUserProfile:{userIDList:{required:!0,rules:["array"],allowEmpty:!1}},updateMyProfile:{nick:{required:!1,rules:["string"],allowEmpty:!0},avatar:{required:!1,rules:["string"],allowEmpty:!0},gender:{required:!1,rules:["string"],allowEmpty:!0},selfSignature:{required:!1,rules:["string"],allowEmpty:!0},allowType:{required:!1,rules:["string"],allowEmpty:!0},birthday:{required:!1,rules:["number"],allowEmpty:!1},language:{required:!1,rules:["string"],allowEmpty:!0},messageSettings:{required:!1,rules:["string"],allowEmpty:!0},adminForbidType:{required:!1,rules:["string"],allowEmpty:!0},level:{required:!1,rules:["number"],allowEmpty:!1},role:{required:!1,rules:["number"],allowEmpty:!0},profileCustomField:{required:!1,rules:["array"],allowEmpty:!0,customValidator:function(s){for(const n of s){if(typeof n!="object")return"Each item in profileCustomField must be an object";if(typeof n?.key!="string")return"Each item.key in profileCustomField must be a string";if(!n?.key.startsWith(XD))return'Each item.key in profileCustomField must start with "Tag_Profile_Custom"'}return!0}}},setSelfStatus:{customStatus:{required:!0,rules:["string"],allowEmpty:!0}},getUserStatus:{userIDList:{required:!0,rules:["array"],allowEmpty:!1}},subscribeUserStatus:{userIDList:{required:!0,rules:["array"],allowEmpty:!1}},unsubscribeUserStatus:{userIDList:{required:!1,rules:["array"],allowEmpty:!0}}},tN={getMyProfile:!0,getUserProfile:!0,updateMyProfile:!0,setSelfStatus:!0,getUserStatus:!0,subscribeUserStatus:!0,unsubscribeUserStatus:!0};class iN{constructor(){this.userProfile=new tf,this.userStatus=new eN,this.userProfile.init(),this.userStatus.init(),Wc({auth:tN,params:tS})}}function iS(s){const n=[];if(!l(s))return n;const g=s.length;if(g===0)return n;for(let u=g-1;u>=0;u--)s[u]==="1"&&n.push(2**(g-u-1));return n}var kd,wC,Ld;(function(s){s.NOT_START="notStart",s.PENDING="pending",s.RESOLVED="resolved",s.REJECTED="rejected"})(kd||(kd={})),function(s){s[s.C2C=1]="C2C",s[s.GROUP=2]="GROUP"}(wC||(wC={})),function(s){s[s.C2C=8]="C2C",s[s.GROUP=2]="GROUP"}(Ld||(Ld={}));class oS{constructor(){this._name="SyncConversationHandler",this._pagingStatus=kd.NOT_START,this._pagingTimeStamp=0,this._pagingStartIndex=0,this._pagingPinnedTimeStamp=0,this._pagingPinnedStartIndex=0}init(){const{notificationCenter:n}=ye;ws.getInstance().registerWorkflowStep(Yt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,qt.CONVERSATION_RECOVER,this._syncConversationList,this),ws.getInstance().registerWorkflowStep(Yt.SYNC_SERVER_INFO_AFTER_LOGIN,qt.CONVERSATION_LIST_SYNC,this._syncConversationListAfterLogin,this),n.subscribeInnerEvent(no.LOGOUT,this._reset,this),n.subscribeInnerEvent(no.DESTROY,this._dispose,this),ye.ssoLog.debug(`${this._name}.init`)}isSyncCompleted(){return this._pagingStatus===kd.RESOLVED}_syncConversationListAfterLogin(){return pA(this,void 0,void 0,function*(){return this._pagingStatus=kd.NOT_START,this._pagingTimeStamp=0,this._pagingStartIndex=0,this._pagingPinnedTimeStamp=0,this._pagingPinnedStartIndex=0,this._syncConversationList()})}_syncConversationList(){return pA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:g}}=ye;n.debug("_syncConversationList","start");try{const u=yield this._pagingGetConversationList(!0);this._pagingStatus=kd.RESOLVED;const{conversationList:E=[]}=u||{};return n.info("_syncConversationList",`success count:${E.length}`),u}catch(u){const E=new gs(u);n.error("_syncConversationList",`fail ${g(u)}`,{error:E})}})}_pagingGetConversationList(n){return pA(this,void 0,void 0,function*(){try{const g=[];this._pagingStatus=kd.PENDING;const u=yield function(iA){return pA(this,void 0,void 0,function*(){const{fromAccount:EA,pagingTimeStamp:RA,pagingStartIndex:kA,pagingPinnedTimeStamp:xA,pagingPinnedStartIndex:LA}=iA;return gg({servcmd:"recentcontact.page_get",data:{AssistFlags:31,MsgAssistFlags:15,OrderType:1,From_Account:EA,StartIndex:kA,TimeStamp:RA,TopStartIndex:LA,TopTimeStamp:xA}})})}({fromAccount:Ar(),pagingTimeStamp:n?this._pagingTimeStamp:0,pagingStartIndex:n?this._pagingStartIndex:0,pagingPinnedTimeStamp:n?this._pagingPinnedTimeStamp:0,pagingPinnedStartIndex:n?this._pagingPinnedStartIndex:0}),{CompleteFlag:E,SessionItem:m=[],TimeStamp:D,StartIndex:M,TopTimeStamp:T,TopStartIndex:P}=u||{};let W=[];if(E===1&&(this._pagingStatus=kd.RESOLVED),m.length>0&&(W=this._getConversationOptions(m),g.push(...W)),ye.notificationCenter.emitInnerEvent(no.SYNC_CONVERSATION_LIST,{conversationUpdateFieldList:W}),this._pagingTimeStamp=D,this._pagingStartIndex=M,this._pagingPinnedTimeStamp=T,this._pagingPinnedStartIndex=P,E!==1){const{conversationList:iA}=yield this._pagingGetConversationList(n);g.push(...iA)}return{conversationList:g}}catch(g){throw g}})}_getConversationOptions(n){const{utils:{isUndefined:g}}=ye,u=this._convertConversationKey(n);return this._filterValidConversations(u).map(E=>(g(E.lastMsg)&&(E.lastMsg={elements:[]}),E.type===wC.C2C?this._assembleC2COption(E):this._assembleGroupOption(E)))}_filterValidConversations(n){return n.filter(({type:g,userID:u})=>g===wC.C2C&&!function(E){let m;return E.startsWith(Lo.CONV_C2C)&&(m=E.replace(Lo.CONV_C2C,"")),m==="@TLS#ERROR"||m==="@TLS#NOT_FOUND"}(u)||g===2)}_assembleC2COption(n){var g,u,E,m,D,M,T,P;const W=this._createUserprofile(n);return{conversationID:`${Lo.CONV_C2C}${n.userID}`,type:Lo.CONV_C2C,lastMessage:{lastTime:n.time,lastSequence:n.sequence,fromAccount:n.lastC2CMsgFromAccount,type:!((g=n.lastMsg)===null||g===void 0)&&g.elements[0]?(u=n.lastMsg)===null||u===void 0?void 0:u.elements[0].type:null,payload:!((E=n.lastMsg)===null||E===void 0)&&E.elements[0]?this._amendLayersOverLimitProp(n.lastMsg.elements[0].content):null,cloudCustomData:((M=(D=(m=n.lastMsg)===null||m===void 0?void 0:m.elements)===null||D===void 0?void 0:D[0])===null||M===void 0?void 0:M.cloudCustomData)||"",isRevoked:n.lastMessageFlag===Ld.C2C,onlineOnlyFlag:!1,nick:"",nameCard:"",version:0,isPeerRead:this._computeIsPeerRead(n),revoker:((P=(T=n.lastMsg)===null||T===void 0?void 0:T.revokerInfo)===null||P===void 0?void 0:P.revoker)||null},unreadCount:0,userProfile:W,peerReadTime:n.peerReadTime,isPinned:n.isPinned===1,customData:n.customMark||"",markList:iS(n.standardMark),conversationGroupList:[],remark:n.friendRemark||"",messageRemindType:this._transMsgRemindType(n.messageRemindType)}}_createUserprofile(n){var g;const{userID:u,nick:E,peerAvatar:m}=n,D=[{tag:"Tag_Profile_IM_Nick",value:E},{tag:"Tag_Profile_IM_Image",value:m}];return(g=ye.user.userProfile)===null||g===void 0?void 0:g.createProfile(u,D)}_computeIsPeerRead(n){const g=Ar(),{lastC2CMsgFromAccount:u,time:E,c2cPeerReadTime:m}=n;return u===g&&E<=m}_assembleGroupOption(n){var g,u,E,m,D;return{conversationID:`${Lo.CONV_GROUP}${n.groupID}`,type:Lo.CONV_GROUP,lastMessage:Object.assign(Object.assign({lastTime:n.time,lastSequence:n.sequence,fromAccount:n.msgGroupFromAccount},this._patchTypeAndPayload(n)),{cloudCustomData:((E=(u=(g=n.lastMsg)===null||g===void 0?void 0:g.elements)===null||u===void 0?void 0:u[0])===null||E===void 0?void 0:E.cloudCustomData)||"",isRevoked:n.lastMessageFlag===Ld.GROUP,onlineOnlyFlag:!1,nick:n.msgGroupFromNickName||"",nameCard:n.msgGroupFromCardName||"",revoker:((D=(m=n.lastMsg)===null||m===void 0?void 0:m.revokerInfo)===null||D===void 0?void 0:D.revoker)||null}),groupProfile:{groupID:n.groupID,name:n.groupNick,avatar:n.groupImage,type:n.groupType,nextMessageSeq:n.nextMessageSeq},unreadCount:this._computeGroupUnreadCount(n),peerReadTime:0,isPinned:n.isPinned===1,version:0,customData:n.customMark||"",markList:iS(n.standardMark),conversationGroupList:[],messageRemindType:this._transMsgRemindType(n.messageRemindType),subType:n.groupType}}_convertConversationKey(n){return n.map(g=>({type:g.Type,userID:g.To_Account,nick:g.C2cNick,peerAvatar:g.C2cImage,time:g.MsgTimeStamp,sequence:g.MsgSeq,lastC2CMsgFromAccount:g.LastC2cMsgFrom_Account,lastMsg:this._convertLastMsgKey(g.LastMsg),lastMessageFlag:g.LastMsgFlags,c2cPeerReadTime:g.C2cPeerReadTime,peerReadTime:g.C2cPeerReadTime,friendRemark:g.C2cRemark,isPinned:g.TopFlags,standardMark:g.StandardMark,customMark:g.CustomMark,messageRemindType:g.MsgRecvOption,groupID:g.ToAccount,groupNick:g.GroupNick,groupImage:g.GroupImage,groupType:g.GroupType,nextMessageSeq:g.GroupNextMsgSeq,msgGroupFromAccount:g.MsgGroupFrom_Account,msgGroupFromNickName:g.MsgGroupFromNickName,msgGroupFromCardName:g.MsgGroupFromCardName,unreadCount:g.UnreadMsgCount,noUnreadCount:g.GroupIgnoredUnreadSeqCount}))}_convertLastMsgKey(n){var g,u,E;const{utils:{isEmpty:m}}=ye;if(m(n))return null;let D="",M=null;if(!m(n.GroupTips)){const{From_Account:T,GroupName:P}=((g=n.GroupTips)===null||g===void 0?void 0:g.GroupInfo)||{};D=Lo.MSG_GRP_TIP,M=Object.assign(Object.assign({},this._parseContent(D,n.GroupTips.MsgBody)),{groupProfile:{from:T,groupName:P}})}return n.MsgBody&&(D=(u=n.MsgBody[0])===null||u===void 0?void 0:u.MsgType,M=this._parseContent(D,n.MsgBody[0])),{event:n.Event,elements:[{type:D,content:M,cloudCustomData:n.CloudCustomData}],revokerInfo:{revoker:(E=n.RevokerInfo)===null||E===void 0?void 0:E.Revoker_Account}}}_parseContent(n,g){var u;if(!g)return g;const E=ye.message.messageFactory.getElementClass(n);return E?(u=E.parseServerPushElement(g))===null||u===void 0?void 0:u.content:g}_amendLayersOverLimitProp(n){const{LayersOverLimit:g}=n;return Do(n,["LayersOverLimit"]).layersOverLimit=g===1,n}_transMsgRemindType(n){let g="";return n===0?g=Lo.MSG_REMIND_ACPT_AND_NOTE:n===1?g=Lo.MSG_REMIND_DISCARD:n===2?g=Lo.MSG_REMIND_ACPT_NOT_NOTE:n===3&&(g=Lo.NOT_RECEIVE_OFFLINE_PUSH_EXCEPT_AT),g}_patchTypeAndPayload(n){var g;const{utils:{isUndefined:u}}=ye,{event:E,elements:m=[]}=n.lastMsg||{};return u(E)?{type:m[0]?m[0].type:null,payload:m[0]?this._amendLayersOverLimitProp(m[0].content):null}:{type:Lo.MSG_GRP_TIP,payload:((g=m?.[0])===null||g===void 0?void 0:g.content)||{}}}_computeGroupUnreadCount(n){const{unreadCount:g=0,noUnreadCount:u=0}=n,E=g-u;return E>0?E:0}_reset(){this._pagingStatus=kd.NOT_START,this._pagingTimeStamp=0,this._pagingStartIndex=0,this._pagingPinnedTimeStamp=0,this._pagingPinnedStartIndex=0}_dispose(){this._reset();const{notificationCenter:n}=ye;n.unSubscribeInnerEvent(no.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(no.DESTROY,this._dispose,this)}}class sS{constructor(){this.syncConversationHandler=new oS,this.syncConversationHandler.init()}}console.log(`TencentCloudLiteChat.VERSION:${Zr}`);var nS={create:function(s){var n,g;const{SDKAppID:u,testEnv:E=!1,devMode:m=!1,unlimitedAVChatRoom:D=!1,scene:M="",oversea:T=!1,instance:P,disableIndependentDomain:W=!1,proxyServer:iA=""}=s;let EA=u;if(!function(kA){if(typeof kA=="number")return!0;const xA=Number(kA);return!Number.isNaN(xA)}(EA))return console.error("Create SDK instance failed. Failed to parse the SDKAppID, please check the arguments"),null;if(EA=Number(EA),Ca.has(EA))return Ca.get(EA);let RA=null;if(P)RA=P,RA._workflowManager&&ws.setInstance(RA._workflowManager),RA._pluginManager&&RA._pluginManager.installBuiltInPlugin(DB),P.isReady()&&((g=(n=ws.getInstance()).executeWorkflow)===null||g===void 0||g.call(n,Yt.SYNC_SERVER_INFO_AFTER_LOGIN));else{const kA=function(){function ae(){return(65536*(1+Math.random())|0).toString(16).substring(1)}return`${ae()+ae()}${ae()}${ae()}${ae()}${ae()}${ae()}${ae()}`}();ye.init({sdkAppId:EA,instanceId:kA,testEnv:E,devMode:m,unlimitedAVChatRoom:D,disableIndependentDomain:W,scene:M,oversea:T,sdkEdition:jm,version:Zr,proxyServer:iA}),ws.getInstance().init(),ye.message=new ZD,ye.user=new iN,ye.login=new Rh,ye.conversation=new sS,au.getInstance().installBuiltInPlugin(DB),RA=Cr.getInstance().exposeApiForClient(),RA._workflowManager=ws.getInstance(),RA._pluginManager=au.getInstance();const{utils:{IS_WORKER_AVAILABLE:xA,USER_AGENT:LA,getPlatformType:SA,isIOSWebView:OA}}=ye,JA=`instanceID:${kA} SDKAppID:${u} platform:${HA} host:${SA()} isIOSWebView:${OA} workerAvailable:${xA} UserAgent:${LA}`;ye.ssoLog.info("sdkConstruct",JA)}return Ca.set(EA,RA),RA},TSignaling:qc,EVENT:Dr,VERSION:Zr,TYPES:Lo};return nS})}(z1)),z1.exports}var KoA=qoA();const ig=yW(KoA);var Z1={exports:{}},joA=Z1.exports,r8;function WoA(){return r8||(r8=1,function(t,i){(function(r,l){t.exports=l()})(joA,function(){function r(ge,XA){if(!(ge instanceof XA))throw new TypeError("Cannot call a class as a function")}function l(ge,XA){for(var _e=0;_e"u"&&typeof uni.requireNativePlugin=="function",WA=TA&&uni.getDeviceInfo().platform.toLocaleLowerCase()==="ios",Ee=(TA&&uni.getDeviceInfo().platform.toLocaleLowerCase(),IA||nA||mA||lA||cA||TA),de=U!==void 0&&(U.nativeModuleProxy!==void 0||U.ReactNative!==void 0),Pe=nA?qq:mA?tt:lA?swan:cA?my:IA?wx:TA?uni:{},pe=function(ge){if(b(ge)!=="object"||ge===null)return!1;var XA=Object.getPrototypeOf(ge);if(XA===null)return!0;for(var _e=XA;Object.getPrototypeOf(_e)!==null;)_e=Object.getPrototypeOf(_e);return XA===_e};function gt(ge){if(ge==null)return!0;if(typeof ge=="boolean")return!1;if(typeof ge=="number")return ge===0;if(typeof ge=="string"||typeof ge=="function"||Array.isArray(ge))return ge.length===0;if(ge instanceof Error)return ge.message==="";if(pe(ge)){for(var XA in ge)if(Object.prototype.hasOwnProperty.call(ge,XA))return!1;return!0}return!1}var pt=function(){return I(function ge(){r(this,ge),this._n="WebRequest"},[{key:"request",value:function(ge,XA){var _e=this,je="".concat(this._n,".request"),Ut=ge.downloadUrl||"",gi=(ge.method||"PUT").toUpperCase(),Fi=ge.url;if(console.log("%c tim-upload-plugin %c","background:#0abf5b; padding:1px; border-radius:3px; color: #fff","background:transparent","".concat(je," URL:").concat(Fi)),ge.qs){var To=function(ki){var ns=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"&",jo=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"=";return gt(ki)?"":pe(ki)?Object.keys(ki).map(function(Ao){var zt=encodeURIComponent(Ao)+jo;return Array.isArray(ki[Ao])?ki[Ao].map(function(oo){return zt+encodeURIComponent(oo)}).join(ns):zt+encodeURIComponent(ki[Ao])}).filter(Boolean).join(ns):void 0}(ge.qs);To&&(Fi+="".concat(Fi.indexOf("?")===-1?"?":"&").concat(To))}var io=new XMLHttpRequest;io.open(gi,Fi,!0),io.responseType=ge.dataType||"text";var Eo=ge.headers||{};if(ge.uploadByIP&&(Eo=w(w({},Eo),{},{host:ge.uploadIP})),!gt(Eo))for(var Vs in Eo)Eo.hasOwnProperty(Vs)&&Vs.toLowerCase()!=="content-length"&&Vs.toLowerCase()!=="user-agent"&&Vs.toLowerCase()!=="origin"&&Vs.toLowerCase()!=="host"&&io.setRequestHeader(Vs,Eo[Vs]);return io.onload=function(){if(io.status===200)XA(null,_e._xhrRes(io,_e._xhrBody(io,Ut,ge.uploadByIP&&ge.uploadIP),Eo));else{if(ge.uploadIP&&ge.url.indexOf(ge.uploadIP)===-1)return ge.url=function(ns,jo){return ns.replace(/^http(s)?:\/\/(.*?)\//,"https://".concat(jo,"/"))}(ge.url,ge.uploadIP),ge.uploadByIP=!0,_e.request(ge,XA);var ki={code:io.status,message:JSON.stringify(io.responseText)};XA(ki,_e._xhrRes(io,_e._xhrBody(io,Ut,ge.uploadByIP&&ge.uploadIP),Eo))}},io.onerror=function(ki){var ns=_e._xhrBody(io,Ut,ge.uploadByIP&&ge.uploadIP),jo={code:io.status,message:JSON.stringify(io.responseText)};ns||io.statusText||io.status!==0||(ki.message="CORS blocked or network error"),XA(jo,_e._xhrRes(io,ns)),jo=null},ge.onProgress&&io.upload&&(io.upload.onprogress=function(ki){var ns=ki.total,jo=ki.loaded,Ao=Math.floor(100*jo/ns);ge.onProgress({total:ns,loaded:jo,percent:(Ao>=100?100:Ao)/100})}),io.send(ge.resources),io}},{key:"_xhrRes",value:function(ge,XA){var _e={};return ge.getAllResponseHeaders().trim().split(`
-`).forEach(function(je){if(je){var Ut=je.indexOf(":"),gi=je.substr(0,Ut).trim().toLowerCase(),Fi=je.substr(Ut+1).trim();_e[gi]=Fi}}),{statusCode:ge.status,statusMessage:ge.statusText,headers:_e,data:XA}}},{key:"_xhrBody",value:function(ge,XA,_e){return ge.status===200&&XA?{location:XA,uploadIP:_e}:{response:ge.responseText,uploadIP:_e}}}])}(),ze=["unknown","image","video","audio","log"],Dt=["name"],Kt=function(){return I(function ge(){r(this,ge)},[{key:"request",value:function(ge,XA){var _e=this,je=ge.resources,Ut=je===void 0?"":je,gi=ge.headers,Fi=gi===void 0?{}:gi,To=ge.url,io=ge.downloadUrl,Eo=io===void 0?"":io,Vs=To,ki=null,ns=Eo.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/),jo=decodeURIComponent(ns[3]),Ao=jo.indexOf("?")>-1?jo.split("?")[0]:jo,zt={key:ge.fileKey?ge.fileKey:Ao,success_action_status:200,"Content-Type":""},oo={};if(WA){var bi=To.split("?sign=");if(bi.length>1){var vs=bi[1];Vs="".concat(bi[0],"?sign=").concat(encodeURIComponent("".concat(vs))),oo.sign=decodeURIComponent(vs),oo.signature=decodeURIComponent(vs)}}var HA={url:Vs,header:Fi,name:"file",filePath:Ut,formData:w(w({},zt),oo),timeout:ge.timeout||3e5};if(cA){var le=HA;le.name,HA=w(w({},function(Ve,Ft){if(Ve==null)return{};var nt,It,Ai=function(ke,Ze){if(ke==null)return{};var vt={};for(var _t in ke)if({}.hasOwnProperty.call(ke,_t)){if(Ze.includes(_t))continue;vt[_t]=ke[_t]}return vt}(Ve,Ft);if(Object.getOwnPropertySymbols){var ei=Object.getOwnPropertySymbols(Ve);for(It=0;It=3e4&&(this.systemClockOffset=To-Fi,XA=!0)}else Math.floor(ge.statusCode/100)===5&&(XA=!0)}return XA}}],[{key:"getVersion",value:function(){return"1.4.3"}}])}()})}(Z1)),Z1.exports}var zoA=WoA();const ZoA=yW(zoA);/**
+`],{type:"application/javascript"});this._worker=new Worker(URL.createObjectURL(g)),this._worker.postMessage({type:ur,url:r})}send(r){var g,u;try{(g=this._worker)===null||g===void 0||g.postMessage({type:Ds,data:r})}catch(E){(u=this._onSendFail)===null||u===void 0||u.call(this,E)}}bindSocketHandlers(r){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=r;if(this._worker){const v={[fs]:g,[re]:u,[At]:E,[Zt]:m,[Jo]:D};this._onSendFail=D,this._worker.onmessage=T=>{var P;const{type:W}=T?.data||{};typeof v[W]=="function"&&((P=v[W])===null||P===void 0||P.call(v,T?.data))}}}unbindSocketHandlers(){this._worker&&(this._worker.onmessage=null)}disconnect(){this._worker&&(this._worker.postMessage({type:Sg}),this._worker.terminate(),this._worker=null),this._blobUrl&&(URL.revokeObjectURL(this._blobUrl),this._blobUrl=null)}}class WI{}var as,ro=new class{constructor(){this._store=new Map}get(n){return this._store.get(n)}getStorage(n){return Ui?ii?my.getStorageSync({key:n}).data:so.getStorageSync(n):this._canUseLocalStorage()?localStorage.getItem(n):{}}set(n,r){const g=this._store.get(n)||{};r instanceof Map?this._store.set(n,r):this._store.set(n,Object.assign(Object.assign({},g),r))}setStorage(n,r){Ui?ii?my.setStorageSync({key:n,data:JSON.stringify(r)}):so.setStorageSync(n,JSON.stringify(r)):this._canUseLocalStorage()&&localStorage.setItem(n,JSON.stringify(r))}clear(n){typeof n=="string"?this._store.set(n,{}):this._store.clear()}clearLocalStorage(n){this._canUseLocalStorage()&&(typeof n=="string"?localStorage.setItem(n,""):localStorage.clear())}reset(){this.clear()}_canUseLocalStorage(){return typeof window<"u"&&navigator&&navigator.cookieEnabled&&localStorage}};class vc{connectSocket(r){return this._socket=so.connectSocket({url:r,header:{"content-type":"application/json"},multiple:!0,complete:()=>{}}),this._socket}send(r){var g;(g=this._socket)===null||g===void 0||g.send({data:r,fail:this._onSendFail})}bindSocketHandlers(r){const{onOpen:g,onMessage:u,onClose:E,onError:m,onSendFail:D}=r;this._socket&&(this._socket.onClose(E),this._socket.onOpen(g),this._socket.onMessage(v=>u(v?.data)),this._socket.onError(()=>m),this._onSendFail=D)}unbindSocketHandlers(){this._socket&&(this._socket.onClose(()=>{}),this._socket.onOpen(()=>{}),this._socket.onMessage(()=>{}),this._socket.onError(()=>{}))}disconnect(){this._socket&&(this._socket.close(),this._socket=null)}}(function(n){n[n.CONNECTED=0]="CONNECTED",n[n.CONNECTING=1]="CONNECTING",n[n.DISCONNECTED=2]="DISCONNECTED"})(as||(as={}));class ag{constructor(r){this._url="",this._readyState=as.DISCONNECTED,this._url=r,this._id=L(),this._emitter=new Ln,ii?this._socket=new vc:ze||ao||Qt||Ve||bi||Pt?this._socket=new An({onError:this._onError.bind(this)}):Hs?this._socket=new WI:this._canUseWebWorker()?this._socket=new ha:this._socket=new Sc,this.connect()}connect(){this.doOpen(),this._bindSocketHandlers()}doOpen(){[as.CONNECTED,as.CONNECTING].includes(this._readyState)||(this._readyState=as.CONNECTING,this._ws=this._socket.connectSocket(this._url))}send(r){this._readyState!==as.CONNECTED?this.reconnect():this._socket.send(r)}reconnect(){[as.CONNECTED,as.CONNECTING].includes(this._readyState)||(this.disconnect(),this.doOpen())}getId(){return this._id}on(r,g,u){this._emitter.on(r,g,u)}off(r,g,u){this._emitter.off(r,g,u)}isConnected(){return this._readyState===as.CONNECTED}disconnect(){this._readyState=as.DISCONNECTED,this._unbindSocketHandlers(),this._socket.disconnect()}_onOpen(r){this._readyState===as.CONNECTING&&(this._readyState=as.CONNECTED,this._emitter.emit("connect",{socketId:this._id,event:r}))}_onMessage(r){this._emitter.emit("message",r)}_onClose(r){this._readyState=as.DISCONNECTED,this._emitter.emit("close",{socketId:this._id,event:r})}_onError(r){this._readyState=as.DISCONNECTED,this._emitter.emit("error",{socketId:this._id,error:r})}_onSendFail(r){this._readyState=as.DISCONNECTED,this._emitter.emit("sendFail",{socketId:this._id,error:r})}_bindSocketHandlers(){this._socket.bindSocketHandlers({onOpen:this._onOpen.bind(this),onMessage:this._onMessage.bind(this),onClose:this._onClose.bind(this),onError:this._onError.bind(this),onSendFail:this._onSendFail.bind(this)})}_unbindSocketHandlers(){this._socket.unbindSocketHandlers()}_canUseWebWorker(){const r=ro.get("cloudConfig")||{};return(s(r.isWorkerEnabled)||r.isWorkerEnabled==="1")&&wo}}const vg={[st.SINGAPORE]:[[2e7,3e7],[172e7,173e7]],[st.KOREA]:[[3e7,4e7],[173e7,174e7]],[st.GERMANY]:[[4e7,5e7],[174e7,175e7]],[st.IND]:[[5e7,6e7],[175e7,176e7]],[st.JPN]:[[6e7,7e7],[176e7,177e7]],[st.USA]:[[7e7,8e7],[177e7,178e7]],[st.INDONESIA]:[[8e7,9e7],[178e7,179e7]],[st.KSA]:[[9e7,1e8],[179e7,18e8]]};function Ba(n){var r;if(!((r=ro.get("instance"))===null||r===void 0)&&r.oversea)return st.OVERSEA;for(const g of Object.keys(vg))for(const[u,E]of vg[g])if(n>=u&&n`${oA}=${W[oA]}`).join("&"));var W;return g?`${n}/binfo?${P}&compress=gzip`:`${n}/info?${P}`}function en(n){const r=ro.get("instance"),{sdkAppId:g,testEnv:u,proxyServer:E}=r,m=Ba(g);if(u)return Xn(Ct.TEST[m].DEFAULT,{isBinary:n});if(!ts(E))return Xn(E,{isBinary:n});const D=Ct.PRODUCTION[m],v=$t&&D.ANYCAST,T=$t,P=!!D.BACKUP_CN;return Xn({[Fo.INITIAL]:()=>(Uo=Fo.DEFAULT,D.DEFAULT),[Fo.DEFAULT]:()=>(Uo=Fo.IPV6,D.IPV6),[Fo.IPV6]:()=>(Uo=Fo.BACKUP,D.BACKUP),[Fo.BACKUP]:()=>T?(Uo=Fo.BACKUP_WEB_ONLY,function(W){const oA=Math.floor(10001*Math.random())+1e4;return W.replace("*",String(oA))}(D.BACKUP_WEB_ONLY)):P?(Uo=Fo.BACKUP_CN,D.BACKUP_CN):v?(Uo=Fo.ANYCAST,D.ANYCAST):D.DEFAULT,[Fo.BACKUP_WEB_ONLY]:()=>P?(Uo=Fo.BACKUP_CN,D.BACKUP_CN):v?(Uo=Fo.ANYCAST,D.ANYCAST):D.DEFAULT,[Fo.BACKUP_CN]:()=>(Uo=v?Fo.ANYCAST:Fo.DEFAULT,D[Uo]),[Fo.ANYCAST]:()=>(Uo=Fo.DEFAULT,D.ANYCAST="",D.DEFAULT)}[Uo](),{isBinary:n})}var Mg=new class{constructor(){this._timeOffsetWithServer=0}getServerTimeMs(){return Date.now()+this._timeOffsetWithServer}getServerTimeSeconds(){return Math.floor(this.getServerTimeMs()/1e3)}getTimeOffsetWithServer(){return this._timeOffsetWithServer}calculateTimeOffsetWithServer(n,r){const g=Date.now(),u=g-n;this._timeOffsetWithServer=r+u-g}};const Mc=16;var Rn=new class{constructor(){this._tasks=[],this._timer=null,this._taskMap=new Map}_addTaskToScheduler(n){const{id:r}=n;this.removeTask(r),this._tasks.push(n),this._taskMap.set(r,n),this._sort(),this._scheduleNextTask()}_createTask(n){const{id:r,callback:g,context:u,isOnce:E=!1,intervalMs:m=Mc}=n,D=Math.max(m,Mc);return{id:r,nextExecuteTime:Date.now()+D,intervalMs:m,callback:g,context:u,isOnce:E}}addTask(n){const r=this._createTask(n);this._addTaskToScheduler(r)}addOnceTask(n){const r=this._createTask(Object.assign(Object.assign({},n),{isOnce:!0}));this._addTaskToScheduler(r)}removeTask(n){const r=this._tasks.findIndex(g=>g.id===n);r>-1&&(this._tasks.splice(r,1),this._taskMap.delete(n),this._scheduleNextTask())}updateTaskInterval(n,r){const g=this._taskMap.get(n);g&&(g.intervalMs=r,g.nextExecuteTime=Date.now()+r,this._sort(),this._scheduleNextTask())}clearAllTasks(){this._tasks=[],this._taskMap.clear(),this._timer&&(clearTimeout(this._timer),this._timer=null)}dispose(){this.clearAllTasks()}_sort(){this._tasks.sort((n,r)=>n.nextExecuteTime-r.nextExecuteTime)}_scheduleNextTask(){this._timer&&(clearTimeout(this._timer),this._timer=null);const n=this._tasks[0];if(n){const r=Math.max(0,n.nextExecuteTime-Date.now());this._timer=setTimeout(()=>this._execute(),r)}}_execute(){const n=Date.now();for(;this._tasks.length&&this._tasks[0].nextExecuteTime<=n;){const r=this._tasks[0];try{r.context?r.callback.call(r.context):r.callback(),r.isOnce?this.removeTask(r.id):(r.nextExecuteTime=n+r.intervalMs,this._sort())}catch(g){console.warn(`Task ${r.id} execution failed:`,g),r.isOnce&&this.removeTask(r.id)}}this._scheduleNextTask()}};function Ua(n){const r=[];for(let g=0;g=55296&&u<=56319){const E=n.charCodeAt(++g)-56320+(u-55296<<10)+65536;r.push(240|E>>18,128|E>>12&63,128|E>>6&63,128|63&E)}else u<=127?r.push(u):u<=2047?r.push(192|u>>6,128|63&u):r.push(224|u>>12,128|u>>6&63,128|63&u)}return new Uint8Array(r)}function Bn(n){const r=Array.isArray(n)?[]:Object.create(null);for(const g in n)Object.prototype.hasOwnProperty.call(n,g)&&_(g)&&n[g]!=null&&(n[g]===null||typeof n[g]!="object"?r[g]=n[g]:r[g]=Bn(n[g]));return r}function Ts(n,r){if(BA.includes(n))return 0;const g=Ua(JSON.stringify(r));let u=4294967295;const{length:E}=g;for(let m=0;m>>=1:u=u>>>1^3988292384}return(4294967295^u)>>>0}function Qa(n){const{servcmd:r,data:g}=n,u=function(m){const D=ro.get("login")||{},v=ro.get("instance")||{};return{servcmd:m,ver:"v4",platform:HA,websdkappid:537048168,websdkversion:"1.7.3",a2:D.a2Key||void 0,tinyid:D.tinyID||void 0,status_instid:D.statusInstanceId||0,sdkappid:v.sdkAppId,contenttype:"json",reqtime:Math.floor(Date.now()/1e3),identifier:D.a2Key?void 0:D.userId,usersig:D.a2Key?void 0:D.userSig,sdkability:478343027,sdkability_ext:lA(""),cappid:v.applicationID||0,tjgID:"",seq:_a(),cs:0}}(r),E=Bn(g);return u.cs=Ts(r,E),{head:u,body:E}}function wn(n){const{servcmd:r,data:g}=n,u=function(m){const D=ro.get("login")||{},v=ro.get("instance")||{};return{servcmd:m,ver:"v4",platform:HA,websdkappid:537048168,websdkversion:"1.7.3",sdkappid:v.sdkAppId,contenttype:"",reqtime:Math.floor(Date.now()/1e3),identifier:"",usersig:"",status_instid:D.statusInstanceId||0,sdkability:478343027,sdkability_ext:lA(""),cappid:v.applicationID||0,seq:_a(),cs:0}}(r),E=Bn(g);return u.cs=Ts(r,E),{head:u,body:E}}let Fa=L();function _a(){return Fa=Fa<2415919103?Fa+1:L(),Fa}function $(){var n;const r=ro.get("login")||{},g=ro.get("instance")||{};return{sdk_type:30,sdk_app_id:g.sdkAppId,sdk_version:"1.6.18",tiny_id:Number(r.tinyID),user_id:r.userId||((n=ro.get("webPush"))===null||n===void 0?void 0:n.userId),platform:HA,instance_id:g.instanceId,trace_id:new Date().getTime()}}var j,MA=Object.freeze({__proto__:null,calcBodyCRC:Ts,filterProtocolDataInvalidFields:Bn,generateCosSpecifiedData:function(n){const{servcmd:r,data:g}=n,u=function(m){const D=ro.get("login")||{},v=ro.get("instance")||{};return{servcmd:m,ver:"v4",platform:HA,websdkappid:537048168,websdkversion:"1.7.3",sdkappid:v.sdkAppId,contenttype:"json",reqtime:Math.floor(Date.now()/1e3),identifier:D.userId,usersig:D.userSig,status_instid:D.statusInstanceId||0,sdkability:478343027,sdkability_ext:lA(""),cappid:v.applicationID||0,seq:_a(),cs:0}}(r),E=Bn(g);return u.cs=Ts(r,E),{head:u,body:E}},generateProtocolData:Qa,generateSSOLogProtocolData:wn,generateSequence:_a,getCommonHead:$,getHostSite:Ba,taskScheduler:Rn,timeManager:Mg});(function(n){n[n.info=4]="info",n[n.warning=5]="warning",n[n.error=6]="error"})(j||(j={}));const zA={method:"extension",networkType:"network_type",eventType:"event_type",code:"error_code",message:"error_message",moreMessage:"more_message",duplicate:"duplicate",costTime:"cost_time",level:"level",uiPlatform:"ui_platform",timestamp:"timestamp"};class oe{constructor(r){this.level=j.info,this._canSendLog=!0,this._logCreatedAt=Mg.getServerTimeMs(),this.timestamp=0,this.networkType=8,this.code=0,this.moreMessage="",this.method="",this.message="",this.costTime=0,this.duplicate=!1,this.eventType=0,this.uiPlatform=this._getUiPlatform(),this._sdkEdition=this._getSDKEdition();const{method:g,eventType:u=0,message:E="",costTime:m=0,error:D,uiPlatform:v,moreMessage:T="",code:P=0,startTime:W=0}=r||{};this.eventType=u,this.method=g,this.message=E,this.costTime=m,this.moreMessage=`${T} startTime:${W}`,this.code=P,D&&this.setError(D),ts(v)||(this.uiPlatform=v)}setMoreMessage(r){this.moreMessage=`${this.moreMessage} ${r}`}updateLogCreatedAtByTimeOffset(){this._logCreatedAt+=Mg.getTimeOffsetWithServer()}end(r=!1){this._canSendLog&&(this._canSendLog=!1,this.timestamp=Mg.getServerTimeMs(),this._ssoLogModule.pushToLogQueue(this._convertSSOLogDataKeyToServe()),r&&this._ssoLogModule.uploadSSOLogData())}setError(r){var g;return r instanceof Error?this._canSendLog?(!((g=ro.get("netWorkMonitor"))===null||g===void 0)&&g.isNetworkOnline&&(r.errorCode&&(this.code=r.errorCode),r.errorMessage&&this.setMoreMessage(r.errorMessage)),this.level=j.error,this):this:(console.warn("SSOLogData.setError value not instanceof Error, please check!"),this)}setLogInfo(r){return Object.keys(r).forEach(g=>{Object.keys(zA).includes(g)&&(this[g]=r[g])}),this}setSSOLogModule(r){this._ssoLogModule=r}_convertSSOLogDataKeyToServe(){const r={};return Object.keys(this).forEach(g=>{const u=g;zA[u]&&(r[zA[u]]=this[u])}),r}_getUiPlatform(){var r;const g=(r=ro.get("instance"))===null||r===void 0?void 0:r.scene;if(typeof g=="string"){const u=Number(g);return isNaN(u)?void 0:u}}_getSDKEdition(){var r;return(r=ro.get("instance"))===null||r===void 0?void 0:r.sdkEdition}}var ye;(function(n){n.RECONNECTED="reconnected",n.CLOUD_CONFIG_UPDATE="cloud_config_update",n.SOCKET_DISCONNECTED="socket_disconnected"})(ye||(ye={}));var He=ye;const Je=20,It=6e4,mt=[4,5,6],Nt="report-logger";var Kt=new class{constructor(){this._sdkAppIdBlackList=[],this._tinyIdWhiteList=[],this._reportLevel=[4,5,6],this._minThreshold=Je,this._maxThreshold=100,this._waitingTime=It,this._lastReportAt=Date.now(),this._ssoLogMap=new Map,this._logLevel=IA.DEBUG,this._throttleConfig={global:{throttleTime:Qe,maxCount:ae},single:{throttleTime:$A,maxCount:jA}},this._globalThrottle={count:0,startTime:Date.now()},this._singleThrottleMap=new Map,$s.subscribeInnerEvent(He.CLOUD_CONFIG_UPDATE,this._handleCloudConfigUpdate,this),Rn.addTask({id:Nt,intervalMs:1e3,callback:this._checkAndReportIfDue,context:this}),this._logQueue=[],this._savePlatFormInfo()}_handleCloudConfigUpdate(n){const{evt_rpt_threshold:r=Je,evt_rpt_waiting:g=It,evt_rpt_level:u=mt,evt_rpt_sdkappid_bl:E="",evt_rpt_tinyid_wl:m="",evt_rpt_global_throttle_time:D=Qe,evt_rpt_global_throttle_count:v=ae,evt_rpt_single_throttle_time:T=$A,evt_rpt_single_throttle_count:P=jA}=n||{};this._sdkAppIdBlackList=E.split(",").map(W=>Number(W)),this._waitingTime=Number(g),this._minThreshold=r,this._reportLevel=u,this._tinyIdWhiteList=m.split(","),this._throttleConfig={global:{throttleTime:D,maxCount:v},single:{throttleTime:T,maxCount:P}}}createSSOLogData(n){const r=new oe(n);return r.setSSOLogModule(this),this._ssoLogMap.set(n.method,r),r}getSSOLogData(n){return this._ssoLogMap.get(n)||{}}pushToLogQueue(n){n&&(this._logQueue.push(n),this._shouldUploadImmediately()&&this.uploadSSOLogData())}setLogLevel(n){[IA.DEBUG,IA.ERROR,IA.INFO,IA.NONE,IA.WARN].includes(n)&&(this._logLevel=n)}debug(n,r="",g){this._log(IA.DEBUG,n,r,g)}info(n,r="",g){this._log(IA.INFO,n,r,g)}warn(n,r="",g){this._log(IA.WARN,n,r,g)}error(n,r="",g){this._log(IA.ERROR,n,r,g)}_shouldUploadImmediately(){return this._logQueue.length>=this._minThreshold}_isReportDue(){return Date.now()>=this._lastReportAt+this._waitingTime}_checkAndReportIfDue(){this._isReportDue()&&this._logQueue.length>0&&this.uploadSSOLogData()}uploadSSOLogData(){return mA(this,void 0,void 0,function*(){if(this._logQueue.length===0)return;const n=this._logQueue.slice();this._logQueue=[];try{const r=this._filterLogs(n);if(r.length===0)return void(this._lastReportAt=Date.now());const g={Header:$(),Event:r};ts(g.Header.user_id)||(yield function(u){const E="imopenstat.tim_web_report_v2",m=wn({servcmd:E,data:u}),D=`${m.head.seq}${E}`;return Se.sendPacket(m,{requestId:D})}(g))}catch(r){this._requeueFailedLogs(n),this.debug("uploadSSOLogData",_s(r))}finally{this._lastReportAt=Date.now()}})}_requeueFailedLogs(n){this._logQueue=n.concat(this._logQueue);const r=this._logQueue.length-200;r>0&&(this._logQueue.splice(0,r),this.debug("uploadSSOLogData",`log queue overflow, dropped ${r} oldest logs`))}_savePlatFormInfo(){var n,r;if(ze){const g=(r=(n=wx.getAccountInfoSync)===null||n===void 0?void 0:n.call(wx))===null||r===void 0?void 0:r.miniProgram;if(g){const{appId:u,envVersion:E}=g;ro.set("instance",{appId:u,envVersion:E})}}else $t&&ro.set("instance",{href:window.location.href})}_filterLogs(n){const{tinyID:r}=ro.get("login")||{},{sdkAppId:g}=ro.get("instance")||{};return this._sdkAppIdBlackList.includes(g)&&!this._tinyIdWhiteList.includes(r)?[]:n.filter(u=>this._reportLevel.includes(u.level))}_checkThrottle(n){return!!this._checkGlobalThrottle()||this._checkSingleThrottle(n)}_checkGlobalThrottle(){const n=Date.now();if(n-this._globalThrottle.startTime>=this._throttleConfig.global.throttleTime)this._globalThrottle.count=1,this._globalThrottle.startTime=n;else if(this._globalThrottle.count++,this._globalThrottle.count>this._throttleConfig.global.maxCount)return!0;return!1}_checkSingleThrottle(n){const r=Date.now(),g=this._singleThrottleMap.get(n);return g?r-g.startTime>=this._throttleConfig.single.throttleTime?(g.count=1,g.startTime=r,!1):g.count>=this._throttleConfig.single.maxCount||(g.count++,!1):(this._singleThrottleMap.set(n,{count:1,startTime:r}),!1)}_shouldLog(n){return n>=this._logLevel&&this._logLevel!==IA.NONE}_shouldReport(n){return this._reportLevel.includes(KA[n])}_formatLog(n,r,g,u){const E=new Date,m=`${E.getHours()}:${E.getMinutes()}:${E.getSeconds()}:${E.getMilliseconds()}`,D=`<${IA[n]}>`;return Gt||Ui?[`${gA} [${m}] ${D} [${r}] ${g}`]:["%c%s%c%s","background:#0abf5b; padding:1px; border-radius:3px; color: #fff",gA,"",`[${m}] ${D} [${r}] ${g} params: ${_s(u)}`]}_log(n,r,g,u){if(this._shouldLog(n)){const E=this._formatLog(n,r,g,u);RA[n].apply(console,E)}if(this._shouldReport(n)){const E=this._getThrottleKey(r,g,u);this._checkThrottle(E)||this.createSSOLogData(Object.assign(Object.assign({message:g},u),{method:r})).end()}}_getThrottleKey(n,r,g){const u=`${n}${r}${_s(Object.assign(Object.assign({},g),{costTime:""}))}`,E=Ua(JSON.stringify(u));let m=4294967295;const{length:D}=E;for(let v=0;v>>=1:m=m>>>1^3988292384}return`${(4294967295^m)>>>0}`}reset(){console.log("SSO_LOG_MODULE.reset"),Rn.removeTask(Nt),$s.unSubscribeInnerEvent(He.CLOUD_CONFIG_UPDATE,this._handleCloudConfigUpdate,this),this._lastReportAt=0,this.uploadSSOLogData(),this._sdkAppIdBlackList=[],this._tinyIdWhiteList=[],this._minThreshold=Je,this._maxThreshold=100,this._waitingTime=It,this._logQueue=[],this._logLevel=IA.DEBUG,this._globalThrottle={count:0,startTime:Date.now()},this._singleThrottleMap.clear()}};const di=15e3,dt="Channel",Ht="channel_schedule_task",$i="channel_reconnect_task",eo="connected",tn="connecting",_i="disconnected",is=1e3,Rg="network_status_change",Er="activity_status_change",Mr="send_fail",jn="reconnect_failed",Tl="socket_error",on="socket_close";function uI(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}function $g(n){return $g=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},$g(n)}function Rc(n){throw new Error('Could not dynamically require "'+n+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}var Tu,Ta={exports:{}},Nl=(Tu||(Tu=1,function(n){n.exports=function r(g,u,E){function m(T,P){if(!u[T]){if(!g[T]){if(!P&&Rc)return Rc(T);if(D)return D(T,!0);var W=new Error("Cannot find module '"+T+"'");throw W.code="MODULE_NOT_FOUND",W}var oA=u[T]={exports:{}};g[T][0].call(oA.exports,function(EA){return m(g[T][1][EA]||EA)},oA,oA.exports,r,g,u,E)}return u[T].exports}for(var D=Rc,v=0;v>>6:(EA<65536?oA[xA++]=224|EA>>>12:(oA[xA++]=240|EA>>>18,oA[xA++]=128|EA>>>12&63),oA[xA++]=128|EA>>>6&63),oA[xA++]=128|63&EA);return oA},u.buf2binstring=function(W){return P(W,W.length)},u.binstring2buf=function(W){for(var oA=new E.Buf8(W.length),EA=0,wA=oA.length;EA>10&1023,SA[wA++]=56320|1023&kA)}return P(SA,wA)},u.utf8border=function(W,oA){var EA;for((oA=oA||W.length)>W.length&&(oA=W.length),EA=oA-1;0<=EA&&(192&W[EA])==128;)EA--;return EA<0||EA===0?oA:EA+v[W[EA]]>oA?EA:oA}},{"./common":1}],3:[function(r,g,u){g.exports=function(E,m,D,v){for(var T=65535&E,P=E>>>16&65535,W=0;D!==0;){for(D-=W=2e3>>1:m>>>1;D[v]=m}return D}();g.exports=function(m,D,v,T){var P=E,W=T+v;m^=-1;for(var oA=T;oA>>8^P[255&(m^D[oA])];return-1^m}},{}],6:[function(r,g,u){g.exports=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}},{}],7:[function(r,g,u){g.exports=function(E,m){var D,v,T,P,W,oA,EA,wA,kA,xA,LA,SA,OA,WA,ue,le,ki,Li,Yt,Fi,hs,Re,Mt,UA,ci;D=E.state,v=E.next_in,UA=E.input,T=v+(E.avail_in-5),P=E.next_out,ci=E.output,W=P-(m-E.avail_out),oA=P+(E.avail_out-257),EA=D.dmax,wA=D.wsize,kA=D.whave,xA=D.wnext,LA=D.window,SA=D.hold,OA=D.bits,WA=D.lencode,ue=D.distcode,le=(1<>>=Yt=Li>>>24,OA-=Yt,(Yt=Li>>>16&255)==0)ci[P++]=65535&Li;else{if(!(16&Yt)){if(!(64&Yt)){Li=WA[(65535&Li)+(SA&(1<>>=Yt,OA-=Yt),OA<15&&(SA+=UA[v++]<>>=Yt=Li>>>24,OA-=Yt,!(16&(Yt=Li>>>16&255))){if(!(64&Yt)){Li=ue[(65535&Li)+(SA&(1<>>=Yt,OA-=Yt,(Yt=P-W)>3,SA&=(1<<(OA-=Fi<<3))-1,E.next_in=v,E.next_out=P,E.avail_in=v>>24&255)+(Re>>>8&65280)+((65280&Re)<<8)+((255&Re)<<24)}function SA(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new E.Buf16(320),this.work=new E.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function OA(Re){var Mt;return Re&&Re.state?(Mt=Re.state,Re.total_in=Re.total_out=Mt.total=0,Re.msg="",Mt.wrap&&(Re.adler=1&Mt.wrap),Mt.mode=wA,Mt.last=0,Mt.havedict=0,Mt.dmax=32768,Mt.head=null,Mt.hold=0,Mt.bits=0,Mt.lencode=Mt.lendyn=new E.Buf32(kA),Mt.distcode=Mt.distdyn=new E.Buf32(xA),Mt.sane=1,Mt.back=-1,oA):EA}function WA(Re){var Mt;return Re&&Re.state?((Mt=Re.state).wsize=0,Mt.whave=0,Mt.wnext=0,OA(Re)):EA}function ue(Re,Mt){var UA,ci;return Re&&Re.state?(ci=Re.state,Mt<0?(UA=0,Mt=-Mt):(UA=1+(Mt>>4),Mt<48&&(Mt&=15)),Mt&&(Mt<8||15=Oi.wsize?(E.arraySet(Oi.window,Mt,UA-Oi.wsize,Oi.wsize,0),Oi.wnext=0,Oi.whave=Oi.wsize):(ci<(Os=Oi.wsize-Oi.wnext)&&(Os=ci),E.arraySet(Oi.window,Mt,UA-ci,Os,Oi.wnext),(ci-=Os)?(E.arraySet(Oi.window,Mt,UA-ci,ci,0),Oi.wnext=ci,Oi.whave=Oi.wsize):(Oi.wnext+=Os,Oi.wnext===Oi.wsize&&(Oi.wnext=0),Oi.whave>>8&255,UA.check=D(UA.check,hg,2,0),Ft=Ut=0,UA.mode=2;break}if(UA.flags=0,UA.head&&(UA.head.done=!1),!(1&UA.wrap)||(((255&Ut)<<8)+(Ut>>8))%31){Re.msg="incorrect header check",UA.mode=30;break}if((15&Ut)!=8){Re.msg="unknown compression method",UA.mode=30;break}if(Ft-=4,Ka=8+(15&(Ut>>>=4)),UA.wbits===0)UA.wbits=Ka;else if(Ka>UA.wbits){Re.msg="invalid window size",UA.mode=30;break}UA.dmax=1<>8&1),512&UA.flags&&(hg[0]=255&Ut,hg[1]=Ut>>>8&255,UA.check=D(UA.check,hg,2,0)),Ft=Ut=0,UA.mode=3;case 3:for(;Ft<32;){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>8&255,hg[2]=Ut>>>16&255,hg[3]=Ut>>>24&255,UA.check=D(UA.check,hg,4,0)),Ft=Ut=0,UA.mode=4;case 4:for(;Ft<16;){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>8),512&UA.flags&&(hg[0]=255&Ut,hg[1]=Ut>>>8&255,UA.check=D(UA.check,hg,2,0)),Ft=Ut=0,UA.mode=5;case 5:if(1024&UA.flags){for(;Ft<16;){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>8&255,UA.check=D(UA.check,hg,2,0)),Ft=Ut=0}else UA.head&&(UA.head.extra=null);UA.mode=6;case 6:if(1024&UA.flags&&(ji<(Do=UA.length)&&(Do=ji),Do&&(UA.head&&(Ka=UA.head.extra_len-UA.length,UA.head.extra||(UA.head.extra=new Array(UA.head.extra_len)),E.arraySet(UA.head.extra,ci,Oi,Do,Ka)),512&UA.flags&&(UA.check=D(UA.check,ci,Do,Oi)),ji-=Do,Oi+=Do,UA.length-=Do),UA.length))break A;UA.length=0,UA.mode=7;case 7:if(2048&UA.flags){if(ji===0)break A;for(Do=0;Ka=ci[Oi+Do++],UA.head&&Ka&&UA.length<65536&&(UA.head.name+=String.fromCharCode(Ka)),Ka&&Do>9&1,UA.head.done=!0),Re.adler=UA.check=0,UA.mode=12;break;case 10:for(;Ft<32;){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>=7&Ft,Ft-=7&Ft,UA.mode=27;break}for(;Ft<3;){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>=1)){case 0:UA.mode=14;break;case 1:if(Fi(UA),UA.mode=20,Mt!==6)break;Ut>>>=2,Ft-=2;break A;case 2:UA.mode=17;break;case 3:Re.msg="invalid block type",UA.mode=30}Ut>>>=2,Ft-=2;break;case 14:for(Ut>>>=7&Ft,Ft-=7&Ft;Ft<32;){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>16^65535)){Re.msg="invalid stored block lengths",UA.mode=30;break}if(UA.length=65535&Ut,Ft=Ut=0,UA.mode=15,Mt===6)break A;case 15:UA.mode=16;case 16:if(Do=UA.length){if(ji>>=5,Ft-=5,UA.ndist=1+(31&Ut),Ut>>>=5,Ft-=5,UA.ncode=4+(15&Ut),Ut>>>=4,Ft-=4,286>>=3,Ft-=3}for(;UA.have<19;)UA.lens[ES[UA.have++]]=0;if(UA.lencode=UA.lendyn,UA.lenbits=7,kI={bits:UA.lenbits},Kl=T(0,UA.lens,0,19,UA.lencode,0,UA.work,kI),UA.lenbits=kI.bits,Kl){Re.msg="invalid code lengths set",UA.mode=30;break}UA.have=0,UA.mode=19;case 19:for(;UA.have>>16&255,bI=65535&Jg,!((Gr=Jg>>>24)<=Ft);){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>=Gr,Ft-=Gr,UA.lens[UA.have++]=bI;else{if(bI===16){for(sE=Gr+2;Ft>>=Gr,Ft-=Gr,UA.have===0){Re.msg="invalid bit length repeat",UA.mode=30;break}Ka=UA.lens[UA.have-1],Do=3+(3&Ut),Ut>>>=2,Ft-=2}else if(bI===17){for(sE=Gr+3;Ft>>=Gr)),Ut>>>=3,Ft-=3}else{for(sE=Gr+7;Ft>>=Gr)),Ut>>>=7,Ft-=7}if(UA.have+Do>UA.nlen+UA.ndist){Re.msg="invalid bit length repeat",UA.mode=30;break}for(;Do--;)UA.lens[UA.have++]=Ka}}if(UA.mode===30)break;if(UA.lens[256]===0){Re.msg="invalid code -- missing end-of-block",UA.mode=30;break}if(UA.lenbits=9,kI={bits:UA.lenbits},Kl=T(P,UA.lens,0,UA.nlen,UA.lencode,0,UA.work,kI),UA.lenbits=kI.bits,Kl){Re.msg="invalid literal/lengths set",UA.mode=30;break}if(UA.distbits=6,UA.distcode=UA.distdyn,kI={bits:UA.distbits},Kl=T(W,UA.lens,UA.nlen,UA.ndist,UA.distcode,0,UA.work,kI),UA.distbits=kI.bits,Kl){Re.msg="invalid distances set",UA.mode=30;break}if(UA.mode=20,Mt===6)break A;case 20:UA.mode=21;case 21:if(6<=ji&&258<=Br){Re.next_out=Yr,Re.avail_out=Br,Re.next_in=Oi,Re.avail_in=ji,UA.hold=Ut,UA.bits=Ft,v(Re,Cn),Yr=Re.next_out,Os=Re.output,Br=Re.avail_out,Oi=Re.next_in,ci=Re.input,ji=Re.avail_in,Ut=UA.hold,Ft=UA.bits,UA.mode===12&&(UA.back=-1);break}for(UA.back=0;Vg=(Jg=UA.lencode[Ut&(1<>>16&255,bI=65535&Jg,!((Gr=Jg>>>24)<=Ft);){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>Ic)])>>>16&255,bI=65535&Jg,!(Ic+(Gr=Jg>>>24)<=Ft);){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>=Ic,Ft-=Ic,UA.back+=Ic}if(Ut>>>=Gr,Ft-=Gr,UA.back+=Gr,UA.length=bI,Vg===0){UA.mode=26;break}if(32&Vg){UA.back=-1,UA.mode=12;break}if(64&Vg){Re.msg="invalid literal/length code",UA.mode=30;break}UA.extra=15&Vg,UA.mode=22;case 22:if(UA.extra){for(sE=UA.extra;Ft>>=UA.extra,Ft-=UA.extra,UA.back+=UA.extra}UA.was=UA.length,UA.mode=23;case 23:for(;Vg=(Jg=UA.distcode[Ut&(1<>>16&255,bI=65535&Jg,!((Gr=Jg>>>24)<=Ft);){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>Ic)])>>>16&255,bI=65535&Jg,!(Ic+(Gr=Jg>>>24)<=Ft);){if(ji===0)break A;ji--,Ut+=ci[Oi++]<>>=Ic,Ft-=Ic,UA.back+=Ic}if(Ut>>>=Gr,Ft-=Gr,UA.back+=Gr,64&Vg){Re.msg="invalid distance code",UA.mode=30;break}UA.offset=bI,UA.extra=15&Vg,UA.mode=24;case 24:if(UA.extra){for(sE=UA.extra;Ft>>=UA.extra,Ft-=UA.extra,UA.back+=UA.extra}if(UA.offset>UA.dmax){Re.msg="invalid distance too far back",UA.mode=30;break}UA.mode=25;case 25:if(Br===0)break A;if(Do=Cn-Br,UA.offset>Do){if((Do=UA.offset-Do)>UA.whave&&UA.sane){Re.msg="invalid distance too far back",UA.mode=30;break}Do>UA.wnext?(Do-=UA.wnext,Bl=UA.wsize-Do):Bl=UA.wnext-Do,Do>UA.length&&(Do=UA.length),GC=UA.window}else GC=Os,Bl=Yr-UA.offset,Do=UA.length;for(Brki?(Yt=Bl[GC+xA[Mt]],Fi=Ft[oE+xA[Mt]]):(Yt=96,Fi=0),SA=1<>Yr)+(OA-=SA)]=Li<<24|Yt<<16|Fi,OA!==0;);for(SA=1<>=1;if(SA!==0?(Ut&=SA-1,Ut+=SA):Ut=0,Mt++,--Cn[Re]==0){if(Re===ci)break;Re=W[oA+xA[Mt]]}if(Os{const v=new Uint8Array(D).slice(4);let T;try{T=Nl.inflate(v,{to:"string"})}catch(P){console.error("inflate error",P)}return T})(n.data):function(D){const v=new Uint8Array(D);let T="",P=0;const{length:W}=v;for(;P0)for(let kA=0;kA{var u;const{uplinkData:E,canResend:m,resolve:D,reject:v,timeout:T}=r;if(m){this._pendingRequests.set(g,{resolve:D,reject:v,timestamp:Date.now(),uplinkData:E,timeout:T,canResend:m});const P=this._isBinarySupported?Ua(E).buffer:E;(u=this._socketAdapter)===null||u===void 0||u.send(P)}else this._pendingRequests.delete(g)})}_onConnect(n){const{socketId:r,event:g={}}=n||{};this._connectionId=r,this._connectionEstablishedTime=Date.now();const u=Date.now()-this._connectionStartTime,E=`${dt}.onConnect cost:${u} ms. socketID:${r} res:${JSON.stringify(g)}`;if(this._ssoLog({method:"onConnect",message:E}),this._checkPendingRequestsAndResend(),this._sendHeartbeatIfReady(),this._isReconnecting){const m=`${dt}.reconnect success`;this._ssoLog({method:"reconnectSuccess",message:m}),$s.emitInnerEvent(He.RECONNECTED),this._isReconnecting=!1}this._resetReconnectDelay(),this._handleConnectStateChange({state:eo,shouldEmitEvent:!0,shouldAttemptReconnect:!1})}_sendAck(n){const r=Qa({servcmd:"openim.ws_msg_push_ack",data:{SessionData:n}});this.sendPacket(r)}_executeScheduledTaskIfReady(){return mA(this,void 0,void 0,function*(){this._clearTimeoutRequest(),this._sendHeartbeatIfReady()})}_canSendHeartbeat(){var n;return((n=this._socketAdapter)===null||n===void 0?void 0:n.isConnected())&&Date.now()>=this._nextHeartbeatAt&&!this._isHeartbeatInProgress}_sendHeartbeat(){return mA(this,void 0,void 0,function*(){var n;const r=Qa({servcmd:"heartbeat.alive",data:{}});try{const g=`${r.head.seq}${r.head.servcmd}`;yield this.sendPacket(r,{requestId:g,timeout:3e3})}catch(g){const u=(n=ro.get("netWorkMonitor"))===null||n===void 0?void 0:n.isNetworkOnline,E=`${dt}.sendHeartbeat failed. isNetWorkOnline:${u} error: ${_s(g)}`;this._ssoLog({method:"sendHeartbeatError",message:E}),this._handleConnectStateChange({state:_i,shouldEmitEvent:!0,shouldAttemptReconnect:!0})}})}_sendHeartbeatIfReady(){return mA(this,void 0,void 0,function*(){this._canSendHeartbeat()&&(this._isHeartbeatInProgress=!0,yield this._sendHeartbeat(),this._isHeartbeatInProgress=!1)})}_updateHeartbeatTime(){this._nextHeartbeatAt=ao?Date.now()+5e3:Date.now()+1e4}_handleNetworkStatusChange(n){const r=`${dt}.networkStatusChange ${JSON.stringify(n)}`;this._ssoLog({method:"networkStatusChange",message:r});const{isNetworkOnline:g,networkType:u}=n;g&&u!=="none"?this._handleConnectStateChange({state:eo,shouldEmitEvent:!1,shouldAttemptReconnect:!0,reason:Rg}):this._handleConnectStateChange({state:_i,shouldEmitEvent:!1,shouldAttemptReconnect:!0,reason:Rg})}isPrivateNetWork(){const n=ro.get("instance")||{};return n.proxyServer&&!n.fileDownloadProxy}_handleConnectStateChange(n){const{state:r,shouldAttemptReconnect:g,shouldEmitEvent:u,reason:E}=n,m=`${dt}._handleConnectStateChange currentConnectState: ${this._currentConnectState} shouldAttemptReconnect: ${g} shouldEmitEvent: ${u} reason: ${E}`;this._currentConnectState!==r&&(this._ssoLog({method:"handleConnectStateChange",message:m}),u&&(Kt.info("_handleConnectStateChange",` from ${this._currentConnectState} to ${r}`),$s.emitOuterEvent("netStateChange",{name:"netStateChange",data:{state:r}}),this._currentConnectState=r,r===_i&&$s.emitInnerEvent(He.SOCKET_DISCONNECTED)),g&&(this._resetReconnectDelay(),Rn.addTask({id:$i,intervalMs:this._intendedDelay,callback:this._scheduleReconnectWithBackoff,context:this})))}_handleActivityStatusChange(n){var r,g;const u=(g=(r=this._socketAdapter)===null||r===void 0?void 0:r._ws)===null||g===void 0?void 0:g.readyState,E=`${dt}.activityStatusChange ${JSON.stringify(n)} readyState: ${u}`;Kt.debug("activityStatusChange",E),u===3&&this._handleConnectStateChange({state:_i,shouldEmitEvent:!0,shouldAttemptReconnect:!0,reason:Er})}_resetReconnectDelay(){var n;Kt.debug(`${dt}._resetReconnectDelay`),Rn.removeTask($i);const r=(n=ro.get("activityMonitor"))===null||n===void 0?void 0:n.isActive;this._intendedDelay=r?is:1e3}_scheduleReconnectWithBackoff(){var n;const r=(n=ro.get("activityMonitor"))===null||n===void 0?void 0:n.isActive;this._intendedDelay=r?Math.min(5e3,Math.max(is,1.5*this._intendedDelay)):Math.min(3e5,Math.max(1e3,1.5*this._intendedDelay));const g=new Date().toTimeString().slice(0,8),u=`${dt}.scheduleReconnectWithBackoff timeStr: ${g} intendedDelay: ${this._intendedDelay}`;Kt.debug(u),this.reconnect(),Rn.updateTaskInterval($i,this._intendedDelay)}_ssoLog(n){const{method:r,message:g}=n;Kt.info(r,g)}_diagnose(){this.isPrivateNetWork()||(this._lastDiagnoseAt=Date.now(),function(n){mA(this,void 0,void 0,function*(){const r=n.split("/")[2];if(!r.startsWith("ws"))return;const g=`https://${r}/v3/netcheck/getconninfo?${n.slice(n.indexOf("info?")+5)}&reqtime=${Date.now()}`;try{yield qi({method:"GET",url:g,data:{}})}catch(u){Kt.warn("diagnoseBySSO",`diagnoseBySSO failed. error:${u.message}`)}})}(this._url),function(n){mA(this,void 0,void 0,function*(){const r=`https://boce-cdn.my-imcloud.com/v3/netcheck/getconninfo?${n.slice(n.indexOf("info?")+5)}&reqtime=${Date.now()}`;try{yield qi({method:"GET",url:r,data:{}})}catch(g){Kt.warn(`diagnoseByCDN', 'diagnoseByCDN failed. error:${g.message}`)}})}(this._url),this._beforeSendInterceptors=[])}_clearTimeoutRequest(){for(const[n,r]of this._pendingRequests.entries()){const{reject:g,timestamp:u,timeout:E}=r;Date.now()-u>=E&&(this._pendingRequests.delete(n),Date.now()-this._lastDiagnoseAt>=3e4&&this._diagnose(),g({errorCode:Zn,errorInfo:"NETWORK_TIMEOUT",data:{requestId:n}}))}}_updateIsBinarySupported(){var n;if(!((n=ro.get("instance"))===null||n===void 0)&&n.devMode)return void(this._isBinarySupported=!1);const r=Vo();if((ii||ze&&r==="windows"||ws)&&(this._isBinarySupported=!1),ao){const{uniRuntimeVersion:g=""}=so.getSystemInfoSync();(function(u){const E=u.split(".").map(Number),[m=0,D=0,v=0]=E;return m>2||!(m<2)&&(D>2||!(D<2)&&v>=6)})(g)||(this._isBinarySupported=!1)}}_isCompressedData(n){const r=new Uint8Array(n);return r[0]===67&&r[1]===79&&r[2]===77&&r[3]===80}};const De={init:function(n){ro.set("instance",n),Se.init()},destroy:function(){Se.dispose(),ro.clear(),Rn.dispose()},notificationCenter:$s,channel:Se,store:ro,ssoLog:Kt,utils:Xa,common:MA,constants:Te},wg=n=>typeof n=="function";function gg(n,r,g){const u=g||[];if(!n||!r)return!1;const E=Object.keys(n).filter(D=>!u.includes(D)),m=Object.keys(r).filter(D=>!u.includes(D));return E.length===m.length&&E.every(D=>!!r.hasOwnProperty(D)&&(typeof n[D]=="object"&&n[D]!==null?gg(n[D],r[D],g):n[D]===r[D]))}var _g;(function(n){n.SDK_READY="sdkStateReady",n.SDK_NOT_READY="sdkStateNotReady",n.SDK_DESTROY="sdkDestroy",n.MESSAGE_RECEIVED="onMessageReceived",n.ROOM_CUSTOM_DATA_RECEIVED="onRoomCustomDataReceived",n.MESSAGE_MODIFIED="onMessageModified",n.MESSAGE_REVOKED="onMessageRevoked",n.MESSAGE_READ_BY_PEER="onMessageReadByPeer",n.MESSAGE_READ_RECEIPT_RECEIVED="onMessageReadReceiptReceived",n.MESSAGE_EXTENSIONS_UPDATED="onMessageExtensionsUpdated",n.MESSAGE_EXTENSIONS_DELETED="onMessageExtensionsDeleted",n.MESSAGE_REACTIONS_UPDATED="onMessageReactionsUpdated",n.CONVERSATION_LIST_UPDATED="onConversationListUpdated",n.TOTAL_UNREAD_MESSAGE_COUNT_UPDATED="onTotalUnreadMessageCountUpdated",n.CONVERSATION_GROUP_LIST_UPDATED="onConversationGroupListUpdated",n.CONVERSATION_IN_GROUP_UPDATED="onConversationInGroupUpdated",n.GROUP_LIST_UPDATED="onGroupListUpdated",n.GROUP_ATTRIBUTES_UPDATED="groupAttributesUpdated",n.GROUP_COUNTER_UPDATED="onGroupCounterUpdated",n.TOPIC_CREATED="onTopicCreated",n.TOPIC_DELETED="onTopicDeleted",n.TOPIC_UPDATED="onTopicUpdated",n.PROFILE_UPDATED="onProfileUpdated",n.USER_STATUS_UPDATED="onUserStatusUpdated",n.BLACKLIST_UPDATED="blacklistUpdated",n.FRIEND_LIST_UPDATED="onFriendListUpdated",n.FRIEND_GROUP_LIST_UPDATED="onFriendGroupListUpdated",n.FRIEND_APPLICATION_LIST_UPDATED="onFriendApplicationListUpdated",n.MY_FOLLOWERS_LIST_UPDATED="onMyFollowersListUpdated",n.MY_FOLLOWING_LIST_UPDATED="onMyFollowingListUpdated",n.MUTUAL_FOLLOWERS_LIST_UPDATED="onMutualFollowersListUpdated",n.KICKED_OUT="kickedOut",n.ERROR="error",n.NET_STATE_CHANGE="netStateChange",n.ALL_RECEIVE_MESSAGE_OPT_UPDATED="onAllReceiveMessageOptUpdated",n.SERVER_CONFIG_UPDATED="onServerConfigUpdated",n.PINNED_GROUP_MESSAGE_UPDATED="onPinnedGroupMessageUpdated",n.WEB_PUSH_MESSAGE_RECEIVED="onWebPushMessageReceived",n.GROUP_ONLINE_MEMBER_COUNT_CHANGED="onGroupOnlineMemberCountChanged",n.RICH_STATUS_CHANGED="onRichStatusChanged"})(_g||(_g={}));var _n,Rr=_g;(function(n){n.LOGOUT="logout",n.DESTROY="destroy",n.CLOUD_CONFIG_UPDATE="cloud_config_update",n.PROFILE_UPDATE="profile_updated",n.ERROR="error",n.RECONNECTED="reconnected",n.FORCE_OFFLINE="im_open_status.stat_forceoffline",n.COMMERCIAL_CONFIG_PUSH="im_sdk_config_mgr.push_imsdk_purchase_bitsv2",n.OVERLOAD_PUSH="OverLoadPush.notify2",n.NEW_MESSAGE="new_message",n.MESSAGE_PUSH="im_open_push.msg_push",n.MESSAGE_DELETED="message_deleted",n.MESSAGE_REVOKED="message_revoked",n.MESSAGE_MODIFIED="message_modified",n.SOCKET_DISCONNECTED="socket_disconnected",n.CONVERSATION_UPDATED="conversation_updated",n.TOPIC_MESSAGE_DELETED="topic_message_deleted",n.TOPIC_MESSAGE_REVOKED="topic_message_revoked",n.TOPIC_MESSAGE_MODIFIED="topic_message_modified",n.TOPIC_NEW_MESSAGE="topic_new_message",n.QUALITY_STAT="quality_stat",n.SYNC_CONVERSATION_LIST="sync_conversation_list",n.HISTORY_MESSAGE_FETCHED="history_message_fetched"})(_n||(_n={}));var Ci,lo=_n;(function(n){n.NEW_INVITATION_RECEIVED="newInvitationReceived",n.INVITEE_ACCEPTED="ts_invitee_accepted",n.INVITEE_REJECTED="ts_invitee_rejected",n.INVITATION_CANCELLED="ts_invitation_cancelled",n.INVITATION_TIMEOUT="ts_invitation_timeout",n.INVITATION_MODIFIED="ts_invitation_modified"})(Ci||(Ci={}));var Xc=Ci;const Ac=Object.assign({},{KICKED_OUT_MULT_ACCOUNT:"multipleAccount",KICKED_OUT_MULT_DEVICE:"multipleDevice",KICKED_OUT_USERSIG_EXPIRED:"userSigExpired",KICKED_OUT_REST_API:"REST_API_Kick"}),Tg={MSG_TEXT:"TIMTextElem",MSG_IMAGE:"TIMImageElem",MSG_AUDIO:"TIMSoundElem",MSG_FILE:"TIMFileElem",MSG_FACE:"TIMFaceElem",MSG_VIDEO:"TIMVideoFileElem",MSG_LOCATION:"TIMLocationElem",MSG_GRP_TIP:"TIMGroupTipElem",MSG_GRP_SYS_NOTICE:"TIMGroupSystemNoticeElem",MSG_CUSTOM:"TIMCustomElem",MSG_MERGER:"TIMRelayElem",MSG_STREAM:"TIMStreamElem"};var qr;(function(n){n.UNSENT="unSend",n.SUCCESS="success",n.FAIL="fail"})(qr||(qr={}));const wc={modify:lo.MESSAGE_MODIFIED,delete:lo.MESSAGE_DELETED,revoke:lo.MESSAGE_REVOKED};var $c;(function(n){n[n.FORWARD=0]="FORWARD",n[n.BACKWARD=1]="BACKWARD"})($c||($c={}));const cg=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},Tg),{MSG_PRIORITY_HIGH:"High",MSG_PRIORITY_NORMAL:"Normal",MSG_PRIORITY_LOW:"Low",MSG_PRIORITY_LOWEST:"Lowest"}),{RECEIVE_WITH_OFFLINE_PUSH_EXCEPT_AT:"AcceptNotNotifyExceptAt",NOT_RECEIVE_OFFLINE_PUSH_EXCEPT_AT:"AcceptNotNotifyExceptAt",NOT_RECEIVE_MSG_EXCEPT_AT:"NotReceiveMsgExceptAt",MSG_AT_ALL:"__kImSDK_MesssageAtALL__"}),{MSG_REMIND_ACPT_AND_NOTE:"AcceptAndNotify",MSG_REMIND_ACPT_NOT_NOTE:"AcceptNotNotify",MSG_REMIND_DISCARD:"Discard"}),{MessageStatus:qr,Direction:$c}),Nu={[wc.modify]:lo.TOPIC_MESSAGE_MODIFIED,[wc.delete]:lo.TOPIC_MESSAGE_DELETED,[wc.revoke]:lo.TOPIC_MESSAGE_REVOKED},SE={GENDER_UNKNOWN:"Gender_Type_Unknown",GENDER_FEMALE:"Gender_Type_Female",GENDER_MALE:"Gender_Type_Male",USER_STATUS_UNKNOWN:0,USER_STATUS_ONLINE:1,USER_STATUS_OFFLINE:2,USER_STATUS_UNLOGINED:3,USER_NOT_FOUND:"@TLS#NOT_FOUND"},Ng=Object.assign({},SE),Oa={CONV_C2C:"C2C",CONV_GROUP:"GROUP",CONV_TOPIC:"TOPIC",CONV_SYSTEM:"@TIM#SYSTEM"},_c=Object.assign(Object.assign(Object.assign(Object.assign({},Oa),{CONV_AT_ME:1,CONV_AT_ALL:2,CONV_AT_ALL_AT_ME:3}),{CONV_MARK_TYPE_STAR:1,CONV_MARK_TYPE_UNREAD:2,CONV_MARK_TYPE_FOLD:4,CONV_MARK_TYPE_HIDE:8}),{READ_ALL_C2C_MSG:"readAllC2CMessage",READ_ALL_GROUP_MSG:"readAllGroupMessage",READ_ALL_MSG:"readAllMessage"}),vE=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},{SNS_TYPE_NO_RELATION:"CheckResult_Type_NoRelation",SNS_TYPE_A_WITH_B:"CheckResult_Type_AWithB",SNS_TYPE_B_WITH_A:"CheckResult_Type_BWithA",SNS_TYPE_BOTH_WAY:"CheckResult_Type_BothWay"}),{ALLOW_TYPE_ALLOW_ANY:"AllowType_Type_AllowAny",ALLOW_TYPE_NEED_CONFIRM:"AllowType_Type_NeedConfirm",ALLOW_TYPE_DENY_ANY:"AllowType_Type_DenyAny"}),{SNS_ADD_TYPE_SINGLE:"Add_Type_Single",SNS_ADD_TYPE_BOTH:"Add_Type_Both"}),{SNS_DELETE_TYPE_SINGLE:"Delete_Type_Single",SNS_DELETE_TYPE_BOTH:"Delete_Type_Both"}),{SNS_APPLICATION_TYPE_BOTH:"Pendency_Type_Both",SNS_APPLICATION_SENT_TO_ME:"Pendency_Type_ComeIn",SNS_APPLICATION_SENT_BY_ME:"Pendency_Type_SendOut",SNS_APPLICATION_AGREE:"Response_Action_Agree",SNS_APPLICATION_AGREE_AND_ADD:"Response_Action_AgreeAndAdd"}),{SNS_CHECK_TYPE_BOTH:"CheckResult_Type_Both",SNS_CHECK_TYPE_SINGLE:"CheckResult_Type_Single"}),{FORBID_TYPE_NONE:"AdminForbid_Type_None",FORBID_TYPE_SEND_OUT:"AdminForbid_Type_SendOut"}),Pa={GRP_WORK:"Private",GRP_PUBLIC:"Public",GRP_MEETING:"ChatRoom",GRP_AVCHATROOM:"AVChatRoom",GRP_COMMUNITY:"Community",GRP_ROOM:"Room",GRP_LIVE:"Live"},ga={COMMUNITY:"@TGS#_",TOPIC:"@TOPIC#_"},Gg={JOINED:1,QUITTED:2,KICKED:3,ADMIN_SET:4,ADMIN_CANCELED:5,GROUP_PROFILE_UPDATED:6,GROUP_MEMBER_PROFILE_UPDATED:7,TOPIC_PROFILE_UPDATED:8},EI=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},Pa),{GRP_MBR_ROLE_OWNER:"Owner",GRP_MBR_ROLE_ADMIN:"Admin",GRP_MBR_ROLE_MEMBER:"Member",GRP_MBR_ROLE_CUSTOM:"Custom"}),{GRP_TIP_MBR_JOIN:1,GRP_TIP_MBR_QUIT:2,GRP_TIP_MBR_KICKED_OUT:3,GRP_TIP_MBR_SET_ADMIN:4,GRP_TIP_MBR_CANCELED_ADMIN:5,GRP_TIP_GRP_PROFILE_UPDATED:6,GRP_TIP_MBR_PROFILE_UPDATED:7,GRP_TIP_BAN_AVCHATROOM_MEMBER:10,GRP_TIP_UNBAN_AVCHATROOM_MEMBER:11}),{JOIN_OPTIONS_FREE_ACCESS:"FreeAccess",JOIN_OPTIONS_NEED_PERMISSION:"NeedPermission",JOIN_OPTIONS_DISABLE_APPLY:"DisableApply",JOIN_STATUS_SUCCESS:"JoinedSuccess",JOIN_STATUS_ALREADY_IN_GROUP:"AlreadyInGroup",JOIN_STATUS_WAIT_APPROVAL:"WaitAdminApproval"}),{INVITE_OPTIONS_DISABLE_INVITE:"DisableInvite",INVITE_OPTIONS_NEED_PERMISSION:"NeedPermission",INVITE_OPTIONS_FREE_ACCESS:"FreeAccess"}),{GRP_PROFILE_OWNER_ID:"ownerID",GRP_PROFILE_CREATE_TIME:"createTime",GRP_PROFILE_LAST_INFO_TIME:"lastInfoTime",GRP_PROFILE_MEMBER_NUM:"memberNum",GRP_PROFILE_MAX_MEMBER_NUM:"maxMemberNum",GRP_PROFILE_JOIN_OPTION:"joinOption",GRP_PROFILE_INVITE_OPTION:"inviteOption",GRP_PROFILE_INTRODUCTION:"introduction",GRP_PROFILE_NOTIFICATION:"notification",GRP_PROFILE_MUTE_ALL_MBRS:"muteAllMembers"}),{GROUP_ID_PREFIX:ga,GROUP_TIPS_OPERATION_TYPE:Gg}),Ss={IOS_OFFLINE_PUSH_NO_SOUND:"push.no_sound",IOS_OFFLINE_PUSH_DEFAULT_SOUND:"default"},Po=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},Ac),cg),Ng),_c),vE),EI),Ss),{NET_STATE_CONNECTING:"connecting",NET_STATE_DISCONNECTED:"disconnected",NET_STATE_CONNECTED:"connected"}),pa={NO_SDKAPPID:2e3,NO_TINYID:2022,NO_A2KEY:2023,USER_NOT_LOGGED_IN:2024,REPEAT_LOGIN:2025,MSG_SEND_FAIL:2100,MSG_SEND_FAIL_NOT_IN_AV:2101,MSG_SEND_GRP_WITH_TOPIC_FAIL:2115,MSG_INSTANCE_REQUIRED:2105,MSG_INVALID_CONV_TYPE:2106,MSG_REVOKE_FAIL:2110,MSG_DELETE_FAIL:2111,MSG_UNREAD_ALL_FAIL:2112,READ_RECEIPT_MSG_LIST_EMPTY:2114,CANNOT_DELETE_GRP_SYSTEM_NOTICE:2116,NOT_MY_FRIEND:2700,NETWORK_ERROR:2800,NETWORK_TIMEOUT:2801,NO_NETWORK:2805,UNCAUGHT_ERROR:2903,INVALID_OPERATION:2905,SDK_IS_NOT_READY:2999,LOGGING_IN:3e3,LOGIN_FAILED:3001,KICKED_OUT_MULT_DEVICE:3002,KICKED_OUT_MULT_ACCOUNT:3003,KICKED_OUT_USERSIG_EXPIRED:3004,LOGGED_OUT:3005,KICKED_OUT_REST_API:3006,NO_USE:3122,OPTIONS_IS_EMPTY:3153,MSG_A2KEY_EXPIRED:20002,ACCOUNT_A2KEY_EXPIRED:70001,HELLO_ANSWER_KICKED_OUT:1002,OPEN_SERVICE_OVERLOAD_ERROR:60022},dr={BASIC:"1",STANDARD:"2",PROFESSIONAL:"3",NODE:"4"},jt={SYNC_SERVER_INFO_AFTER_RE_ONLINE:"sync-server-info-after-re-online",SYNC_SERVER_INFO_AFTER_LOGIN:"sync-server-info-after-login",RECEIVE_C2C_NEW_MESSAGE:"receive-c2c-new-message",RECEIVE_GROUP_NEW_MESSAGE:"receive-group-new-message",RECEIVE_GROUP_TIPS_NOTIFICATION:"receive-group-tips-notification"},Xt={USER_STATUS_UPDATE:"user-status-update",CONVERSATION_RECOVER:"conversation-recover",HISTORY_MESSAGE_RECOVER:"history-message-recover",BLACKLIST_RECOVER:"blacklist-recover",FRIEND_RECOVER:"friend-recover",GROUP_ATTRIBUTE_CACHE_CLEAR:"group-attribute-cache-clear",UNREAD_MESSAGE_RECOVER:"unread-message-recover",HANDLE_NEW_MESSAGE:"handle-new-message",HANDLE_CONVERSATION_PROFILE_UPDATED:"handle-conversation-profile-updated",COMMERCIAL_CONFIG_UPDATE:"commercial-config-update",UNREAD_MESSAGE_SYNC:"unread-message-sync",FRIEND_AND_BLACKLIST_SYNC:"friend-and-blacklist-sync",SIGNALING_MESSAGE_RECOVER:"signaling-message-recover",GROUP_LIST_SYNC:"group-list-sync",CONVERSATION_LIST_SYNC:"conversation-list-sync",USER_PROFILE_SYNC:"user-profile-sync",CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED:"conversation-update-after-unread-sync-finished",CONVERSATION_UPDATE_AFTER_GROUP_LIST_SYNC_FINISHED:"conversation-update-after-group-list-sync-finished",HANDLE_C2C_NEW_MESSAGE:"handle-c2c-new-message",HANDLE_GROUP_NEW_MESSAGE:"handle-group-new-message",CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE:"create-or-update-conversation-by-receive-new-message",HANDLE_GROUP_TIPS_FROM_SYNC_UNREAD:"handle-group-tips-from-sync-unread",HANDLE_C2C_REVOKED_MESSAGE_FROM_SYNC_UNREAD:"handle-c2c-revoked-message-from-sync-unread",GROUP_REVOKED_NOTICE_RECOVER:"group-revoked-notice-recover",CLOUD_CONFIG_SYNC:"cloud-config-sync",UPDATE_GROUP_NEXT_SEQUENCE:"update-group-next-sequence",EMIT_C2C_MESSAGE_EVENT:"emit-c2c-message-event",EMIT_GROUP_MESSAGE_EVENT:"emit-group-message-event",CONVERSATION_GROUP_LIST_SYNC:"conversation-group-list-sync",CONVERSATION_GROUP_UPDATE:"conversation-group-update",UPDATE_TOPIC_AFTER_UNREAD_SYNC_FINISHED:"update-topic-after-unread-sync-finished",UPDATE_TOPIC_BY_RECEIVE_NEW_MESSAGE:"update-topic-by-received-new-message",TOPIC_REQUEST_INFO_RESET:"topic-request-info-reset",QUALITY_REPORT:"quality-report",GROUP_TIPS_RECOVER:"group-tips-recover",HANDLE_GROUP_TIPS_NOTIFICATION:"handle-group-tips-notification",C2C_HISTORY_MESSAGE_RECOVER:"c2c-history-message-recover",FRIEND_APPLICATION_LIST_RECOVER:"friend-application-list-recover",EMIT_GROUP_TIPS_EVENT:"emit-group-tips-event",STREAM_MESSAGE_RECOVER:"stream-message-recover"},bg={[jt.SYNC_SERVER_INFO_AFTER_RE_ONLINE]:[{stepId:Xt.USER_STATUS_UPDATE},{stepId:Xt.GROUP_ATTRIBUTE_CACHE_CLEAR},{stepId:Xt.UNREAD_MESSAGE_SYNC,dependency:Xt.C2C_HISTORY_MESSAGE_RECOVER},{stepId:Xt.CONVERSATION_RECOVER},{stepId:Xt.HISTORY_MESSAGE_RECOVER,dependency:Xt.CONVERSATION_RECOVER},{stepId:Xt.BLACKLIST_RECOVER},{stepId:Xt.FRIEND_RECOVER},{stepId:Xt.FRIEND_APPLICATION_LIST_RECOVER},{stepId:Xt.GROUP_REVOKED_NOTICE_RECOVER,dependency:Xt.HISTORY_MESSAGE_RECOVER},{stepId:Xt.GROUP_TIPS_RECOVER,dependency:Xt.HISTORY_MESSAGE_RECOVER},{stepId:Xt.TOPIC_REQUEST_INFO_RESET},{stepId:Xt.HANDLE_C2C_REVOKED_MESSAGE_FROM_SYNC_UNREAD,dependency:Xt.UNREAD_MESSAGE_SYNC},{stepId:Xt.HANDLE_GROUP_TIPS_FROM_SYNC_UNREAD,dependency:Xt.UNREAD_MESSAGE_SYNC},{stepId:Xt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,dependency:[Xt.UNREAD_MESSAGE_SYNC,Xt.CONVERSATION_RECOVER]},{stepId:Xt.EMIT_C2C_MESSAGE_EVENT,dependency:[Xt.UNREAD_MESSAGE_SYNC,Xt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED],skipIfDependencyMissing:!1},{stepId:Xt.C2C_HISTORY_MESSAGE_RECOVER,dependency:Xt.CONVERSATION_RECOVER},{stepId:Xt.STREAM_MESSAGE_RECOVER}],[jt.SYNC_SERVER_INFO_AFTER_LOGIN]:[{stepId:Xt.COMMERCIAL_CONFIG_UPDATE},{stepId:Xt.CLOUD_CONFIG_SYNC},{stepId:Xt.USER_PROFILE_SYNC},{stepId:Xt.UNREAD_MESSAGE_SYNC},{stepId:Xt.FRIEND_AND_BLACKLIST_SYNC},{stepId:Xt.GROUP_LIST_SYNC},{stepId:Xt.CONVERSATION_LIST_SYNC},{stepId:Xt.SIGNALING_MESSAGE_RECOVER,dependency:Xt.UNREAD_MESSAGE_SYNC},{stepId:Xt.UPDATE_TOPIC_AFTER_UNREAD_SYNC_FINISHED,dependency:[Xt.UNREAD_MESSAGE_SYNC]},{stepId:Xt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,dependency:[Xt.UNREAD_MESSAGE_SYNC,Xt.CONVERSATION_LIST_SYNC]},{stepId:Xt.CONVERSATION_UPDATE_AFTER_GROUP_LIST_SYNC_FINISHED,dependency:[Xt.GROUP_LIST_SYNC,Xt.CONVERSATION_LIST_SYNC]},{stepId:Xt.CONVERSATION_GROUP_LIST_SYNC},{stepId:Xt.CONVERSATION_GROUP_UPDATE,dependency:[Xt.CONVERSATION_LIST_SYNC,Xt.CONVERSATION_GROUP_LIST_SYNC]},{stepId:Xt.QUALITY_REPORT}],[jt.RECEIVE_C2C_NEW_MESSAGE]:[{stepId:Xt.HANDLE_C2C_NEW_MESSAGE},{stepId:Xt.UNREAD_MESSAGE_SYNC},{stepId:Xt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,dependency:Xt.HANDLE_C2C_NEW_MESSAGE},{stepId:Xt.EMIT_C2C_MESSAGE_EVENT,dependency:[Xt.HANDLE_C2C_NEW_MESSAGE,Xt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE],skipIfDependencyMissing:!1},{stepId:Xt.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,dependency:[Xt.UNREAD_MESSAGE_SYNC]}],[jt.RECEIVE_GROUP_NEW_MESSAGE]:[{stepId:Xt.HANDLE_GROUP_NEW_MESSAGE},{stepId:Xt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,dependency:Xt.HANDLE_GROUP_NEW_MESSAGE},{stepId:Xt.UPDATE_GROUP_NEXT_SEQUENCE,dependency:Xt.HANDLE_GROUP_NEW_MESSAGE},{stepId:Xt.UPDATE_TOPIC_BY_RECEIVE_NEW_MESSAGE,dependency:Xt.HANDLE_GROUP_NEW_MESSAGE},{stepId:Xt.EMIT_GROUP_MESSAGE_EVENT,dependency:[Xt.HANDLE_GROUP_NEW_MESSAGE,Xt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE],skipIfDependencyMissing:!1}],[jt.RECEIVE_GROUP_TIPS_NOTIFICATION]:[{stepId:Xt.HANDLE_GROUP_TIPS_NOTIFICATION},{stepId:Xt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,dependency:Xt.HANDLE_GROUP_TIPS_NOTIFICATION},{stepId:Xt.EMIT_GROUP_TIPS_EVENT,dependency:[Xt.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,Xt.HANDLE_GROUP_TIPS_NOTIFICATION],skipIfDependencyMissing:!1}]},dI={MESSAGE_SEND_SUCCESS_RATE:"messageSendSuccessRate"},Cr={TOTAL_COUNT:"sendMessageTotalCount",SUCCESS_COUNT:"sendMessageSuccessCount",FAILED_COUNT:"sendMessageFailedCount",SEND_COST:"sendMessageCost"},zI=["login","getMyProfile","getUserProfile","updateMyProfile","setSelfStatus","getUserStatus","subscribeUserStatus","unsubscribeUserStatus","modifyMessage","deleteGroupMember","dismissGroup","getGroupMemberList","getGroupOnlineMemberCount","joinGroup","markGroupMemberList","quitGroup","searchCloudMessages","searchCloudGroups","searchCloudGroupMembers","searchCloudUsers","getMyFollowingList","getMyFollowersList","getMutualFollowersList","followUser","unfollowUser","getUserFollowInfo","checkFollowType","getFriendProfile","addFriend","deleteFriend","updateFriend","checkFriend","setFriendApplicationRead","createFriendGroup","deleteFriendGroup","addToFriendGroup","removeFromFriendGroup","renameFriendGroup","changeGroupOwner","createGroup","dismissGroup","getGroupList","getGroupOnlineMemberCount","getGroupProfile","searchGroupByID","updateGroupProfile","handleGroupApplication","deleteGroupAttributes","getGroupAttributes","initGroupAttributes","setGroupAttributes","addGroupMember","deleteGroupMember","getGroupMemberList","getGroupMemberProfile","setGroupMemberMuteTime","setGroupMemberNameCard","setGroupMemberRole","deleteMessage","revokeMessage","setMessageExtensions","getMessageExtensions","deleteMessageExtensions","getMessageList","addMessageReaction","removeMessageReaction","clearHistoryMessage","sendMessageReadReceipt","getMessageReadReceiptList","getGroupMessageReadMemberList","createMergerMessage","invite","accept","cancel","reject","modifyInvitation","deleteConversation","pinConversation","setMessageRead","setAllMessageRead","getConversationList","getTotalUnreadMessageCount","renameConversationGroup","deleteConversationGroup","markConversation","setConversationCustomData","deleteConversationsFromGroup","addConversationsToGroup","createConversationGroup"];var $a=Object.freeze({__proto__:null,ERROR_CODE:pa,InnerEvent:lo,NEED_LOG_API:zI,OuterConstant:Po,OuterEvent:Rr,PUSH:Ss,QUALITY_METRICS:dI,SDK_EDITION:dr,SDK_INFO:{VERSION:"1.7.3",APPID:537048168},SEND_MESSAGE_STAT:Cr,SignalingEvent:Xc,WEB_PUSH_ACCOUNT_TYPE:1,WORKFLOW_DEFINITIONS:bg,WORKFLOW_NAME:jt,WORKFLOW_STEP:Xt}),ca,Qn,Tn;(function(n){n[n.USER_INITIATED=0]="USER_INITIATED",n[n.KICKED_OUT=1]="KICKED_OUT"})(ca||(ca={})),function(n){n[n.multipleAccount=1]="multipleAccount",n[n.multipleDevice=2]="multipleDevice",n[n.restApi=3]="restApi"}(Qn||(Qn={})),function(n){n[n.multipleDevice=3002]="multipleDevice",n[n.multipleAccount=3003]="multipleAccount",n[n.usersigExpired=70001]="usersigExpired",n[n.restApi=20002]="restApi"}(Tn||(Tn={}));const Gu={[Qn.multipleAccount]:"multipleAccount",[Qn.multipleDevice]:"multipleDevice",[Qn.restApi]:"REST_API_Kick",[Tn.multipleAccount]:"multipleAccount",[Tn.multipleDevice]:"multipleDevice",[Tn.restApi]:"REST_API_Kick",[Tn.usersigExpired]:"userSigExpired"},kg="login_online_presence_task",{ERROR:xa,DESTROY:Al,FORCE_OFFLINE:ZI}=lo,{KICKED_OUT_MULT_ACCOUNT:ME,KICKED_OUT_MULT_DEVICE:CI,KICKED_OUT_REST_API:bu,ACCOUNT_A2KEY_EXPIRED:Gl,MSG_A2KEY_EXPIRED:Tc}=pa;class ku{init(){const{notificationCenter:r}=De;r.subscribeInnerEvent(ZI,this._handleForceOfflineFromServerPush,this),r.subscribeInnerEvent(xa,Tc,this._handleForceOfflineFromResponse,this,this._isChatLoginEvent),r.subscribeInnerEvent(xa,Gl,this._handleForceOfflineFromResponse,this,this._isChatLoginEvent),r.subscribeInnerEvent(xa,ME,this._handleForceOfflineFromResponse,this),r.subscribeInnerEvent(xa,CI,this._handleForceOfflineFromResponse,this),r.subscribeInnerEvent(xa,bu,this._handleForceOfflineFromResponse,this),r.subscribeInnerEvent(Al,this._dispose,this)}_handleForceOfflineFromServerPush(r){var g;if(((g=De.store.get("login"))===null||g===void 0?void 0:g.isLoggedIn)===!0){const{EventArray:u=[]}=r?.body||{};this._extractKickedOutMessages(u).forEach(E=>{const{KickoutMsgNotify:{KickType:m,NewInstInfo:D,Instid:v}}=E;this._isCurrentInstanceKickedOut(v)&&this._processKickedOutReasonInfo({kickedOutReasonCode:m,newInstanceInfo:D})})}}_extractKickedOutMessages(r){return r.reduce((g,u)=>[...g,...u.C2cNotifyMsgArray||[]],[]).filter(g=>{var u;return this._isKickedOut((u=g?.KickoutMsgNotify)===null||u===void 0?void 0:u.KickType)})}_handleForceOfflineFromResponse(r){const{errorCode:g}=r;this._processKickedOutReasonInfo({kickedOutReasonCode:g})}_processKickedOutReasonInfo(r){return mA(this,void 0,void 0,function*(){const{kickedOutReasonCode:g}=r,{ssoLog:u,utils:{safeStringify:E}}=De;try{this._logKickedOutEvent(r),this._shouldLogoutAfterKickedOut(g)?yield De.login.loginAction.logout(ca.KICKED_OUT):De.login.loginAction.handleLogoutCompleted()}catch(m){u.debug("_processKickedOutReasonInfo",` fail ${E(m)}`)}finally{De.notificationCenter.emitOuterEvent(Rr.KICKED_OUT,{data:{type:Gu[g]},name:Rr.KICKED_OUT})}})}_logKickedOutEvent(r){const{kickedOutReasonCode:g,newInstanceInfo:u={}}=r,E=`type:${Gu[g]} newInstanceInfo: ${JSON.stringify(u)}`;De.ssoLog.warn("kickedOut",E)}_isKickedOut(r){return[Qn.multipleAccount,Qn.multipleDevice,Qn.restApi].includes(r)}_isChatLoginEvent(r){const{requestHead:g}=r||{};return g?.idtype!==1}_shouldLogoutAfterKickedOut(r){return![Tn.usersigExpired,Qn.restApi].includes(r)}_isCurrentInstanceKickedOut(r){const{isLoggedIn:g,statusInstanceId:u}=De.store.get("login")||{};return g===!0&&r===u}_dispose(){const{notificationCenter:r}=De;r.unSubscribeInnerEvent(ZI,this._handleForceOfflineFromServerPush,this),r.unSubscribeInnerEvent(xa,Gl,this._handleForceOfflineFromResponse,this),r.unSubscribeInnerEvent(xa,Tc,this._handleForceOfflineFromResponse,this),r.unSubscribeInnerEvent(xa,ME,this._handleForceOfflineFromResponse,this),r.unSubscribeInnerEvent(xa,CI,this._handleForceOfflineFromResponse,this),r.unSubscribeInnerEvent(xa,bu,this._handleForceOfflineFromResponse,this),r.unSubscribeInnerEvent(Al,this._dispose,this)}}function Lu(n){return mA(this,void 0,void 0,function*(){const r="im_open_status.wslogin",g=De.common.generateProtocolData({servcmd:r,data:{State:"Online",is_web_uniapp:0,InstType:0,CustomInfo:n}}),u=`${g.head.seq}${r}`,E=yield De.channel.sendPacket(g,{timeout:9e4,requestId:u});if(E){const{HelloInterval:m,InstId:D,TinyId:v,TimeStamp:T,CustomStatus:P,PurchaseBits:W,A2Key:oA,RichMsgAuthKey:EA,ErrorCode:wA,ErrorInfo:kA,ActionStatus:xA}=E;return{helloInterval:m,instanceID:D,tinyID:v,timeStamp:T,customStatus:P,purchaseBits:W,a2Key:oA,authKey:EA,errorCode:wA,errorInfo:kA,actionStatus:xA}}})}function bl(){const{store:n}=De;return Ba(n.get("instance").sdkAppId)!==st.CHINA}function Es(n){var r;try{const g=ro.getStorage("errorMessage");if(!n||!g)return"";const u=((r=JSON.parse(g))===null||r===void 0?void 0:r.errorMessage)||{},{code:E,replacement1:m="",replacement2:D=""}=n;if(!E)return"";const v=bl()?`${E}_en`:`${E}_cn`;let T=u[u[v]?v:E]||"";return T&&(m&&(T=T.replace("$replacement1",m)),D&&(T=T.replace("$replacement2",D))),T}catch(g){return console.warn("Error parsing stored error messages:",g),""}}class Cs extends Error{constructor(r={}){r.code=r.code||r.errorCode;let{functionName:g="Unknown",code:u,message:E="",data:m="",moreMessage:D="",errorMessage:v=""}=r;v=(u?Es(r):"")||v||E;let T=u?`${g} failed. error: {"message": ${v}, "code": ${u}}`:`${g} failed. error: {"message": ${v}}`;T=`${T} ${D}`,super(),this.code=u,this.errorCode=u,this.errorMessage=v,this.message=T,this.data=m}}function Ed(n,r){var g;if(n&&((g=De.store.get("login"))===null||g===void 0?void 0:g.isLoggedIn)!==!0)throw new Cs({code:pa.USER_NOT_LOGGED_IN,functionName:r})}function hI(n,r,g){if(Array.isArray(n))for(let u=0;u{return P===(W=u,Object.prototype.toString.call(W).match(/^\[object (.*)\]$/)[1].toLowerCase());var W})){for(let W=0;W{const{interceptor:E,context:m}=u;E.apply(m,[g])})}(n)}function Nc(n,r){RE.push({interceptor:n,context:r})}function el(n){const{params:r,auth:g}=n;r&&typeof r=="object"&&Object.assign(kl,r),g&&typeof g=="object"&&Object.assign(dd,g)}function In(n){return De.store.get("commercialConfig").get(n)}class Fs{constructor(){this._handlers=new Map,this._activeWorkflows=new Map,this._stepStartTimes=new Map,this._logHandlers={start:(r,g)=>{const u=Date.now();g?(this._stepStartTimes.set(`${r}-${g}`,u),De.ssoLog.debug("_executeWorkflowStep",`[Workflow ${r}] Step ${g} started at ${new Date(u).toISOString()}`)):(this._workflowStartTimes.set(r,u),De.ssoLog.debug("_executeWorkflowStep",`[Workflow ${r}] started at ${new Date(u).toISOString()}`))},success:(r,g)=>{const u=Date.now();if(g){const E=this._stepStartTimes.get(`${r}-${g}`),m=E?u-E:0;this._stepStartTimes.delete(`${r}-${g}`),De.ssoLog.debug("_executeWorkflowStep",`[Workflow ${r}] Step ${g} completed successfully at ${new Date(u).toISOString()} (${m}ms)`)}else{const E=this._workflowStartTimes.get(r),m=E?u-E:0;this._workflowStartTimes.delete(r),De.ssoLog.debug("_executeWorkflowStep",`[Workflow ${r}] completed successfully at ${new Date(u).toISOString()} (${m}ms)`)}},error:(r,g,u)=>{const{ssoLog:E,utils:{safeStringify:m}}=De,D=Date.now();if(g){const v=this._stepStartTimes.get(`${r}-${g}`),T=v?D-v:0;this._stepStartTimes.delete(`${r}-${g}`),E.error("_executeWorkflowStep",`[Workflow ${r}] Step ${g} failed at ${new Date(D).toISOString()} (${T}ms) ${m(u)}`,{error:u})}else{const v=this._workflowStartTimes.get(r),T=v?D-v:0;this._workflowStartTimes.delete(r),E.error("_executeWorkflowStep",`[Workflow ${r}] failed at ${new Date(D).toISOString()} (${T}ms) ${m(u)}`,{error:u})}}}}static getInstance(){return Fs._instance||(Fs._instance=new Fs),Fs._instance}static setInstance(r){Fs._instance=r}init(){this._initializeWorkflows()}registerWorkflowStep(r,g,u,E){if(!this._handlers.has(r))return void De.ssoLog.debug("registerWorkflowStep",`Workflow '${r}' not defined in core`);if(!bg[r].find(D=>D.stepId===g))return void De.ssoLog.debug("registerWorkflowStep",`Step '${g}' not defined in workflow '${r}'`);const m=this._handlers.get(r);m.has(g)||m.set(g,E?u.bind(E):u)}executeWorkflow(r,g){return mA(this,void 0,void 0,function*(){if(!this._validateWorkflow(r))return;De.ssoLog.debug("executeWorkflow",`[Workflow ${r}] Started execution at ${new Date().toISOString()}`);const u=bg[r],E={},m={cancelled:!1};this._activeWorkflows.set(r,{cancelToken:m});try{const D=new Map;u.forEach(T=>{D.set(T.stepId,T)});const v={workflowName:r,pendingSteps:new Set(u.map(T=>T.stepId)),completedSteps:new Set,runningSteps:new Set,stepMap:D,stepResults:E,data:g,cancelToken:m};yield new Promise((T,P)=>{const W=()=>{if(m.cancelled)return void T();this._getExecutableSteps({pendingSteps:v.pendingSteps,completedSteps:v.completedSteps,stepMap:v.stepMap,workflowName:r}).filter(oA=>!v.runningSteps.has(oA)).forEach(oA=>{v.completedSteps.has(oA)||v.runningSteps.has(oA)||this._executeWorkflowStep(oA,v,{onComplete:()=>{if(v.pendingSteps.size===0)return void T();this._getExecutableSteps({pendingSteps:v.pendingSteps,completedSteps:v.completedSteps,stepMap:v.stepMap,workflowName:r}).filter(EA=>!v.runningSteps.has(EA)).length===0&&v.runningSteps.size===0&&(De.ssoLog.debug("executeWorkflow",`Workflow ${r} completed with some steps skipped due to dependency failures`),T())},onError:P,onStepComplete:W})})};W()}),De.ssoLog.debug("executeWorkflow",`[Workflow ${r}] Completed execution at ${new Date().toISOString()}`)}catch(D){De.ssoLog.error("executeWorkflow",`[Workflow ${r}] Failed execution at ${new Date().toISOString()}`,{error:D})}finally{this._activeWorkflows.delete(r)}})}_executeWorkflowStep(r,g,u){return mA(this,void 0,void 0,function*(){const{workflowName:E,runningSteps:m,stepMap:D,stepResults:v,data:T}=g;m.add(r),this._logWorkflowExecution(E,r,"start");try{const P=D.get(r);let W=null;P?.dependency&&(c(P.dependency)?W=v[P.dependency]:Array.isArray(P.dependency)&&(W={},P.dependency.forEach(EA=>{W[EA]=v[EA]})));const oA=this._handlers.get(E).get(r);if(oA){const EA=yield Promise.resolve(oA({data:T,result:W}));v[r]=EA,this._logWorkflowExecution(E,r,"success")}g.completedSteps.add(r)}catch(P){const W=`[Workflow].${E}.${r}`,{errorCode:oA,errorInfo:EA=`${W} failed`}=P||{},wA=new Cs({functionName:W,code:oA,message:EA});De.ssoLog.error(W,EA,{error:wA}),this._logWorkflowExecution(E,r,"error",P),u.onError(P)}finally{m.delete(r),g.pendingSteps.delete(r),u.onStepComplete(),u.onComplete()}})}reset(){this._cancelAllWorkflows()}destroy(){this.reset(),this._handlers.clear()}_initializeWorkflows(){Object.keys(bg).forEach(r=>{this._handlers.has(r)||this._handlers.set(r,new Map)})}_cancelWorkFlow(r){const g=this._activeWorkflows.get(r);if(!g)return;const{cancelToken:u}=g;u.cancelled=!0,this._activeWorkflows.delete(r)}_cancelAllWorkflows(){Object.keys(bg).forEach(r=>{this._cancelWorkFlow(r)})}_validateWorkflow(r){return bg[r]?!!this._handlers.get(r):!1}_getExecutableSteps(r){const{pendingSteps:g,completedSteps:u,stepMap:E,workflowName:m}=r;return Array.from(g).filter(D=>{const v=E.get(D)||{},{dependency:T,skipIfDependencyMissing:P=!0}=v;if(!T)return!0;if(c(T))return this._isStepRegistered({workflowName:m,stepId:T})?u.has(T):!P;if(C(T)){if(T.filter(W=>!this._isStepRegistered({workflowName:m,stepId:W})).length>0&&P)return!1;for(const W of T)if(!u.has(W))return!1;return!0}return!1})}_isStepRegistered(r){var g;const{workflowName:u,stepId:E}=r;return(g=this._handlers.get(u))===null||g===void 0?void 0:g.has(E)}_logWorkflowExecution(r,g,u,E){this._logHandlers[u](r,g)}}const ma=new Map,ea=({type:n,groupID:r})=>n===Po.GRP_COMMUNITY||`${r}`.startsWith(ga.COMMUNITY)&&!`${r}`.includes(ga.TOPIC),tl=(n="")=>{const r=n.startsWith("GROUP")?n.replace("GROUP",""):n;return r.startsWith(ga.COMMUNITY)&&`${r}`.includes(ga.TOPIC)},Cd="openim",ec="million_group_open_http_svc";function lg(n){return mA(this,void 0,void 0,function*(){const{servcmd:r,data:g}=function(m){const{data:D}=m;return wE(D)||tc(D)}(n)?function(m){let{servcmd:D,data:v}=m;return tc(v)?function(T){const{servcmd:P,data:W}=T;let{GroupId:oA=""}=W;const EA=oA;return[oA]=EA.split(ga.TOPIC),{servcmd:$n(P),data:Object.assign(Object.assign({},W),{GroupId:oA,TopicId:EA})}}(m):(wE(v)&&(D=$n(D)),{servcmd:D,data:v})}(n):n,u=De.common.generateProtocolData({servcmd:r,data:g}),E=`${u.head.seq}${r}`;return De.channel.sendPacket(u,{requestId:E,timeout:n.timeout})})}function wE(n){const{Type:r,GroupId:g,GroupIdList:u=[]}=n,E=g||u[0]||"";return ea({type:r,groupID:E})}function tc(n){const{GroupId:r=""}=n;return tl(r)}function $n(n){if(n.includes(Cd))return n;const r=n.split(".")[1];return`${ec}.${r}`}function ar(){var n;return(n=De.store.get("login"))===null||n===void 0?void 0:n.userId}const Ya=n=>C(n)||f(n),hd=(n,r,g,u)=>{if(!Ya(n)||!Ya(r))return 0;let E=0;const m=Object.keys(r);let D;for(let v=0,T=m.length;v{if(s(r))return"";if(n===Po.MSG_TEXT)return r.text||"";const g=XI[n];return g?Uu(g):""},ol=[{cmd:"ws_get_user_status",interval:5,count:20},{cmd:"ws_status_subscribe",interval:5,count:20},{cmd:"ws_status_unsubscribe",interval:5,count:20},{cmd:"get_group_self_member_info",interval:5,count:20},{cmd:"modify_group_base_info",interval:1,count:8},{cmd:"get_pendency",interval:1,count:15},{cmd:"set_group_attr",interval:5,count:10},{cmd:"modify_group_attr",interval:5,count:10},{cmd:"delete_group_attr",interval:5,count:10},{cmd:"clear_group_attr",interval:5,count:10},{cmd:"get_group_attr",interval:5,count:20},{cmd:"update_group_counter",interval:5,count:20},{cmd:"get_group_counter",interval:5,count:20},{cmd:"get_topic",interval:1,count:10},{cmd:"read_all_unread_msg",interval:1,count:1},{cmd:"query",interval:5,count:20}],$I="im_sdk_config_mgr.fetch_config",QI="im_sdk_config_mgr.push_configv2",sl="cloud-config",nl=2996,Na=new class{init(n){this.core=n}};function Lg(n){return mA(this,void 0,void 0,function*(){const{sdkAppId:r}=Na.core.store.get("instance")||{},g=Na.core.helper.generateProtocolData({servcmd:$I,data:{uint32_sdkappid:r,uint64_version:n}}),u=`${g.head.seq}${$I}`;return Na.core.channel.sendPacket(g,{requestId:u})})}var Ns=new class{constructor(){this._core=null,this._expirationTime=0,this._version=0,this._isFetching=!1,this._cmdFrequencyLimitMap=new Map,this._methodCallFrequencyMap=new Map}install(n){this._core=n;const{notificationCenter:r,InnerEvent:g,helper:u,constants:{WORKFLOW_NAME:E,WORKFLOW_STEP:m},channel:D}=n;r.subscribeInnerEvent(QI,this._handlePushedConfig,this),u.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_LOGIN,m.CLOUD_CONFIG_SYNC,this._handleLoginSuccess,this),r.subscribeInnerEvent(g.LOGOUT,this._reset,this),r.subscribeInnerEvent(g.DESTROY,this._dispose,this),u.registerExperimentalAPI("getServerConfig",this),this._updateCmdFreqLimitMap(ol),D.registerBeforeSendInterceptor(this.checkMethodCallOverLimit,this)}getServerConfig(n){return mA(this,void 0,void 0,function*(){var r;const g={code:0,data:""};return n&&(g.data=((r=this._core.store.get("cloudConfig"))===null||r===void 0?void 0:r[n])||""),g})}checkMethodCallOverLimit(n){if(!this._cmdFrequencyLimitMap.has(n))return;if(!this._methodCallFrequencyMap.has(n))return void this._methodCallFrequencyMap.set(n,{startTime:Date.now(),methodCallCounter:1});const{count:r,interval:g}=this._cmdFrequencyLimitMap.get(n);let{startTime:u,methodCallCounter:E}=this._methodCallFrequencyMap.get(n);if(Date.now()-u>1e3*g)this._methodCallFrequencyMap.set(n,{startTime:Date.now(),methodCallCounter:1});else if(E+=1,this._methodCallFrequencyMap.set(n,{startTime:u,methodCallCounter:E}),E>r)throw new this._core.helper.ChatError({code:nl,replacement1:n})}_handlePushedConfig(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=this._core;r.info("_handlePushedConfig",g(n)),yield this._updateCloudConfig(n)})}_handleLoginSuccess(){return mA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:r}}=this._core;try{if(this._canFetch()){const g=yield Lg(this._version);n.info("_fetchCloudConfigIfLogin",r(g)),yield this._updateCloudConfig(g)}this._core.helper.taskScheduler.addTask({id:sl,intervalMs:1e3,callback:this._fetchCloudConfigIfReady,context:this})}catch(g){n.debug("_fetchCloudConfigIfLogin",r(g))}})}_fetchCloudConfigIfReady(){return mA(this,void 0,void 0,function*(){const{ssoLog:n,utils:{safeStringify:r}}=this._core;if(this._canFetch())try{const g=yield Lg(this._version);n.info("_fetchCloudConfigIfReady",r(g)),yield this._updateCloudConfig(g)}catch(g){n.error("_fetchCloudConfigIfReady",r(g))}})}_updateCloudConfig(n){return mA(this,void 0,void 0,function*(){const r=this._parseCloudConfig(n);r&&(this._core.store.set("cloudConfig",r),yield this._parseCmdFreqLimit(),this._core.notificationCenter.emitInnerEvent(this._core.InnerEvent.CLOUD_CONFIG_UPDATE,r),this._core.notificationCenter.emitOuterEvent(this._core.OuterEvent.SERVER_CONFIG_UPDATED,{name:this._core.OuterEvent.SERVER_CONFIG_UPDATED,data:{config:r}}))})}_canFetch(){const{isLoggedIn:n}=this._core.store.get("login")||{};return n&&!this._isFetching&&Date.now()>=this._expirationTime}_parseCloudConfig(n){const{int32_error_code:r,str_error_message:g,str_json_config:u,uint32_expired_time:E,uint32_sdkappid:m,uint64_version:D}=n;let v=null;if(r===0){if(this._version!==D)try{v=JSON.parse(u),this._version=D}catch{}this._expirationTime=Date.now()+1e3*E}else this._expirationTime=r===void 0?Date.now()+36e5:Date.now()+12e4;return v}_parseCmdFreqLimit(){return mA(this,void 0,void 0,function*(){var n;let r=(n=yield this.getServerConfig("cmd_frequency_limit"))===null||n===void 0?void 0:n.data;const{isEmpty:g}=this._core.utils;if(!g(r))try{r=JSON.parse(r),this._updateCmdFreqLimitMap(r)}catch(u){console.warn(u)}})}_updateCmdFreqLimitMap(n){n.forEach(r=>{this._cmdFrequencyLimitMap.set(r.cmd,{interval:r.interval,count:r.count})})}_reset(){this._core.helper.taskScheduler.removeTask(sl),this._core.store.clear("cloudConfig"),this._updateCmdFreqLimitMap(ol),this._methodCallFrequencyMap.clear(),this._expirationTime=0,this._version=0,this._isFetching=!1}_dispose(){const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(QI,this._handlePushedConfig,this),n.unSubscribeInnerEvent(r.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this),this._reset()}};class Ar{constructor(r=0,g=0){this.high=r,this.low=g}equal(r){return r!==null&&this.low===r.low&&this.high===r.high}toString(){const r=Number(this.high).toString(16);let g=Number(this.low).toString(16);if(g.length<8){let u=8-g.length;for(;u;)g=`0${g}`,u--}return r+g}}const Gc={SEARCH_GRP_SNS:new Ar(0,Math.pow(2,1)).toString(),AV_HISTORY_MSG:new Ar(0,Math.pow(2,2)).toString(),GRP_COMMUNITY:new Ar(0,Math.pow(2,3)).toString(),MSG_TO_SPECIFIED_GRP_MBR:new Ar(0,Math.pow(2,4)).toString(),AV_MBR_LIST:new Ar(0,Math.pow(2,6)).toString(),USER_STATUS:new Ar(0,Math.pow(2,7)).toString(),CONV_MARK:new Ar(0,Math.pow(2,9)).toString(),CONV_GROUP:new Ar(0,Math.pow(2,10)).toString(),AV_BAN_MBR:new Ar(0,Math.pow(2,11)).toString(),MSG_EXT:new Ar(0,Math.pow(2,13)).toString(),GRP_COUNTER:new Ar(0,Math.pow(2,15)).toString(),PLUGIN_TRANSLATE:new Ar(Math.pow(2,6)).toString(),PLUGIN_VOICE_TO_TEXT:new Ar(Math.pow(2,7)).toString(),PLUGIN_CS:new Ar(Math.pow(2,8)).toString(),PLUGIN_PUSH:new Ar(Math.pow(2,9)).toString(),PLUGIN_BOT:new Ar(Math.pow(2,10)).toString(),MSG_REACTION:new Ar(Math.pow(2,16)).toString(),FOLLOW:new Ar(Math.pow(2,20)).toString()},Au="CommercialConfig",eu="commercial-config";var _E=new class{constructor(){this._core=null,this._expirationTime=0,this._isFetching=!1,this._featureMap=new Map,this._methodKeyMap=new Map,this._purchaseBits="0"}install(n){this._core=n;const{helper:r,notificationCenter:g,constants:{WORKFLOW_NAME:u,WORKFLOW_STEP:E,InnerEvent:m}}=n;g.subscribeInnerEvent(m.COMMERCIAL_CONFIG_PUSH,this._handlePushedConfig,this),g.subscribeInnerEvent(m.LOGOUT,this._handleLogout,this),g.subscribeInnerEvent(m.DESTROY,this._dispose,this),r.registerWorkflowStep(u.SYNC_SERVER_INFO_AFTER_LOGIN,E.COMMERCIAL_CONFIG_UPDATE,this._syncCommercialConfig,this),n.helper.registerExperimentalAPI("isCommercialAbilityEnabled",this),n.helper.registerExperimentalAPI("queryCommercialAbility",this)}isCommercialAbilityEnabled(n){return mA(this,void 0,void 0,function*(){const r=parseInt(n,10).toString(2),{length:g}=r;let u,E=!0;for(let m=g-1,D=0;m>=0;m--,D++)if(r.charAt(m)==="1"&&(u=D<32?new Ar(0,2**D).toString():new Ar(2**(D-32),0).toString(),!this._featureMap.get(u))){E=!1;break}return this._core.ssoLog.debug("isFeatureEnabled",`${Au}.isFeatureEnabled decimalNumber:${n} key:${u} ret:${E}`),{code:0,data:{enabled:E}}})}queryCommercialAbility(){return this._purchaseBits}_fetchAndParseCommercialConfig(){return mA(this,void 0,void 0,function*(){var n;const{ssoLog:r,utils:{safeStringify:g},common:{buildAndSendPacket:u}}=this._core;try{this._isFetching=!0;const E=yield u({servcmd:"im_sdk_config_mgr.fetch_imsdk_purchase_bitsv2",data:{uint32_sdkappid:(n=this._core.store.get("instance"))===null||n===void 0?void 0:n.sdkAppId}});E&&(this._parseCommercialConfig(E),this._core.store.set("commercialConfig",this._methodKeyMap))}catch(E){r.error("_fetchAndParseCommercialConfig",g(E))}finally{this._isFetching=!1}})}_syncCommercialConfig(n){return mA(this,void 0,void 0,function*(){const{purchaseBits:r}=n?.data||{};r&&(this._parsePurchaseBits(r),this._core.store.set("commercialConfig",this._methodKeyMap)),this._canFetch()&&(yield this._fetchAndParseCommercialConfig()),this._core.helper.taskScheduler.addTask({id:eu,intervalMs:1e3,callback:this._fetchCommercialConfigIfReady,context:this})})}_canFetch(){var n;const r=(n=this._core.store.get("login"))===null||n===void 0?void 0:n.isLoggedIn,g=Date.now()>=this._expirationTime;return r&&!this._isFetching&&g}_handlePushedConfig(n){n?.body&&(this._parseCommercialConfig(n.body),this._core.store.set("commercialConfig",this._methodKeyMap))}_fetchCommercialConfigIfReady(){return mA(this,void 0,void 0,function*(){this._canFetch()&&(yield this._fetchAndParseCommercialConfig())})}_parseCommercialConfig(n){const{ssoLog:r}=this._core;if(typeof n!="object")return;const{int32_error_code:g,str_error_message:u,str_purchase_bits:E,uint32_expired_time:m}=n;g===0?(this._parsePurchaseBits(E),this._expirationTime=Date.now()+1e3*m):g===void 0?(r.warn("_parseCommercialConfig",`${Au}._parseCommercialConfig failed. Invalid message format:`,n),this._expirationTime=Date.now()+36e5):(r.warn("_parseCommercialConfig",`${Au}._parseCommercialConfig errorCode:${g} errorMessage:${u}`),this._expirationTime=Date.now()+12e4)}_isValidPurchaseBits(n){return n&&typeof n=="string"&&n.length>=1&&n.length<=64&&/[01]{1,64}/.test(n)}_parsePurchaseBits(n){const{ssoLog:r,utils:{safeStringify:g}}=this._core;if(this._isValidPurchaseBits(n)){this._purchaseBits=n,this._featureMap.clear(),this._methodKeyMap.clear();let u=null;for(let E=n.length-1,m=0;E>=0;E--,m++)if(u=m<32?new Ar(0,2**m).toString():new Ar(2**(m-32),0).toString(),n[E]==="1"){this._featureMap.set(u,!0);const D=this._getKeyByValue(Gc,u);D&&this._methodKeyMap.set(D,!0)}else{this._featureMap.set(u,!1);const D=this._getKeyByValue(Gc,u);D&&this._methodKeyMap.set(D,!1)}}else r.warn("_parsePurchaseBits",`${Au}.parsePurchaseBits invalid purchases:${g(n)}`)}_getKeyByValue(n,r){const g=Object.entries(n).find(([u,E])=>E===r);return g?g[0]:void 0}_handleLogout(){this._reset()}_dispose(){this._reset(),this._core.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.COMMERCIAL_CONFIG_PUSH,this._handlePushedConfig,this),this._core.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),this._core.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this)}_reset(){this._core.helper.taskScheduler.removeTask(eu),this._core.store.set("commercialConfig",{}),this._expirationTime=0,this._isFetching=!1,this._featureMap.clear(),this._purchaseBits="0"}},ch=new class{constructor(){this._core=null,this._serverOverloadInfoMap=new Map}install(n){this._core=n;const{notificationCenter:r,InnerEvent:g,channel:u}=this._core;r.subscribeInnerEvent(g.OVERLOAD_PUSH,this._handleOverLoadPush,this),r.subscribeInnerEvent(g.LOGOUT,this._reset,this),r.subscribeInnerEvent(g.DESTROY,this._dispose,this),u.registerBeforeSendInterceptor(this.checkServerOverload,this)}checkServerOverload(n){if(!this._serverOverloadInfoMap.has(n))return;const{overloadStartTimestamp:r,delaySeconds:g}=this._serverOverloadInfoMap.get(n);if(Date.now()-r<=1e3*g)throw new this._core.helper.ChatError({functionName:n,message:"service is busy, please try again later"});this._serverOverloadInfoMap.delete(n)}_handleOverLoadPush(n){const{OverLoadServCmd:r,DelaySecs:g}=n;this._serverOverloadInfoMap.set(r,{overloadStartTimestamp:Date.now(),delaySeconds:g})}_reset(){this._serverOverloadInfoMap.clear()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.OVERLOAD_PUSH,this._handleOverLoadPush,this),n.unSubscribeInnerEvent(r.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}},dC=new class{constructor(){this.name="ConfigCenter"}install(n){Na.init(n),Ns.install(n),_E.install(n),ch.install(n)}},lh=new class{constructor(){this.name="ErrorMessage",this._core=null}install(n){return mA(this,void 0,void 0,function*(){if(this._core=n,this._canFetch()){const r=yield this._fetchErrorMessage();if(!r)return;const g=this._parseResponse(r);this._saveErrorMessage(g)}})}_canFetch(){const n=this._core.store.getStorage("errorMessage");return!n||this._isExpired(n)}_saveErrorMessage(n){this._core.store.setStorage("errorMessage",{errorMessage:n,errorMessageSavedTime:new Date().getTime()})}_fetchErrorMessage(){return mA(this,void 0,void 0,function*(){try{return yield this._core.helper.httpRequest({method:"GET",url:"https://web.sdk.qcloud.com/im/download/error-message/v3/0.0.6/tim-error-message.txt"})}catch(n){console.error(n)}})}_isExpired(n){if(!n)return!0;const{errorMessageSavedTime:r}=n;return r&&new Date().getTime()-r>=6048e5}_parseResponse(n){if(typeof n=="string"){const r=n.split(`;
+`),g={},u=new RegExp(/'/g);for(let E=0;E{var WA,ue,le;const ki=function(Li,Yt){const{From_Account:Fi,From_AccountHeadurl:hs,From_AccountNick:Re,IsNeedReadReceipt:Mt,MsgBody:UA,MsgClientTime:ci,MsgRandom:Os,MsgSeq:Oi,MsgTimeStamp:Yr,SendMsgControl:ji,SupportMessageExtension:Br,To_Account:Ut,TinyId:Ft,MsgCheckResult:oE,CloudCustomData:Cn,IsPeerRead:Do,MsgFlagBits:Bl,MsgVersion:GC,EventArray:Gr}=Li;return{from:Fi,avatar:hs,nick:Re,needReadReceipt:Mt===1,readReceiptSentByPeer:Do,clientTime:ci,messageFlagBits:Bl,random:Os,sequence:Oi,time:Yr,messageControlInfo:ji,isSupportExtension:Br,to:Ut,tinyID:Ft,checkResult:oE,cloudCustomData:Cn,messageVersion:GC,eventArray:Gr,elements:Yt.message.messageHelper.parseServerPushMessageElement(UA)}}(OA,xA);if(!((le=(ue=(WA=OA?.EventArray)===null||WA===void 0?void 0:WA[0])===null||ue===void 0?void 0:ue.hasOwnProperty)===null||le===void 0)&&le.call(ue,"C2cNotifyMsgArray"))SA.push(...function(Li){var Yt;const Fi=[];return(Yt=Li.EventArray)===null||Yt===void 0||Yt.forEach(hs=>{var Re,Mt;const{C2cNotifyMsgArray:UA}=hs,ci=(Mt=(Re=UA?.[0])===null||Re===void 0?void 0:Re.WithdrawC2cMsgNotify)===null||Mt===void 0?void 0:Mt.C2cWithdrawInfoArray;Array.isArray(ci)&&Fi.push(...ci)}),Fi}(OA));else{const Li=xA.message.messageFactory.createMessage(Object.assign(Object.assign({},ki),{conversationType:"C2C",flow:"in"})),{elements:Yt}=ki;Li.setElement(Yt),LA.push(Li)}}),{unreadMessageList:LA,revokedMessageList:SA}}(T.MsgList,r);return{syncFlag:T?.SyncFlag,unreadMessageList:EA,revokedMessageList:wA,unreadCountList:P,overflowUnreadCountList:W,cookie:T?.Cookie,groupTipList:oA}}catch(T){console.warn(T)}})}var Ug,Io;(function(n){n[n.START_SYNC=0]="START_SYNC",n[n.SYNCING=1]="SYNCING",n[n.SYNC_COMPLETE=2]="SYNC_COMPLETE"})(Ug||(Ug={})),function(n){n[n.LOGIN_SUCCESS=0]="LOGIN_SUCCESS",n[n.NEW_MESSAGE_RECEIVED=1]="NEW_MESSAGE_RECEIVED"}(Io||(Io={}));var CC=new class{constructor(){this.name="UnreadMessageSynchronizer",this._unreadDBMessageMap=new Map,this._cookie="",this._localConversationIDListBeforeDisconnect=[]}install(n){this._core=n;const{constants:r}=n;n.helper.registerWorkflowStep(r.WORKFLOW_NAME.SYNC_SERVER_INFO_AFTER_RE_ONLINE,r.WORKFLOW_STEP.UNREAD_MESSAGE_SYNC,this._syncUnreadDBMessageAfterReOnline,this),n.helper.registerWorkflowStep(r.WORKFLOW_NAME.RECEIVE_C2C_NEW_MESSAGE,r.WORKFLOW_STEP.UNREAD_MESSAGE_SYNC,this._syncUnreadDBMessageAfterNewMessageReceived,this),n.helper.registerWorkflowStep(r.WORKFLOW_NAME.SYNC_SERVER_INFO_AFTER_LOGIN,r.WORKFLOW_STEP.UNREAD_MESSAGE_SYNC,this._syncUnreadDBMessageAfterLogin,this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.SOCKET_DISCONNECTED,this._handleDisconnect,this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.LOGOUT,this._reset,this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this)}_syncUnreadMessage(n){return mA(this,void 0,void 0,function*(){const{isAfterReOnline:r=!1,isAfterNewMessageReceived:g=!1,isAfterLogin:u=!1}=n||{};let E=Ug.START_SYNC;const m=[],D=[],v=[],T=[];for(;this._canContinueSync({cookie:this._cookie,syncFlag:E});){const P=yield this._fetchUnreadDBMessage({cookie:this._cookie,syncFlag:E,syncTriggerEvent:g?Io.NEW_MESSAGE_RECEIVED:Io.LOGIN_SUCCESS});if(!P)break;const{unreadMessageList:W=[],revokedMessageList:oA=[],overflowUnreadCountList:EA,unreadCountList:wA,groupTipList:kA}=P;if(this._cookie=P?.cookie||"",E=P?.syncFlag,this._parseAndSaveUnreadMessageList(W),v.push(...oA),this._updateConversationUnreadOptions({unreadCountList:wA,overflowUnreadCountList:EA,conversationUpdateFieldList:m}),Array.isArray(kA)&&D.push(...kA),r){const{messages:xA}=this._handleNewMessageList(W);T.push(...xA)}}return r?{conversationUpdateFieldList:m,revokedMessageList:v,unreadMessageMap:this._unreadDBMessageMap,groupTipList:D,messages:T,isUnreadC2CMessage:!0}:{conversationUpdateFieldList:m,isInstantMessage:!u,isUnreadC2CMessage:!0,revokedMessageList:v,unreadMessageMap:this._unreadDBMessageMap,groupTipList:D}})}_syncUnreadDBMessageAfterLogin(){return mA(this,void 0,void 0,function*(){return this._cookie="",this._syncUnreadMessage({isAfterLogin:!0})})}_syncUnreadDBMessageAfterNewMessageReceived(n){return mA(this,void 0,void 0,function*(){if(n.data.Flag===1)return this._syncUnreadMessage({isAfterNewMessageReceived:!0})})}_updateConversationUnreadOptions(n){const{unreadCountList:r,overflowUnreadCountList:g,conversationUpdateFieldList:u}=n,{constants:{OuterConstant:{CONV_C2C:E,CONV_SYSTEM:m}}}=this._core;r?.forEach(D=>{const{From_Account:v,UnreadCount:T}=D;if(v!==m){const P=u.find(({conversationID:W})=>W===`${E}${v}`);P?P.unreadCount=T:u.push({conversationID:`${E}${v}`,unreadCount:T,type:E})}}),g?.forEach(D=>{const{From_Account:v,LastMsgTime:T}=D;v!==m&&(u.find(({conversationID:P})=>P===`${E}${v}`)||u.push({conversationID:`${E}${v}`,type:E,lastMsgTime:T}))})}_syncUnreadDBMessageAfterReOnline(){return mA(this,void 0,void 0,function*(){return this._syncUnreadMessage({isAfterReOnline:!0})})}_updateMessageProfile(n){var r;const{messageDataHandler:g}=this._core.message||{},u=(r=this._core.store.get("login"))===null||r===void 0?void 0:r.userId,{from:E,nick:m,avatar:D,conversationID:v=""}=n;if(E!==u){const T=g.getLatestMsgSentByPeer(v);if(T){const{nick:P,avatar:W}=T;m&&D?m===P&&D===W||g.updateNickAndAvatarOfSentMessage({conversationID:v,latestNick:m,latestAvatar:D,isSentByMe:!1}):(n.nick=P,n.avatar=W)}}else{const T=g.getLatestMsgSentByMe(v);!T||m===T.nick&&D===T.avatar||g.updateNickAndAvatarOfSentMessage({conversationID:v,latestNick:m,latestAvatar:D,isSentByMe:!0})}}_handleNewMessageList(n){const{messageDataHandler:r}=this._core.message||{},g=new Map,u=[];return n.forEach(E=>{this._updateMessageProfile(E);let m=E.isModified===1;if(r.isMessageSentByCurrentInstance(E)?E.isModified=m:m=!1,E.isOnlineMessage())E._onlineOnlyFlag=!0,r.isMessageSentByCurrentInstance(E)||u.push(E);else if(this._shouldStoreUnreadMessage(E)){if(r.storeConversationMessage(E)){const{conversationID:D,conversationType:v,conversationSubType:T,flow:P,_isExcludedFromUnreadCount:W,_isExcludedFromLastMessage:oA}=E,EA=oA?"":E;g.has(D)?(g.get(D).lastMessage=EA,P==="in"&&(W||g.get(D).unreadCount++)):g.set(D,{conversationID:D,type:v,subType:T,unreadCount:W||P!=="in"?0:1,lastMessage:EA})}r.isMessageSentByCurrentInstance(E)&&!m||u.push(E)}}),{messages:u,conversationOptions:g}}_shouldStoreUnreadMessage(n){var r;const{conversationID:g}=n,{message:u,appStore:E,utils:{isEmpty:m}}=this._core||{},D=Array.from(((r=E.conversationStore.getConversationMap())===null||r===void 0?void 0:r.keys())||[]),v=this._getLocalLastMessageTime(g);return!u.messageDataHandler.isInMessageList(n)&&D.includes(g)&&this._localConversationIDListBeforeDisconnect.includes(g)&&!m(v)}_fetchUnreadDBMessage(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=this._core;try{r.debug("_fetchUnreadDBMessage",`unread-message-synchronizer._fetchUnreadDBMessage options:${g(n)}`);const E=yield rl(n,this._core);if(!E)return null;const{syncFlag:m,unreadMessageList:D,revokedMessageList:v,cookie:T,unreadCountList:P,overflowUnreadCountList:W,groupTipList:oA}=E;return this._parseAndSaveUnreadMessageList(D),{syncFlag:m,cookie:T,unreadMessageList:D,revokedMessageList:v,unreadCountList:P,overflowUnreadCountList:W,groupTipList:oA}}catch(u){console.log(u)}})}_canContinueSync({cookie:n,syncFlag:r}){var g;return r===Ug.START_SYNC||r===Ug.SYNCING&&!(!((g=this._core)===null||g===void 0)&&g.helper.isEmpty(n))}_parseAndSaveUnreadMessageList(n){n.forEach(r=>{const{ID:g}=r;this._unreadDBMessageMap.set(g,r)})}_handleDisconnect(){var n;const{appStore:r}=this._core;this._localConversationIDListBeforeDisconnect=Array.from(((n=r.conversationStore.getConversationMap())===null||n===void 0?void 0:n.keys())||[])}_getLocalLastMessageTime(n){const{message:r}=this._core,g=r.messageDataHandler.getLocalMessageList(n),u=g[g.length-1];return u?.time}_reset(){this._cookie="",this._unreadDBMessageMap.clear()}_dispose(){var n,r;(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),(r=this._core)===null||r===void 0||r.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this),this._reset()}},TE=new class{init(n){var r;this._core=n,this._visibilityChangeHandler=this._handleVisibilityChange.bind(this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this),document?.addEventListener("visibilitychange",this._visibilityChangeHandler),(r=this._core)===null||r===void 0||r.store.set("activityMonitor",{isActive:!0})}_handleVisibilityChange(){var n,r;const g=document?.visibilityState==="visible";(n=this._core)===null||n===void 0||n.store.set("activityMonitor",{isActive:g}),(r=this._core)===null||r===void 0||r.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:g})}_reset(){var n;(n=this._core)===null||n===void 0||n.store.clear("activityMonitor")}_dispose(){document?.removeEventListener("visibilitychange",this._visibilityChangeHandler);const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this),this._reset()}},NE=new class{init(n){var r;this._core=n,this._bindAppActivityEvent(),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this),(r=this._core)===null||r===void 0||r.store.set("activityMonitor",{isActive:!0})}_bindAppActivityEvent(){var n,r,g,u,E;const{MINI_APP_NAMESPACE:m,IN_TT_MINI_GAME:D,IN_WX_MINI_GAME:v}=((n=this._core)===null||n===void 0?void 0:n.utils)||{};D||v?((r=m?.onShow)===null||r===void 0||r.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!0}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!0})}),(g=m?.onHide)===null||g===void 0||g.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!1}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!1})})):((u=m?.onAppShow)===null||u===void 0||u.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!0}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!0})}),(E=m?.onAppHide)===null||E===void 0||E.call(m,()=>{var T,P;(T=this._core)===null||T===void 0||T.store.set("activityMonitor",{isActive:!1}),(P=this._core)===null||P===void 0||P.notificationCenter.emitInnerEvent("activityStatusChange",{isActive:!1})}))}_reset(){var n;(n=this._core)===null||n===void 0||n.store.clear("activityMonitor")}_dispose(){const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this),this._reset()}},Bd=new class{init(n){const{IN_MINI_APP:r,IN_WX_MINI_PLUGIN:g}=n.helper;g||(r?NE.init(n):TE.init(n))}};const GE="none",al="online";var pI=new class{init(n){this._core=n,this._activateNetworkMonitoring(),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this)}_activateNetworkMonitoring(){return mA(this,void 0,void 0,function*(){navigator.onLine?this._onOnline():this._onOffline(),this._onOnlineCallback=this._onOnline.bind(this),this._onOfflineCallback=this._onOffline.bind(this),window.addEventListener("online",this._onOnlineCallback),window.addEventListener("offline",this._onOfflineCallback)})}_deactivateNetworkMonitoring(){this._onOnlineCallback!==null&&(window.removeEventListener("online",this._onOnlineCallback),this._onOnlineCallback=null),this._onOfflineCallback!==null&&(window.removeEventListener("offline",this._onOfflineCallback),this._onOfflineCallback=null)}_onNetworkStatusChange(n){var r,g;const{isConnected:u,networkType:E}=n;(r=this._core)===null||r===void 0||r.store.set("netWorkMonitor",{isNetworkOnline:u,networkType:E}),(g=this._core)===null||g===void 0||g.notificationCenter.emitInnerEvent("networkStatusChange",{isNetworkOnline:u,networkType:E})}_onOnline(){this._onNetworkStatusChange({isConnected:!0,networkType:al})}_onOffline(){this._onNetworkStatusChange({isConnected:!1,networkType:GE})}_reset(){var n;this._deactivateNetworkMonitoring(),(n=this._core)===null||n===void 0||n.store.clear("netWorkMonitor")}_dispose(){var n,r;(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent((r=this._core)===null||r===void 0?void 0:r.InnerEvent.DESTROY,this._dispose,this),this._reset()}},Fu=new class{init(n){this._core=n,this._activateNetworkMonitoring(),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this)}_activateNetworkMonitoring(){return mA(this,void 0,void 0,function*(){try{const{utils:{MINI_APP_NAMESPACE:n}}=this._core;this._mpNetworkStatusCallback=this._onNetworkStatusChange.bind(this),n.onNetworkStatusChange(this._onNetworkStatusChange.bind(this))}catch(n){console.error(n)}})}_deactivateNetworkMonitoring(){if(this._mpNetworkStatusCallback!==null){const{utils:{MINI_APP_NAMESPACE:n}}=this._core;n.offNetworkStatusChange&&n.offNetworkStatusChange(this._mpNetworkStatusCallback),this._mpNetworkStatusCallback=null}}_onNetworkStatusChange(n){var r,g;const{isConnected:u,networkType:E}=n;(r=this._core)===null||r===void 0||r.store.set("netWorkMonitor",{isNetworkOnline:u,networkType:E}),(g=this._core)===null||g===void 0||g.notificationCenter.emitInnerEvent("networkStatusChange",{isNetworkOnline:u,networkType:E})}_reset(){var n;this._deactivateNetworkMonitoring(),(n=this._core)===null||n===void 0||n.store.clear("netWorkMonitor")}_dispose(){var n,r;(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent((r=this._core)===null||r===void 0?void 0:r.InnerEvent.DESTROY,this._dispose,this),this._reset()}},Ou=new class{init(n){const{IN_MINI_APP:r}=n.utils;r?Fu.init(n):pI.init(n)}},hC=new class{constructor(){this.name="SystemStateMonitor"}install(n){Bd.init(n),Ou.init(n)}};const Tr=new Set(["tui_room_svr.*","callkit_records_svr.*","room_engine_srv.*","room_engine_http_srv.*","room_engine_mic.*","live_engine_srv.*","live_engine_http_srv.*","live_engine_pk.*","trtc_ai_service.*","call_engine_srv.*"]),Ig="tui_room_svr.*";var bc=new class{constructor(){this.name="BusinessCommandTransfer",this._transferredCommands=Tr}install(n){this._core=n;const{notificationCenter:r,InnerEvent:g,helper:u}=n;r.subscribeInnerEvent(g.CLOUD_CONFIG_UPDATE,this._onCloudConfigUpdate,this),r.subscribeInnerEvent(g.LOGOUT,this._reset,this),r.subscribeInnerEvent(g.DESTROY,this._dispose,this),r.subscribeInnerEvent("im_open_push.msg_push",r.InnerEventSubType.BUSINESS_COMMAND,this._onServerPushBusinessCommand,this),u.registerExperimentalAPI("sendTRTCCustomData",this,"transferBusinessCommand"),u.registerExperimentalAPI("sendRoomCustomData",this,"transferBusinessCommand")}transferBusinessCommand(n){return mA(this,void 0,void 0,function*(){const r="transferBusinessCommand";try{const{serviceCommand:g=Ig}=n||{};if(!this._isValidTransferredCommand(g))throw new this._core.helper.ChatError({code:2995,functionName:r});return{code:0,data:(yield function(E,m){return mA(this,void 0,void 0,function*(){const{helper:D,channel:v}=m,{serviceCommand:T=Ig,data:P}=E||{};let W={};try{W=typeof P=="string"?JSON.parse(P):P}catch(wA){console.warn(wA)}const oA=D.generateProtocolData({servcmd:T,data:W}),EA=`${oA.head.seq}${T}`;return v.sendPacket(oA,{requestId:EA,shouldRejectOnError:!1})})}(n,this._core))||{}}}catch(g){throw console.warn(g),new this._core.helper.ChatError({code:g?.errorCode,message:g?.errorInfo,data:{},functionName:r})}})}_onCloudConfigUpdate(n={}){try{if(typeof n.rtc_cmd!="string")return;const r=JSON.parse(n.rtc_cmd);Array.isArray(r)&&(this._transferredCommands=new Set([...this._transferredCommands,...r]))}catch(r){console.log(r)}}_isValidTransferredCommand(n=""){const r=`${n?.split(".")[0]}.*`;return this._transferredCommands.has(r)}_onServerPushBusinessCommand(n){const{OuterEvent:r,notificationCenter:g}=this._core,{MsgContent:u}=n||{},{ROOM_CUSTOM_DATA_RECEIVED:E}=r;g.emitOuterEvent(E,{name:E,data:u})}_reset(){this._transferredCommands=Tr}_dispose(){const{notificationCenter:n,InnerEvent:r}=this._core;this._reset(),n.unSubscribeInnerEvent(r.CLOUD_CONFIG_UPDATE,this._onCloudConfigUpdate,this),n.unSubscribeInnerEvent(r.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this),n.unSubscribeInnerEvent("im_open_push.msg_push",n.InnerEventSubType.BUSINESS_COMMAND,this._onServerPushBusinessCommand,this)}};const Pu=1,Ll=2,Qd=3,ta=4,mI=5,Un="TIMCustomElem",BC="C2C",gl="GROUP",pd="invite",fI="accept",Va="cancel",QC="reject",Ja="modifyInvitation",fr="signaling",md=8010,xu="signaling-timeout";function yr(n){return n.filter(r=>{if(r.type===Un){const{cloudCustomData:g="",payload:{data:u=""}={}}=r,E=g.match(/"type":"tsignaling"/),m=u.match(/inviteID/),D=u.match(/actionType/);return E||m&&D}return!1})}function kc(n){const{data:r}=n.payload;try{return JSON.parse(r)}catch(g){return console.error(g),null}}function cl(n,r){return n.toString(16).padStart(r,"0")}function Fg(n){if(n<0||n>53)throw new Error("Number of digits must be between 0 and 53");if(n<=30)return Math.floor(Math.random()*(1<0;const v=this._core.common.getCurrentUserID();return D.includes(v)}return!0}updateSignaling(n){const r=`${fr}.updateSignaling`,{inviteID:g,inviter:u,inviteeList:E,groupID:m}=n;if(console.log(`${r} inviteID:${g} inviter:${u} groupID:${m}`),m&&this.hasSignaling(g)){const D=E[0],{inviteeList:v}=this._onlineSignalingMap.get(g);v.includes(D)&&(v.splice(v.indexOf(D),1),console.log(`${r} remove ${D}. localInviteeList.length:${v.length}`)),v.length===0&&this.removeSignaling(g)}else this.removeSignaling(g)}setSignalingListenStatus(n){this._isSignalingListening=n}getSignalingListenStatus(){return this._isSignalingListening}_dispose(){var n,r;this._reset(),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this),(r=this._core)===null||r===void 0||r.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),this._isSignalingListening=!1}_reset(){this._onlineSignalingMap.clear()}},ic=new class{init(n){this._core=n}createInviteSignaling(n){const r=this._generateInviteID(),g=this._createInviteSignalingData(Object.assign(Object.assign({},n),{inviteID:r})),{groupID:u,inviteeList:E}=g,m=u||E[0];return{signaling:this._createSignaling(g,m),signalingData:g,signalingExtensionOptions:this._createSignalingExtensionOptions(n)}}createAcceptSignaling(n){const r=this._createAcceptSignalingData(n),{groupID:g,inviter:u}=r,E=g||u;return{signaling:this._createSignaling(r,E),signalingData:r,signalingExtensionOptions:this._createSignalingExtensionOptions(n)}}createCancelSignaling(n){const r=this._createCancelSignalingData(n),{groupID:g,inviteeList:u}=r,E=g||u[0];return{signaling:this._createSignaling(r,E),signalingData:r,signalingExtensionOptions:this._createSignalingExtensionOptions(n)}}createRejectSignaling(n){const r=this._createRejectSignalingData(n),{groupID:g,inviter:u}=r,E=g||u;return{signaling:this._createSignaling(r,E),signalingData:r,signalingExtensionOptions:this._createSignalingExtensionOptions(n)}}createTimeoutSignaling(n){const{isInviter:r=!1}=n,g=this._createTimeoutSignalingData(n),{groupID:u,inviteeList:E,inviter:m}=g,D=u||(r?E[0]:m);return{signaling:this._createSignaling(g,D),signalingData:g,signalingExtensionOptions:this._createSignalingExtensionOptions(g)}}_createSignalingExtensionOptions(n){var r,g;const{data:u="",onlineUserOnly:E,inviteID:m="",offlinePushInfo:D,actionType:v}=n,T=((g=(r=Ho.getSignaling(m))===null||r===void 0?void 0:r.signaling)===null||g===void 0?void 0:g._onlineOnlyFlag)||!1;return{onlineUserOnly:E||T,offlinePushInfo:D,messageControlInfo:this._createMessageControlInfo(u,v)}}_createMessageControlInfo(n,r){const g=r===mI&&!!n.match(/excludeTimeoutSignalingFromHistoryMessage/),u=!!n.match(/excludeFromHistoryMessage/)||!!n.match(/excludeOriginalSignalingFromHistoryMessage/);return{excludedFromContentModeration:!0,excludedFromUnreadCount:g||u,excludedFromLastMessage:g||u}}_createInviteSignalingData(n){const r=`${fr}._createInviteSignalingData`,{userID:g,timeout:u=0,groupID:E="",inviteeList:m=[]}=n,D=this._core.common.getCurrentUserID(),v=Object.assign(Object.assign({},this._generateBaseSignalData(n)),{actionType:Pu,inviter:D,inviteeList:E?m:[g],timeout:u});return console.log(`${r} signalingData:`,v),v}_createAcceptSignalingData(n){const r=`${fr}._createAcceptSignalingData`,{inviteID:g}=n,u=this._core.common.getCurrentUserID(),{inviter:E,groupID:m}=Ho.getSignaling(g),D=Object.assign(Object.assign({},this._generateBaseSignalData(n)),{actionType:Qd,groupID:m,inviter:E,inviteeList:[u]});return console.log(`${r} signalingData:`,D),D}_createCancelSignalingData(n){const r=`${fr}._createCancelSignalingData`,{inviteID:g}=n,u=this._core.common.getCurrentUserID(),{inviteeList:E,groupID:m}=Ho.getSignaling(g),D=Object.assign(Object.assign({},this._generateBaseSignalData(n)),{actionType:Ll,groupID:m,inviter:u,inviteeList:E});return console.log(`${r} signalingData:`,D),D}_createRejectSignalingData(n){const r=`${fr}._createRejectSignalingData`,{inviteID:g}=n,u=this._core.common.getCurrentUserID(),{inviter:E,groupID:m}=Ho.getSignaling(g),D=Object.assign(Object.assign({},this._generateBaseSignalData(n)),{actionType:ta,groupID:m,inviter:E,inviteeList:[u]});return console.log(`${r} signalingData:`,D),D}_createTimeoutSignalingData(n){const r=`${fr}._createTimeoutSignalingData`,{isInviter:g=!1,inviteID:u}=n,{inviteeList:E,inviter:m}=Ho.getSignaling(u),D=this._core.common.getCurrentUserID(),v=Object.assign(Object.assign({},this._generateBaseSignalData(n)),{actionType:mI,inviter:m,inviteeList:g?E:[D]});return console.log(`${r} signalingData:`,v),v}_createSignaling(n,r){var g,u,E;const{groupID:m=""}=n,D={to:r,conversationType:m?gl:BC,priority:"High",payload:{data:JSON.stringify(n)}};return(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageFactory)===null||E===void 0?void 0:E.createCustomMessage(D)}_generateInviteID(){return[cl(Fg(32),8),cl(Fg(16),4),cl(16384|Fg(12),4),cl(32768|Fg(14),4),cl(Fg(48),12)].join("-")}_generateBaseSignalData(n){const{data:r="",inviteID:g="",groupID:u=""}=n;return{businessID:1,timeout:0,data:r,inviteID:g,groupID:u}}},Ag=new class{constructor(){this._isProcessingSignaling=!1}init(n){this._core=n,n.helper.registerApi({apiName:"invite",context:this}),n.helper.registerApi({apiName:"accept",context:this}),n.helper.registerApi({apiName:"cancel",context:this}),n.helper.registerApi({apiName:"reject",context:this}),n.helper.registerApi({apiName:"modifyInvitation",context:this}),n.helper.registerApi({apiName:"getSignalingInfo",context:this}),n.helper.registerApi({apiName:"addSignalingListener",context:this}),n.helper.registerApi({apiName:"removeSignalingListener",context:this}),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.LOGOUT,this._reset,this)}invite(n){return mA(this,void 0,void 0,function*(){var r;try{this._validateBeforeInvite(n);const{signaling:g,signalingData:u,signalingExtensionOptions:E}=ic.createInviteSignaling(n),m=yield this._sendSignaling(g,E);if(m?.code===0){const{inviteID:D,timeout:v}=u;return Ho.saveSignaling(D,Object.assign(Object.assign({},u),{signaling:g})),v>0&&((r=this._core)===null||r===void 0||r.helper.taskScheduler.addOnceTask({id:`${xu}-${D}`,intervalMs:1e3*(v+5),callback:this.handleInvitationExpiryTimer.bind(this,D)})),Object.assign(Object.assign({},m),{inviteID:D})}return m}catch(g){throw g}})}accept(n){return mA(this,void 0,void 0,function*(){try{const{inviteID:r}=n;this._validateBeforeAccept(r),this._isProcessingSignaling=!0;const{signaling:g,signalingData:u,signalingExtensionOptions:E}=ic.createAcceptSignaling(n),m=yield this._sendSignaling(g,E);return m?.code===0?(Ho.updateSignaling(u),Object.assign(Object.assign({},m),{inviteID:r})):m}catch(r){throw r}finally{this._isProcessingSignaling=!1}})}cancel(n){return mA(this,void 0,void 0,function*(){try{const{inviteID:r}=n;this._validateBeforeCancel(r),this._isProcessingSignaling=!0;const{signaling:g,signalingExtensionOptions:u}=ic.createCancelSignaling(n),E=yield this._sendSignaling(g,u);return E?.code===0?(Ho.removeSignaling(r),Object.assign(Object.assign({},E),{inviteID:r})):E}catch(r){throw r}finally{this._isProcessingSignaling=!1}})}reject(n){return mA(this,void 0,void 0,function*(){try{const{inviteID:r}=n;this._validateBeforeReject(r),this._isProcessingSignaling=!0;const{signaling:g,signalingExtensionOptions:u}=ic.createRejectSignaling(n),E=yield this._sendSignaling(g,u);return E?.code===0?(Ho.removeSignaling(r),Object.assign(Object.assign({},E),{inviteID:r})):E}catch(r){throw r}finally{this._isProcessingSignaling=!1}})}modifyInvitation(n){return mA(this,void 0,void 0,function*(){var r,g;const{inviteID:u,data:E}=n;let m="";try{this._validateBeforeModifyInvitation(u);const D=Ho.getSignaling(u),{signaling:v}=D,T=vo(D,["signaling"]);m=v.payload.data,T.data=E,v.payload.data=JSON.stringify(T);const P=yield(g=(r=this._core)===null||r===void 0?void 0:r.message.messageAction)===null||g===void 0?void 0:g.modifyMessage(v);return Ho.hasSignaling(u)&&Ho.saveSignaling(u,Object.assign(Object.assign({},T),{signaling:v})),P}catch(D){if(m){const{signaling:v}=Ho.getSignaling(u);v.payload.data=m}throw D}})}getSignalingInfo(n){const{ssoLog:r,utils:{safeStringify:g}}=this._core;if(yr([n]).length===0)return;const u=kc(n),E={businessID:u.businessID||1,inviteID:u.inviteID,groupID:u.groupID||"",inviter:u.inviter||"",inviteeList:u.inviteeList||[],data:u.data||"",actionType:u.actionType||Pu,timeout:u.timeout||0};return r.debug(`${fr} getSignalingInfo ${g(E)}`),E}addSignalingListener(n,r,g){var u,E;n===((u=this._core)===null||u===void 0?void 0:u.SignalingEvent.NEW_INVITATION_RECEIVED)&&Ho.setSignalingListenStatus(!0),(E=this._core)===null||E===void 0||E.notificationCenter.subscribeOuterEvent(n,r,g)}removeSignalingListener(n,r,g){var u,E;n===((u=this._core)===null||u===void 0?void 0:u.SignalingEvent.NEW_INVITATION_RECEIVED)&&Ho.setSignalingListenStatus(!1),(E=this._core)===null||E===void 0||E.notificationCenter.unSubscribeOuterEvent(n,r,g)}handleInvitationExpiryTimer(n){const r=Ho.getOnlineSignalingMap(),g=this._core.common.getCurrentUserID();if(!r.has(n))return;const u=r.get(n).inviter===g;this._sendTimeoutNotice({inviteID:n,isInviter:u})}_sendSignaling(n,r){return mA(this,void 0,void 0,function*(){var g,u,E;return(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageSender)===null||E===void 0?void 0:E.sendMessage(n,r)})}_sendTimeoutNotice(n){return mA(this,void 0,void 0,function*(){var r,g,u;this._core.ssoLog.debug("_sendTimeoutNotice",`${fr}._sendTimeoutNotice params:${JSON.stringify(n)}`);const{isInviter:E,inviteID:m}=n,{signaling:D,signalingData:v,signalingExtensionOptions:T}=ic.createTimeoutSignaling(n),P=yield this._sendSignaling(D,T);if(P?.code===0){const{data:W,groupID:oA,inviteeList:EA,inviter:wA}=v;(r=this._core)===null||r===void 0||r.notificationCenter.emitOuterEvent((g=this._core)===null||g===void 0?void 0:g.SignalingEvent.INVITATION_TIMEOUT,{name:(u=this._core)===null||u===void 0?void 0:u.SignalingEvent.INVITATION_TIMEOUT,data:{data:W,groupID:oA,inviteID:m,inviteeList:EA,inviter:wA,isSelfTimeout:!0,message:D}}),E?Ho.removeSignaling(m):Ho.updateSignaling(v)}})}_validateInviteId(n,r){if(!Ho.hasSignaling(r))throw new this._core.helper.ChatError({functionName:n,code:md})}_validateProcessStatus(n){if(this._isProcessingSignaling)throw new this._core.helper.ChatError({functionName:n,message:"processing other signaling operations"})}_validateBeforeInvite(n){const r=pd,{userID:g}=n,u=this._core.common.getCurrentUserID();if(g===u)throw new this._core.helper.ChatError({functionName:r,message:`cannot invite yourself, currentUserId:${u}, inviteeId:${g}`})}_validateBeforeAccept(n){const r=fI;this._validateInviteId(r,n),this._validateProcessStatus(r);const g=this._core.common.getCurrentUserID(),{inviteeList:u}=Ho.getSignaling(n);if(!u.includes(g)){const E=`userID:${g} not in inviteeList. inviteID:${n}`;throw new this._core.helper.ChatError({functionName:r,message:E})}}_validateBeforeCancel(n){const r=Va;this._validateInviteId(r,n),this._validateProcessStatus(r);const g=this._core.common.getCurrentUserID(),{inviter:u}=Ho.getSignaling(n);if(u!==g){const E=`unmatched inviter:${u} and my userID:${g}`;throw new this._core.helper.ChatError({functionName:r,message:E})}}_validateBeforeReject(n){const r=QC;this._validateInviteId(r,n),this._validateProcessStatus(r);const g=this._core.common.getCurrentUserID(),{inviteeList:u}=Ho.getSignaling(n);if(!u.includes(g)){const E=`userID:${g} not in inviteeList. inviteID:${n}`;throw new this._core.helper.ChatError({functionName:r,message:E})}}_validateBeforeModifyInvitation(n){const r=Ja;this._validateInviteId(r,n)}_dispose(){var n,r;this._reset(),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this),(r=this._core)===null||r===void 0||r.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this)}_reset(){this._isProcessingSignaling=!1}},Ul=new class{constructor(){this._actionProcessor=new Map([[Pu,this._onNewInvitationReceived.bind(this)],[ta,this._onInviteeRejected.bind(this)],[Qd,this._onInviteeAccepted.bind(this)],[Ll,this._onInvitationCancelled.bind(this)],[mI,this._onInvitationTimeout.bind(this)]])}init(n){this._core=n,n.notificationCenter.subscribeOuterEvent(n.OuterEvent.MESSAGE_RECEIVED,this._handleMessageReceived,this),n.notificationCenter.subscribeOuterEvent(n.OuterEvent.MESSAGE_MODIFIED,this._handleMessageModified,this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this._dispose,this)}handleActionSignaling(n){n.forEach(r=>{const g=kc(r);if(g){const u=this._actionProcessor.get(g.actionType);u?.(g,r)}})}_handleMessageReceived(n){if(!Ho.getSignalingListenStatus())return;const r=yr(n.data);r.length!==0&&this.handleActionSignaling(r)}_handleMessageModified(n){if(!Ho.getSignalingListenStatus())return;const r=yr(n.data);r.length>0&&r.forEach(g=>{const u=kc(g);u&&this._onInvitationModified(u,g)})}_onNewInvitationReceived(n,r){var g,u;const E=`${fr}._onNewInvitationReceived`,{inviteID:m,inviteeList:D,groupID:v}=n,T=this._core.common.getCurrentUserID();if(this._core.ssoLog.debug("_onNewInvitationReceived",`${E} signalingData:${JSON.stringify(n)}}`),v&&!D.includes(T))return;let{timeout:P}=n;const W=Date.now()/1e3-r.time;P>0&&W>0&&P>W&&(P-=W);const oA=Ho.getSignaling(m);oA!==n&&(oA||Ho.saveSignaling(m,Object.assign(Object.assign({},n),{signaling:r})),P>0&&((g=this._core)===null||g===void 0||g.helper.taskScheduler.addOnceTask({id:`${xu}-${m}`,intervalMs:1e3*P,callback:Ag.handleInvitationExpiryTimer.bind(Ag,m)})),this._emitEvent({name:(u=this._core)===null||u===void 0?void 0:u.SignalingEvent.NEW_INVITATION_RECEIVED,data:Object.assign(Object.assign({},this._generateBaseEmitData(n)),{inviteeList:D})}))}_onInviteeRejected(n){var r;const g=`${fr}._onInviteeRejected`,{inviteID:u,inviter:E,groupID:m,inviteeList:D}=n,v=Ho.hasSignaling(u);this._core.ssoLog.debug("_onInviteeRejected",`${g} inviteID:${u} hasInviteID:${v} inviter:${E} groupID:${m}`),v&&(Ho.updateSignaling(n),this._emitEvent({name:(r=this._core)===null||r===void 0?void 0:r.SignalingEvent.INVITEE_REJECTED,data:Object.assign(Object.assign({},this._generateBaseEmitData(n)),{invitee:D[0]})}))}_onInviteeAccepted(n){var r;const g=`${fr}._onInviteeAccepted`,{inviteID:u,inviter:E,groupID:m,inviteeList:D}=n,v=Ho.hasSignaling(u);this._core.ssoLog.debug("_onInviteeAccepted",`${g} inviteID:${u} hasInviteID:${v} inviter:${E} groupID:${m}`),v&&(Ho.updateSignaling(n),this._emitEvent({name:(r=this._core)===null||r===void 0?void 0:r.SignalingEvent.INVITEE_ACCEPTED,data:Object.assign(Object.assign({},this._generateBaseEmitData(n)),{invitee:D[0]})}))}_onInvitationCancelled(n){var r;const g=`${fr}._onInvitationCancelled`,{inviteID:u,inviter:E,groupID:m}=n,D=Ho.hasSignaling(u);this._core.ssoLog.debug("_onInvitationCancelled",`${g} inviteID:${u} hasInviteID:${D} inviter:${E} groupID:${m}`),D&&(Ho.removeSignaling(u),this._emitEvent({name:(r=this._core)===null||r===void 0?void 0:r.SignalingEvent.INVITATION_CANCELLED,data:this._generateBaseEmitData(n)}))}_onInvitationTimeout(n){var r;const g=`${fr}._onInvitationTimeout`,{inviteID:u,inviteeList:E}=n,m=Ho.hasSignaling(u);this._core.ssoLog.debug("_onInvitationTimeout",`${g} inviteID:${u} hasInviteID:${m} data:${n.data}`),m&&(Ho.updateSignaling(n),this._emitEvent({name:(r=this._core)===null||r===void 0?void 0:r.SignalingEvent.INVITATION_TIMEOUT,data:Object.assign(Object.assign({},this._generateBaseEmitData(n)),{inviteeList:E,isSelfTimeout:!1})}))}_onInvitationModified(n,r){var g;const u=`${fr}._onInvitationModified`,{inviteID:E,data:m}=n,D=Ho.hasSignaling(E);this._core.ssoLog.debug("_onInvitationModified",`${u} inviteID:${E} data:${m}`),D&&(Ho.saveSignaling(E,Object.assign(Object.assign({},n),{signaling:r})),this._emitEvent({name:(g=this._core)===null||g===void 0?void 0:g.SignalingEvent.INVITATION_MODIFIED,data:{inviteID:E,data:m}}))}_emitEvent(n){var r;(r=this._core)===null||r===void 0||r.notificationCenter.emitOuterEvent(n.name,n)}_generateBaseEmitData(n){const{inviteID:r,inviter:g,groupID:u,data:E}=n;return{inviteID:r,inviter:g,groupID:u,data:E||""}}_dispose(){var n,r,g;(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeOuterEvent(this._core.OuterEvent.MESSAGE_RECEIVED,this._handleMessageReceived,this),(r=this._core)===null||r===void 0||r.notificationCenter.unSubscribeOuterEvent(this._core.OuterEvent.MESSAGE_MODIFIED,this._handleMessageModified,this),(g=this._core)===null||g===void 0||g.notificationCenter.unSubscribeOuterEvent(this._core.InnerEvent.DESTROY,this._dispose,this)}},ia=new class{constructor(){this._offlineSignalingMap=new Map}init(n){this._core=n;const{notificationCenter:r,helper:g,constants:{InnerEvent:u,WORKFLOW_STEP:E,WORKFLOW_NAME:m}}=n;r.subscribeInnerEvent(u.DESTROY,this._dispose,this),r.subscribeInnerEvent(u.LOGOUT,this._reset,this),g.registerWorkflowStep(m.SYNC_SERVER_INFO_AFTER_LOGIN,E.SIGNALING_MESSAGE_RECOVER,this._handleC2COfflineMessage,this)}_handleC2COfflineMessage(n){const{result:{unreadMessageMap:r}={}}=n||{};if(!(r?.size!==0&&Ho.getSignalingListenStatus()))return;const g=yr([...r.values()]);if(g.length!==0&&(g.forEach(u=>{this._handleC2CActionType(u)}),this._offlineSignalingMap.size>0)){const u=this._sortOfflineSignalingByTime();Ul.handleActionSignaling(u)}}_handleC2CActionType(n){const r=kc(n);if(!r)return;const{actionType:g}=r;g===Pu?this._saveValidOfflineInvite(r,n):this._removeOfflineInvite(r)}_saveValidOfflineInvite(n,r){const{inviteID:g,inviteeList:u=[],timeout:E=0}=n,m=this._core.common.getCurrentUserID();if(!u.includes(m))return;const D=Date.now()/1e3-r.time;E>0&&D>E&&E!==0||this._offlineSignalingMap.set(g,Object.assign(Object.assign({},n),{signalingList:[r]}))}_removeOfflineInvite(n){const{inviteID:r=""}=n;this._offlineSignalingMap.has(r)&&this._offlineSignalingMap.delete(r)}_sortOfflineSignalingByTime(){let n=[];return this._offlineSignalingMap.forEach(r=>{n=[...n,...r.signalingList]}),n.sort((r,g)=>r.time-g.time)}_dispose(){var n,r;this._reset(),(n=this._core)===null||n===void 0||n.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.LOGOUT,this._reset,this),(r=this._core)===null||r===void 0||r.notificationCenter.unSubscribeInnerEvent(this._core.InnerEvent.DESTROY,this._dispose,this)}_reset(){this._offlineSignalingMap.clear()}};const Ih={invite:{userID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0},timeout:{required:!1,rules:["number"],allowEmpty:!1},onlineUserOnly:{required:!1,rules:["boolean"],allowEmpty:!1},offlinePushInfo:{required:!1,rules:["object"],allowEmpty:!1}},cancel:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}},accept:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}},reject:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}},modifyInvitation:{inviteID:{required:!0,rules:["string"],allowEmpty:!1},data:{required:!1,rules:["string"],allowEmpty:!0}}},sn={invite:!0,cancel:!0,accept:!0,reject:!0,modifyInvitation:!0};var tu=new class{constructor(){this.name="Signaling"}install(n){Ag.init(n),Ul.init(n),ic.init(n),Ho.init(n),ia.init(n),n.helper.registerValidateConfig({auth:sn,params:Ih})}};const qs=new class{init(n){this.core=n}};function Lc(n){let r;const{message:g}=qs.core,{conversationID:u,messageID:E}=n;return r=g.messageDataHandler.getLocalMessageList(u).find(m=>m.ID===E),!r&&(r=g.messageDataHandler.getSparseMessageList(u).find(m=>m.ID===E)),r}function oc(n){return n.map(r=>{const{from:g,to:u,cloudCustomData:E,avatar:m,nick:D,ID:v,clientSequence:T,clientTime:P,messageRandom:W,messageSequence:oA,time:EA}=r;return{ClientSeq:T,CloudCustomData:E,From_Account:g,From_AccountHeadurl:m,From_AccountNick:D,Id:v,MsgBody:JSON.parse(JSON.stringify(r.transformElementsToServerFormat())),MsgClientTime:P,MsgRandom:W,Random:W,MsgSeq:oA,MsgTimeStamp:EA,ReceiverId:u,SenderId:g,To_Account:u}})}function Dr(n){var r;const{From_Account:g,From_AccountHeadurl:u,From_AccountNick:E,GroupId:m,MsgClientTime:D,ClientSeq:v,To_Account:T,MsgTimeStamp:P,TinyId:W,MsgRandom:oA,MsgSeq:EA}=n;return{from:g,avatar:u,nick:E,clientTime:D,time:P,tinyID:W,random:oA,sequence:EA,to:T,groupID:m,clientSequence:v,_elements:(r=n.MsgBody)===null||r===void 0?void 0:r.map(wA=>{const{MsgType:kA}=wA;return qs.core.message.messageFactory.getElementClass(kA).parseServerPushElement(wA)})}}var Kr,eg;(function(n){n.MSG_TEXT="TIMTextElem",n.MSG_CUSTOM="TIMCustomElem",n.MSG_LOCATION="TIMLocationElem",n.MSG_FACE="TIMFaceElem",n.MSG_STREAM="TIMStreamElem"})(Kr||(Kr={})),function(n){n[n.FORWARD=0]="FORWARD",n[n.BACKWARD=1]="BACKWARD"}(eg||(eg={}));const bE="MSG_REACTION",pC="MSG_EXT",uh=0,uo=1,Uc={ZH_CN:"zh (cmn-Hans-CN)",EN_US:"en-US",YUE_HK:"yue-Hant-HK",JA_JP:"ja-JP",ZH_PY:"zh-PY"},Fl="16k_zh",mC="16k_en",fC="16k_yue",Ol="16k_ja",iu="16k_zh-PY",yI={[Uc.ZH_CN]:Fl,[Uc.EN_US]:mC,[Uc.YUE_HK]:fC,[Uc.JA_JP]:Ol,[Uc.ZH_PY]:iu},DI=/\.(wav|pcm|ogg-opus|speex|silk|mp3|m4a|aac|amr)/,kE={READ:0,UNREAD:1},Pl=1,xl=2,Og=3;var sc;(function(n){n.IN="in",n.OUT="out"})(sc||(sc={}));const fd=16,LE=17;var Fc;(function(n){n[n.DATA=0]="DATA",n[n.REVOKED=1]="REVOKED"})(Fc||(Fc={}));var ou;(function(n){n[n.NORMAL=0]="NORMAL",n[n.TIMEOUT=1]="TIMEOUT"})(ou||(ou={}));const ho="StreamMsg.PushStreamHttp";var UE=new class{constructor(){this._reactionsMap=new Map}init(n){this._core=n;const{helper:r,notificationCenter:g,InnerEvent:{MESSAGE_PUSH:u},InnerEventSubType:{MESSAGE_REACTION_UPDATED:E,MESSAGE_REACTION_UPDATED_SYNC:m}}=n;r.registerApi({apiName:"addMessageReaction",context:this}),r.registerApi({apiName:"removeMessageReaction",context:this}),r.registerApi({apiName:"getMessageReactions",context:this}),r.registerApi({apiName:"getAllUserListOfMessageReaction",context:this}),g.subscribeInnerEvent(u,E,this._handleReactionUpdated,this),g.subscribeInnerEvent(u,m,this._handleReactionSync,this)}addMessageReaction(n,r){return mA(this,void 0,void 0,function*(){const{OuterConstant:g,ssoLog:u,helper:E}=this._core;this._validateMessageReactionBusinessCapability();const{conversationID:m,ID:D,conversationType:v,from:T,to:P,clientSequence:W,random:oA,time:EA,sequence:wA}=n,kA=`conversationID:${m} messageID:${D} reactionID:${r}`;try{return this._recordMessageReactedByMe(D,r),v===g.CONV_C2C?yield function(xA,LA){return mA(this,void 0,void 0,function*(){var SA;const{from:OA,to:WA,clientSequence:ue,random:le,time:ki,reactionID:Li}=xA,Yt={From_Account:OA,To_Account:WA,MsgKey:`${ue}_${le}_${ki}`,Reaction:Li,Add_Account:[(SA=LA.store.get("login"))===null||SA===void 0?void 0:SA.userId]};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_add",data:Yt})})}({from:T,to:P,clientSequence:W,random:oA,time:EA,reactionID:r},this._core):v===g.CONV_GROUP&&(yield function(xA,LA){return mA(this,void 0,void 0,function*(){var SA;const{to:OA,reactionID:WA,sequence:ue}=xA,le={GroupId:OA,MsgSeq:ue,Reaction:WA,Add_Account:[(SA=LA.store.get("login"))===null||SA===void 0?void 0:SA.userId]};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_add",data:le})})}({to:P,reactionID:r,sequence:wA},this._core)),{code:0,successLog:{message:kA}}}catch(xA){this._removeMyReactionRecord(D,r);const{errorCode:LA}=xA||{};throw new E.ChatError({functionName:"addMessageReaction",code:LA,moreMessage:kA})}})}removeMessageReaction(n,r){return mA(this,void 0,void 0,function*(){const{OuterConstant:g,helper:u}=this._core;this._validateMessageReactionBusinessCapability();const{conversationID:E,ID:m,conversationType:D,from:v,to:T,clientSequence:P,random:W,time:oA,sequence:EA}=n,wA=`conversationID:${E} messageID:${m} reactionID:${r}`;try{return this._removeMyReactionRecord(m,r),D===g.CONV_C2C?yield function(kA,xA){return mA(this,void 0,void 0,function*(){var LA;const{from:SA,to:OA,clientSequence:WA,random:ue,time:le,reactionID:ki}=kA,Li={From_Account:SA,To_Account:OA,MsgKey:`${WA}_${ue}_${le}`,Reaction:ki,Del_Account:[(LA=xA.store.get("login"))===null||LA===void 0?void 0:LA.userId]};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_del",data:Li})})}({from:v,to:T,clientSequence:P,random:W,time:oA,reactionID:r},this._core):D===g.CONV_GROUP&&(yield function(kA,xA){return mA(this,void 0,void 0,function*(){var LA;const{to:SA,reactionID:OA,sequence:WA}=kA,ue={GroupId:SA,MsgSeq:WA,Reaction:OA,Del_Account:[(LA=xA.store.get("login"))===null||LA===void 0?void 0:LA.userId]};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_del",data:ue},xA)})}({to:T,reactionID:r,sequence:EA},this._core)),{code:0,successLog:{message:wA}}}catch(kA){const{errorCode:xA}=kA||{};throw new u.ChatError({functionName:"removeMessageReaction",code:xA,moreMessage:wA})}})}getAllUserListOfMessageReaction(n){return mA(this,void 0,void 0,function*(){this._validateMessageReactionBusinessCapability();const{message:r,reactionID:g,nextSeq:u=0}=n,E=n.count>100?100:n.count,{conversationID:m}=r,{ssoLog:D,helper:v,constants:T}=this._core;try{let P=null;if(P=m.startsWith(T.OuterConstant.CONV_C2C)?yield function(W){return mA(this,void 0,void 0,function*(){const{message:oA,nextSeq:EA,reactionID:wA,count:kA}=W,{from:xA,to:LA,clientSequence:SA,random:OA,time:WA}=oA,ue={Reaction:wA,NextSeq:EA,Count:kA,From_Account:xA,To_Account:LA,MsgKey:`${SA}_${OA}_${WA}`};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_iterate",data:ue})})}({message:r,reactionID:g,nextSeq:u,count:E}):yield function(W){return mA(this,void 0,void 0,function*(){const{message:oA,nextSeq:EA,reactionID:wA,count:kA}=W,{sequence:xA,to:LA}=oA,SA={Reaction:wA,NextSeq:EA,GroupId:LA,Count:kA,MsgSeq:xA};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_iterate",data:SA})})}({message:r,reactionID:g,nextSeq:u,count:E}),P){const{Reaction_Account:W,NextSeq:oA}=P,EA=yield this._getUserProfileList(W);return{code:0,data:{nextSeq:oA,isCompleted:u===0,userList:EA}}}}catch(P){const{errorCode:W}=P||{};throw new v.ChatError({functionName:"getAllUserListOfMessageReaction",code:W})}})}getMessageReactions(n){return mA(this,void 0,void 0,function*(){const{constants:r}=this._core;this._validateMessageReactionBusinessCapability();const{messageList:g,maxUserCountPerReaction:u=10}=n,E=g[0];let m=null;const D=new Map,{from:v,to:T,conversationType:P}=E,W=this._generateMessageKeyList(g,D);P===r.OuterConstant.CONV_C2C?m=yield function(kA){return mA(this,void 0,void 0,function*(){const{from:xA,to:LA,messageKeyList:SA,maxUserCountPerReaction:OA}=kA,WA={From_Account:xA,To_Account:LA,MsgKeyList:SA,Count:OA};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.reaction_multi_stat",data:WA})})}({from:v,to:T,messageKeyList:W,maxUserCountPerReaction:u}):P===r.OuterConstant.CONV_GROUP&&(m=yield function(kA){return mA(this,void 0,void 0,function*(){const{groupId:xA,messageSequenceList:LA,maxUserCountPerReaction:SA}=kA,OA={GroupId:xA,MsgSeqList:LA,Count:SA};return qs.core.common.buildAndSendPacket({servcmd:"openim_msg_ext_http_svc.group_reaction_multi_stat",data:OA})})}({groupId:T,messageSequenceList:W,maxUserCountPerReaction:u}));const{Results:oA=[]}=m||{},EA=this._extractUserIDsFromReactionResults(oA),wA=yield this._getUserProfileMap(EA);return{code:0,data:{resultList:oA.map(kA=>{const{ReactionList:xA,MsgSeq:LA,MsgKey:SA}=kA;return{messageID:this._generateMessageID({messageSequence:LA,messageKey:SA,messageIDMap:D}),reactionList:xA.map(OA=>{const{Reaction:WA,Count:ue,Reaction_Account:le,ReactedByMe:ki}=OA;return{reactionID:WA,totalUserCount:ue,partialUserList:this._generatePartialUserInfo({userIDList:le,userProfileMap:wA}),reactedByMyself:ki===1}})}})}}})}dispose(){this._reactionsMap.clear()}_extractUserIDsFromReactionResults(n){const r=[];return n?.forEach(g=>{const{ReactionList:u=[]}=g;u.forEach(E=>{E.Reaction_Account&&r.push(...E.Reaction_Account)})}),r}_getUserProfileList(n){return mA(this,void 0,void 0,function*(){var r;try{const g=yield(r=this._core.user.userProfile)===null||r===void 0?void 0:r.getUserProfile({userIDList:n});return g?g.data:[]}catch{return[]}})}_getUserProfileMap(n){return mA(this,void 0,void 0,function*(){const r=new Map;return(yield this._getUserProfileList(n)).forEach(g=>{const{nick:u,avatar:E,userID:m}=g;r.set(m,{nick:u,avatar:E,userID:m})}),r})}_recordMessageReactedByMe(n,r){const g=`${n}-${r}`;this._reactionsMap.has(g)?this._reactionsMap.get(g).reactedByMe=!0:this._reactionsMap.set(g,{reactedByMe:!0})}_removeMyReactionRecord(n,r){const g=`${n}-${r}`;this._reactionsMap.has(g)&&(this._reactionsMap.get(g).reactedByMe=!1)}_recordMessageReactionInfo(n){const{messageID:r,reactionID:g,reactionInfo:u}=n,E=`${r}-${g}`,m=this._reactionsMap.get(E)||{};this._reactionsMap.set(E,Object.assign(Object.assign({},m),u))}_validateMessageReactionBusinessCapability(){const{helper:n,constants:r}=this._core;if(!n.checkBusinessCapabilityBits(bE))throw new n.ChatError({functionName:"addMessageReaction",code:r.ERROR_CODE.NO_USE,replacement1:"addMessageReaction"})}_handleReactionUpdated(n){const{MsgReactionNotifyList:r}=n,{notificationCenter:g,constants:u}=this._core;r.forEach(E=>mA(this,void 0,void 0,function*(){const{C2CMsgInfo:m,GroupMsgInfo:D,MsgReactionSummary:v}=E,{TinyId:T,MsgClientTime:P,MsgRandom:W}=Object.assign(Object.assign({},m),D),oA=`${T}-${P}-${W}`,EA=this._extractUserIDsFromReactionResults([{ReactionList:v}]),wA=yield this._getUserProfileMap(EA),kA=v.map(xA=>{var LA;const{Reaction:SA,Reaction_Account:OA}=xA,WA=this._generatePartialUserInfo({userIDList:OA,userProfileMap:wA}),ue=OA?xA.Count:0,le=((LA=this._reactionsMap.get(`${oA}-${SA}`))===null||LA===void 0?void 0:LA.reactedByMe)||!1;return this._recordMessageReactionInfo({messageID:oA,reactionID:SA,reactionInfo:{reactionID:SA,totalUserCount:ue,partialUserList:WA}}),{reactionID:SA,totalUserCount:ue,partialUserList:WA,reactedByMyself:le}});g.emitOuterEvent(u.OuterEvent.MESSAGE_REACTIONS_UPDATED,{name:u.OuterEvent.MESSAGE_REACTIONS_UPDATED,data:{messageID:oA,reactionList:kA}})}))}_handleReactionSync(n){var r;const{notificationCenter:g,constants:u}=this._core,{C2CMsgInfo:E={},GroupMsgInfo:m={},Reaction:D,OperateType:v}=n.MsgReactionNotify,{TinyId:T="",MsgClientTime:P=0,MsgRandom:W=0}=Object.assign(Object.assign({},E),m),oA=`${T}-${P}-${W}`,EA=`${oA}-${D}`;if(v===1?this._recordMessageReactedByMe(oA,D):this._removeMyReactionRecord(oA,D),(r=this._reactionsMap.get(EA))===null||r===void 0?void 0:r.reactionID){const wA=this._reactionsMap.get(EA);wA.reactedByMyself=v===1,g.emitOuterEvent(u.OuterEvent.MESSAGE_REACTIONS_UPDATED,{name:u.OuterEvent.MESSAGE_REACTIONS_UPDATED,data:{messageID:oA,reactionList:[wA]}})}}_generatePartialUserInfo({userIDList:n,userProfileMap:r}){const g=[];return n?.forEach(u=>{r.has(u)&&g.push(r.get(u))}),g}_generateMessageID(n){const{messageSequence:r,messageKey:g,messageIDMap:u}=n;return g?u.get(g):u.get(r)}_generateMessageKeyList(n,r){const{constants:g}=this._core,u=n[0],{conversationType:E}=u;let m=[];return E===g.OuterConstant.CONV_C2C?m=n.map(D=>{const{clientSequence:v,random:T,time:P,ID:W}=D,oA=`${v}_${T}_${P}`;return r.set(oA,W),oA}):E===g.OuterConstant.CONV_GROUP&&(m=n.map(D=>{const{ID:v,sequence:T}=D;return r.set(T,v),T})),m}},tg=new class{init(n){this._core=n;const{helper:r,InnerEvent:{MESSAGE_PUSH:g},InnerEventSubType:{C2C_MESSAGE_READ_RECEIPT:u,GROUP_MESSAGE_READ_RECEIPT:E},notificationCenter:m}=n;r.registerApi({apiName:"sendMessageReadReceipt",context:this}),r.registerApi({apiName:"getMessageReadReceiptList",context:this}),r.registerApi({apiName:"getGroupMessageReadMemberList",context:this}),m.subscribeInnerEvent(g,u,this._handleC2CMessageReadReceipt,this),m.subscribeInnerEvent(g,E,this._handleGroupMessageReadReceipt,this)}sendMessageReadReceipt(n){return mA(this,void 0,void 0,function*(){var r;const{common:g,constants:u}=this._core,E=this._filterValidMessageSendByOther(n);if(E.length===0)throw new g.ChatError({code:u.ERROR_CODE.READ_RECEIPT_MSG_LIST_EMPTY});try{const{conversationType:m}=E[0];return m===u.OuterConstant.CONV_C2C?yield function(D){return mA(this,void 0,void 0,function*(){const{common:v,constants:T}=qs.core,P=D[0].conversationID.replace(T.OuterConstant.CONV_C2C,""),W=D.map(EA=>{const{from:wA,to:kA,sequence:xA,random:LA,time:SA,clientTime:OA}=EA;return{From_Account:wA,To_Account:kA,MsgSeq:xA,MsgRandom:LA,MsgTime:SA,MsgClientTime:OA}}),oA={Peer_Account:P,C2CMsgInfo:W};return v.buildAndSendPacket({servcmd:"openim.c2c_msg_read_receipt",data:oA})})}(E):yield function(D){return mA(this,void 0,void 0,function*(){const{common:v,constants:T}=qs.core,P={GroupId:D[0].conversationID.replace(T.OuterConstant.CONV_GROUP,""),MsgSeqList:D.map(W=>({MsgSeq:W.sequence}))};return v.buildAndSendPacket({servcmd:"group_open_http_svc.group_msg_receipt",data:P})})}(E),{code:0,data:{}}}catch(m){const{errorCode:D,errorInfo:v}=m;throw new g.ChatError({code:D,message:v,moreMessage:`peerAccount:${(r=E?.[0])===null||r===void 0?void 0:r.conversationID}`})}})}getMessageReadReceiptList(n){return mA(this,void 0,void 0,function*(){const{common:r,constants:g}=this._core;try{const{conversationType:u}=n[0];if(u===g.OuterConstant.CONV_GROUP){const E=this._filterValidMessageSendByMe(n);if(E?.length>0){const m=yield function(v){return mA(this,void 0,void 0,function*(){const{common:T,constants:P}=qs.core,W={GroupId:v[0].conversationID.replace(P.OuterConstant.CONV_GROUP,""),MsgSeqList:v.map(oA=>({MsgSeq:oA.sequence}))};return T.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_msg_receipt",data:W})})}(E),{GroupMsgReceiptList:D}=m||{};this._updateGroupMessagesReadReceiptInfo({messageList:n,readReceiptList:D})}}return{code:0,data:{messageList:n}}}catch(u){const{errorCode:E,errorInfo:m}=u;throw new r.ChatError({code:E,message:m})}})}getGroupMessageReadMemberList(n){return mA(this,void 0,void 0,function*(){const{constants:r,common:g}=this._core,{message:u,filter:E=kE.READ,cursor:m=""}=n,{conversationID:D,sequence:v,ID:T}=u,P=D.replace(r.OuterConstant.CONV_GROUP,""),W=n.count>=100?100:n.count;try{const oA=yield function(EA){return mA(this,void 0,void 0,function*(){const{sequence:wA,groupID:kA,filter:xA,cursor:LA,count:SA}=EA,OA={MsgSeq:wA,GroupId:kA,Filter:xA,Cursor:LA,Num:SA};return qs.core.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_msg_receipt_detail",data:OA})})}({groupID:P,sequence:v,filter:E,cursor:m,count:W});if(oA){const{Cursor:EA,IsFinish:wA,UnreadList:kA,ReadList:xA}=oA,LA={cursor:EA,isCompleted:wA===1,messageID:T,unreadUserIDList:[],readUserIDList:[]};return E===kE.READ?LA.readUserIDList=xA.map(SA=>SA.Read_Account):E===kE.UNREAD&&(LA.unreadUserIDList=kA.map(SA=>SA.Unread_Account)),{code:0,data:LA}}}catch(oA){const{errorCode:EA,errorInfo:wA}=oA;throw new g.ChatError({code:EA,message:wA})}})}_handleC2CMessageReadReceipt(n){const r=[],{constants:g,helper:u}=this._core,{C2cMsgInfo:E,PeerReadTime:m,Peer_Account:D}=n;if(u.isEmpty(E))return;const v=`${g.OuterConstant.CONV_C2C}${D}`;E?.forEach(T=>{const{TinyId:P,MsgClientTime:W,MsgRandom:oA}=T,EA=`${P}-${W}-${oA}`,wA=Lc({conversationID:v,messageID:EA});wA&&!wA.readReceiptInfo.isPeerRead&&(wA.readReceiptInfo.isPeerRead=!0,wA.readReceiptInfo.timestamp=m,r.push({userID:D,messageID:EA,isPeerRead:!0,timestamp:m}))}),this._emitReadReceiptEventIfNeed(r)}_updateGroupMessagesReadReceiptInfo(n){const{messageList:r,readReceiptList:g}=n,u=new Map;r.forEach(E=>{u.set(E.sequence,E)}),g?.forEach(E=>{if(E.Code===0){const{MsgSeq:m,ReadNum:D,UnreadNum:v}=E,T=u.get(m);T&&(T.readReceiptInfo.readCount=D,T.readReceiptInfo.unreadCount=v)}})}_handleGroupMessageReadReceipt(n){const r=[],{constants:g}=this._core,{GroupTips:u}=n;u.forEach(E=>{const{MsgBody:{GroupMsgReceiptList:m},GroupInfo:{GroupId:D}}=E,v=`${g.OuterConstant.CONV_GROUP}${D}`;m?.forEach(T=>{const{TinyId:P,MsgClientTime:W,MsgRandom:oA,ReadNum:EA,UnreadNum:wA}=T,kA=`${P}-${W}-${oA}`,xA=Lc({conversationID:v,messageID:kA}),LA={groupID:D,messageID:kA,readCount:0,unreadCount:0};xA&&(typeof EA=="number"&&(xA.readReceiptInfo.readCount=EA,LA.readCount=EA),typeof wA=="number"&&(xA.readReceiptInfo.unreadCount=wA,LA.unreadCount=wA),r.push(LA))})}),this._emitReadReceiptEventIfNeed(r)}_emitReadReceiptEventIfNeed(n){const{notificationCenter:r,OuterEvent:g}=this._core;n.length>0&&r.emitOuterEvent(g.MESSAGE_READ_RECEIPT_RECEIVED,{name:g.MESSAGE_READ_RECEIPT_RECEIVED,data:n})}_filterValidMessageSendByOther(n){return this._filterNeedReadReceiptMessages(n).filter(r=>{const{from:g}=r;return g!==this._core.common.getCurrentUserID()})}_filterValidMessageSendByMe(n){const{OuterConstant:r}=this._core.constants;return this._filterNeedReadReceiptMessages(n).filter(g=>{const{from:u,status:E}=g;return u===this._core.common.getCurrentUserID()&&E===r.MessageStatus.SUCCESS})}_filterNeedReadReceiptMessages(n){return n.filter(r=>r.needReadReceipt===!0)}dispose(){const{InnerEvent:{MESSAGE_PUSH:n},InnerEventSubType:{C2C_MESSAGE_READ_RECEIPT:r,GROUP_MESSAGE_READ_RECEIPT:g},notificationCenter:u}=this._core;u.unSubscribeInnerEvent(n,r,this._handleC2CMessageReadReceipt,this),u.unSubscribeInnerEvent(n,g,this._handleGroupMessageReadReceipt,this)}};function su(n,r,g){return mA(this,void 0,void 0,function*(){const{common:{buildAndSendPacket:u}}=qs.core,{from:E,to:m,clientSequence:D,random:v,time:T}=n;return u({servcmd:"openim_msg_ext_http_svc.set_key_values",data:{From_Account:E,To_Account:m,MsgKey:`${D}_${v}_${T}`,OperateType:g,ExtensionList:r}})})}function Yu(n,r,g){return mA(this,void 0,void 0,function*(){const{common:{buildAndSendPacket:u}}=qs.core,{to:E,sequence:m}=n;return u({servcmd:"openim_msg_ext_http_svc.group_set_key_values",data:{GroupId:E,MsgSeq:m,OperateType:g,ExtensionList:r}})})}var Oc=new class{constructor(){this._messageExtensionsMap=new Map,this._extensionsLatestSequenceMap=new Map,this._completedFetchExtensions=new Set}init(n){this._core=n;const{notificationCenter:r,helper:{registerApi:g},InnerEvent:{MESSAGE_PUSH:u,LOGOUT:E},InnerEventSubType:{MESSAGE_EXTENSIONS_UPDATED:m}}=n;g({apiName:"setMessageExtensions",context:this}),g({apiName:"getMessageExtensions",context:this}),g({apiName:"deleteMessageExtensions",context:this}),r.subscribeInnerEvent(u,m,this._handleMessageExtensionsNotify,this),r.subscribeInnerEvent(E,this.reset,this)}setMessageExtensions(n,r){return mA(this,void 0,void 0,function*(){this._validateMessageExtensionBusinessCapability("setMessageExtensions");const{constants:{OuterConstant:g},ssoLog:u}=this._core,{ID:E,conversationID:m,sequence:D,time:v,conversationType:T}=n;let P=r;r.length>20&&(P=r.slice(0,20),u.warn("setMessageExtensions","the length of extensions cannot exceed 20"));const W=this._generateServerExtensions(n,P),oA=`convID:${m} messageID:${E} sequence:${D} time:${v} count:${P.length}`;try{let EA;if(T===g.CONV_C2C?EA=yield su(n,W,Pl):T===g.CONV_GROUP&&(EA=yield Yu(n,W,Pl)),EA){const{resultList:wA,successCount:kA,failureCount:xA}=this._handleModifyMessageExtensions(n,EA);return{code:0,data:{extensions:wA},successLog:{message:`${oA} successCount:${kA} failCount:${xA}`}}}return{code:0,data:{extensions:[]}}}catch(EA){const{errorCode:wA}=EA;throw new this._core.helper.ChatError({functionName:"setMessageExtensions",code:wA,moreMessage:oA})}})}getMessageExtensions(n){return mA(this,void 0,void 0,function*(){const{utils:{isUndefined:r}}=this._core;this._validateMessageExtensionBusinessCapability("getMessageExtensions");const{conversationID:g,ID:u,sequence:E,time:m}=n,D=`convID:${g} messageID:${u} sequence:${E} time:${m}`;try{let v;this._completedFetchExtensions.has(u)&&(v=this._extensionsLatestSequenceMap.get(u));const T=yield this._fetchMessageExtensions(n,v);return r(v)&&T.length>1&&this._completedFetchExtensions.add(u),{code:0,data:{extensions:T},successLog:{message:D}}}catch(v){const{errorCode:T,errorInfo:P=""}=v||{};throw new this._core.common.ChatError({code:T,message:P,moreMessage:D})}})}deleteMessageExtensions(n,r){return mA(this,void 0,void 0,function*(){this._validateMessageExtensionBusinessCapability("deleteMessageExtensions");const{utils:{isEmpty:g},constants:{OuterConstant:u}}=this._core,{conversationType:E,conversationID:m,sequence:D,ID:v,time:T}=n;let P=Og;const W=[];g(r)||(P=xl,r?.forEach(wA=>{W.push({key:wA,value:"",seq:0})}));const oA=`convID:${m} messageID:${v} sequence:${D} time:${T} operateType:${P}`,EA=this._generateServerExtensions(n,W);try{let wA;if(E===u.CONV_C2C?wA=yield su(n,EA,P):E===u.CONV_GROUP&&(wA=yield Yu(n,EA,P)),wA){const{resultList:kA,successCount:xA,failureCount:LA}=this._handleModifyMessageExtensions(n,wA);return{code:0,data:{extensions:kA},successLog:{message:`${oA}successCount:${xA} failCount:${LA}`}}}return{code:0,data:{extensions:[]}}}catch(wA){const{errorCode:kA}=wA;throw new this._core.helper.ChatError({functionName:"deleteMessageExtensions",code:kA,moreMessage:oA})}})}reset(){this._messageExtensionsMap.clear(),this._extensionsLatestSequenceMap.clear(),this._completedFetchExtensions.clear()}dispose(){this.reset();const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:r,LOGOUT:g},InnerEventSubType:{MESSAGE_EXTENSIONS_UPDATED:u}}=this._core;n.unSubscribeInnerEvent(r,u,this._handleMessageExtensionsNotify,this),n.subscribeInnerEvent(g,this.reset,this)}_handleModifyMessageExtensions(n,r){const{ID:g}=n,{Seq:u}=r,E=r.ExtensionList||[],m=[];let D=0,v=0,T=[];return E.forEach(P=>{const{ErrorCode:W,Extension:oA}=P,{Key:EA,Value:wA,Seq:kA}=oA;m.push({code:W,key:EA,value:wA}),W===0?D++:v++,T.push({key:EA,value:wA,seq:kA})}),this._extensionsLatestSequenceMap.set(g,u),T.length>0&&this._updateLocalExtensions(n.ID,T),{resultList:m,successCount:D,failureCount:v}}_updateLocalExtensions(n,r){this._messageExtensionsMap.has(n)||this._messageExtensionsMap.set(n,new Map);const g=this._messageExtensionsMap.get(n);r?.forEach(u=>{const{key:E,seq:m,value:D=""}=u;g?.set(E,{value:D,seq:m})})}_fetchMessageExtensions(n,r){return mA(this,void 0,void 0,function*(){const{constants:{OuterConstant:g},utils:{isEmpty:u}}=this._core;try{let E;const{conversationType:m,ID:D}=n;if(m===g.CONV_C2C?E=yield function(v,T){const{common:{buildAndSendPacket:P}}=qs.core,{from:W,to:oA,clientSequence:EA,random:wA,time:kA}=v;return P({servcmd:"openim_msg_ext_http_svc.get_key_values",data:{From_Account:W,To_Account:oA,MsgKey:`${EA}_${wA}_${kA}`,StartSeq:T}})}(n,r):m===g.CONV_GROUP&&(E=yield function(v,T){const{common:{buildAndSendPacket:P}}=qs.core,{to:W,sequence:oA}=v;return P({servcmd:"openim_msg_ext_http_svc.group_get_key_values",data:{GroupId:W,MsgSeq:oA,StartSeq:T}})}(n,r)),E){const{LatestSeq:v,ClearSeq:T,CompleteFlag:P}=E,W=(E.ExtensionList||[]).map(EA=>({key:EA.Key,value:EA.Value,seq:EA.Seq}));if(this._updateLocalExtensions(D,W),this._clearLocationExtensions(D,T),this._extensionsLatestSequenceMap.set(D,v),P!==1){const EA=W[W.length-1].seq+1;return this._fetchMessageExtensions(n,EA)}const oA=[];if(this._messageExtensionsMap.has(D)){const EA=this._messageExtensionsMap.get(D);EA?.forEach((wA,kA)=>{const{value:xA}=wA;u(xA)||oA.push({key:kA,value:xA})})}return oA}}catch(E){throw E}})}_clearLocationExtensions(n,r){if(!(r<=0)&&this._messageExtensionsMap.has(n)){const g=this._messageExtensionsMap.get(n);g?.forEach((u,E)=>{u.seq<=r&&g.delete(E)})}}_generateServerExtensions(n,r){const{ID:g}=n;if(this._messageExtensionsMap.has(g)){const u=this._messageExtensionsMap.get(g);return r.map(E=>{var m;const{key:D,value:v}=E;let T=0;return u?.has(D)&&(T=(m=u.get(D))===null||m===void 0?void 0:m.seq),{Key:D,Value:v,Seq:T}})}return r.map(u=>({Key:u.key,Value:u.value,Seq:0}))}_validateMessageExtensionBusinessCapability(n){const{helper:r,constants:g}=this._core;if(!r.checkBusinessCapabilityBits(pC))throw new r.ChatError({functionName:n,code:g.ERROR_CODE.NO_USE,replacement1:n})}_handleMessageExtensionsNotify(n){const{SetKVInfo:r,DeleteKVInfo:g,ClearKVInfo:u,MsgOptType:E,TinyId:m,MsgLastSeq:D,ExtensionC2cMsgInfo:v,ExtensionGroupMsgInfo:T}=n?.MsgExtensionNotify||{},P=v||T||{},{MsgClientTime:W,MsgRandom:oA}=P,EA=`${m}-${W}-${oA}`;this._extensionsLatestSequenceMap.set(EA,D),E===Pl?this._handleMessageExtensionsUpdated({messageID:EA,updateMessageExtensionsInfo:r}):E===xl?this._handleMessageExtensionsDeleted({messageID:EA,deleteMessageExtensionsInfo:g}):E===Og&&this._handleMessageExtensionsCleared({messageID:EA,clearMessageExtensionsInfo:u})}_handleMessageExtensionsUpdated(n){const{notificationCenter:r,OuterEvent:g}=this._core,{messageID:u,updateMessageExtensionsInfo:E=[]}=n,m=[];E.forEach(D=>{const{MsgKeyValue:v=[]}=D,T=v.map(P=>(m.push({key:P.Key,value:P.Value}),{key:P.Key,value:P.Value,seq:P.Seq}));this._updateLocalExtensions(u,T)}),r.emitOuterEvent(g.MESSAGE_EXTENSIONS_UPDATED,{name:g.MESSAGE_EXTENSIONS_UPDATED,data:{messageID:u,extensions:m}})}_handleMessageExtensionsDeleted(n){const{notificationCenter:r,OuterEvent:g}=this._core,{messageID:u,deleteMessageExtensionsInfo:E=[]}=n,m=[];E.forEach(D=>{const{MsgKeyValue:v=[]}=D,T=v.map(P=>(m.push(P.Key),{key:P.Key,seq:P.Seq}));this._updateLocalExtensions(u,T)}),r.emitOuterEvent(g.MESSAGE_EXTENSIONS_DELETED,{name:g.MESSAGE_EXTENSIONS_DELETED,data:{messageID:u,keyList:m}})}_handleMessageExtensionsCleared(n){const{notificationCenter:r,OuterEvent:{MESSAGE_EXTENSIONS_DELETED:g},utils:{isEmpty:u}}=this._core,{messageID:E,clearMessageExtensionsInfo:m=[]}=n,D=[];m.forEach(v=>{const{ClearMsgSeq:T}=v;this._messageExtensionsMap.has(E)&&(this._messageExtensionsMap.get(E)||[]).forEach((P,W)=>{P.seq<=T&&!u(P.value)&&D.push(W)}),this._clearLocationExtensions(E,T)}),r.emitOuterEvent(g,{name:g,data:{messageID:E,keyList:D}})}};const SI={key:"message",required:!0,rules:["object"],allowEmpty:!1,customValidator:n=>{const{constants:{OuterConstant:r}}=qs.core;return n.status!==r.MessageStatus.SUCCESS?"message is not success":n.isSupportExtension===!0||"message is not support extension"}},ll={setMessageExtensions:[SI,{key:"extensions",required:!0,rules:["array"],allowEmpty:!1}],getMessageExtensions:[SI],deleteMessageExtensions:[SI]},Il=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({deleteMessage:[{required:!0,rules:["array"],allowEmpty:!1}],revokeMessage:[{required:!0,rules:["object"],allowEmpty:!1}],resendMessage:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"options",required:!1,rules:["object"],allowEmpty:!1}],getMessageList:{conversationID:{required:!0,rules:["string"],allowEmpty:!1},nextReqMessageID:{required:!1,rules:["string"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0}},getMessageListHopping:{conversationID:{required:!0,rules:["string"],allowEmpty:!1},sequence:{required:!1,rules:["number"],allowEmpty:!0},direction:{required:!1,rules:["number"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0}},createTextAtMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1,customValidator:n=>{const r=function(g){var u;return typeof g?.text!="string"||typeof g.text=="string"&&((u=g?.text)===null||u===void 0?void 0:u.length)===0?"payload.text is invalid.":!0}(n);return r!==!0?r:!(n?.atUserList&&!Array.isArray(n.atUserList))||"atUserList should be an array or undefind."}}},findMessage:[{required:!0,rules:["string"],allowEmpty:!1}],translateText:{sourceTextList:{required:!0,rules:["array"],allowEmpty:!1},sourceLanguage:{required:!0,rules:["string"],allowEmpty:!1},targetLanguage:{required:!0,rules:["string"],allowEmpty:!1}},createForwardMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1,customValidator:n=>!(!n.startsWith("C2C")&&!n.startsWith("GROUP"))||"conversationType is invalid."},payload:{required:!0,rules:["object"],allowEmpty:!1}},createLocationMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1,customValidator:n=>{const{utils:{isString:r,isNumber:g}}=qs.core;return r(n?.description)?g(n?.longitude)?!!g(n?.latitude)||"payload.latitude must be a number.":"payload.longitude must be a number.":"payload.description must be a string."}}}},{addMessageReaction:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"reactionID",required:!0,rules:["string"],allowEmpty:!1}],removeMessageReaction:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"reactionID",required:!0,rules:["string"],allowEmpty:!1}],getMessageReactions:{messageList:{required:!0,rules:["array"],allowEmpty:!1},maxUserCountPerReaction:{required:!1,rules:["number"],allowEmpty:!0,customValidator:n=>typeof n!="number"?"maxUserCountPerReaction is invalid.":!(n<0||n>10)||"maxUserCountPerReaction should between [0, 10]."}},getAllUserListOfMessageReaction:{message:{required:!0,rules:["object"],allowEmpty:!1,customValidator:n=>n.status==="success"||"message is invalid."},reactionID:{required:!0,rules:["string"],allowEmpty:!1},nextSeq:{required:!1,rules:["number"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0}}}),{sendMessageReadReceipt:[{required:!0,rules:["array"],allowEmpty:!1}],getMessageReadReceiptList:[{required:!0,rules:["array"],allowEmpty:!1}],getGroupMessageReadMemberList:{message:{required:!0,rules:["object"],allowEmpty:!1},filter:{required:!1,rules:["number"],allowEmpty:!0},count:{required:!1,rules:["number"],allowEmpty:!0},cursor:{required:!1,rules:["string"],allowEmpty:!0}}}),ll),{pinGroupMessage:{groupID:{required:!0,rules:["string"],allowEmpty:!1},message:{required:!0,rules:["object"],allowEmpty:!1},isPinned:{required:!0,rules:["boolean"],allowEmpty:!1}},getPinnedGroupMessageList:[{key:"groupID",required:!0,rules:["string"],allowEmpty:!1}]}),{createQuoteMessage:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"quotedMessage",required:!0,rules:["object"],allowEmpty:!1}]}),Ha=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({deleteMessage:!0,revokeMessage:!0,resendMessage:!0,getMessageList:!0,getMessageListHopping:!0,createTextAtMessage:!0,findMessage:!0,translateText:!0,createForwardMessage:!0,createLocationMessage:!0},{addMessageReaction:!0,removeMessageReaction:!0,getMessageReactions:!0,getAllUserListOfMessageReaction:!0}),{sendMessageReadReceipt:!0,getMessageReadReceiptList:!0,getGroupMessageReadMemberList:!0}),{setMessageExtensions:!0,getMessageExtensions:!0,deleteMessageExtensions:!0}),{pinGroupMessage:!0,getPinnedGroupMessageList:!0}),{createQuoteMessage:!0});class FE{constructor(r){this._core=r}deleteMessage(r){return mA(this,void 0,void 0,function*(){const{to:g,messageIdentifiers:u}=r,E={From_Account:this._core.common.getCurrentUserID(),To_Account:g,MsgKeyList:u};return this._core.common.buildAndSendPacket({servcmd:"openim.delete_c2c_msg_ramble",data:E})})}revokeMessage(r){return mA(this,void 0,void 0,function*(){const{to:g,from:u,sequence:E,time:m,random:D}=r,v={MsgInfo:{From_Account:u,To_Account:g,MsgSeq:E,MsgRandom:D,MsgTimeStamp:m}};return this._core.common.buildAndSendPacket({servcmd:"openim.msgwithdraw",data:v})})}}class la{constructor(r){this._core=r}deleteMessage(r){return mA(this,void 0,void 0,function*(){const{to:g,messageIdentifiers:u}=r,E={GroupId:g,Deleter_Account:this._core.common.getCurrentUserID(),Seqs:u};return this._core.common.buildAndSendPacket({servcmd:"group_open_http_svc.delete_group_ramble_msg_by_seq",data:E})})}revokeMessage(r){return mA(this,void 0,void 0,function*(){const{to:g,sequence:u}=r,E={GroupId:g,MsgSeqList:[{MsgSeq:u}]};return this._core.common.buildAndSendPacket({servcmd:"group_open_http_svc.group_msg_recall",data:E})})}}const Nn=2116;class Fr{constructor(r){this._core=r}generateRevokeMessage(r){const{conversationID:g,sequence:u,random:E,tinyID:m,clientTime:D,revokeReason:v,revoker:T}=r;let P={};const{messageDataHandler:W}=this._core.message;return P=W.revokeMessage({conversationID:g,sequence:u,random:E,revoker:T}),P||(P={conversationID:g,sequence:u},m&&D&&E&&(P.ID=`${m}-${D}-${E}`)),P.revoker=T,P.revokeReason=v,P.revokerInfo={userID:T,nick:"",avatar:""},P}updateRevokerInfo(r){return mA(this,void 0,void 0,function*(){const g=r.map(u=>u.revoker);try{const u=yield this._fetchUserInfos(g);u&&r.forEach(E=>{const{revoker:m}=E;u[m]&&(E.revokerInfo.nick=u[m].nick||"",E.revokerInfo.avatar=u[m].avatar||"",E.revokerInfo.userID=m)})}catch(u){console.debug(u)}})}_fetchUserInfos(r){return mA(this,void 0,void 0,function*(){var g,u;const E=yield(g=this._core.user.userProfile)===null||g===void 0?void 0:g.getUserProfile({userIDList:r});return E?.data?(u=E.data)===null||u===void 0?void 0:u.reduce((m,{userID:D,nick:v,avatar:T})=>(m[D]={nick:v||"",avatar:T||""},m),{}):null})}}var ul=new class{constructor(){this._core=null,this._c2cMessageAction=null,this._groupMessageAction=null}init(n){this._core=n,this._groupMessageAction=new la(n),this._c2cMessageAction=new FE(n),this._messageHelper=new Fr(n);const{helper:r}=n;r.registerApi({apiName:"deleteMessage",context:this}),r.registerApi({apiName:"revokeMessage",context:this}),r.registerApi({apiName:"resendMessage",context:this}),r.registerApi({apiName:"findMessage",context:this}),r.registerApi({apiName:"createQuoteMessage",context:this})}deleteMessage(n){return mA(this,void 0,void 0,function*(){let r=[],g=[];const{conversationID:u,conversationType:E}=n[0],m=u.replace(E,"");if(E==="@TIM#SYSTEM")throw new this._core.helper.ChatError({code:Nn});if(n.forEach(D=>{const{conversationID:v,conversationType:T,status:P,_onlineOnlyFlag:W,sequence:oA,random:EA,time:wA}=D||{};if(P==="success"&&v===u&&T===E){if(!W){const kA=T==="C2C"?`${oA}_${EA}_${wA}`:String(oA);r.push(kA)}g.push(D)}}),r.length===0)return this._handleDeleteMessageSuccess(g),{code:0,data:{messageList:g}};r.length>30&&(r=r.slice(0,30),g=g.slice(0,30));try{return E==="C2C"?yield this._c2cMessageAction.deleteMessage({to:m,messageIdentifiers:r}):yield this._groupMessageAction.deleteMessage({to:m,messageIdentifiers:r}),this._handleDeleteMessageSuccess(g),{code:0,data:{messageList:g}}}catch(D){const{utils:{safeStringify:v}}=this._core,{errorCode:T,errorInfo:P}=D;throw new this._core.helper.ChatError({functionName:"deleteMessage",code:T,message:P,moreMessage:`messageIdentifiers: ${v(r)}`})}})}revokeMessage(n){return mA(this,void 0,void 0,function*(){var r;const{conversationType:g,isRevoked:u,ID:E,type:m,from:D,to:v}=n;let T=null;const P=`type:${m} from:${D} to:${v} ID:${E}`;if(g==="@TIM#SYSTEM")throw new this._core.helper.ChatError({message:"system message cannot be revoked"});if(u)throw new this._core.helper.ChatError({message:"message has been revoked",moreMessage:P});try{if(T=g==="C2C"?yield this._c2cMessageAction.revokeMessage(n):yield this._groupMessageAction.revokeMessage(n),T){const{RecallRetList:W}=T,oA=((r=W?.[0])===null||r===void 0?void 0:r.RetCode)||0;if(oA!==0)throw new this._core.helper.ChatError({code:oA,moreMessage:P});return n.isRevoked=!0,yield this._handleRevokeMessageSuccess(n),{code:0,data:{message:n},successLog:{message:P}}}}catch(W){const{errorCode:oA}=W;throw new this._core.helper.ChatError({functionName:"revokeMessage",code:oA,moreMessage:P})}})}resendMessage(n,r){return mA(this,void 0,void 0,function*(){var g,u;return n.isResend=!0,n.status="unSend",(u=(g=this._core)===null||g===void 0?void 0:g.apiMap)===null||u===void 0?void 0:u.sendMessage(n,r)})}findMessage(n){return this._core.message.messageDataHandler.findMessage(n)}createQuoteMessage(n,r){const{ID:g,time:u,sequence:E}=r;return n.quoteInfo={msgID:g,messageTime:u,messageSequence:E},n}_handleDeleteMessageSuccess(n){if(n.length===0)return;const{message:{messageDataHandler:r},common:{isTopic:g},notificationCenter:u,InnerEvent:E}=this._core;n.forEach(D=>{D.isDeleted=!0;const v=r.getLocalMessageList(D.conversationID);v?.forEach(T=>{T.ID===D.ID&&(T.isDeleted=!0)})});const{conversationID:m=""}=n[0];g(m)?u.emitInnerEvent(E.TOPIC_MESSAGE_DELETED,m):u.emitInnerEvent(E.MESSAGE_DELETED,m)}_handleRevokeMessageSuccess(n){return mA(this,void 0,void 0,function*(){var r;const g=(r=this._core.store.get("login"))===null||r===void 0?void 0:r.userId,{conversationID:u,sequence:E,random:m}=n;this._core.message.messageDataHandler.revokeMessage({conversationID:u,sequence:E,random:m,revoker:g}),yield this._messageHelper.updateRevokerInfo([n])})}};class Yl{static parseServerPushElement(r){const{MsgContent:g={}}=r,{Index:u,Data:E}=g;return new Yl({index:u,data:E})}constructor(r){this.type=Kr.MSG_FACE;const{index:g,data:u}=r;this.content={index:g,data:u}}validateBeforeSend(){var r,g;return typeof((r=this.content)===null||r===void 0?void 0:r.index)=="number"&&typeof((g=this.content)===null||g===void 0?void 0:g.data)=="string"?{isValid:!0}:{isValid:!1,error:{message:"content is invalid"}}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{index:E,data:m}=u;return{MsgType:this.type,MsgContent:{Index:E,Data:m}}}}class Pc{static parseServerPushElement(r){const{MsgContent:g={}}=r,{Desc:u,Longitude:E,Latitude:m}=g;return new Pc({description:u,longitude:E,latitude:m})}constructor(r){this.type=Kr.MSG_LOCATION;const{description:g,longitude:u,latitude:E}=r;this.content={description:g,longitude:u,latitude:E}}validateBeforeSend(){return{isValid:!0}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{description:E,longitude:m,latitude:D}=u;return{MsgType:this.type,MsgContent:{Desc:E,Longitude:m,Latitude:D}}}}class OE{static parseServerPushElement(r){const{MsgContent:g={}}=r,{StreamMsgID:u,CompatibleText:E,Markdown:m,BinaryData:D,ErrorCode:v,ErrorMsg:T}=g;return new OE({streamMessageID:u,compatibleText:E,markdown:m,binaryData:D,errorCode:v,errorMessage:T})}constructor(r){this.type=Kr.MSG_STREAM,this.content={streamMessageID:"",compatibleText:"",errorCode:0,errorMessage:"",isStreamEnded:!1},this._chunks=[],this._latestIndex=0;const{streamMessageID:g,compatibleText:u,markdown:E,binaryData:m,errorCode:D=0,errorMessage:v="",isStreamEnded:T=!1,chunks:P=[],latestIndex:W=0}=r;this.content.streamMessageID=g,this.content.compatibleText=u,this.content.markdown=E,this.content.binaryData=m,this.content.errorCode=D,this.content.errorMessage=v,this.content.isStreamEnded=T,this.content.chunks=P,this.content.latestIndex=W}updateChunks(r){if(!r||r.length===0)return;const g=r.sort((m,D)=>m.index-D.index),u=this._getMaxRevokedChunkIndex(g);u>=0&&(this._chunks=[],this._latestIndex=u,this._updateContent());const E=this._getValidChunks(g);if(E.length!==0&&(this._mergeAndSortChunks(E),this._chunks.length>0)){const m=this._chunks[this._chunks.length-1];this._latestIndex=m.index,this._updateContent(),this.content.isStreamEnded=m.isLast}}getLatestIndex(){return this._latestIndex}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{streamMessageID:E,chunks:m}=u,D=m?.map(v=>({EventType:v.eventType||"data",Index:v.index,Markdown:v.markdown,IsLast:v.isLast}));return{MsgType:this.type,MsgContent:{StreamMsgID:E,Chunks:D}}}validateBeforeSend(){var r,g;return((g=(r=this.content)===null||r===void 0?void 0:r.chunks)===null||g===void 0?void 0:g.length)>0?{isValid:!0}:{isValid:!1,error:{message:"content is invalid"}}}_filterContinuousChunks(r,g){if(r.length===0)return[];const u=[];let E=g;for(const m of r){if(m.index>E)break;m.index===E&&(u.push(m),E++)}return u}_mergeAndSortChunks(r){const g=new Map;this._chunks.forEach(u=>{g.set(u.index,u)}),r.forEach(u=>{g.set(u.index,u)}),this._chunks=Array.from(g.values()).sort((u,E)=>u.index-E.index)}_updateContent(){this.content.markdown=this._chunks.map(g=>g.markdown).join("");const r=this._chunks.map(g=>g.binaryData).filter(g=>g?.length>0);if(r.length===0)this.content.binaryData=new Uint8Array(0);else if(r.length===1)this.content.binaryData=r[0];else{const g=r.reduce((m,D)=>m+D.length,0),u=new Uint8Array(g);let E=0;for(const m of r)u.set(m,E),E+=m.length;this.content.binaryData=u}}_getMaxRevokedChunkIndex(r){let g=-1;for(let u=0;ug&&(g=E.index)}return g}_getValidChunks(r){const g=r.filter(u=>u.eventType===Fc.DATA&&u.index>this._latestIndex);return this._filterContinuousChunks(g,this._latestIndex+1)}}var xc=new class{init(n){this._core=n,n.message.messageFactory.registerElementClass(Kr.MSG_FACE,Yl),n.message.messageFactory.registerElementClass(Kr.MSG_LOCATION,Pc),n.message.messageFactory.registerElementClass(Kr.MSG_STREAM,OE),n.helper.registerApi({apiName:"createFaceMessage",context:this}),n.helper.registerApi({apiName:"createTextAtMessage",context:this}),n.helper.registerApi({apiName:"createForwardMessage",context:this}),n.helper.registerApi({apiName:"createLocationMessage",context:this})}createFaceMessage(n){if(!n)return null;const{index:r,data:g}=n?.payload||{},u=new Yl({index:r,data:g}),E=this._core.common.getCurrentUserID(),m=this._core.message.messageFactory.createMessage(Object.assign(Object.assign({},n),{from:E}));return m.setElement(u),m}createTextAtMessage(n){const{atUserList:r}=n?.payload||{},g=this._core.apiMap.createTextMessage(n),{OuterConstant:u}=this._core;if(!g)return null;if(Array.isArray(r)){const E=[],m=[];r.forEach(D=>{D!==u.MSG_AT_ALL?(E.push({GroupAtAllFlag:uh,GroupAt_Account:D}),m.push(D)):(E.push({GroupAtAllFlag:uo}),m.push(u.MSG_AT_ALL))}),g._groupAtInfoList=E,g.atUserList=m}return g}createForwardMessage(n){const{helper:r,OuterConstant:g}=this._core,{to:u,conversationType:E,priority:m,payload:D,needReadReceipt:v,receiverList:T,cloudCustomData:P="",isSupportExtension:W=!1}=n;if(!Array.isArray(D._elements))throw new r.ChatError({functionName:"createForwardMessage",code:2454});if(D.type===g.MSG_GRP_TIP)throw new r.ChatError({functionName:"createForwardMessage",code:2453});const oA=this._core.common.getCurrentUserID(),EA=this._core.message.messageFactory.createMessage({to:u,from:oA,conversationType:E,isPlaceMessage:0,priority:m,payload:D,needReadReceipt:v,isSupportExtension:W,cloudCustomData:P,receiverList:T});return EA.setRelayFlag(!0),EA.setElement(D._elements[0]),EA}createLocationMessage(n){if(!n)return null;const{description:r,longitude:g,latitude:u}=n?.payload||{},E=new Pc({description:r,longitude:g,latitude:u}),m=this._core.common.getCurrentUserID(),D=this._core.message.messageFactory.createMessage(Object.assign(Object.assign({},n),{from:m}));return D.setElement(E),D}};let Vu=class{init(n){this._messageHelper=new Fr(n),this._core=n;const{notificationCenter:r,InnerEvent:{MESSAGE_PUSH:g},InnerEventSubType:{C2C_REVOKED_MESSAGE:u},helper:{registerWorkflowStep:E},constants:{WORKFLOW_NAME:m,WORKFLOW_STEP:D}}=n;r.subscribeInnerEvent(g,u,this._handleC2CNotifyMessage,this),E(m.SYNC_SERVER_INFO_AFTER_RE_ONLINE,D.HANDLE_C2C_REVOKED_MESSAGE_FROM_SYNC_UNREAD,this._handleC2CRevokeMessagesFromUnreadMessageSync,this)}_handleC2CNotifyMessage(n){const{C2cNotifyMsgArray:r}=n;r?.forEach(g=>{Object.keys(g).includes("WithdrawC2cMsgNotify")&&this._handleC2CRevokeMessage(g)})}_handleC2CRevokeMessage(n){return mA(this,void 0,void 0,function*(){try{const{WithdrawC2cMsgNotify:{C2cWithdrawInfoArray:r}}=n;yield this._parseAndEmitC2CRevokedMessages(r)}catch(r){console.debug(r)}})}_parseAndEmitC2CRevokedMessages(n){return mA(this,void 0,void 0,function*(){const r=[],{notificationCenter:g,OuterEvent:u,common:{getCurrentUserID:E}}=this._core;n.forEach(m=>{var D;const{MsgRand:v,MsgSeq:T,To_Account:P,From_Account:W,RevokerInfo:{Revoker_Account:oA,Revoke_Reason:EA}}=m,wA=E()===W?`C2C${P}`:`C2C${W}`,kA=((D=m?.RevokerInfo)===null||D===void 0?void 0:D.Reason)||EA,xA=this._messageHelper.generateRevokeMessage({conversationID:wA,sequence:T,random:v,revoker:oA,revokeReason:kA});r.push(xA)}),r.length>0&&(yield this._messageHelper.updateRevokerInfo(r),g.emitOuterEvent(u.MESSAGE_REVOKED,{name:u.MESSAGE_REVOKED,data:r}))})}_handleC2CRevokeMessagesFromUnreadMessageSync(n){return mA(this,void 0,void 0,function*(){const{revokedMessageList:r}=n.result;yield this._parseAndEmitC2CRevokedMessages(r)})}dispose(){const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:r},InnerEventSubType:{C2C_REVOKED_MESSAGE:g}}=this._core;n.unSubscribeInnerEvent(r,g,this._handleC2CNotifyMessage,this)}},yC=class{init(n){this._messageHelper=new Fr(n),this._core=n;const{notificationCenter:r,InnerEvent:{MESSAGE_PUSH:g},InnerEventSubType:{GROUP_MESSAGE_REVOKED:u}}=n;r.subscribeInnerEvent(g,u,this._handleGroupNotifyMessage,this)}_handleGroupNotifyMessage(n){const{GroupTips:r}=n;r?.forEach(g=>{var u;Array.isArray((u=g?.MsgBody)===null||u===void 0?void 0:u.GroupWithdrawInfoArray)&&this._handleGroupRevokeMessage(g)})}_handleGroupRevokeMessage(n){return mA(this,void 0,void 0,function*(){try{const{RevokerInfo:r,MsgBody:{GroupWithdrawInfoArray:g},GroupInfo:u}=n,E=[],m=[],{notificationCenter:D,OuterEvent:v,utils:{isEmpty:T},common:{isCommunity:P}}=this._core;let W=!1;u&&(W=P({groupID:u.GroupId})||!T(u.TopicId)),g.forEach(oA=>{const{Random:EA,MsgSeq:wA,GroupId:kA,MsgClientTime:xA,TinyId:LA,TopicId:SA,RevokerInfo:{Revoker_Account:OA=r?.Revoker_Account||"",Reason:WA=r?.Reason||""}}=oA,ue=SA?`GROUP${SA}`:`GROUP${kA}`,le=this._messageHelper.generateRevokeMessage({conversationID:ue,sequence:wA,random:EA,tinyID:LA,clientTime:xA,revoker:OA,revokeReason:WA});W?(le.revokerInfo.nick=u.From_AccountNick,le.revokerInfo.avatar=u.From_AccountHeadurl,E.push(le)):m.push(le)}),m.length>0&&(yield this._messageHelper.updateRevokerInfo(m),E.push(...m)),E.length!==0&&D.emitOuterEvent(v.MESSAGE_REVOKED,{name:v.MESSAGE_REVOKED,data:E})}catch(r){console.debug(r)}})}dispose(){const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:r},InnerEventSubType:{GROUP_MESSAGE_REVOKED:g}}=this._core;n.unSubscribeInnerEvent(r,g,this._handleGroupNotifyMessage,this)}};var nu=new class{constructor(){this._c2cMessageReceiver=new Vu,this._groupMessageReceiver=new yC}init(n){this._c2cMessageReceiver.init(n),this._groupMessageReceiver.init(n)}dispose(){this._c2cMessageReceiver.dispose(),this._groupMessageReceiver.dispose()}},Eh=new class{constructor(){this._core=null}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"translateText",context:this})}translateText(n){return mA(this,void 0,void 0,function*(){try{const{sourceLanguage:r,sourceTextList:g,targetLanguage:u}=n,E=yield function(m,D){return mA(this,void 0,void 0,function*(){var v,T;const{sourceTextList:P,sourceLanguage:W,targetLanguage:oA}=m,{store:EA,common:wA}=D,kA={SourceText:P,Source:W,Target:oA,FromAccount:(v=EA.get("login"))===null||v===void 0?void 0:v.tinyID,SDKAppID:(T=EA.get("instance"))===null||T===void 0?void 0:T.sdkAppId},xA=yield wA.buildAndSendPacket({servcmd:"im_open_translate.ws_batch_trans_text",data:kA});if(xA){const{CmdErrorCode:LA,TargetText:SA}=xA;return{cmdErrorCode:LA,translatedTextList:SA}}})}({sourceLanguage:r,sourceTextList:g,targetLanguage:u},this._core);if(E){const{cmdErrorCode:{ErrorCode:m,ErrorInfo:D},translatedTextList:v}=E;if(m===0)return{code:0,data:{translatedTextList:v}};throw{errorCode:m,errorInfo:D,message:D}}}catch(r){const{errorCode:g,errorInfo:u}=r||{};throw new this._core.helper.ChatError({functionName:"translateText",code:g,message:u})}})}},Ju=new class{init(n){this._core=n,n.helper.registerApi({apiName:"convertVoiceToText",context:this})}convertVoiceToText(n){return mA(this,void 0,void 0,function*(){var r;const{message:g,language:u=Uc.ZH_PY}=n;let{url:E}=g.payload||{};const m=this._core.common.getCurrentUserID();g.from===m&&g.flow==="out"&&(E=g.payload.remoteAudioUrl),this._validateVoiceFormat(E);const D=((r=DI.exec(E))===null||r===void 0?void 0:r[1])||"mp3",v=yI[u]||iu;try{const T=yield function(P){var W;const{store:oA,common:EA}=qs.core,{url:wA,format:kA,serverLanguageType:xA}=P,LA={BytesUrl:wA,BytesEngServiceType:xA,BytesVoiceFormat:kA,Uint32Sdkappid:(W=oA.get("instance"))===null||W===void 0?void 0:W.sdkAppId,Uint64SourceType:0};return EA.buildAndSendPacket({servcmd:"im_open_speech.ws_sentence_recognition",data:LA})}({url:E,format:D,serverLanguageType:v});if(T){const{CmdErrorCode:P,BytesResult:W}=T;if(P.ErrorCode===0)return{code:0,data:{result:W}};throw{code:P.ErrorCode,message:P.ErrorInfo}}}catch(T){const{code:P,message:W}=T||{};throw new this._core.common.ChatError({functionName:"convertVoiceToText",code:P,message:W})}})}_validateVoiceFormat(n){if(!DI.test(n))throw new this._core.common.ChatError({code:2119})}};class vI{constructor(r){const{constants:g,common:u,utils:E}=qs.core,{CONV_C2C:m,CONV_GROUP:D}=g.OuterConstant,{ID:v,tinyID:T,from:P,to:W,clientTime:oA=u.timeManager.getServerTimeSeconds()||0,random:EA,sequence:wA,cloudCustomData:kA="",nick:xA="",avatar:LA="",clientSequence:SA,conversationType:OA,groupID:WA,_elements:ue,time:le}=r;this.ID=v||`${T}-${oA}-${EA}`,this.messageRandom=EA,this.from=P,this.messageSender=P,this.time=le,this.messageSequence=wA,this.clientSequence=SA||wA,this.clientTime=oA,this.cloudCustomData=kA,this.messageReceiver=W,this.avatar=LA,this.nick=xA;const ki=E.deepCopyWithMethods(ue);ki.forEach(Li=>{Li.payload=Li.content,delete Li.content}),this.messageBody=ki,v?OA.startsWith(m)?this.receiverUserID=W:OA.startsWith(D)&&(this.receiverGroupID=W):WA?(this.receiverGroupID=WA,this.messageReceiver=WA):W&&(this.receiverUserID=W,this.messageReceiver=W)}transformElementsToServerFormat(){return this.messageBody?Array.isArray(this.messageBody)?this.messageBody.map(r=>r.transformToServerFormat({isMergerMessage:!0})):this.messageBody.transformToServerFormat({isMergerMessage:!0}):null}}class El{static parseServerPushElement(r){const{MsgContent:g}=r,{MsgList:u=[],CompatibleText:E,AbstractList:m,Title:D,PbMsgKey:v,JsonMsgKey:T}=g||{},P=u.map(W=>Dr(W));return new El({messageList:P,title:D,abstractList:m,compatibleText:E,pbDownloadKey:v,downloadKey:T})}constructor(r){this.type=qs.core.constants.OuterConstant.MSG_MERGER;const{messageList:g,title:u,abstractList:E,compatibleText:m,pbDownloadKey:D="",downloadKey:v="",version:T=0,layersOverLimit:P=!1}=r,W=[];g.forEach(oA=>{if(oA){const EA=new vI(oA);W.push(EA)}}),this.content={messageList:W,title:u,abstractList:E,compatibleText:m,version:T,downloadKey:v,pbDownloadKey:D,layersOverLimit:P}}validateBeforeSend(){const{isEmpty:r}=qs.core.helper;return r(this.content.messageList)?{isValid:!1,error:{message:"content is invalid"}}:{isValid:!0}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{abstractList:E,compatibleText:m,downloadKey:D,layersOverLimit:v,pbDownloadKey:T,title:P,version:W,messageList:oA}=u;return{MsgType:this.type,MsgContent:{AbstractList:E,CompatibleText:m,JsonMsgKey:D,LayersOverLimit:v,PbMsgKey:T,Title:P,Version:W,MsgList:oc(oA)}}}}var DC=new class{init(n){this._core=n;const{message:r,helper:g,constants:{OuterConstant:u}}=n;r.messageFactory.registerElementClass(u.MSG_MERGER,El),g.registerApi({apiName:"createMergerMessage",context:this}),g.registerApi({apiName:"sendMessage",context:this,matcher:E=>E[0].type===u.MSG_MERGER}),g.registerApi({apiName:"downloadMergerMessage",context:this})}createMergerMessage(n){const{common:r}=this._core;if(!n)return null;const g=new El(n.payload),u=r.getCurrentUserID(),E=this._core.message.messageFactory.createMessage(Object.assign(Object.assign({},n),{from:u}));return E.setRelayFlag(!0),E.setElement(g),E}sendMessage(n,r){return mA(this,void 0,void 0,function*(){var g,u,E;try{const m=function(P){let W="utf-8";qs.core.helper.IN_BROWSER&&document&&(W=document.charset.toLowerCase());let oA,EA=0,wA=0;if(wA=P.length,W==="utf-8"||W==="utf8")for(let kA=0;kA11264){D=this._core.utils.deepCopyWithMethods(n);try{const{JsonMsgKey:P,PbMsgKey:W}=yield function(EA){return mA(this,void 0,void 0,function*(){const{payload:{messageList:wA}}=EA,kA={MsgList:oc(wA)};return qs.core.common.buildAndSendPacket({servcmd:"im_long_msg.save_relay_json_msg",data:kA})})}(D),{payload:oA}=D;v=new El(Object.assign(Object.assign({},oA),{messageList:[],downloadKey:P,pbDownloadKey:W})),D.setElement(v)}catch(P){console.error(P)}}const{data:{message:T}}=yield(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageSender)===null||E===void 0?void 0:E.sendMessage(D,r);return v&&T.setElement(n._elements),{code:0,data:{message:T}}}catch(m){const{errorCode:D}=m;throw new this._core.helper.ChatError({code:D})}})}downloadMergerMessage(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r}=this._core,g=n.payload,{downloadKey:u,pbDownload:E,type:m,messageList:D}=g,v=vo(g,["downloadKey","pbDownload","type","messageList"]);try{const T=yield function(oA){return mA(this,void 0,void 0,function*(){return qs.core.common.buildAndSendPacket({servcmd:"im_long_msg.get_relay_json_msg",data:{JsonMsgKey:oA}})})}(u),{MsgList:P}=T||{},W=P?.map(oA=>{const EA=Dr(oA);return new vI(EA)});return typeof n.isOnlineMessage=="function"?n.setElement({type:n.type,content:Object.assign({messageList:W},v)}):(n.payload.messageList=W,n.payload.downloadKey="",n.payload.pbDownloadKey=""),r.info("downloadMergerMessage",` success downloadKey:${u}`),n}catch(T){const{errorCode:P}=T;throw new this._core.helper.ChatError({functionName:"downloadMergerMessage",code:P,moreMessage:u})}})}},Ia=new class{init(n){this._core=n,this._core.helper.registerExperimentalAPI("sendComboMessage",this)}sendComboMessage(n){return mA(this,void 0,void 0,function*(){const{appStore:r,message:g,common:{getCurrentUserID:u},utils:{isArray:E}}=this._core,{GroupId:m,To_Account:D}=n;n.From_Account=n.From_Account||u();let v=null;if(m){v=this._generateGroupMessage(Object.assign(Object.assign({},n),{ToGroupId:m}));const T=r.userStore.getUserProfile(u());v.level=T?.level||0,E(D)&&D.length>0&&(v._receiverList=D)}else D&&(v=this._generateC2CMessage(n));return g.messageSender.sendMessage(v,n)})}_generateC2CMessage(n){const{message:r,OuterConstant:{CONV_C2C:g}}=this._core,u=g,E=r.messageHelper.parseServerPushMessage(n),m=r.messageFactory.createMessage(Object.assign(Object.assign({},E),{conversationType:u,flow:sc.OUT})),{elements:D}=E;return m.setElement(D),m}_generateGroupMessage(n){const{message:r,OuterConstant:{CONV_GROUP:g}}=this._core,u=g,E=r.messageHelper.parseServerGroupMessage(n),m=r.messageFactory.createMessage(Object.assign(Object.assign({},E),{conversationType:u,flow:sc.OUT})),{elements:D}=E;return m.setElement(D),m}},nc=new class{init(n){this._core=n;const{helper:r,notificationCenter:g,InnerEvent:{MESSAGE_PUSH:u},InnerEventSubType:{GROUP_MESSAGE_PINNED:E}}=n;g.subscribeInnerEvent(u,E,this._handleGroupMessagePinned,this),r.registerApi({apiName:"pinGroupMessage",context:this}),r.registerApi({apiName:"getPinnedGroupMessageList",context:this})}pinGroupMessage(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,common:{isTopic:g},OuterConstant:{GROUP_ID_PREFIX:u},helper:{ChatError:E}}=this._core;let{groupID:m,message:D,isPinned:v}=n;const{sequence:T}=D;try{return yield function(P){return mA(this,void 0,void 0,function*(){const{common:{buildAndSendPacket:W,getCurrentUserID:oA}}=qs.core,{groupID:EA,sequence:wA,isPinned:kA}=P,xA=oA(),LA=kA?"group_open_http_svc.pin_message":"group_open_http_svc.unpin_message",SA={GroupId:EA,MsgSeq:wA};return kA?SA.Pinner_Account=xA:SA.UnPinner_Account=xA,W({servcmd:LA,data:SA})})}({groupID:m,sequence:T,isPinned:v}),{code:0,data:{}}}catch(P){const{errorCode:W,errorInfo:oA}=P||{};throw new E({code:W,message:oA})}})}getPinnedGroupMessageList(n){return mA(this,void 0,void 0,function*(){let r=[];try{const g=yield function(u){return mA(this,void 0,void 0,function*(){const{groupID:E}=u,{common:{buildAndSendPacket:m}}=qs.core;return m({servcmd:"group_open_http_svc.get_pinned_messages",data:{GroupId:E}})})}({groupID:n});if(g){const{PinnedMsgList:u=[]}=g;r=yield this._updatePinnedMessageInfo({serverPinnedMessageList:u,groupID:n})}return{code:0,data:{messageList:r}}}catch(g){throw g}})}_handleGroupMessagePinned(n){const{message:{messageHelper:r,messageFactory:g},notificationCenter:u,OuterEvent:E,OuterConstant:m}=this._core;n.GroupTips.forEach(D=>{const{ToGroupId:v,MsgBody:{PinnedMsg:T,OpType:P,MsgOperatorMemberExtraInfo:W,SdkGroupMessageId:oA}}=D,{UserId:EA,NickName:wA="",ImageUrl:kA=""}=W;let xA=null,LA=!1;if(P===fd){LA=!0;const SA=r.parseServerGroupMessage(T);xA=g.createMessage(Object.assign(Object.assign({},SA),{conversationType:m.CONV_GROUP,flow:"in"})),xA.setElement(SA.elements),xA.pinnerInfo={userID:EA,nick:wA,avatar:kA}}else if(P===LE){const{ClientTime:SA,Random:OA,SenderTinyId:WA,ServerTime:ue,MsgSeq:le}=oA;xA={ID:`${WA}-${SA}-${OA}`,sequence:le,random:OA,time:ue,clientTime:SA}}xA&&u.emitOuterEvent(E.PINNED_GROUP_MESSAGE_UPDATED,{name:E.PINNED_GROUP_MESSAGE_UPDATED,data:{groupID:v,message:xA,isPinned:LA,operatorInfo:{userID:EA,nick:wA,avatar:kA}}})})}_findMessageBySequence(n,r){const{message:{messageDataHandler:g}}=this._core;return[...g.getLocalMessageList(n),...g.getSparseMessageList(n)].find(u=>u.sequence===r)}_updatePinnedMessageInfo(n){return mA(this,arguments,void 0,function*({serverPinnedMessageList:r,groupID:g}){const{OuterConstant:{CONV_GROUP:u},utils:{isEmpty:E}}=this._core,m=[],D=[],v=[],T=new Map,P=`${u}${g}`;for(let oA=0;oA{const{sequence:kA}=wA,xA=T.get(kA),LA=oA[xA]||{userID:xA,nick:"",avatar:""};wA.pinnerInfo=LA}),m.sort((wA,kA)=>wA.sequence-kA.sequence),m}return[]})}_fetchPinnedMessageInfo(n){return mA(this,void 0,void 0,function*(){var r,g;const{message:{messageHistory:u},user:{userProfile:E},utils:{isArray:m}}=this._core,{conversationID:D,messageSequenceList:v,pinnerIDList:T}=n,P=yield Promise.all([this._fetchMessageBySequence({conversationID:D,messageSequenceList:v}),E?.getUserProfile({userIDList:T})]);if(m(P)){const W={};return(((r=P[1])===null||r===void 0?void 0:r.data)||[]).forEach(oA=>{const{userID:EA,nick:wA="",avatar:kA=""}=oA;W[EA]={userID:EA,nick:wA,avatar:kA}}),{messageList:((g=P[0])===null||g===void 0?void 0:g.messageList)||[],pinnerInfoMap:W}}})}_fetchMessageBySequence(n){return mA(this,void 0,void 0,function*(){const{utils:{isEmpty:r},message:{messageHistory:g}}=this._core,{conversationID:u,messageSequenceList:E}=n;return r(E)?[]:g.getGroupRoamingMessagesByAnchor({conversationID:u,messageSequenceList:E,getType:3})})}};class ug{constructor(r){this.eventType=Fc.DATA,this.index=0,this.markdown="",this.isLast=!1,this.binaryData=null;const{EventType:g,Index:u,Markdown:E,IsLast:m,BinaryData:D}=r;this.eventType=g,this.index=u,this.markdown=E,this.isLast=m,this.binaryData=D}}var MI=new class{constructor(){this._messageMap=new Map,this._retryCountMap=new Map}init(n){this._core=n;const{notificationCenter:r,OuterEvent:{MESSAGE_RECEIVED:g},InnerEvent:{HISTORY_MESSAGE_FETCHED:u},common:{workflowManager:E},constants:{WORKFLOW_NAME:m,WORKFLOW_STEP:D}}=n;r.subscribeInnerEvent(ho,this._handleStreamMessageChunkPush,this),r.subscribeOuterEvent(g,this._handleMessageReceived,this),r.subscribeInnerEvent(u,this.processHistoryMessage,this),E.registerWorkflowStep(m.SYNC_SERVER_INFO_AFTER_RE_ONLINE,D.STREAM_MESSAGE_RECOVER,this._recoverStreamMessage,this)}processHistoryMessage(n){const{utils:{isEmpty:r,safeStringify:g},ssoLog:u}=this._core;try{n?.forEach(E=>{var m;if(this._isValidStreamMessage(E)){const D=(m=E?._elements)===null||m===void 0?void 0:m[0],{streamMessageID:v,markdown:T,binaryData:P}=D?.content||{};r(T)&&r(P)?(this._messageMap.set(v,E),this._fetchStreamMessageChunks(E)):D.content.isStreamEnded=!0}})}catch(E){u.error("processHistoryMessage.error",g(E))}}_handleMessageReceived(n){const r=n.data;r?.forEach(g=>{var u,E;if(this._isValidStreamMessage(g)){const{streamMessageID:m}=((E=(u=g?._elements)===null||u===void 0?void 0:u[0])===null||E===void 0?void 0:E.content)||{};m&&(this._messageMap.set(m,g),this._fetchStreamMessageChunks(g))}})}_isValidStreamMessage(n){var r,g;const{utils:{isEmpty:u}}=this._core,{streamMessageID:E}=((g=(r=n?._elements)===null||r===void 0?void 0:r[0])===null||g===void 0?void 0:g.content)||{};return n.type===Kr.MSG_STREAM&&!u(E)}_fetchStreamMessageChunks(n){return mA(this,void 0,void 0,function*(){var r,g;const{constants:{ERROR_CODE:u},ssoLog:E,utils:{safeStringify:m}}=this._core,D=(r=n._elements)===null||r===void 0?void 0:r[0],v=(g=D?.content)===null||g===void 0?void 0:g.streamMessageID;try{const{from:T,to:P}=n,W=D.getLatestIndex();if(D.content.isStreamEnded)return;const oA=yield function(EA){return mA(this,void 0,void 0,function*(){const{from:wA,to:kA,streamMessageID:xA,index:LA}=EA,SA={From_Account:wA,To_Account:kA,StreamMsgID:xA,AckIndex:LA};return qs.core.common.buildAndSendPacket({servcmd:"StreamMsg.GetStreamHttp",data:SA,timeout:5e3})})}({from:T,to:P,streamMessageID:v,index:W});if(oA){const{ErrorCode:EA,ErrorInfo:wA}=oA;if(EA!==0)throw D.content.errorCode=EA,D.content.errorMessage=wA,{errorCode:EA,errorMessage:wA}}}catch(T){if(T.errorCode===u.NETWORK_TIMEOUT&&this._shouldRetryFetch(v)){const P=this._retryCountMap.get(v)||0;E.debug("_fetchStreamMessageChunks.timeout",`error: ${m(T)} retried: ${P}`),this._retryCountMap.set(v,P+1),this._fetchStreamMessageChunks(n)}else E.error("_fetchStreamMessageChunks.error",m(T))}})}_shouldRetryFetch(n){const{utils:{isNumber:r}}=this._core;if(!this._retryCountMap.has(n))return this._retryCountMap.set(n,1),!0;const g=this._retryCountMap.get(n);return!!(r(g)&&g<=3)}_onStreamEnded(n,r,g){const{ssoLog:u}=this._core;g.content.isStreamEnded=!0,g.stopReason=r,this._messageMap.delete(n),u.debug("_onStreamEnded",`streamMessage end, StopReason: ${r}`)}_handleStreamMessageChunkPush(n){var r;const{ssoLog:g}=this._core,{StopReason:u,Chunks:E,StreamID:m}=n?.body||{},D=this._messageMap.get(m);if(!D)return void g.warn(`_handleStreamMessageChunkPush, unfounded message: ${m}`);const v=(r=D._elements)===null||r===void 0?void 0:r[0];if(v&&this._validateExpectedChunk(v,E)){if(E.length>0){const T=E.map(P=>new ug(P));v.updateChunks(T)}this._emitMessageModify(D),function(T,P){mA(this,void 0,void 0,function*(){const{common:{generateProtocolData:W},utils:{safeStringify:oA},ssoLog:EA,channel:wA}=qs.core,kA={StreamMsgID:T,AckIndex:P};try{const xA=W({servcmd:"StreamMsg.AckHttp",data:kA});wA.sendPacket(xA)}catch(xA){EA.debug("sendStreamChunkAck",oA(xA))}})}(m,v.getLatestIndex()),v.content.isStreamEnded&&this._onStreamEnded(m,u,v)}}_emitMessageModify(n){const{notificationCenter:r,OuterEvent:{MESSAGE_MODIFIED:g}}=this._core;r.emitOuterEvent(g,{name:g,data:[n]})}_validateExpectedChunk(n,r){const g=n.getLatestIndex()+1;let u=!1;for(let E=0;Em.Index).join(", ")}]`),!1}return!0}_recoverStreamMessage(){this._retryCountMap.clear();const{ssoLog:n,utils:{safeStringify:r}}=this._core;try{const g=Array.from(this._messageMap.entries());for(let u=Math.max(0,g.length-300);u{const LA=this._getResponseBody(kA,E,oA&&EA),SA=this._buildResponse(kA,LA);if(kA.status===200)r(null,SA);else{if(EA&&!wA.includes(EA))return n.url=this._domainName2IP(wA,EA),n.uploadByIP=!0,this.request(n,r);r({code:kA.status,message:JSON.stringify(kA.responseText)},SA)}},kA.onerror=()=>{const LA=this._getResponseBody(kA,E,oA&&EA),SA=this._buildResponse(kA,LA),OA={code:kA.status,message:kA.status===0?"CORS blocked or network error":JSON.stringify(kA.responseText)};r(OA,SA)},n.onProgress&&kA.upload&&(kA.upload.onprogress=LA=>{const{total:SA,loaded:OA}=LA,WA=Math.min(Math.floor(100*OA/SA),100);n.onProgress({total:SA,loaded:OA,percent:WA/100})}),kA.send(P),kA})}_buildResponse(n,r){const g={};return n.getAllResponseHeaders().trim().split(`
+`).forEach(u=>{if(u){const[E,m]=u.split(":").map(D=>D.trim());g[E.toLowerCase()]=m}}),{statusCode:n.status,statusMessage:n.statusText,headers:g,data:r}}_getResponseBody(n,r,g){return n.status===200&&r?{location:r,uploadIP:g}:{response:n.responseText,uploadIP:g}}_queryString(n,r="&",g="="){var u;const{isEmpty:E,isPlainObject:m}=(u=this._core)===null||u===void 0?void 0:u.utils;return E(n)?"":m(n)?Object.keys(n).map(D=>{const v=encodeURIComponent(D)+g;return Array.isArray(n[D])?n[D].map(T=>v+encodeURIComponent(T)).join(r):v+encodeURIComponent(n[D])}).filter(Boolean).join(r):void 0}_domainName2IP(n,r){return n.replace(/^http(s)?:\/\/(.*?)\//,`https://${r}/`)}};const qu=["unknown","image","video","audio","log"];var RI=new class{init(n){this._core=n}request(n,r){var g;const{MINI_APP_NAMESPACE:u,IN_ALIPAY_MINI_APP:E,isUniIOSApp:m}=(g=this._core)===null||g===void 0?void 0:g.utils,{resources:D="",headers:v={},url:T,downloadUrl:P=""}=n;let W=T,oA=null;const EA=P?P.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/):null;if(!EA)return void console.warn("message Invalid download URL format");const wA=decodeURIComponent(EA[3]),kA=wA.includes("?")?wA.split("?")[0]:wA||"",xA={key:n.fileKey||kA,success_action_status:200,"Content-Type":""},LA={};if(m()){const[OA,WA]=T.split("?sign=");WA&&(W=`${OA}?sign=${encodeURIComponent(WA)}`,LA.sign=decodeURIComponent(WA),LA.signature=decodeURIComponent(WA))}let SA={url:W,header:v,name:"file",filePath:D,formData:Object.assign(Object.assign({},xA),LA),timeout:n.timeout||3e5};if(E){const{name:OA}=SA,WA=vo(SA,["name"]);SA=Object.assign(Object.assign({},WA),{fileName:"file",fileType:n.fileType?qu[n.fileType]:"image"})}return oA=u.uploadFile(Object.assign(Object.assign({},SA),{success:OA=>{this._handleResponse({response:OA,downloadUrl:P,callback:r})},fail:OA=>{this._handleResponse({response:OA,downloadUrl:P,callback:r})}})),oA.onProgressUpdate&&oA.onProgressUpdate(OA=>{n.onProgress&&n.onProgress({total:OA.totalBytesExpectedToSend||0,loaded:OA.totalBytesSent||0,percent:OA.progress?Math.floor(OA.progress)/100:0})}),oA}_handleResponse(n){const{downloadUrl:r,response:g,callback:u}=n,E={};if(g.header)for(const D in g.header)g.header.hasOwnProperty(D)&&(E[D.toLowerCase()]=g.header[D]);const m=+g.statusCode;m===200?u(null,{statusCode:m,headers:E,data:Object.assign(Object.assign({},g.data),{location:r})}):u({code:m,message:JSON.stringify(g.data)},{statusCode:m,headers:E,data:void 0})}};function dl(n){return function(r){return Object.prototype.toString.call(r).match(/^\[object (.*)\]$/)[1].toLowerCase()}(n)==="file"}function Or(n){const r=n||99999999;return Math.round(Math.random()*r)}function Pr(n,r=!0,g=!0){const u=Date.now();return r?g?u-n+" ms":`${Math.round((u-n)/1e3)} s`:g?u-n:Math.round((u-n)/1e3)}function Eg(n){return`${Array.from({length:8},()=>Math.floor(65536*(1+Math.random())).toString(16).substring(1)).join("")}-${n}`}function hr(n,r){return Math.round(Number(n)*10**r)/10**r}function Nr(n){return n<=1048576?`${hr(n/1024,1)}KB/s`:`${hr(n/1048576,1)}MB/s`}const rc="TIMImageElem",Pg="TIMSoundElem",qa="TIMFileElem",Vl="TIMVideoFileElem",fa="RichMediaMessagePlugin",wI=["rich.my-imcloud.com","imrich.qcloud.com"],ru=1,ya=2,Cl=3,xE=255;var au;(function(n){n.UNSENT="unSend",n.SUCCESS="success",n.FAIL="fail"})(au||(au={}));const YE={wechat:/^(wxfile:\/\/tmp_|http:\/\/temp\/|cloud:\/\/temp-)/,alipay:/^(https:\/\/resource\/|alipayfile:\/\/tmp\/)/,baidu:/^(http:\/\/tmp\/|swanfile:\/\/tmp_)/,bytedance:/^(ttfile:\/\/tmp_|\/(var|tmp)\/|tttemp:\/\/)/,qq:/^(qqfile:\/\/tmp_|http:\/\/qtemp\/)/},jr=Symbol("isCustomUpload");var gu,Vt=new class{init(n){this._core=n}addAuthToUrl(n=""){if(this._isMiniProgramTempFile(n))return n;const r=function(g){return g?g.startsWith("https://")?g:g.startsWith("http://")?g.replace("http://","https://"):g:""}(n);return this.processResourceUrl(r)}removeAuthToUrl(n){return function(r,g){const[u,E]=r.split("?");if(!E)return u;const m=E.split("&").reduce((v,T)=>{const[P,W]=T.split("=");return P&&P!==g&&(v[P]=W||""),v},{}),D=Object.keys(m).map(v=>`${v}${m[v]?`=${m[v]}`:""}`).join("&");return D?`${u}?${D}`:u}(n,"authKey")}_isMiniProgramTempFile(n){return!!this.getPlatformFlags().IN_MINI_APP&&Object.values(YE).some(r=>r.test(n))}extractFileFromInput(n){const{utils:{isArray:r}}=this._core;return dl(n)?n:function(g){if(typeof g!="object"||g===null)return!1;const u=Object.getPrototypeOf(g);if(u===null)return!0;let E=u;for(;Object.getPrototypeOf(E)!==null;)E=Object.getPrototypeOf(E);return u===E}(n)&&typeof uni<"u"?r(n.tempFiles)&&n.tempFiles.length>0?n.tempFiles[0]:r(n.files)?n.files[0]:n.tempFile?n.tempFile:null:n instanceof HTMLInputElement&&n.files&&n.files.length>0?n.files[0]:null}probeImageWidthHeight(n){return mA(this,void 0,void 0,function*(){var r;const{IN_MINI_APP:g,IN_BROWSER:u}=((r=this._core)===null||r===void 0?void 0:r.utils)||{};return this._shouldSkipProbing()?{width:0,height:0}:u?this._probeImageDimensionsWeb(n):g?this._probeImageDimensionsMiniApp(n):void 0})}isSimpleCos(){var n;const r=((n=this._core)===null||n===void 0?void 0:n.store.get("cloudConfig"))||{},{simple_cos:g}=r;return g!=="0"}getFileDNList(){var n;let r=wI;const g=((n=this._core)===null||n===void 0?void 0:n.store.get("cloudConfig"))||{},{file_dn_list:u}=g;if(u===void 0)return r;try{JSON.parse(u).forEach(E=>{r.includes(E)||r.push(E)})}catch(E){console.warn(E),r=wI}return r}getPlatform(){var n;return(n=this._core)===null||n===void 0?void 0:n.utils.platform}generateUUID(n,r){var g;let u=`${this.getSDKAppID()}-${this.getCurrentUserID()}-${(g=this._core)===null||g===void 0?void 0:g.utils.randomString()}`;if(r)return`${u}.${r}`;const E=n.name||n.value||n.url||n.tempFilePath,m=E&&E.slice(E.lastIndexOf(".")+1);return m&&(u=`${u}.${m}`),u}processResourceUrl(n){if(!n)return"";let r=n;const g=this.getFileDownloadProxy(),u=this.getAuthKey(),E=this.getFileDNList();return g&&(n.startsWith("http://")?r=n.replace(/^http:\/\/[^/]+/,g):n.startsWith("https://")&&(r=n.replace(/^https:\/\/[^/]+/,g))),u&&r.indexOf("authKey=")===-1&&function(D,v){let T=!1;if(D){const P=D.match(/:\/\/([0-9]?\.)?(.[^/:]+)/),W=P&&P[2]||"";if(W.includes("rich-dev"))return!0;for(let oA=0;oA-1?`${r}&authKey=${u}`:`${r}?authKey=${u}`),r}getCurrentUserID(){var n,r;return(r=(n=this._core)===null||n===void 0?void 0:n.store.get("login"))===null||r===void 0?void 0:r.userId}getSDKAppID(){var n,r;return(r=(n=this._core)===null||n===void 0?void 0:n.store.get("instance"))===null||r===void 0?void 0:r.sdkAppId}getFileDownloadProxy(){var n,r;return((r=(n=this._core)===null||n===void 0?void 0:n.store.get("instance"))===null||r===void 0?void 0:r.fileDownloadProxy)||""}getFileUploadProxy(){var n,r;return((r=(n=this._core)===null||n===void 0?void 0:n.store.get("instance"))===null||r===void 0?void 0:r.fileUploadProxy)||""}getAuthKey(){var n,r;return((r=(n=this._core)===null||n===void 0?void 0:n.store.get("login"))===null||r===void 0?void 0:r.authKey)||""}isPrivateNetWork(){var n,r;return(r=(n=this._core)===null||n===void 0?void 0:n.store.get("instance"))===null||r===void 0?void 0:r.proxyServer}getPlatformFlags(){var n;const{IN_BROWSER:r,IN_MINI_APP:g,IN_RN_APP:u,IN_UNI_NATIVE_APP:E}=(n=this._core)===null||n===void 0?void 0:n.utils;return{IN_BROWSER:r,IN_MINI_APP:g,IN_RN_APP:u,IN_UNI_NATIVE_APP:E}}isEmpty(n){var r;const{isEmpty:g}=(r=this._core)===null||r===void 0?void 0:r.utils;return g(n)}generateURL(n,r){const{needAddAuthToUrl:g=!0}=r||{};return g?this.addAuthToUrl(n):n}_probeImageDimensionsMiniApp(n){var r;const{MINI_APP_NAMESPACE:g}=((r=this._core)===null||r===void 0?void 0:r.utils)||{};return new Promise(u=>{g.getImageInfo({src:n,success:E=>u({width:E.width,height:E.height}),fail:()=>u({width:0,height:0})})})}_shouldSkipProbing(){var n;const{IN_RN_APP:r,IS_IE:g,IE_VERSION:u,IN_WX_MINI_GAME:E}=((n=this._core)===null||n===void 0?void 0:n.utils)||{};return r||g&&u===9||E}_probeImageDimensionsWeb(n){return new Promise(r=>{const g=new Image,u=()=>{g.onload=null,g.onerror=null,g.src=""};g.onload=()=>{r({width:g.width,height:g.height}),u()},g.onerror=()=>{r({width:0,height:0}),u()},g.src=n})}},Ku={exports:{}},ju=(gu||(gu=1,function(n){n.exports=function(r){var g=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function u(LA,SA){var OA=LA[0],WA=LA[1],ue=LA[2],le=LA[3];WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&ue|~WA&le)+SA[0]-680876936|0)<<7|OA>>>25)+WA|0)&WA|~OA&ue)+SA[1]-389564586|0)<<12|le>>>20)+OA|0)&OA|~le&WA)+SA[2]+606105819|0)<<17|ue>>>15)+le|0)&le|~ue&OA)+SA[3]-1044525330|0)<<22|WA>>>10)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&ue|~WA&le)+SA[4]-176418897|0)<<7|OA>>>25)+WA|0)&WA|~OA&ue)+SA[5]+1200080426|0)<<12|le>>>20)+OA|0)&OA|~le&WA)+SA[6]-1473231341|0)<<17|ue>>>15)+le|0)&le|~ue&OA)+SA[7]-45705983|0)<<22|WA>>>10)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&ue|~WA&le)+SA[8]+1770035416|0)<<7|OA>>>25)+WA|0)&WA|~OA&ue)+SA[9]-1958414417|0)<<12|le>>>20)+OA|0)&OA|~le&WA)+SA[10]-42063|0)<<17|ue>>>15)+le|0)&le|~ue&OA)+SA[11]-1990404162|0)<<22|WA>>>10)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&ue|~WA&le)+SA[12]+1804603682|0)<<7|OA>>>25)+WA|0)&WA|~OA&ue)+SA[13]-40341101|0)<<12|le>>>20)+OA|0)&OA|~le&WA)+SA[14]-1502002290|0)<<17|ue>>>15)+le|0)&le|~ue&OA)+SA[15]+1236535329|0)<<22|WA>>>10)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&le|ue&~le)+SA[1]-165796510|0)<<5|OA>>>27)+WA|0)&ue|WA&~ue)+SA[6]-1069501632|0)<<9|le>>>23)+OA|0)&WA|OA&~WA)+SA[11]+643717713|0)<<14|ue>>>18)+le|0)&OA|le&~OA)+SA[0]-373897302|0)<<20|WA>>>12)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&le|ue&~le)+SA[5]-701558691|0)<<5|OA>>>27)+WA|0)&ue|WA&~ue)+SA[10]+38016083|0)<<9|le>>>23)+OA|0)&WA|OA&~WA)+SA[15]-660478335|0)<<14|ue>>>18)+le|0)&OA|le&~OA)+SA[4]-405537848|0)<<20|WA>>>12)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&le|ue&~le)+SA[9]+568446438|0)<<5|OA>>>27)+WA|0)&ue|WA&~ue)+SA[14]-1019803690|0)<<9|le>>>23)+OA|0)&WA|OA&~WA)+SA[3]-187363961|0)<<14|ue>>>18)+le|0)&OA|le&~OA)+SA[8]+1163531501|0)<<20|WA>>>12)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA&le|ue&~le)+SA[13]-1444681467|0)<<5|OA>>>27)+WA|0)&ue|WA&~ue)+SA[2]-51403784|0)<<9|le>>>23)+OA|0)&WA|OA&~WA)+SA[7]+1735328473|0)<<14|ue>>>18)+le|0)&OA|le&~OA)+SA[12]-1926607734|0)<<20|WA>>>12)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA^ue^le)+SA[5]-378558|0)<<4|OA>>>28)+WA|0)^WA^ue)+SA[8]-2022574463|0)<<11|le>>>21)+OA|0)^OA^WA)+SA[11]+1839030562|0)<<16|ue>>>16)+le|0)^le^OA)+SA[14]-35309556|0)<<23|WA>>>9)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA^ue^le)+SA[1]-1530992060|0)<<4|OA>>>28)+WA|0)^WA^ue)+SA[4]+1272893353|0)<<11|le>>>21)+OA|0)^OA^WA)+SA[7]-155497632|0)<<16|ue>>>16)+le|0)^le^OA)+SA[10]-1094730640|0)<<23|WA>>>9)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA^ue^le)+SA[13]+681279174|0)<<4|OA>>>28)+WA|0)^WA^ue)+SA[0]-358537222|0)<<11|le>>>21)+OA|0)^OA^WA)+SA[3]-722521979|0)<<16|ue>>>16)+le|0)^le^OA)+SA[6]+76029189|0)<<23|WA>>>9)+ue|0,WA=((WA+=((ue=((ue+=((le=((le+=((OA=((OA+=(WA^ue^le)+SA[9]-640364487|0)<<4|OA>>>28)+WA|0)^WA^ue)+SA[12]-421815835|0)<<11|le>>>21)+OA|0)^OA^WA)+SA[15]+530742520|0)<<16|ue>>>16)+le|0)^le^OA)+SA[2]-995338651|0)<<23|WA>>>9)+ue|0,WA=((WA+=((le=((le+=(WA^((OA=((OA+=(ue^(WA|~le))+SA[0]-198630844|0)<<6|OA>>>26)+WA|0)|~ue))+SA[7]+1126891415|0)<<10|le>>>22)+OA|0)^((ue=((ue+=(OA^(le|~WA))+SA[14]-1416354905|0)<<15|ue>>>17)+le|0)|~OA))+SA[5]-57434055|0)<<21|WA>>>11)+ue|0,WA=((WA+=((le=((le+=(WA^((OA=((OA+=(ue^(WA|~le))+SA[12]+1700485571|0)<<6|OA>>>26)+WA|0)|~ue))+SA[3]-1894986606|0)<<10|le>>>22)+OA|0)^((ue=((ue+=(OA^(le|~WA))+SA[10]-1051523|0)<<15|ue>>>17)+le|0)|~OA))+SA[1]-2054922799|0)<<21|WA>>>11)+ue|0,WA=((WA+=((le=((le+=(WA^((OA=((OA+=(ue^(WA|~le))+SA[8]+1873313359|0)<<6|OA>>>26)+WA|0)|~ue))+SA[15]-30611744|0)<<10|le>>>22)+OA|0)^((ue=((ue+=(OA^(le|~WA))+SA[6]-1560198380|0)<<15|ue>>>17)+le|0)|~OA))+SA[13]+1309151649|0)<<21|WA>>>11)+ue|0,WA=((WA+=((le=((le+=(WA^((OA=((OA+=(ue^(WA|~le))+SA[4]-145523070|0)<<6|OA>>>26)+WA|0)|~ue))+SA[11]-1120210379|0)<<10|le>>>22)+OA|0)^((ue=((ue+=(OA^(le|~WA))+SA[2]+718787259|0)<<15|ue>>>17)+le|0)|~OA))+SA[9]-343485551|0)<<21|WA>>>11)+ue|0,LA[0]=OA+LA[0]|0,LA[1]=WA+LA[1]|0,LA[2]=ue+LA[2]|0,LA[3]=le+LA[3]|0}function E(LA){var SA,OA=[];for(SA=0;SA<64;SA+=4)OA[SA>>2]=LA.charCodeAt(SA)+(LA.charCodeAt(SA+1)<<8)+(LA.charCodeAt(SA+2)<<16)+(LA.charCodeAt(SA+3)<<24);return OA}function m(LA){var SA,OA=[];for(SA=0;SA<64;SA+=4)OA[SA>>2]=LA[SA]+(LA[SA+1]<<8)+(LA[SA+2]<<16)+(LA[SA+3]<<24);return OA}function D(LA){var SA,OA,WA,ue,le,ki,Li=LA.length,Yt=[1732584193,-271733879,-1732584194,271733878];for(SA=64;SA<=Li;SA+=64)u(Yt,E(LA.substring(SA-64,SA)));for(OA=(LA=LA.substring(SA-64)).length,WA=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],SA=0;SA>2]|=LA.charCodeAt(SA)<<(SA%4<<3);if(WA[SA>>2]|=128<<(SA%4<<3),SA>55)for(u(Yt,WA),SA=0;SA<16;SA+=1)WA[SA]=0;return ue=(ue=8*Li).toString(16).match(/(.*?)(.{0,8})$/),le=parseInt(ue[2],16),ki=parseInt(ue[1],16)||0,WA[14]=le,WA[15]=ki,u(Yt,WA),Yt}function v(LA){var SA,OA,WA,ue,le,ki,Li=LA.length,Yt=[1732584193,-271733879,-1732584194,271733878];for(SA=64;SA<=Li;SA+=64)u(Yt,m(LA.subarray(SA-64,SA)));for(OA=(LA=SA-64>2]|=LA[SA]<<(SA%4<<3);if(WA[SA>>2]|=128<<(SA%4<<3),SA>55)for(u(Yt,WA),SA=0;SA<16;SA+=1)WA[SA]=0;return ue=(ue=8*Li).toString(16).match(/(.*?)(.{0,8})$/),le=parseInt(ue[2],16),ki=parseInt(ue[1],16)||0,WA[14]=le,WA[15]=ki,u(Yt,WA),Yt}function T(LA){var SA,OA="";for(SA=0;SA<4;SA+=1)OA+=g[LA>>8*SA+4&15]+g[LA>>8*SA&15];return OA}function P(LA){var SA;for(SA=0;SA"u"||ArrayBuffer.prototype.slice||function(){function LA(SA,OA){return(SA=0|SA||0)<0?Math.max(SA+OA,0):Math.min(SA,OA)}ArrayBuffer.prototype.slice=function(SA,OA){var WA,ue,le,ki,Li=this.byteLength,Yt=LA(SA,Li),Fi=Li;return OA!==r&&(Fi=LA(OA,Li)),Yt>Fi?new ArrayBuffer(0):(WA=Fi-Yt,ue=new ArrayBuffer(WA),le=new Uint8Array(ue),ki=new Uint8Array(this,Yt,WA),le.set(ki),ue)}}(),xA.prototype.append=function(LA){return this.appendBinary(W(LA)),this},xA.prototype.appendBinary=function(LA){this._buff+=LA,this._length+=LA.length;var SA,OA=this._buff.length;for(SA=64;SA<=OA;SA+=64)u(this._hash,E(this._buff.substring(SA-64,SA)));return this._buff=this._buff.substring(SA-64),this},xA.prototype.end=function(LA){var SA,OA,WA=this._buff,ue=WA.length,le=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(SA=0;SA>2]|=WA.charCodeAt(SA)<<(SA%4<<3);return this._finish(le,ue),OA=P(this._hash),LA&&(OA=kA(OA)),this.reset(),OA},xA.prototype.reset=function(){return this._buff="",this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},xA.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash.slice()}},xA.prototype.setState=function(LA){return this._buff=LA.buff,this._length=LA.length,this._hash=LA.hash,this},xA.prototype.destroy=function(){delete this._hash,delete this._buff,delete this._length},xA.prototype._finish=function(LA,SA){var OA,WA,ue,le=SA;if(LA[le>>2]|=128<<(le%4<<3),le>55)for(u(this._hash,LA),le=0;le<16;le+=1)LA[le]=0;OA=(OA=8*this._length).toString(16).match(/(.*?)(.{0,8})$/),WA=parseInt(OA[2],16),ue=parseInt(OA[1],16)||0,LA[14]=WA,LA[15]=ue,u(this._hash,LA)},xA.hash=function(LA,SA){return xA.hashBinary(W(LA),SA)},xA.hashBinary=function(LA,SA){var OA=P(D(LA));return SA?kA(OA):OA},xA.ArrayBuffer=function(){this.reset()},xA.ArrayBuffer.prototype.append=function(LA){var SA,OA=wA(this._buff.buffer,LA),WA=OA.length;for(this._length+=LA.byteLength,SA=64;SA<=WA;SA+=64)u(this._hash,m(OA.subarray(SA-64,SA)));return this._buff=SA-64>2]|=WA[SA]<<(SA%4<<3);return this._finish(le,ue),OA=P(this._hash),LA&&(OA=kA(OA)),this.reset(),OA},xA.ArrayBuffer.prototype.reset=function(){return this._buff=new Uint8Array(0),this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},xA.ArrayBuffer.prototype.getState=function(){var LA=xA.prototype.getState.call(this);return LA.buff=EA(LA.buff),LA},xA.ArrayBuffer.prototype.setState=function(LA){return LA.buff=oA(LA.buff,!0),xA.prototype.setState.call(this,LA)},xA.ArrayBuffer.prototype.destroy=xA.prototype.destroy,xA.ArrayBuffer.prototype._finish=xA.prototype._finish,xA.ArrayBuffer.hash=function(LA,SA){var OA=P(v(new Uint8Array(LA)));return SA?kA(OA):OA},xA}()}(Ku)),Ku.exports),SC=uI(ju),K=new class{constructor(){this.uploadFileTryCount=0,this.maxRetries=1,this.systemClockOffset=0,this.httpRequest=null,this.uploadFileType="",this.duration=900,this.fetchCosTryCount=0}init(n){var r;this._core=n;const{IN_MINI_APP:g}=n.utils;this.httpRequest=g?RI:Hu,(r=this.httpRequest)===null||r===void 0||r.init(n)}uploadToCOS(n){return mA(this,void 0,void 0,function*(){const r=`${fa} uploadToCOS`,{ssoLog:g,utils:{safeStringify:u}}=this._core,{file:E}=n;this.uploadFileType=n.uploadFileType,g.debug("uploadToCOS",`${r} options:${u(n)}`);try{const m=Date.now(),D=yield this._createCosOptions(n),v=D.fileExistsInCOS?{data:{location:D.downloadUrl}}:yield this._uploadFile(D);this._handleUploadError(v,n);const T=this._createUploadResult(E,v),P=Date.now()-m,W=function(EA){return EA<1024?`${EA}B`:EA<1048576?`${Math.floor(EA/1024)}KB`:`${Math.floor(EA/1048576)}MB`}(E.size),oA=`size:${W} time:${P}ms speed:${Nr(1e3*E.size/P)}`;return g.debug("uploadToCOS",`${r} ok. name:${E.name} ${oA}`),{uploadOptions:D,response:T}}catch(m){throw g.warn("uploadToCOS",`${r} failed, error:${u(m)}`),m}})}_handleUploadError(n,r){var g,u;const{ChatError:E}=(g=this._core)===null||g===void 0?void 0:g.helper;if(n.statusCode===403)throw r.url,!((u=n?.data)===null||u===void 0)&&u.uploadIP&&n.data.uploadIP,new E({message:"Upload failed with status 403"})}_createUploadResult(n,r){return{fileName:n.name,fileSize:n.size,fileType:n.type.slice(n.type.indexOf("/")+1).toLowerCase(),location:r.data.location||"",uploadTime:Pr(Date.now(),!1),uploadSpeed:Nr(1e3*n.size/Pr(Date.now(),!1))}}_createCosOptions(n){return mA(this,void 0,void 0,function*(){const{fileName:r,resources:g,uploadMethod:u}=yield this._prepareUploadParams(n),E=this._isC2CConversation(n.message.conversationID)?1:2;try{const m=yield this._fetchCosSignatureUrl({fileType:this.uploadFileType,fileName:r,uploadMethod:u,duration:this.duration,userID:n.message.from,conversationType:E}),{uploadUrl:D,downloadUrl:v,requestSnapshotUrl:T,thumbUrl:P,largeUrl:W,fileKey:oA,existFlag:EA}=m,wA=!Vt.isPrivateNetWork()&&m.uploadIP;return{url:this._getRawOrUploadProxyUrl(D),fileType:this.uploadFileType,fileName:r,resources:g,downloadUrl:v,requestSnapshotUrl:T,thumbUrl:P,largeUrl:W,fileKey:oA,uploadIP:wA||"",fileExistsInCOS:EA===1,onProgress:kA=>this._handleUploadProgress(kA,n)}}catch(m){throw console.error("Failed to create COS pre-signed URL options:",m),m}})}_prepareUploadParams(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g,isEmpty:u}}=this._core;r.debug("_prepareUploadParams",` prepareUploadParams:${g(n)}`);const{file:E}=n,{IN_MINI_APP:m,IN_RN_APP:D}=Vt.getPlatformFlags(),v=m||D,T=v&&n.message.type!==qa,{name:P}=E,W=P.slice(P.lastIndexOf(".")),oA=`${Or(999999)}${W}`,EA=T?E.name:oA,wA=yield this._generateHashFileName(E);return{fileName:u(wA)?Eg(EA):`${wA}${W}`,resources:v?E.url:E,uploadMethod:v?1:0}})}_generateHashFileName(n){return mA(this,void 0,void 0,function*(){const{utils:{IN_MINI_APP:r,IN_BROWSER:g,IN_UNI_NATIVE_APP:u,isArray:E},ssoLog:m}=this._core,D=Date.now();let v="";return g&&(v=yield this._generateHashFileNameInWeb(n)),r&&(E(n.tempFiles)&&(n=n.tempFiles[0]),u||(v=yield this._generateFileNameInMiniProgram(n)),u&&(v=yield this._generateFileNameInUNINativeApp(n))),m.info("_generateHashFileName",`hashFileName:${v} costTime:${Date.now()-D}`),v})}_generateHashFileNameInWeb(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=this._core;let u="";try{u=yield new Promise((E,m)=>{const D=File.prototype.slice||File.prototype.mozSlice||File.prototype.webkitSlice;D||(r.warn("_generateHashFileNameInWeb","Browser does not support file slicing"),E(""));const v=10485760,T=Math.ceil(n.size/v);let P=0;const W=new SC.ArrayBuffer,oA=new FileReader,EA=setTimeout(()=>{oA.abort(),r.warn("_generateHashFileNameInWeb","File hash generation timeout"),E("")},2e3);function wA(){const kA=P*v,xA=kA+v>=n.size?n.size:kA+v;oA.readAsArrayBuffer(D.call(n,kA,xA))}oA.onload=kA=>{r.debug("_generateHashFileNameInWeb",`read chunk nr ${P+1} of ${T}`),W.append(kA.target.result),P++,P{clearTimeout(EA),m(kA)},wA()})}catch(E){r.warn("_generateHashFileNameInWeb",g(E))}return u})}_generateFileNameInMiniProgram(n){return mA(this,void 0,void 0,function*(){const{utils:{MINI_APP_NAMESPACE:r,safeStringify:g,isEmpty:u},ssoLog:E}=this._core;let m="";if(u(n.url))return E.warn("_generateFileNameInMiniProgram","file.url is empty"),m;if(typeof r?.getFileSystemManager!="function")return E.warn("_generateFileNameInUNINativeApp","getFileSystemManager is not a function"),m;try{m=yield new Promise((D,v)=>{r.getFileSystemManager().getFileInfo({filePath:n.url,success:T=>{D(T.digest)},fail:T=>{v(T)}})})}catch(D){E.warn("_generateFileNameInMiniProgram",g(D))}return m})}_generateFileNameInUNINativeApp(n){return mA(this,void 0,void 0,function*(){var r;const{utils:{safeStringify:g,isEmpty:u},ssoLog:E}=this._core;let m="";if(u(n.url))return E.warn("_generateFileNameInUNINativeApp","file.url is empty"),m;if(typeof((r=plus==null?void 0:plus.io)===null||r===void 0?void 0:r.getFileInfo)!="function")return E.warn("_generateFileNameInUNINativeApp","plus.io.getFileInfo is not a function"),m;try{m=yield new Promise((D,v)=>{plus.io.getFileInfo({filePath:n.url,success:T=>{D(T.digest)},fail:T=>{v(T)}})})}catch(D){E.warn("_generateFileNameInMiniProgram",g(D))}return m})}_handleUploadProgress(n,r){if(typeof r.onProgress=="function")try{r.onProgress(n.percent)}catch(g){throw console.warn("Upload progress callback error:",g),g}}_fetchCosSignatureUrl(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=this._core,u=Vt.isSimpleCos(),E=this._prepareCosRequestData(n),m=u?"im_cos_msg.simple_sig":"im_cos_msg.pre_sig";try{const D=yield function(T,P,W){return mA(this,void 0,void 0,function*(){try{const{helper:oA,channel:EA}=W,wA=oA.generateCosSpecifiedData({servcmd:T,data:P}),kA=`${wA.head.seq}${T}`;return yield EA.sendPacket(wA,{requestId:kA})}catch(oA){throw console.warn("getCosSig error:",oA),oA}})}(m,E,this._core);this.fetchCosTryCount=0;const v=this._processResponse(D);return r.debug("_fetchCosSignatureUrl",` ok. isSimpleCos:${u} data:${g(v)}`),v||{}}catch(D){if(this.fetchCosTryCount<1)return this.fetchCosTryCount++,this._fetchCosSignatureUrl(n);throw this.fetchCosTryCount=0,D}})}_processResponse(n){var r;const g=Vt.isSimpleCos(),u=g?(r=n?.rpt_pre_sig)===null||r===void 0?void 0:r[0]:n;if(!u)return{};if(g){const{str_final_ip:W,rpt_pre_sig:oA,uint32_file_id:EA,uint32_exist_flag:wA,str_download_url:kA,str_upload_url:xA,str_snapshot_url:LA,str_file_key:SA}=u;return{uploadIP:W,preSig:oA,fileID:EA,existFlag:wA,downloadUrl:kA,uploadUrl:xA,requestSnapshotUrl:LA,fileKey:SA}}const{upload_url:E,download_url:m,snapshot_url:D,thumb_url:v,large_url:T,file_key:P}=u;return{uploadUrl:E,downloadUrl:m,requestSnapshotUrl:D,thumbUrl:v,largeUrl:T,fileKey:P}}_prepareCosRequestData(n){return Vt.isSimpleCos()?{uint32_upload_method:n.uploadMethod,uint32_platform:Vt.getPlatform(),uint32_sdkappid:Vt.getSDKAppID(),str_user_id:n.userID,uint32_scene:n.conversationType,rpt_upload_object:[{uint32_file_id:1,uint32_file_type:n.fileType,str_file_name:n.fileName}]}:{file_type:n.fileType,file_name:n.fileName,upload_method:n.uploadMethod,Duration:n.duration}}_uploadFile(n){return mA(this,void 0,void 0,function*(){return new Promise((r,g)=>{this.httpRequest.request(n,(u,E)=>{u&&this.uploadFileTryCount=3e4}_syncSystemClock(n){var r,g,u;const E=((r=n.headers)===null||r===void 0?void 0:r.date)||((g=n.headers)===null||g===void 0?void 0:g.Date)||((u=n.error)===null||u===void 0?void 0:u.ServerTime);if(E){const m=Date.now(),D=Date.parse(E);this.systemClockOffset=D-m}}_getRawOrUploadProxyUrl(n){const r=Vt.getFileUploadProxy();let g=n;return r&&(g=n.replace(/^https:\/\/[^/]+/,r)),g}_isC2CConversation(n){return n.slice(0,3)==="C2C"}};const U=2108,sA=2251,b=2252,x=2253,iA=["jpg","jpeg","gif","png","bmp","image","webp"],uA={JPG:1,JPEG:1,GIF:2,PNG:3,BMP:4,UNKNOWN:255},_A=1,te=2;class fe{constructor(r,g){this.instanceID=Or(9999999),this.sizeType=r.type||0,this.type=0,this.size=r.size||0,this.width=r.width||0,this.height=r.height||0,this.imageUrl=Vt.addAuthToUrl(r.imageUrl||r.url||""),this.url=Vt.addAuthToUrl(r.url||g)}setSizeType(r){this.sizeType=r}setType(r){this.type=r}setImageUrl(r){r&&(this.imageUrl=Vt.addAuthToUrl(r))}getImageUrl(){return this.imageUrl}}function p(n){const{originUrl:r,originWidth:g,originHeight:u,min:E=198}=n,m=parseInt(g)||0,D=parseInt(u)||0,v={url:void 0,width:0,height:0};if((m<=D?m:D)<=E)v.url=r,v.width=m,v.height=D;else{D<=m?(v.width=Math.ceil(m*E/D),v.height=E):(v.width=E,v.height=Math.ceil(D*E/m));const T=r&&r.indexOf("?")>-1?`${r}&`:`${r}?`;v.url=E===198?`${T}imageView2/3/w/198/h/198`:`${T}imageView2/3/w/720/h/720`}if(r===void 0){const{url:T}=v;return vo(v,["url"])}return v}class B{constructor(r){this._imageMemoryURL="",this._percent=0,this.type=rc;const{uuid:g,file:u,imageFormat:E,imageInfoArray:m=[],isCustomUpload:D=!1}=r;this._imageMemoryURL=this.createImageDataAsURL(u),this.content={imageFormat:E,uuid:g,imageInfoArray:[]},this[jr]=D,this.initImageInfoArray(m),this.autoFixUrl()}static parseServerPushElement(r){const{MsgContent:g}=r,{ImageFormat:u,ImageInfoArray:E,UUID:m}=g,D=function(v){return v.map(T=>({size:T.Size,type:T.Type,width:T.Width,height:T.Height,url:T.URL}))}(E);return new B({imageFormat:u,imageInfoArray:D,uuid:m})}createImageDataAsURL(r){let g="";const{IN_MINI_APP:u,IN_RN_APP:E,IN_BROWSER:m}=Vt.getPlatformFlags();return r&&((u||E)&&(g=r.url),m&&(g=window.URL.createObjectURL(r))),g}initImageInfoArray(r=[]){const g={type:0,size:0,width:0,height:0,url:""};for(let u=0;u<3;u++){const E=r[u]||Object.assign({},g),m=new fe(E,this._imageMemoryURL);m.setSizeType(u+1),m.setType(u),this.addImageInfo(m)}this.updateAccessSideImageInfoArray()}autoFixUrl(){const r=["http","https"];this.content.imageInfoArray.forEach(g=>{if(!g.url||g.imageUrl==="")return;const[u,...E]=g.imageUrl.split("://"),m=E.join("://");r.includes(u)||g.setImageUrl(`https://${m}`)})}updatePercent(r){this._percent=Math.min(r,1)}updateImageFormat(r){this.content.imageFormat=uA[r.toUpperCase()]||uA.UNKNOWN}addImageInfo(r){this.content.imageInfoArray.length>=3||this.content.imageInfoArray.push(r)}updateImageInfoArray(r){const g=this.content.imageInfoArray.length;let u;for(let E=0;E({InstanceId:g.instanceID,Type:g.sizeType,MsgType:g.type,Size:g.size,Width:g.width,Height:g.height,URL:Vt.removeAuthToUrl(g.imageUrl)}))}}const M=new class{init(n){this.core=n}},G={[ru]:"i",[Cl]:"a",[ya]:"v",[xE]:"f"};let O=null,z=null;function X(n){var r;const{store:g,utils:{isNumber:u,safeStringify:E},ssoLog:m}=M.core;try{const D=((r=g.get("cloudConfig"))===null||r===void 0?void 0:r.upload_size_limit)||"";D!==z&&(z=D,O=JSON.parse(D)||{});const v=O?.[G[n]];if(u(v))return 1024*v*1024}catch(D){m.debug("getCloudControlUploadSizeLimit",E(D))}return null}var rA=new class{constructor(){this._messageOptionsMap=new Map}init(n){var r;this._core=n;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=n;u.registerApi({apiName:"createImageMessage",context:this}),u.registerExperimentalAPI("createImageMessage",this,"createCustomUploadImageMessage"),(r=m?.messageFactory)===null||r===void 0||r.registerElementClass(rc,B),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createImageMessage(n){var r,g,u;try{const E=(r=this._core.store.get("login"))===null||r===void 0?void 0:r.userId,m=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:E})),D=this._processImage(n);n.payload.file=D;const v={imageFormat:uA.UNKNOWN,uuid:Vt.generateUUID(D),file:D,imageInfoArray:[]},T=new B(v);return m.setElement(T),this._messageOptionsMap.set(m.clientSequence,n),m}catch(E){throw E}}createCustomUploadImageMessage(n){var r,g,u,E;const{store:m,utils:{isEmpty:D}}=this._core,v=(r=m.get("login"))===null||r===void 0?void 0:r.userId,T=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:v})),{largeImageUuid:P,largeFileSize:W,largeImageWidth:oA,largeImageHeight:EA,largeImageUrl:wA,originImageUuid:kA,originFileSize:xA,originImageWidth:LA,originImageHeight:SA,originImageUrl:OA,thumbImageUuid:WA,thumbFileSize:ue,thumbImageWidth:le,thumbImageHeight:ki,thumbImageUrl:Li}=((E=n?.payload)===null||E===void 0?void 0:E.file)||{};if(D(OA)||D(kA))throw new Error("createImageMessageExperimental originImageUrl or originImageUuid is empty");const Yt=new B({imageFormat:uA.UNKNOWN,uuid:kA,imageInfoArray:[{instanceID:kA,size:xA,width:LA,height:SA,imageUrl:OA,url:OA},{instanceID:P,size:W,width:oA,height:EA,imageUrl:wA,url:wA},{instanceID:WA,size:ue,width:le,height:ki,imageUrl:Li,url:Li}],isCustomUpload:!0});return T.setElement(Yt),this._messageOptionsMap.set(T.clientSequence,n),T._skipUpload=!0,T}upload(n){return mA(this,void 0,void 0,function*(){const r=n.getElements()[0],{file:g}=this._messageOptionsMap.get(n.clientSequence).payload;this._validateBeforeUploadImage(g);const u=yield this._performImageUpload(r,n,g),E=this._generateImageInfo(u);return r.updateImageFormat(u?.fileType),r.updateImageInfoArray(E),this._updateImageType(r.content.imageInfoArray),n})}_performImageUpload(n,r,g){return mA(this,void 0,void 0,function*(){const{to:u}=r,E={uploadFileType:ru,file:g,to:u,message:r,onProgress:v=>{var T,P;n.updatePercent(v),(P=(T=this._messageOptionsMap.get(r.clientSequence))===null||T===void 0?void 0:T.onProgress)===null||P===void 0||P.call(T,v)}},{uploadOptions:m,response:D}=yield K.uploadToCOS(E);return this._parseResponse(m,D)})}_generateImageInfo(n){const{location:r,fileSize:g,width:u,height:E,smallImageUrl:m,smallImageWidth:D,smallImageHeight:v,largeImageUrl:T,largeImageWidth:P,largeImageHeight:W,imageInfoArray:oA}=n,EA=Vt.addAuthToUrl(r),wA={size:g,url:EA,width:u,height:E};return oA?.length>0?this._processImageInfoArray(oA,g):m&&T?[Object.assign({},wA),{largeImageUrl:T,largeImageWidth:P,largeImageHeight:W},{smallImageUrl:m,smallImageWidth:D,smallImageHeight:v}]:[Object.assign({},wA),this._generateThumbInfo(EA,u,E,720),this._generateThumbInfo(EA,u,E,198)]}_generateThumbInfo(n,r,g,u){return p({originUrl:n,originWidth:r,originHeight:g,min:u})}_processImageInfoArray(n,r){let g,u,E;for(const m of n)m.type===1?(u=m,u.size=r):m.type===2?(E=m,E.size=r):(g=m,g.size=r);return[Object.assign({},g),Object.assign({},E),Object.assign({},u)]}_parseResponse(n,r){return mA(this,void 0,void 0,function*(){try{const{thumbUrl:g,largeUrl:u,downloadUrl:E}=n;if(g&&u&&(yield this._getImageInfoByUrl(g,r,"thumb"),yield this._getImageInfoByUrl(u,r,"large")),Vt.isSimpleCos()&&!Vt.isPrivateNetWork()&&(yield this._getImageInfoArray(E,r),r?.uploadIP)){const m=this._extractDomainFromUrl(E);m&&(yield this._getDownloadIP(m,r))}return r}catch(g){throw g}})}_extractDomainFromUrl(n){var r;try{const g=n.match(/:\/\/([^\/]+)/);return g?g[1]:null}catch(g){return(r=this._core)===null||r===void 0||r.ssoLog.warn("_extractDomainFromUrl",`Failed to extract domain from URL:${g.message}`),null}}_getImageInfoByUrl(n,r,g){return mA(this,void 0,void 0,function*(){var u;try{const E=Vt.addAuthToUrl(n),{width:m=0,height:D=0}=yield Vt.probeImageWidthHeight(E);r.width=m,r.height=D,g==="thumb"?(r.smallImageUrl=n,r.smallImageWidth=m,r.smallImageHeight=D):(r.largeImageUrl=n,r.largeImageWidth=m,r.largeImageHeight=D)}catch(E){(u=this._core)===null||u===void 0||u.ssoLog.warn("_getImageInfoByUrl",`Failed to get ${g} image info:${E.message}`)}})}_validateBeforeUploadImage(n){var r;const{ChatError:g}=(r=this._core)===null||r===void 0?void 0:r.helper;if(!n)throw new g({code:sA});this._checkImageType(n),this._checkImageSize(n)}_processImage(n){var r;try{const{IN_MINI_APP:g}=(r=this._core)===null||r===void 0?void 0:r.utils;let{file:u}=n.payload;return u=g?this._processMiniAppImageFile(u):this._processWebImageFile(u),u}catch(g){throw g}}_processMiniAppImageFile(n){dl(n)&&console.warn("FileUnsupportedInMiniApp","createImageMessage");const r=n.tempFiles[0].path||n.tempFiles[0].tempFilePath;return{url:r,name:r.slice(r.lastIndexOf("/")+1),size:n.tempFiles&&n.tempFiles[0].size||1,type:r.slice(r.lastIndexOf(".")+1).toLowerCase()}}_processWebImageFile(n){var r;const{ChatError:g}=(r=this._core)===null||r===void 0?void 0:r.helper,u=Vt.extractFileFromInput(n);if(!u)throw new g({message:"Invalid file. Pass either `e.target` (from file input) or a File object"});return u}_getDownloadIP(n,r){return mA(this,void 0,void 0,function*(){const g=`${fa} getDownloadIP domainName: ${n}`;try{const u=yield function(m,D){return mA(this,void 0,void 0,function*(){try{const{helper:v,channel:T}=D,P="im_cos_msg.get_final_ip",W={str_domain:m},oA=v.generateProtocolData({servcmd:P,data:W}),EA=`${oA.head.seq}${P}`;return yield T.sendPacket(oA,{requestId:EA})}catch(v){throw console.warn("getFinalIP error:",v),v}})}(n,this._core);if(!u||!u.str_final_ip)return;console.log(`${g} ok. downloadIP:${u}`);const E=r.location.split("/");E[0]=u.str_final_ip,r.location=E.join("/")}catch(u){console.warn(u)}})}_getImageInfoArray(n,r){return mA(this,void 0,void 0,function*(){try{const g=yield function(u,E){return mA(this,void 0,void 0,function*(){try{const{helper:m,channel:D}=E,v="im_cos_msg.get_imageinfo",T={str_image_url:u},P=m.generateProtocolData({servcmd:v,data:T}),W=`${P.head.seq}${v}`;return yield D.sendPacket(P,{requestId:W})}catch(m){throw console.warn("getImageInfo error:",m),m}})}(n,this._core);return r.imageInfoArray=this._processImageInfoResponse(g),r}catch(g){throw r.imageInfoArray=void 0,g}})}_processImageInfoResponse(n){if(!n)return[];const{rpt_msg_image_info:r}=n;return r.map(g=>({type:g.uint32_image_type,url:g.str_url,width:g.uint32_width,height:g.uint32_height,imageFormat:g.str_image_format}))}_checkImageType(n){const{utils:r,helper:g}=this._core;let u="";if(r.IN_MINI_APP&&(u=n.url.slice(n.url.lastIndexOf(".")+1)),r.IN_BROWSER&&(u=n.name.slice(n.name.lastIndexOf(".")+1)),iA.indexOf(u.toLowerCase())<0)throw new g.ChatError({code:b})}_checkImageSize(n){const{utils:r,helper:g,store:u}=this._core;let E=0;if(E=(r.IN_MINI_APP,n.size),E===0)throw new g.ChatError({code:U});if(E>=(X(ru)||20971520))throw new g.ChatError({code:x})}_updateImageType(n){n[1].type=te,n[2].type=_A}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}};const DA=2108,GA=2401,JA=2402,se="2.5.0",he="1.18.0";function Xe(n,r){const g=n.split("."),u=r.split("."),E=Math.max(g.length,u.length);for(;g.lengthv)return 1;if(D0;return{isValid:r,error:r?null:{message:"content can not be empty"}}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{uuid:E,downloadFlag:m,fileUrl:D,fileName:v,fileSize:T}=u;return{MsgType:this.type,MsgContent:{Download_Flag:m,Url:Vt.removeAuthToUrl(D),FileName:v,FileSize:T,UUID:E}}}_getFileInfo(r){const{utils:{IN_UNI_NATIVE_APP:g}}=M.core;if(r.fileName&&r.fileSize)return{size:r.fileSize,name:r.fileName};const{file:u}=r;return u?(g&&this._processNativeAppFile(u),{size:u.size,name:u.name}):{size:0,name:""}}_processNativeAppFile(r){if(r.path&&r.path.includes(".")){const g=r.path.slice(r.path.lastIndexOf(".")+1).toLowerCase();r.type=g,r.name||(r.name=`${Or(999999)}.${g}`)}r.name||(r.type="",r.name=r.path.slice(r.path.lastIndexOf("/")+1).toLowerCase()),r.suffix&&(r.type=r.suffix),r.url||(r.url=r.path)}}ct=jr;var xt=new class{constructor(){this._messageOptionsMap=new Map}init(n){var r;this._core=n;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=n;u.registerApi({apiName:"createFileMessage",context:this}),u.registerExperimentalAPI("createFileMessage",this,"createCustomUploadFileMessage"),(r=m?.messageFactory)===null||r===void 0||r.registerElementClass(qa,ut),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createFileMessage(n){var r,g,u;try{this._checkVersion();const E=this._processFile(n.payload.file);n.payload.file=E;const m=(r=this._core.store.get("login"))===null||r===void 0?void 0:r.userId,D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:m})),v={uuid:Vt.generateUUID(E),file:E},T=new ut(v);return D.setElement(T),this._messageOptionsMap.set(D.clientSequence,n),D}catch(E){throw E}}createCustomUploadFileMessage(n){var r,g,u;try{const{store:E,message:m,utils:{isEmpty:D}}=this._core,v=(r=E.get("login"))===null||r===void 0?void 0:r.userId,{url:T,uuid:P,fileSize:W,fileName:oA=""}=((g=n?.payload)===null||g===void 0?void 0:g.file)||{};if(D(T))throw new Error("url is required");const EA=(u=m.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:v})),wA=new ut({url:T,uuid:P,file:{size:W,name:oA},isCustomUpload:!0});return EA.setElement(wA),EA}catch(E){throw E}}upload(n){return mA(this,void 0,void 0,function*(){const{file:r}=this._messageOptionsMap.get(n.clientSequence).payload;this._validateBeforeUploadFile(r);const g=n.getElements()[0],u=yield this._performFileUpload(g,n,r),E=Vt.addAuthToUrl(u?.location);return g.updateFileUrl(E),n})}_validateBeforeUploadFile(n){const{helper:{ChatError:r}}=this._core;if(!n)throw new r({code:GA});const g=X(xE)||104857600;if(n.size>g)throw new r({code:JA});if(n.size===0)throw new r({code:DA})}_performFileUpload(n,r,g){return mA(this,void 0,void 0,function*(){const{to:u}=r,E={uploadFileType:xE,file:g,to:u,message:r,onProgress:D=>{var v,T;n.updatePercent(D),(T=(v=this._messageOptionsMap.get(r.clientSequence))===null||v===void 0?void 0:v.onProgress)===null||T===void 0||T.call(v,D)}},{response:m}=yield K.uploadToCOS(E);return m})}_processFile(n){var r,g;const{IN_BROWSER:u,IN_RN_APP:E,IN_WX_MINI_APP:m,IN_QQ_MINI_APP:D,IN_UNI_NATIVE_APP:v}=(r=this._core)===null||r===void 0?void 0:r.utils,{ChatError:T}=(g=this._core)===null||g===void 0?void 0:g.helper;if(u||v){const P=Vt.extractFileFromInput(n);if(!P)throw new T({message:"Invalid file. Pass either `e.target` (from file input) or a File object"});return P}if(m||D){const{tempFiles:P}=n;return Object.assign(Object.assign({},P[0]),{url:P[0].path})}return E?Object.assign(Object.assign({},n),{url:n.uri}):n}_checkVersion(){var n,r;const{MINI_APP_NAMESPACE:g,IN_MINI_APP:u,IN_WX_MINI_APP:E,IN_QQ_MINI_APP:m,IN_UNI_NATIVE_APP:D}=(n=this._core)===null||n===void 0?void 0:n.utils,{ChatError:v}=(r=this._core)===null||r===void 0?void 0:r.helper;if(u){if(!(E||m||D))throw new v({message:"Unsupported mini app environment"});const T=g.getSystemInfoSync().SDKVersion;if(E&&Xe(T,se)<0)throw new v({message:`WXChooseMessageFile requires SDK version ${se} or higher`});if(m&&Xe(T,he)<0)throw new v({message:`QQChooseMessageFile requires SDK version ${he} or higher`})}}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}};const Wt=2108,Ki=2351,Eo=2352,no=["mp4","quicktime","mov","video"];var hi;class qo{constructor(r){this.type=Vl,this.uploadProgress=0,this[hi]=!1;const g=typeof r?.videoSecond=="number"?r?.videoSecond:0;this[jr]=r.isCustomUpload||!1,this.content={remoteVideoUrl:Vt.addAuthToUrl(r.remoteVideoUrl||r.videoUrl||""),videoFormat:r.videoFormat,videoSecond:parseInt(g?.toString(),10),videoSize:r.videoSize,videoUrl:Vt.addAuthToUrl(r.videoUrl),videoDownloadFlag:2,videoUUID:r.videoUUID,thumbUUID:r.thumbUUID,thumbFormat:r.thumbFormat,thumbWidth:r.thumbWidth,snapshotWidth:r.thumbWidth,thumbHeight:r.thumbHeight,snapshotHeight:r.thumbHeight,thumbSize:r.thumbSize,snapshotSize:r.thumbSize,thumbDownloadFlag:2,thumbUrl:Vt.addAuthToUrl(r.thumbUrl),snapshotUrl:Vt.addAuthToUrl(r.thumbUrl)}}static parseServerPushElement(r){const{MsgContent:g}=r,{VideoUrl:u,VideoFormat:E,VideoSecond:m,VideoSize:D,VideoDownloadFlag:v,VideoUUID:T,ThumbUUID:P,ThumbFormat:W,ThumbWidth:oA,SnapshotWidth:EA,ThumbHeight:wA,SnapshotHeight:kA,ThumbSize:xA,SnapshotSize:LA,ThumbDownloadFlag:SA,ThumbUrl:OA,SnapshotUrl:WA}=g;return new qo({videoUrl:u,videoFormat:E,videoSecond:m,videoSize:D,videoDownloadFlag:v,videoUUID:T,thumbUUID:P,thumbFormat:W,thumbWidth:oA,snapshotWidth:EA,thumbHeight:wA,snapshotHeight:kA,thumbSize:xA,snapshotSize:LA,thumbDownloadFlag:SA,thumbUrl:OA,snapshotUrl:WA})}updatePercent(r){this.uploadProgress=Math.min(r,1)}updateVideoUrl(r){r&&(this.content.remoteVideoUrl=r)}updateSnapshotInfo(r){const{snapshotUrl:g,snapshotWidth:u,snapshotHeight:E}=r;Vt.isEmpty(g)||(this.content.thumbUrl=this.content.snapshotUrl=g),Vt.isEmpty(u)||(this.content.thumbWidth=this.content.snapshotWidth=Number(u)),Vt.isEmpty(E)||(this.content.thumbHeight=this.content.snapshotHeight=Number(E))}validateBeforeSend(){if(this[jr])return{isValid:!0};const r=this.content.remoteVideoUrl!=="";return{isValid:r,error:r?null:{message:"content can not be empty"}}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{remoteVideoUrl:E,videoFormat:m,videoSecond:D,videoSize:v,videoDownloadFlag:T,videoUUID:P,thumbUUID:W,thumbFormat:oA,thumbWidth:EA,snapshotWidth:wA,thumbHeight:kA,snapshotHeight:xA,thumbSize:LA,snapshotSize:SA,thumbDownloadFlag:OA,thumbUrl:WA,snapshotUrl:ue}=u;return{MsgType:this.type,MsgContent:{VideoUrl:Vt.removeAuthToUrl(E),VideoFormat:m,VideoSecond:D,VideoSize:v,VideoDownloadFlag:T,VideoUUID:P,ThumbUUID:W,ThumbFormat:oA,ThumbWidth:EA,SnapshotWidth:wA,ThumbHeight:kA,SnapshotHeight:xA,ThumbSize:LA,SnapshotSize:SA,ThumbDownloadFlag:OA,ThumbUrl:Vt.removeAuthToUrl(WA),SnapshotUrl:Vt.removeAuthToUrl(ue)}}}}hi=jr;var gs,yi=new class{constructor(){this._messageOptionsMap=new Map}init(n){var r;this._core=n;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=n;u.registerApi({apiName:"createVideoMessage",context:this}),u.registerExperimentalAPI("createVideoMessage",this,"createCustomUploadVideoMessage"),(r=m?.messageFactory)===null||r===void 0||r.registerElementClass(Vl,qo),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createVideoMessage(n){var r,g,u;try{const E=this._processVideo(n);n.payload.file=E;const m=(r=this._core.store.get("login"))===null||r===void 0?void 0:r.userId,D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:m})),v={videoFormat:E.videoFile.type,videoSecond:hr(E.videoFile.second,0),videoSize:E.videoFile.size,remoteVideoUrl:"",videoUrl:E.videoFile.url,videoUUID:Vt.generateUUID(E.videoFile),thumbUUID:Vt.generateUUID(E.videoFile,"jpg"),thumbWidth:E.width||200,thumbHeight:E.height||200,thumbUrl:E.thumbUrl,thumbSize:E.thumbSize,thumbFormat:"jpg"},T=new qo(v);return D.setElement(T),this._messageOptionsMap.set(D.clientSequence,n),D}catch(E){throw E}}createCustomUploadVideoMessage(n){var r,g,u;try{const{store:E,message:m}=this._core;this._validateCustomUploadVideoMessage(n);const D=(r=E.get("login"))===null||r===void 0?void 0:r.userId,{videoUrl:v,videoUuid:T,duration:P,snapshotUrl:W,snapshotUuid:oA,videoFileSize:EA,videoType:wA,snapshotWidth:kA,snapshotHeight:xA,snapshotFileSize:LA,snapshotType:SA="jpg"}=((g=n?.payload)===null||g===void 0?void 0:g.file)||{},OA=(u=m.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:D})),WA=new qo({videoFormat:wA,videoSecond:P||0,videoSize:EA,remoteVideoUrl:v,videoUrl:v,videoUUID:T,thumbUUID:oA,thumbWidth:kA||200,thumbHeight:xA||200,thumbUrl:W,thumbSize:LA,thumbFormat:SA,isCustomUpload:!0});return OA.setElement(WA),this._messageOptionsMap.set(OA.clientSequence,n),OA}catch(E){throw E}}upload(n){return mA(this,void 0,void 0,function*(){const r=n.getElements()[0],{file:g}=this._messageOptionsMap.get(n.clientSequence).payload;this._validateBeforeUploadVideo(g);const u=yield this._performVideoUpload(r,n,g),{location:E,snapshotInfo:m}=u,D=Vt.addAuthToUrl(E);return r.updateVideoUrl(D),Vt.isEmpty(m)||r.updateSnapshotInfo(m),n})}_validateBeforeUploadVideo(n){const{helper:{ChatError:r}}=this._core,g=X(ya)||104857600;if(n.videoFile.size>g)throw new r({code:Ki});if(n.videoFile.size===0)throw new r({code:Wt});if(no.indexOf(n.videoFile.type)===-1)throw new r({code:Eo})}_validateCustomUploadVideoMessage(n){var r;const{utils:{isEmpty:g,isNumber:u}}=this._core,{videoUrl:E,videoUuid:m,duration:D,snapshotUrl:v,snapshotUuid:T}=((r=n?.payload)===null||r===void 0?void 0:r.file)||{};if(g(E)||g(m)||!u(D)||g(v)||g(T))throw new Error("Invalid video message options: missing required fields (videoUrl, videoUuid, duration, snapshotUrl, snapshotUuid)")}_performVideoUpload(n,r,g){return mA(this,void 0,void 0,function*(){const{to:u}=r,E={uploadFileType:ya,file:g,to:u,message:r,onProgress:v=>{var T,P;n.updatePercent(v),(P=(T=this._messageOptionsMap.get(r.clientSequence))===null||T===void 0?void 0:T.onProgress)===null||P===void 0||P.call(T,v)}},{response:m,uploadOptions:D}=yield K.uploadToCOS(E);return{snapshotInfo:yield this._getSnapshotInfoByUrl(D.requestSnapshotUrl),location:m.location}})}_processVideo(n){var r,g;try{const{ChatError:u}=(r=this._core)===null||r===void 0?void 0:r.helper,{IN_MINI_APP:E,IN_BROWSER:m}=(g=this._core)===null||g===void 0?void 0:g.utils;let{file:D}=n.payload,v={};if(E&&(v=this._processMiniVideoFile(D),D.name=v.name,D.url=v.url,D.type=v.type),m){const T=Vt.extractFileFromInput(D);if(!T)throw new u({message:"Invalid file. Pass either `e.target` (from file input) or a File object"});D=T,v=this._processWebVideoFile(D)}return D.videoFile=v,D.thumbUrl="",D.thumbSize=0,D}catch(u){throw console.warn(`${fa} _processFile error:`,u),u}}_processMiniVideoFile(n){const{utils:{IN_UNI_NATIVE_APP:r},helper:{ChatError:g}}=this._core;if(dl(n))throw new g({message:"FileUnsupportedInMiniApp"});Array.isArray(n.tempFiles)&&(n=n.tempFiles[0]);let u=n.tempFilePath.slice(n.tempFilePath.lastIndexOf(".")+1).toLowerCase();return r&&(u=n.fileType||u),{url:n.tempFilePath,name:n.tempFilePath.slice(n.tempFilePath.lastIndexOf("/")+1),size:n.size||1,second:n.duration||0,type:u}}_processWebVideoFile(n){const{name:r,size:g=1,duration:u=0,type:E}=n,m=E.split("/")[1];return{url:window.URL.createObjectURL(n),name:r,size:g,second:u,type:m}}_getSnapshotInfoByUrl(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r}=this._core;try{r.debug("_getSnapshotInfoByUrl",`${fa} _getSnapshotInfoByUrl url:${n}`);const g={version:1,platform:Vt.getPlatform(),cover_name:Eg(Or(99999)),snapshot_url:n},u=yield function(T,P){return mA(this,void 0,void 0,function*(){try{const W="im_cos_msg.video_cover",{helper:oA,channel:EA}=P,wA=oA.generateCosSpecifiedData({servcmd:W,data:T}),kA=`${wA.head.seq}${W}`;return yield EA.sendPacket(wA,{requestId:kA})}catch(W){throw console.warn("getSnapshotInfo error:",W),W}})}(g,this._core),{download_url:E}=u||{};if(r.debug("_getSnapshotInfoByUrl",`${fa} _getSnapshotInfoByUrl OK snapshotUrl:${E}`),Vt.isEmpty(E))return{};const m=Vt.addAuthToUrl(E),{width:D=0,height:v=0}=yield Vt.probeImageWidthHeight(m);return{snapshotUrl:m,snapshotWidth:D,snapshotHeight:v}}catch(g){throw g}})}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}};class to{constructor(r){this.uploadProgress=0,this.type=Pg,this[gs]=!1,this[jr]=r.isCustomUpload||!1,this.content={downloadFlag:2,second:r.second,size:r.size,url:Vt.generateURL(r.url,{needAddAuthToUrl:!this[jr]}),remoteAudioUrl:Vt.addAuthToUrl(r.url||""),uuid:r.uuid}}static parseServerPushElement(r){const{MsgContent:g}=r,{Url:u,Download_Flag:E,Second:m,Size:D,UUID:v}=g;return new to({url:u,downloadFlag:E,second:m,size:D,uuid:v})}updatePercent(r){this.uploadProgress=Math.min(r,1)}updateAudioUrl(r){this.content.remoteAudioUrl=r}validateBeforeSend(){if(this[jr])return{isValid:!0};const r=this.content.remoteAudioUrl!=="";return{isValid:r,error:r?null:{message:"content can not be empty"}}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{uuid:E,downloadFlag:m,remoteAudioUrl:D,size:v,second:T}=u;return{MsgType:this.type,MsgContent:{Url:Vt.removeAuthToUrl(D),Download_Flag:m,Second:T,Size:v,UUID:E}}}}gs=jr;const nn=2108,be=2300,bt=2301;var FA=new class{constructor(){this._messageOptionsMap=new Map}init(n){var r;this._core=n;const{notificationCenter:g,helper:u,InnerEvent:E,message:m}=n;u.registerApi({apiName:"createAudioMessage",context:this}),u.registerExperimentalAPI("createAudioMessage",this,"createCustomUploadAudioMessage"),(r=m?.messageFactory)===null||r===void 0||r.registerElementClass(Pg,to),g.subscribeInnerEvent(E.DESTROY,this._dispose,this)}createAudioMessage(n){var r,g,u;try{let{file:E}=n.payload;E=this._processAudioFile(n.payload.file),n.payload.file=E;const m=(r=this._core.store.get("login"))===null||r===void 0?void 0:r.userId,D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:m})),v={second:Math.max(1,Math.round((E.duration||E.second)/1e3)),size:E.fileSize||E.size||1,url:E.tempFilePath||E.uri||E.url,uuid:Vt.generateUUID(E)},T=new to(v);return D.setElement(T),this._messageOptionsMap.set(D.clientSequence,n),D}catch(E){throw E}}createCustomUploadAudioMessage(n){var r,g,u;try{this._validateCustomUploadOptions(n);const{store:E,message:m}=this._core,D=(r=E.get("login"))===null||r===void 0?void 0:r.userId,{url:v,uuid:T,duration:P,fileSize:W}=((g=n?.payload)===null||g===void 0?void 0:g.file)||{},oA=(u=m.messageFactory)===null||u===void 0?void 0:u.createMessage(Object.assign(Object.assign({},n),{from:D})),EA=new to({second:P,size:W||1,url:v,uuid:T,isCustomUpload:!0});return oA.setElement(EA),this._messageOptionsMap.set(oA.clientSequence,n),oA}catch(E){throw E}}upload(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=this._core;r.debug("upload",`${fa} uploadAudio message:${g(n)}`);const{file:u}=this._messageOptionsMap.get(n.clientSequence).payload;this._validateBeforeUploadAudio(u);const E=n.getElements()[0],m=yield this._performAudioUpload(E,n,u),D=Vt.addAuthToUrl(m?.location);return E.updateAudioUrl(D),n})}_validateBeforeUploadAudio(n){const{helper:{ChatError:r},store:g}=this._core;if(!n)throw new r({code:be});const u=X(Cl)||20971520;if(n.size>u)throw new r({code:bt});if(n.size===0)throw new r({code:nn})}_performAudioUpload(n,r,g){return mA(this,void 0,void 0,function*(){const{to:u}=r,E={uploadFileType:Cl,file:g,to:u,message:r,onProgress:D=>{var v,T;n.updatePercent(D),(T=(v=this._messageOptionsMap.get(r.clientSequence))===null||v===void 0?void 0:v.onProgress)===null||T===void 0||T.call(v,D)}},{response:m}=yield K.uploadToCOS(E);return m})}_processAudioFile(n){var r;const{IN_MINI_APP:g,IN_BROWSER:u}=(r=this._core)===null||r===void 0?void 0:r.utils;return g?this._processMiniFile(n):u?this._processWebFile(n):void 0}_processMiniFile(n){return{url:n.tempFilePath,name:n.tempFilePath.slice(n.tempFilePath.lastIndexOf("/")+1),size:n.fileSize,second:n.duration,type:n.tempFilePath.slice(n.tempFilePath.lastIndexOf(".")+1).toLowerCase()}}_processWebFile(n){if(n.tempFilePath||n.uri)return n;const r=URL.createObjectURL(n);return n.tempFilePath=r,n}_validateCustomUploadOptions(n){var r;const{utils:{isEmpty:g}}=this._core,{url:u,uuid:E,duration:m}=((r=n?.payload)===null||r===void 0?void 0:r.file)||{};if(g(u)||g(E)||g(m))throw new Error("Invalid audio message options")}_reset(){this._messageOptionsMap.clear()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}};const oi={to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1},cloudCustomData:{required:!1,rules:["string"],allowEmpty:!1},priority:{required:!1,rules:["string"],allowEmpty:!1},customModerationConfigurationID:{required:!1,rules:["string"],allowEmpty:!1},onProgress:{required:!1,rules:["function"],allowEmpty:!1}},pn={createImageMessage:oi,createAudioMessage:oi,createVideoMessage:oi,createFileMessage:oi},ni={createImageMessage:!0,createAudioMessage:!0,createVideoMessage:!0,createFileMessage:!0},ys={[rc]:rA,[qa]:xt,[Vl]:yi,[Pg]:FA};var Ti=new class{constructor(){this.name="RichMediaMessage"}install(n){this._core=n;const{constants:{OuterConstant:{MSG_AUDIO:r,MSG_FILE:g,MSG_IMAGE:u,MSG_VIDEO:E}}}=n;M.init(n),rA.init(n),xt.init(n),yi.init(n),FA.init(n),K.init(n),Vt.init(n),n.helper.registerApi({apiName:"sendMessage",context:this,matcher:m=>[r,g,u,E].includes(m[0].type)}),n.helper.registerValidateConfig({auth:ni,params:pn})}sendMessage(n,r){return mA(this,void 0,void 0,function*(){var g,u,E;try{return this._isCustomUpload(n)||(yield this._upload(n)),yield(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageSender)===null||E===void 0?void 0:E.sendMessage(n,r)}catch(m){throw m}})}_upload(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=this._core;if(r.debug("_upload",` uploadFile message:${g(n)}`),n._relayFlag!==!0)try{const u=ys[n.type];u&&(yield u.upload(n),r.info("_upload",` type:${n.type}`))}catch(u){throw n.status=au.FAIL,u instanceof Error&&(u.data={message:n}),this._core.message.messageDataHandler.storeConversationMessage(n),u}})}_isCustomUpload(n){var r,g;return((g=(r=n._elements)===null||r===void 0?void 0:r[0])===null||g===void 0?void 0:g[jr])===!0}};const yo=new class{init(n){this.core=n}};class yt{constructor(r){this.conversationID=r.conversationID||"",this.unreadCount=r.unreadCount||0,this.type=r.type||"",this.lastMessage=yo.core.common.buildLastMessage(r.lastMessage),this.peerReadTime=r.peerReadTime||0,this.groupAtInfoList=[],this.remark=r.remark||"",this.isPinned=r.isPinned||!1,this.messageRemindType=r.messageRemindType,this.markList=r.markList||[],this.customData=r.customData||"",this.conversationGroupList=r.conversationGroupList||[],this.draftText=r.draftText||"",this.userProfile=r.userProfile,this.groupProfile=r.groupProfile,this.subType=r.subType||"",this._isInfoCompleted=!1,this._init()}_init(){var r;const{core:{OuterConstant:g,utils:{isUndefined:u}}}=yo;u(this.userProfile)&&this.type===g.CONV_C2C?this.userProfile={userID:this.conversationID.replace(g.CONV_C2C,"")}:this.type===g.CONV_GROUP&&(!this.subType&&(!((r=this.groupProfile)===null||r===void 0)&&r.type)&&(this.subType=this.groupProfile.type),u(this.groupProfile)&&(this.groupProfile={groupID:this.conversationID.replace(g.CONV_GROUP,""),selfInfo:{},lastMessage:{},type:this.subType}))}updateUnreadCount(r){var g;const{core:{OuterConstant:u,utils:{isUndefined:E},store:m}}=yo,{nextUnreadCount:D,isFromGetConversations:v,isUnreadC2CMessage:T}=r;if(E(D))return;if(this.subType===u.GRP_AVCHATROOM)return void(this.unreadCount=0);if(v&&this.type===u.CONV_GROUP)return void(this.unreadCount=D);if(T&&this.type===u.CONV_C2C)return void(this.unreadCount=D);const P=((g=m.get("cloudConfig"))===null||g===void 0?void 0:g.support_unread_count_for_meeting)==="1";this.subType!==u.GRP_MEETING||P?this.unreadCount+=D:this.unreadCount=0}updateLastMessage(r){this.lastMessage=yo.core.common.buildLastMessage(r)}reduceUnreadCount(){return this.unreadCount>=1&&(this.unreadCount-=1,!0)}isLastMessageRevoked(r){const{core:{OuterConstant:g}}=yo,{sequence:u,time:E}=r;return this.type===g.CONV_C2C&&u===this.lastMessage.lastSequence&&E===this.lastMessage.lastTime||this.type===g.CONV_GROUP&&u===this.lastMessage.lastSequence}setLastMessageRevoked(r){this.lastMessage.isRevoked=r}setLastMessageRevoker(r){this.lastMessage.revoker=r}setDraftText(r){this.draftText=r}updateGroupAtInfoList(r){const{core:{common:{updateGroupAtInfo:g}}}=yo;g(r,this.groupAtInfoList)}clearGroupAtInfoList(){this.groupAtInfoList.length=0}getProfileCompleted(){return this._isInfoCompleted}setProfileCompleted(){this._isInfoCompleted=!0}}const St=n=>{const{core:{OuterConstant:r,utils:{isString:g}}}=yo;return g(n)&&n.slice(0,3)===r.CONV_C2C},dg=n=>{const{core:{OuterConstant:r,utils:{isString:g}}}=yo;return g(n)&&n.slice(0,5)===r.CONV_GROUP},Js=n=>{const{core:{OuterConstant:r,utils:{isString:g}}}=yo;return g(n)&&n===r.CONV_SYSTEM};function io(n){const{OuterConstant:r}=yo.core;let g="";return n===0?g=r.MSG_REMIND_ACPT_AND_NOTE:n===1?g=r.MSG_REMIND_DISCARD:n===2?g=r.MSG_REMIND_ACPT_NOT_NOTE:n===3&&(g=r.NOT_RECEIVE_OFFLINE_PUSH_EXCEPT_AT),g}function Wr(n){const{OuterConstant:r}=yo.core;let g;return n.startsWith(r.CONV_C2C)&&(g=n.replace(r.CONV_C2C,"")),g==="@TLS#ERROR"||g==="@TLS#NOT_FOUND"}function ac(n,r){const{helper:g}=yo.core,u=new g.ChatError({functionName:n,code:r?.errorCode||r?.code,message:r?.errorInfo||r?.message});throw console.error(`${n} fail:`,u),u}var ls,ua;(function(n){n[n.OFF=0]="OFF",n[n.ON=1]="ON"})(ls||(ls={})),function(n){n[n.ONLY_CONVERSATIONID=1]="ONLY_CONVERSATIONID"}(ua||(ua={}));var Da;(function(n){n[n.CONV_NOT_FOUND=2500]="CONV_NOT_FOUND",n[n.USER_OR_GRP_NOT_FOUND=2501]="USER_OR_GRP_NOT_FOUND",n[n.CONV_UN_RECORDED_TYPE=2502]="CONV_UN_RECORDED_TYPE"})(Da||(Da={}));const oa=0,H=1;var QA=new class{constructor(){this._name="GetC2CMessageRemindType"}init(n){this._core=n}get(n){return mA(this,void 0,void 0,function*(){try{const{common:r}=this._core,g=yield function(E,m){return mA(this,void 0,void 0,function*(){const{toAccount:D,userIDList:v}=E,T={To_Account:D,Peer_Account:v};return m.common.buildAndSendPacket({servcmd:"openim.get_c2c_peer_mute_notifications",data:T})})}({toAccount:r.getCurrentUserID(),userIDList:n},this._core),{MuteNotificationsList:u=[]}=g||{};u.forEach(E=>{const{Peer_Account:m,MuteNotifications:D}=E,v=`${this._core.OuterConstant.CONV_C2C}${m}`,T=io(D);NA.patchMessageRemindType([v],T)})}catch(r){console.error(`${this._name}.get fail:`,r)}})}},yA=new class{constructor(){this._name="GetGroupMessageRemindType"}init(n){this._core=n}get(n){return mA(this,void 0,void 0,function*(){if(n.length!==0)try{const r=yield function(u,E){return mA(this,void 0,void 0,function*(){const{groupIDList:m,responseFilter:D}=u,v={GroupIdList:m,ResponseFilter:D};return E.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_self_member_info",data:v})})}({groupIDList:n,responseFilter:{MemberInfoFilter:["MsgFlag"]}},this._core),{GroupInfo:g=[]}=r||{};g.forEach(u=>{var E;const{GroupId:m,MemberList:D}=u,v=((E=D[0])===null||E===void 0?void 0:E.MsgFlag)||"",T=`${this._core.OuterConstant.CONV_GROUP}${m}`;NA.patchMessageRemindType([T],v)})}catch(r){console.error(`${this._name}.get fail:`,r)}})}},NA=new class{constructor(){this._name="ConversationDataHandler",this._totalUnreadCount=0,this._groupAtTipsList=[]}init(n){this._core=n;const{helper:r,notificationCenter:g,appStore:{conversationStore:u},constants:{WORKFLOW_NAME:E,WORKFLOW_STEP:m},InnerEvent:{SYNC_CONVERSATION_LIST:D,MESSAGE_PUSH:v,NEW_MESSAGE:T,MESSAGE_DELETED:P,MESSAGE_REVOKED:W,MESSAGE_MODIFIED:oA,CONVERSATION_UPDATED:EA,LOGOUT:wA,DESTROY:kA},InnerEventSubType:{C2C_MESSAGE_PEER_READ:xA}}=n;this._conversationStore=u,r.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_LOGIN,m.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,this._handleUnreadSyncFinished,this),r.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_LOGIN,m.CONVERSATION_UPDATE_AFTER_GROUP_LIST_SYNC_FINISHED,this._handleGroupListSyncFinished,this),r.registerWorkflowStep(E.RECEIVE_C2C_NEW_MESSAGE,m.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,this._handleNewMessage,this),r.registerWorkflowStep(E.RECEIVE_C2C_NEW_MESSAGE,m.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,this._handleUnreadSyncFinished,this),r.registerWorkflowStep(E.RECEIVE_GROUP_NEW_MESSAGE,m.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,this._handleNewMessage,this),r.registerWorkflowStep(E.SYNC_SERVER_INFO_AFTER_RE_ONLINE,m.CONVERSATION_UPDATE_AFTER_UNREAD_SYNC_FINISHED,this._handleUnreadSyncFinished,this),r.registerWorkflowStep(E.RECEIVE_GROUP_TIPS_NOTIFICATION,m.CREATE_OR_UPDATE_CONVERSATION_BY_RECEIVE_NEW_MESSAGE,this._handleNewMessage,this);const{InnerEventSubType:{GROUP_AT_TIPS:LA}}=g;g.subscribeInnerEvent(D,this._handleConversationSynced,this),g.subscribeInnerEvent(T,this._handleNewMessage,this),g.subscribeInnerEvent(v,LA,this._handleNewGroupAtTips,this),g.subscribeInnerEvent(P,this._handleMessageDeleted,this),g.subscribeInnerEvent(W,this._handleMessageRevoked,this),g.subscribeInnerEvent(oA,this._handleMessageModified,this),g.subscribeInnerEvent(EA,this._handleConversationUpdated,this),g.subscribeInnerEvent(v,xA,this._handleMessageRead,this),g.subscribeInnerEvent(wA,this._reset,this),g.subscribeInnerEvent(kA,this._dispose,this),n.ssoLog.debug(`${this._name}.init`)}_handleConversationSynced(n){this.updateLocalConversationList({conversationUpdateFieldList:n.conversationUpdateFieldList||[],isFromGetConversations:!0,updateUnreadCount:!0}),this.emitConversationListUpdate()}_handleUnreadSyncFinished(n){const{constants:{WORKFLOW_STEP:r}}=this._core,{conversationUpdateFieldList:g=[],groupTipList:u=[],isUnreadC2CMessage:E}=n.result[r.UNREAD_MESSAGE_SYNC]||{};let m=!1;g.forEach(D=>{const{conversationID:v,unreadCount:T}=D,P=this.getLocalConversation(v);P&&P.unreadCount!==T&&(P.updateUnreadCount({nextUnreadCount:T,isUnreadC2CMessage:E}),m=!0)}),m&&this.emitConversationListUpdate(),this._handleGroupAtTipsSynced(u)}_handleGroupAtTipsSynced(n){var r;for(let g=0;g0&&this._handleNewGroupAtTips({GroupTips:v._groupAtInfoList}),m=!0}m&&this.emitConversationListUpdate()}_handleNewMessage(n){const{conversationUpdateFieldList:r=[],isInstantMessage:g=!0,isUnreadC2CMessage:u=!1,updateUnreadCount:E=!0}=n.result||{};if(r.length===0)return;const{common:{isTopic:m}}=this._core;m(r[0].conversationID)||(this.updateLocalConversationList({conversationUpdateFieldList:r,isInstantMessage:g,isUnreadC2CMessage:u,isFromGetConversations:!1,updateUnreadCount:E}),r.filter(D=>this._isConversationNeedShow(D.conversationID)).length>0&&this.emitConversationListUpdate())}_handleNewGroupAtTips(n){const{GroupTips:r=[]}=n;r.forEach(g=>{const{GroupAtTips:u,MsgBody:E,MsgRandom:m,ClientSeq:D}=g;let v={};u?v=this._convertGroupAtTipsKey(u):E?v=Object.assign({},this._convertGroupAtTipsKey(E)):g.groupAtType&&(v=Object.assign({},g)),v.__random=m,v.__sequence=D,this._groupAtTipsList.push(v)}),console.log(`${this._name}._handleNewGroupAtTips groupAtTipsList: ${JSON.stringify(this._groupAtTipsList)}`),this._updateGroupAtInfoList()}_convertGroupAtTipsKey(n){const{From_Account:r,GroupId:g,MsgSeq:u,GroupAtType:E}=n;return{from:r,groupID:g,sequence:u,groupAtType:E}}_updateGroupAtInfoList(){if(this._groupAtTipsList.length===0)return;const{common:n,OuterConstant:r}=this._core,g=n.getCurrentUserID();let u=!1;this._groupAtTipsList.forEach(E=>{const{groupID:m,from:D}=E;if(D!==g){const v=this.getLocalConversation(`${r.CONV_GROUP}${m}`);v&&(v.updateGroupAtInfoList(E),u=!0)}}),u&&this.emitConversationListUpdate(),this._groupAtTipsList.length=0}_handleMessageDeleted(n){var r,g;console.log(`${this._name}._handleMessageDeleted, conversationID:`,n);const{message:{messageDataHandler:u},OuterConstant:E}=this._core,m=u?.getLocalMessageList(n)||[];let D={};for(let P=(m.length||0)-1;P>=0;P--)if(!m[P].isDeleted&&m[P]._isExcludedFromLastMessage!==!0){D=m[P];break}const v=this.getLocalConversation(n);if(!v)return;let T=!1;v.lastMessage.lastSequence===D.sequence&&v.lastMessage.lastTime===D.time||(!((g=(r=this._core)===null||r===void 0?void 0:r.helper)===null||g===void 0)&&g.isEmpty(D)&&(D=void 0),v.updateLastMessage(D),T=!0),n.startsWith(E.CONV_C2C)&&this.updateUnreadCount(n),T&&(this.emitConversationListUpdate(),console.log(`${this._name}._handleMessageDeleted. update conversationID:${n} with lastMessage:`,v.lastMessage))}_handleMessageRevoked(n){const{messageList:r=[],updateUnreadCount:g=!0}=n;if(console.log(`${this._name}._handleMessageRevoked messageList:${r.length}`),r.length===0)return;let u=null,E=!1;r.forEach(m=>{u=this.getLocalConversation(m.conversationID),u&&(g&&u.reduceUnreadCount()&&(E=!0),u.isLastMessageRevoked({sequence:m.sequence,time:m.time})&&(u.setLastMessageRevoked(!0),u.setLastMessageRevoker(m.revoker),E=!0))}),E&&this.emitConversationListUpdate()}_handleMessageModified(n){const{utils:{isEmpty:r},common:{getMessagePreviewText:g},ssoLog:u}=this._core;u.debug(`${this._name}._handleMessageModified`,JSON.stringify(n));const{conversationID:E,messageList:m}=n,D=this.getLocalConversation(E);if(r(D))return;const{lastMessage:v}=D;if(v){const T=m?.[0]||{};v.lastTime===T.time&&v.lastSequence===T.sequence&&v.version!==T.version&&(v.type=T.type,v.payload=T.payload,v.messageForShow=g(T.type,T.payload),v.cloudCustomData=T.cloudCustomData,v.version=T.version,this.emitConversationListUpdate(),console.log(`${this._name} conversationID:${E} lastMessage updated`))}}_handleConversationUpdated(n){this.emitConversationListUpdate(n?.needSort)}updateLocalConversationList(n){const{isFromGetConversations:r}=n,{newConversationList:g}=this._getTmpConversationListMapping(n);this._sortConversationList(),r||this._updateNewConversationProfile(g),this._core.ssoLog.debug("updateLocalConversationList",` newConversationList: ${g.length}`)}_getTmpConversationListMapping(n){const{OuterConstant:r}=this._core,{conversationUpdateFieldList:g,isFromGetConversations:u,isInstantMessage:E,isUnreadC2CMessage:m=!1,updateUnreadCount:D}=n,v=[],T=g?.length;for(let P=0;P{v[1].isPinned===!0?n(v[1].lastMessage.lastTime)?u.push(v):g.push(v):n(v[1].lastMessage.lastTime)?m.push(v):E.push(v)});const D=g.sort((v,T)=>T[1].lastMessage.lastTime-v[1].lastMessage.lastTime).concat(u).concat(E.sort((v,T)=>T[1].lastMessage.lastTime-v[1].lastMessage.lastTime)).concat(m);this._updateConversationMapFromList(D)}_updateNewConversationProfile(n){if(n.length===0)return;const r=[],g=[],{OuterConstant:{CONV_GROUP:u,CONV_C2C:E}}=this._core;n.forEach(m=>{const{conversationID:D,type:v}=m;if(v===E){const T=D.replace(E,"");r.push(T)}else if(v===u){const T=D.replace(u,"");g.push(T)}}),r.length>0&&this._updateC2CConversation(r),g.length>0&&this._updateGroupConversation(g)}_updateC2CConversation(n){var r;const{OuterConstant:{CONV_C2C:g},appStore:{userStore:u},user:E}=this._core;let m=!1;(r=E.userProfile)===null||r===void 0||r.getUserProfile({userIDList:n}).then(D=>{(D?.data||[]).forEach(v=>{var T;const{userID:P}=v,W=this.getLocalConversation(`${g}${P}`);if(W){const oA=((T=u.getFriend(P))===null||T===void 0?void 0:T.remark)||"";W.remark=oA,W.userProfile=v,m=!0}}),m&&this.emitConversationListUpdate()}).catch(D=>{}),QA.get(n)}_updateGroupConversation(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:{CONV_GROUP:r},appStore:{groupStore:g},utils:{safeStringify:u},ssoLog:E,apiMap:{getGroupProfile:m}}=this._core;let D=!1;try{yield Promise.all(n.map(v=>mA(this,void 0,void 0,function*(){const T=g.getGroup(v),P=this.getLocalConversation(`${r}${v}`);T&&P&&(P.groupProfile=T,D=!0),P&&!P.getProfileCompleted()&&typeof m=="function"&&(yield m({groupID:v}))}))),yA.get(n),D&&this.emitConversationListUpdate()}catch(v){E.debug("_updateGroupConversation",u(v))}})}_handleMessageRead(n){const{OuterConstant:{CONV_C2C:r}}=this._core,{C2cNotifyMsgArray:g=[]}=n||{};g.forEach(u=>{const{To_Account:E,UinPairReadArray:m=[]}=u?.C2cReadedReceipt||{};m?.forEach(D=>{const{LastReadTime:v}=D,T=`${r}${E}`;this._updateConversationReadInfo({conversationID:T,peerReadTime:v}),this._updateMessageListPeerRead({conversationID:T,peerReadTime:v})})})}_updateConversationReadInfo(n){const{appStore:r,utils:{isEmpty:g},common:{getCurrentUserID:u}}=this._core,{conversationID:E,peerReadTime:m}=n,D=r.conversationStore.getConversationMap();if(D.has(E)){const v=D.get(E);v.peerReadTime=m;const T=v?.lastMessage;g(T)||T.fromAccount===u()&&T.lastTime<=m&&!T.isPeerRead&&(T.isPeerRead=!0,r.conversationStore.updateConversation(E,{lastMessage:T}))}}_updateMessageListPeerRead(n){const{notificationCenter:r,OuterEvent:g,message:u}=this._core,{conversationID:E,peerReadTime:m}=n,D=u.messageDataHandler.getLocalMessageList(E),v=u.messageDataHandler.getSparseMessageList(E),T=[];D.forEach(P=>{P.time<=m&&!P.isPeerRead&&P.flow==="out"&&(P.isPeerRead=!0,T.push(P))}),v.forEach(P=>{P.time<=m&&!P.isPeerRead&&P.flow==="out"&&(P.isPeerRead=!0,T.push(P))}),r.emitOuterEvent(g.MESSAGE_READ_BY_PEER,{name:g.MESSAGE_READ_BY_PEER,data:T})}_isConversationNeedShow(n){var r,g;const{OuterConstant:{CONV_GROUP:u,GRP_ROOM:E,GRP_LIVE:m},utils:{isUndefined:D}}=this._core,v=this.getLocalConversation(n);if(D(v))return!0;const T=v.type===u&&((r=v.groupProfile)===null||r===void 0?void 0:r.type)===E,P=v.type===u&&((g=v.groupProfile)===null||g===void 0?void 0:g.type)===m;return!(T||P)}updateUnreadCount(n,r=!0){var g,u;let E=!1;const m=this.getLocalConversation(n),D=(u=(g=this._core)===null||g===void 0?void 0:g.message.messageDataHandler)===null||u===void 0?void 0:u.getLocalMessageList(n);if(!m)return E;const v=m.unreadCount,T=D?.filter(P=>!P.isRead&&!P._onlineOnlyFlag&&!P.isDeleted).length;return console.log(`${this._name}._updateUnreadCount conversationID:${n} currentUnreadCount:${v} newUnreadCount:${T}`),v!==T&&(m.unreadCount=T,E=!0,r===!0&&this.emitConversationListUpdate()),E}emitConversationListUpdate(n=!1){var r,g;n&&this._sortConversationList();const{OuterEvent:{CONVERSATION_LIST_UPDATED:u},conversation:E}=this._core,m=this.getLocalConversationList();this._emitEvent({name:u,data:m,isSyncCompleted:(g=(r=E?.syncConversationHandler)===null||r===void 0?void 0:r.isSyncCompleted)===null||g===void 0?void 0:g.call(r)}),this._emitTotalUnreadCountUpdate()}_emitTotalUnreadCountUpdate(){var n;const r=this.getTotalUnreadMessageCount();this._totalUnreadCount!==r&&(this._core.ssoLog.debug("_emitTotalUnreadCountUpdate",` from ${this._totalUnreadCount} to ${r}`),this._totalUnreadCount=r,this._emitEvent({name:(n=this._core)===null||n===void 0?void 0:n.OuterEvent.TOTAL_UNREAD_MESSAGE_COUNT_UPDATED,data:r}))}_emitEvent(n){var r;(r=this._core)===null||r===void 0||r.notificationCenter.emitOuterEvent(n.name,n)}getTotalUnreadMessageCount(){const{OuterConstant:n,utils:{isEmpty:r}}=this._core,g=this.getLocalConversationList();let u=0;return g.forEach(E=>{E.type!==n.CONV_SYSTEM&&(r(E.messageRemindType)||E.messageRemindType===n.MSG_REMIND_ACPT_AND_NOTE)&&(u+=E.unreadCount)}),u}getLocalConversationList(){return[...this._conversationStore.getConversationMap().values()].filter(n=>this._isConversationNeedShow(n.conversationID))}hasLocalConversation(n){return this._conversationStore.getConversationMap().has(n)}getLocalConversation(n){return this._conversationStore.getConversationMap().get(n)}setLocalConversation(n,r){return this._conversationStore.getConversationMap().set(n,r)}deleteLocalConversation(n){this._conversationStore.getConversationMap().delete(n)}_updateConversationMapFromList(n){this._clearConversationMap();for(const[r,g]of n)this.setLocalConversation(r,g)}_clearConversationMap(){this._conversationStore.getConversationMap().clear()}patchMessageRemindType(n,r){let g=!1;n.forEach(u=>{const E=this.getLocalConversation(u);E?.messageRemindType!==r&&(E.messageRemindType=r,g=!0)}),console.log(`${this._name}.patchMessageRemindType conversationIDList:${n} messageRemindType:${r} hasUpdated:${g}`),g&&this.emitConversationListUpdate()}markMessageAsRead(n){const{message:{messageDataHandler:r}}=this._core,{conversationID:g,lastReadTime:u=0,lastReadSequence:E=0}=n,m=r?.getLocalMessageList(g);if(m.length===0)return;const{length:D}=m;for(let v=D-1;v>=0;v--){const T=m[v],P=u&&T.time>u,W=E&&T.sequence>E;if(!P&&!W){if(T.flow==="in"&&T.isRead)break;T.setIsRead(!0)}}}appendToPinnedConversation(n){const r=[...this._conversationStore.getConversationMap().entries()],g=r.findIndex(u=>u[1].isPinned===!1);r.splice(g,0,[n.conversationID,n]),this._updateConversationMapFromList(r),this.emitConversationListUpdate()}_reset(){this._clearConversationMap(),this._totalUnreadCount=0,this._groupAtTipsList=[]}_dispose(){const{notificationCenter:n,InnerEvent:{NEW_MESSAGE:r,MESSAGE_DELETED:g,MESSAGE_REVOKED:u,MESSAGE_MODIFIED:E,CONVERSATION_UPDATED:m,LOGOUT:D,DESTROY:v,SYNC_CONVERSATION_LIST:T}}=this._core,{InnerEventSubType:{GROUP_AT_TIPS:P}}=n;n.unSubscribeInnerEvent(r,this._handleNewMessage,this),n.unSubscribeInnerEvent(r,P,this._handleNewGroupAtTips,this),n.unSubscribeInnerEvent(g,this._handleMessageDeleted,this),n.unSubscribeInnerEvent(u,this._handleMessageRevoked,this),n.unSubscribeInnerEvent(E,this._handleMessageModified,this),n.unSubscribeInnerEvent(m,this._handleConversationUpdated,this),n.unSubscribeInnerEvent(T,this._handleConversationSynced,this),n.unSubscribeInnerEvent(D,this._reset,this),n.unSubscribeInnerEvent(v,this._dispose,this)}},Ae=new class{constructor(){this._name="GetConversationList"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"getConversationList",context:this})}getConversationList(n){return mA(this,void 0,void 0,function*(){return{code:0,data:{conversationList:this._getConversationList(n),isSyncCompleted:this._core.conversation.syncConversationHandler.isSyncCompleted()}}})}_getConversationList(n){const{utils:{isUndefined:r,isArray:g,isPlainObject:u}}=this._core;if(r(n))return NA.getLocalConversationList();if(g(n))return n.length===0?[]:NA.getLocalConversationList().filter(E=>n.includes(E.conversationID));if(u(n)){const{type:E,markType:m,groupName:D,hasUnreadCount:v,hasGroupAtInfo:T}=n;return NA.getLocalConversationList().filter(P=>this._filterType(P,E)&&this._filterMarkType(P,m)&&this._filterGroupName(P,D)&&this._filterUnreadCount(P,v)&&this._filterGroupAtInfo(P,T))}return[]}_filterType(n,r){const{OuterConstant:g}=this._core;return r!==g.CONV_C2C&&r!==g.CONV_GROUP||n.type===r}_filterGroupName(n,r){const{utils:{isString:g}}=this._core;return!g(r)||(r===""?n.conversationGroupList.length===0:n.conversationGroupList.includes(r))}_filterMarkType(n,r){const{utils:{isNumber:g}}=this._core;return!g(r)||(r===0?n.markList.length===0:n.markList.includes(r))}_filterUnreadCount(n,r){let g=!0;return r===!0?g=n.unreadCount>=1:r===!1&&(g=n.unreadCount===0),g}_filterGroupAtInfo(n,r){let g=!0;return r===!0?g=n.groupAtInfoList.length>=1:r===!1&&(g=n.groupAtInfoList.length===0),g}},Ne=new class{constructor(){this._name="GetConversationProfile"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"getConversationProfile",context:this})}getConversationProfile(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:{CONV_C2C:r,CONV_GROUP:g,GRP_AVCHATROOM:u},appStore:{groupStore:E},utils:{isEmpty:m}}=this._core,D={code:0,data:{}};let v=NA.getLocalConversation(n);if(Js(n))return D.data.conversation=v,D;let T=!1;const P=St(n)?r:g;if(m(v)&&(T=!0,v=new yt({conversationID:n,type:P})),console.log(`${this._name}.getConversationProfile conversationID:${n} isNewConversation:${T}`),D.data.conversation=v,v?.getProfileCompleted())return D;if(P===r){const W=n.replace(r,"");yield this._handleC2CConversation(v,W),T&&(yield QA.get([W]))}if(P===g){const W=n.replace(g,"");if(!E.getGroup(W))return D;yield this._handleGroupConversation(v,W),T&&v.groupProfile.type!==u&&(yield yA.get([W]))}return D})}_handleC2CConversation(n,r){return mA(this,void 0,void 0,function*(){var g,u;const{user:E,helper:m,utils:{isEmpty:D},appStore:{conversationStore:v,userStore:T}}=this._core,{conversationID:P}=n,W=yield(g=E.userProfile)===null||g===void 0?void 0:g.getUserProfile({userIDList:[r]});if(W?.data.length===0)throw new m.ChatError({code:Da.USER_OR_GRP_NOT_FOUND});n.userProfile=W?.data[0];const oA=(u=T.getFriend(r))===null||u===void 0?void 0:u.remark;D(oA)||n.remark===oA||(n.remark=oA),n.setProfileCompleted();const EA=NA.hasLocalConversation(P);console.log(`${this._name}._handleC2CConversation conversationID:${P} hasLocalConversation: ${EA}`),EA?v.updateConversation(P,n):NA.appendToPinnedConversation(n)})}_handleGroupConversation(n,r){return mA(this,void 0,void 0,function*(){const{apiMap:{getGroupProfile:g},appStore:{conversationStore:u}}=this._core,{conversationID:E}=n,m=yield g({groupID:r});n.groupProfile=m?.data.group,n.setProfileCompleted();const D=NA.hasLocalConversation(E);console.log(`${this._name}._handleGroupConversation conversationID:${E} hasLocalConversation: ${D}`),D?u.updateConversation(E,n):NA.appendToPinnedConversation(n)})}},de=new class{init(n){const{helper:r}=n;r.registerApi({apiName:"getTotalUnreadMessageCount",context:this})}getTotalUnreadMessageCount(){return NA.getTotalUnreadMessageCount()}},Ue=new class{constructor(){this._serverGroupConversationLastReadSeqMap=new Map,this._name="SetMessageRead"}init(n){this._core=n;const{helper:r,common:{isTopic:g},notificationCenter:u,InnerEvent:{MESSAGE_PUSH:E},InnerEventSubType:{ALL_MESSAGE_READ:m}}=n;r.registerApi({apiName:"setMessageRead",context:this,matcher:D=>!g(D[0].conversationID)}),r.registerApi({apiName:"setAllMessageRead",context:this}),u.subscribeInnerEvent(E,m,this._handleAllMessageRead,this)}handleC2CMessageReadSync(n){const{helper:{isEmpty:r},OuterConstant:g}=this._core;n.forEach(u=>{const{ReadC2cMsgNotify:E}=u;if(!r(E)){const{UinPairReadArray:m=[]}=E;m.forEach(D=>{const{From_Account:v,LastReadTime:T}=D,P=`${g.CONV_C2C}${v}`;console.log(`${this._name}.handleC2CMessageReadSync conversationID:${P} lastReadTime:${T}`),NA.markMessageAsRead({conversationID:P,lastReadTime:T}),NA.updateUnreadCount(P)})}})}handleGroupMessageReadSync(n){const{OuterConstant:r,utils:{isUndefined:g}}=this._core;n.forEach(u=>{const{GroupReadInfoArray:E}=u.MsgBody;g(E)||E.forEach(m=>{const{GroupId:D,LastReadMsgSeq:v}=m,T=`${r.CONV_GROUP}${D}`;console.log(`${this._name}.handleGroupMessageReadSync conversationID:${T} lastReadSequence:${v}`),NA.markMessageAsRead({conversationID:T,lastReadSequence:v}),NA.updateUnreadCount(T),this._clearGroupAtInfoList(T)})})}setMessageRead(n){return mA(this,void 0,void 0,function*(){var r,g;const{OuterConstant:u}=this._core,{conversationID:E}=n,m={code:0,data:{}},D=NA.getLocalConversation(E);let v=`${this._name}.setMessageRead conversationID:${E} unreadCount:${D?.unreadCount||0}`;if(m.successLog={message:v},!D)return m;const T=!(!((g=(r=this._core)===null||r===void 0?void 0:r.helper)===null||g===void 0)&&g.isEmpty(D.groupAtInfoList));if(D.type===u.CONV_GROUP&&T&&this._deleteGroupAtTips(E),D.unreadCount===0)return m;const{helper:{ChatError:P}}=this._core;try{if(D.type===u.CONV_C2C){const W=this._getLocalMessageMaxTime(D);v+=`lastMessageTime:${W}`,yield this._setC2CMessageRead(E,W)}if(D.type===u.CONV_GROUP){const W=this._getLocalMessageMaxSequence(D);v+=`lastMessageSequence:${W}`,yield this._setGroupMessageRead(E,W)}}catch(W){const{errorCode:oA,errorInfo:EA}=W;throw new P({functionName:"setMessageRead",code:oA,message:EA,moreMessage:v})}return D.type===u.CONV_SYSTEM&&(D.unreadCount=0),NA.emitConversationListUpdate(),Object.assign(Object.assign({},m),{successLog:{message:v}})})}setAllMessageRead(){return mA(this,arguments,void 0,function*(n={}){const{OuterConstant:{READ_ALL_MSG:r},utils:{safeStringify:g}}=this._core;let u=`scope:${n.scope}`;n.scope||(n.scope=r);const{scope:E}=n,m=this._generateSetAllMessageReadRequestData(E);if(m.allC2CMessageReadStatus===oa&&m.groupMessageReadInfoList.length===0)return{code:0};try{const D=yield function(v){return mA(this,void 0,void 0,function*(){const{allC2CMessageReadStatus:T,groupMessageReadInfoList:P}=v,W={C2CReadAllMsg:T,GroupReadInfo:P};return yo.core.common.buildAndSendPacket({servcmd:"openim.read_all_unread_msg",data:W})})}(m);if(D){const{GroupReadInfoArray:v,C2CReadAllMsg:T}=D,P=this._parseGroupReadInfo(v);this._updateAllConversationReadStatus({allC2CMessageReadStatus:T})>0&&NA.emitConversationListUpdate(),u+=`failureGroupInfoList:${g(P)}`}return{code:0,successLog:{message:u}}}catch(D){const{errorCode:v}=D;throw new this._core.helper.ChatError({functionName:"setAllMessageRead",code:v,moreMessage:u})}})}_handleAllMessageRead(n){const{GroupReadInfoArray:r,C2CReadAllMsg:g}=n;this._parseGroupReadInfo(r),this._updateAllConversationReadStatus({allC2CMessageReadStatus:g})>0&&NA.emitConversationListUpdate()}_updateAllConversationReadStatus(n){const{OuterConstant:{CONV_C2C:r,CONV_GROUP:g},appStore:u}=this._core,E=u.conversationStore.getConversationMap(),{allC2CMessageReadStatus:m}=n;let D=0;for(const[v,T]of E)if(T.unreadCount>=1){if(m===H&&T.type===r){const P=this._getLocalMessageMaxTime(T);NA.markMessageAsRead({conversationID:v,lastReadTime:P})}else if(T.type===g){const P=v.replace(g,"");if(this._serverGroupConversationLastReadSeqMap.has(P)){const W=this._serverGroupConversationLastReadSeqMap.get(P);NA.markMessageAsRead({conversationID:v,lastReadSequence:W})}}NA.updateUnreadCount(v,!1)&&(D+=1)}return D}_generateSetAllMessageReadRequestData(n){const{OuterConstant:{CONV_C2C:r,CONV_GROUP:g,READ_ALL_C2C_MSG:u},appStore:E}=this._core,m={allC2CMessageReadStatus:oa,groupMessageReadInfoList:[]},D=E.conversationStore.getConversationMap();for(const[,v]of D){const{type:T,unreadCount:P}=v;if(this._shouldSetAllMessageRead({scope:n,type:T,unreadCount:P})){if(T===r&&m.allC2CMessageReadStatus===oa){if(m.allC2CMessageReadStatus=H,n===u)break}else if(T===g){const W=this._getLocalMessageMaxSequence(v),{groupID:oA}=v.groupProfile;m.groupMessageReadInfoList.push({GroupId:oA,MsgSeq:W})}}}return m}_parseGroupReadInfo(n){const{utils:{isUndefined:r}}=this._core,g=[];return n?.forEach(u=>{const{GroupId:E,MsgSeq:m,RetCode:D,LastReadMsgSeq:v}=u;r(D)?this._serverGroupConversationLastReadSeqMap.set(E,v):(this._serverGroupConversationLastReadSeqMap.set(E,m),D!==0&&g.push(`${E}-${m}-${D}`))}),g}_deleteGroupAtTips(n){return mA(this,void 0,void 0,function*(){console.log(`${this._name}._deleteGroupAtTips conversationID:${n}`);const r=NA.getLocalConversation(n);if(!r)return;const g=r?.groupAtInfoList||[];if(g.length!==0)try{const{common:{getCurrentUserID:u,isCommunity:E},OuterConstant:{CONV_GROUP:m,CONV_AT_ALL:D}}=this._core;let v=[...g];if(E({groupID:n.replace(m,"")})&&(v=g.filter(P=>!P.atTypeArray.includes(D)),v.length===0))return void this._clearGroupAtInfoList(n,!1);const T=v.map(P=>({From_Account:P.from,To_Account:u(),MsgSeq:P.__sequence,MsgRandom:P.__random,GroupId:P.groupID}));yield function(P,W){return mA(this,void 0,void 0,function*(){const{messageListToDelete:oA}=P,EA={DelMsgList:oA};return W.common.buildAndSendPacket({servcmd:"openim.deletemsg",data:EA})})}({messageListToDelete:T},this._core),console.log(`${this._name}._deleteGroupAtTips ok. count:${g.length}`),this._clearGroupAtInfoList(n)}catch(u){console.error(`${this._name}._deleteGroupAtTips fail:`,u)}})}_clearGroupAtInfoList(n,r=!0){const g=NA.getLocalConversation(n);g&&(g.groupAtInfoList.length>0&&(g.clearGroupAtInfoList(),console.log(`${this._name}._clearGroupAtInfoList conversationID:${n} needEmitConversationUpdate:${r}`)),r&&NA.emitConversationListUpdate())}_getLocalMessageMaxTime(n){var r;const{conversationID:g}=n,u=this._core.message.messageDataHandler.getLocalMessageList(g),E=Math.max(...u.map(D=>D.time));let m=((r=n?.lastMessage)===null||r===void 0?void 0:r.lastTime)||0;return E>m&&(console.log(`${this._name}._getLocalMessageMaxTime update lastMessageTime from ${m} to ${E}`),m=E),m}_getLocalMessageMaxSequence(n){var r;const{conversationID:g}=n,u=this._core.message.messageDataHandler.getLocalMessageList(g),E=Math.max(...u.map(D=>D.sequence));let m=((r=n?.lastMessage)===null||r===void 0?void 0:r.lastSequence)||0;return E>m&&(console.log(`${this._name}._getLocalMessageMaxSequence update lastMessageSequence from ${m} to ${E}`),m=E),m}_setC2CMessageRead(n,r){return mA(this,void 0,void 0,function*(){try{yield function(g,u){return mA(this,void 0,void 0,function*(){return u.common.buildAndSendPacket({servcmd:"openim.msgreaded",data:g})})}({C2CMsgReaded:{Cookie:"",C2CMsgReadedItem:[{To_Account:n.replace("C2C",""),LastedMsgTime:r,Receipt:1}]}},this._core),console.log(`${this._name}._setC2CMessageRead ok, lastReadTime:${r}`),NA.markMessageAsRead({conversationID:n,lastReadTime:r}),NA.updateUnreadCount(n)}catch(g){throw console.warn(`${this._name}._setC2CMessageRead fail:`,g),g}})}_setGroupMessageRead(n,r){return mA(this,void 0,void 0,function*(){try{yield function(g,u){return mA(this,void 0,void 0,function*(){const{groupID:E,lastMessageSequence:m}=g,D={GroupId:E,MsgReadedSeq:m};return u.common.buildAndSendPacket({servcmd:"group_open_http_svc.msg_read_report",data:D})})}({groupID:n.replace("GROUP",""),lastMessageSequence:r},this._core),console.log(`${this._name}._setGroupMessageRead ok, lastReadSequence:${r}`),NA.markMessageAsRead({conversationID:n,lastReadSequence:r}),NA.updateUnreadCount(n)}catch(g){throw console.warn(`${this._name}._setGroupMessageRead fail:`,g),g}})}_shouldSetAllMessageRead(n){const{OuterConstant:{CONV_C2C:r,CONV_GROUP:g,READ_ALL_MSG:u,READ_ALL_C2C_MSG:E,READ_ALL_GROUP_MSG:m}}=this._core,{type:D,scope:v,unreadCount:T}=n;return!(T<=0)&&(!(D!==r||![u,E].includes(v))||!(D!==g||![u,m].includes(v)))}},Ee=new class{constructor(){this._name="PinConversation"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"pinConversation",context:this})}handleConversationPinned(n,r){const{utils:{isArray:g}}=this._core;if(!g(n))return;const{OuterConstant:u}=this._core;let E=!1;n.forEach(m=>{const{Type:D,Peer_Account:v,GroupId:T}=m;let P;D===1?P=NA.getLocalConversation(`${u.CONV_C2C}${v}`):D===2&&(P=NA.getLocalConversation(`${u.CONV_GROUP}${T}`)),P&&(console.log(`${this._name}.handleConversationPinned conversationID:${P.conversationID} localPinned:${P.isPinned} remotePinned:${r}`),r&&!P.isPinned&&(P.isPinned=!0,E=!0),!r&&P.isPinned&&(P.isPinned=!1,E=!0))}),E&&NA.emitConversationListUpdate(!0)}pinConversation(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:r,common:g,helper:{ChatError:u}}=this._core,{conversationID:E,isPinned:m}=n,D={code:0,data:{conversationID:E}},v=NA.getLocalConversation(E);if(v&&v.isPinned===m)return D;if(Js(E))return v&&(v.isPinned=m),NA.emitConversationListUpdate(!0),D;const T=`conversationID:${E} isPinned:${m}`;try{let P=null;if(St(E)?P={Type:1,To_Account:E.replace(r.CONV_C2C,"")}:dg(E)&&(P={Type:2,GroupId:E.replace(r.CONV_GROUP,"")}),yield function(oA,EA){return mA(this,void 0,void 0,function*(){const{fromAccount:wA,operationType:kA,itemList:xA}=oA,LA={From_Account:wA,OperationType:kA,RecentContactItem:xA};return EA.common.buildAndSendPacket({servcmd:"recentcontact.top",data:LA})})}({fromAccount:g.getCurrentUserID(),operationType:m===!0?1:2,itemList:[P]},this._core)){if(v)v.isPinned!==m&&(v.isPinned=m);else{const oA=new yt({conversationID:E,type:St(E)?r.CONV_C2C:r.CONV_GROUP,isPinned:m});NA.setLocalConversation(E,oA)}NA.emitConversationListUpdate(!0)}return Object.assign(Object.assign({},D),{successLog:{message:T}})}catch(P){const{errorCode:W,errorInfo:oA}=P;throw new u({functionName:"pinConversation",code:W,message:oA,moreMessage:T})}})}},xe=new class{constructor(){this._name="DeleteConversation"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"deleteConversation",context:this})}handleConversationDeleted(n){const{utils:{isArray:r}}=this._core;if(!r(n))return;const{OuterConstant:g}=this._core,u=[];n.forEach(E=>{const{Type:m,Peer_Account:D,GroupId:v}=E;m===1&&u.push(`${g.CONV_C2C}${D}`),m===2&&u.push(`${g.CONV_GROUP}${v}`)}),console.log(`${this._name}.handleConversationDeleted conversationIDList:${u}`),this._deleteLocalConversationList(u)}deleteConversation(n){return mA(this,void 0,void 0,function*(){const{utils:{isString:r}}=this._core;if(r(n))return this._deleteConversation({conversationIDList:[n],flag:ua.ONLY_CONVERSATIONID});const g=Object.assign({},n);return g.conversationIDList.length>100&&(g.conversationIDList=g.conversationIDList.slice(0,100)),this._deleteConversation(g)})}_deleteConversation(n){return mA(this,void 0,void 0,function*(){const{conversationIDList:r,clearHistoryMessage:g=!0,flag:u=0}=n,{helper:{ChatError:E}}=this._core,m=`conversationIDList:${r} clearHistoryMessage:${g}`;try{const D=yield Promise.all([this._deleteConversationFromLocal(r),this._deleteConversationFromServer(r,g)]),v=[...D[0],...D[1]];if(v.length===0)throw new this._core.helper.ChatError({code:Da.CONV_NOT_FOUND});return{code:0,data:u===ua.ONLY_CONVERSATIONID?{conversationID:v[0]}:{conversationIDList:v},successLog:{message:m}}}catch(D){const{errorCode:v,errorInfo:T}=D;throw new E({code:v,message:T,moreMessage:m})}})}_deleteConversationFromLocal(n){const{OuterConstant:r}=this._core;return n.filter(g=>{var u;if(!NA.hasLocalConversation(g))return!1;const E=(u=NA.getLocalConversation(g))===null||u===void 0?void 0:u.type;return E!==r.CONV_GROUP||this._hasLocalGroup(g)?E===r.CONV_SYSTEM&&(this._deleteLocalConversation(g),!0):(this._deleteLocalConversation(g),!0)})}_deleteConversationFromServer(n,r){return mA(this,void 0,void 0,function*(){const{OuterConstant:g,common:u}=this._core,E={fromAccount:u.getCurrentUserID(),conversationList:[],clearHistoryMessage:r?1:0};if(n.forEach(D=>{var v;if(NA.hasLocalConversation(D)){const T=((v=NA.getLocalConversation(D))===null||v===void 0?void 0:v.type)||"",P=D.replace(T,"");T===g.CONV_C2C?E.conversationList.push({To_Account:P,Type:1}):T===g.CONV_GROUP&&this._hasLocalGroup(D)&&E.conversationList.push({ToGroupid:P,Type:2})}}),E.conversationList.length===0)return[];const m=yield function(D,v){return mA(this,void 0,void 0,function*(){const{fromAccount:T,conversationList:P,clearHistoryMessage:W}=D,oA={From_Account:T,ContactItem:P,ClearRamble:W};return v.common.buildAndSendPacket({servcmd:"recentcontact.batch_delete",data:oA})})}(E,this._core);if(m){const{ResultItem:D=[]}=m,v=[];return D.length>0&&D.forEach(T=>{if(T.ResultCode===0){const P=T.Type===1?`${g.CONV_C2C}${T.To_Account}`:`${g.CONV_GROUP}${T.ToGroupid}`;v.push(P)}}),this._deleteLocalConversationList(v),v}return[]})}_deleteLocalConversationList(n){let r=!1;n.forEach(g=>{NA.hasLocalConversation(g)&&(this._deleteLocalConversation(g,!1),r=!0)}),console.log(`${this._name}._deleteLocalConversationList isUpdate:${r}`),r&&NA.emitConversationListUpdate()}_deleteLocalConversation(n,r=!0){const g=NA.hasLocalConversation(n);console.log(`${this._name}._deleteLocalConversation conversationID:${n} has:${g}`),g&&(NA.deleteLocalConversation(n),this._deleteConversationLocalMessage(n),r&&NA.emitConversationListUpdate())}_hasLocalGroup(n){const{OuterConstant:{CONV_GROUP:r},appStore:{groupStore:g}}=this._core,u=n.replace(r,"");return!!g.getGroup(u)}_deleteConversationLocalMessage(n){console.log(`${this._name}._deleteConversationLocalMessage conversationID:${n}`),this._core.message.messageDataHandler.deleteConversationMessageList(n),this._core.message.messageHistory.completedHistoryConversations.delete(n)}},_t=new class{constructor(){this._name="SetConversationDraft"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setConversationDraft",context:this})}setConversationDraft(n){return mA(this,void 0,void 0,function*(){const{conversationID:r,draftText:g}=n;if(console.log(`${this._name} conversationID:${r} draftText:${g}`),!NA.hasLocalConversation(r))throw new this._core.helper.ChatError({code:Da.CONV_NOT_FOUND});const u=NA.getLocalConversation(r);return u?.setDraftText(g),NA.emitConversationListUpdate(),{code:0,data:{conversation:u}}})}},ti=new class{constructor(){this._name="SetC2CMessageRemindType"}init(n){this._core=n}set(n,r){return mA(this,void 0,void 0,function*(){n.length>30&&(console.warn(`${this._name}.set userIDList length:${n.length} exceeds limit 30`),n.splice(30));const g=function(){const{MSG_REMIND_ACPT_AND_NOTE:P,MSG_REMIND_DISCARD:W,MSG_REMIND_ACPT_NOT_NOTE:oA}=yo.core.OuterConstant;return{[P]:0,[W]:1,[oA]:2}}()[r],u=yield function(P,W){return mA(this,void 0,void 0,function*(){const{userIDList:oA,receiveMessageOption:EA}=P,wA={Peer_Account:oA,Mute_Notifications:EA};return W.common.buildAndSendPacket({servcmd:"openim.set_c2c_peer_mute_notifications",data:wA})})}({userIDList:n,receiveMessageOption:g},this._core),{ErrorList:E=[]}=u||{},m=[];E.forEach(P=>{const{Peer_Account:W,ErrorCode:oA}=P;m.push({userID:W,code:oA});const EA=n.indexOf(W);EA>-1&&n.splice(EA,1)});const D=[],v=[],{OuterConstant:T}=this._core;return n.forEach(P=>{v.push(`${T.CONV_C2C}${P}`),D.push({userID:P})}),NA.patchMessageRemindType(v,r),{code:0,data:{successUserIDList:D,failureUserIDList:m}}})}},ui=new class{constructor(){this._name="SetGroupMessageRemindType"}init(n){this._core=n}set(n,r){return mA(this,void 0,void 0,function*(){const{common:{getCurrentUserID:g,isTopic:u},OuterConstant:E}=this._core;if(yield function(m,D){return mA(this,void 0,void 0,function*(){const{groupID:v,userID:T,receiveMessageOption:P}=m,W={GroupId:v,Member_Account:T,MsgFlag:P};return D.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_member_info",data:W})})}({groupID:n,userID:g(),receiveMessageOption:r},this._core),!u(n)){const m=`${E.CONV_GROUP}${n}`;NA.patchMessageRemindType([m],r)}return{code:0,data:{groupID:n,messageRemindType:r}}})}},Rt=new class{constructor(){this._name="SetMessageRemindType"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setMessageRemindType",context:this})}handleC2CMessageRemindTypeSync(n){const{helper:{isEmpty:r},OuterConstant:g,ssoLog:u}=this._core;n.forEach(E=>{const{MuteNotificationsSync:m}=E;if(!r(m)){const{To_Account:D,MuteNotifications:v}=m,T=D.map(W=>`${g.CONV_C2C}${W}`),P=io(v);u.debug(`${this._name}.handleC2CMessageRemindTypeSync conversationIDList:${T} messageRemindType:${P}`),NA.patchMessageRemindType(T,P)}})}setMessageRemindType(n){return mA(this,void 0,void 0,function*(){const r="setMessageRemindType",{groupID:g,userIDList:u,messageRemindType:E}=n,{helper:m,utils:{isUndefined:D},ssoLog:v}=this._core;try{if(!D(g))return v.debug(`${this._name}.${r} groupID:${g} messageRemindType:${E}`),yield ui.set(g,E);if(!D(u))return v.debug(`${this._name}.${r} userIDList:${u} messageRemindType:${E}`),yield ti.set(u,E);throw new m.ChatError({functionName:r,message:"userIDList or groupID is required"})}catch(T){throw new m.ChatError({functionName:r,code:T?.errorCode,message:T?.errorInfo,moreMessage:`groupID:${g} userIDList:${u} messageRemindType:${E}`})}})}},fi=new class{init(n){n.ssoLog.debug("ConversationAction.init"),this._core=n,Ae.init(n),Ne.init(n),de.init(n),Ue.init(n),Ee.init(n),xe.init(n),_t.init(n),Rt.init(n);const{notificationCenter:r,InnerEvent:{MESSAGE_PUSH:g,DESTROY:u}}=this._core,{InnerEventSubType:{CONV_MODIFIED:E,C2C_MESSAGE_READ_SYNC:m,GROUP_MESSAGE_READ_SYNC:D,C2C_REMIND_TYPE_SYNC:v}}=r;r.subscribeInnerEvent(g,E,this._onConversationModified,this),r.subscribeInnerEvent(g,m,this._onC2CMessageReadSync,this),r.subscribeInnerEvent(g,v,this._onC2CMessageRemindTypeSync,this),r.subscribeInnerEvent(g,D,this._onGroupMessageReadSync,this),r.subscribeInnerEvent(u,this._dispose,this)}_onConversationModified(n){const{constants:{ConvModifyPushType:r}}=this._core,{RecentContactMod:g=[]}=n;g.forEach(u=>{const{PushType:E}=u;if(E===r.CONV_DELETED){const{RecentContactList:m}=u.RecentContactDeleteItem;xe.handleConversationDeleted(m)}if(E===r.CONV_PINED){const{RecentContactList:m}=u.RecentContactTopItem;Ee.handleConversationPinned(m,!0)}if(E===r.CONV_UNPINED){const{RecentContactList:m}=u.RecentContactTopItem;Ee.handleConversationPinned(m,!1)}})}_onC2CMessageReadSync(n){const{C2cNotifyMsgArray:r=[]}=n;Ue.handleC2CMessageReadSync(r)}_onC2CMessageRemindTypeSync(n){const{C2cNotifyMsgArray:r=[]}=n;Rt.handleC2CMessageRemindTypeSync(r)}_onGroupMessageReadSync(n){const{GroupTips:r=[]}=n;Ue.handleGroupMessageReadSync(r)}_dispose(){const{notificationCenter:n,InnerEvent:{MESSAGE_PUSH:r,DESTROY:g}}=this._core,{InnerEventSubType:{CONV_MODIFIED:u,C2C_MESSAGE_READ_SYNC:E,GROUP_MESSAGE_READ_SYNC:m,C2C_REMIND_TYPE_SYNC:D}}=n;n.unSubscribeInnerEvent(r,u,this._onConversationModified,this),n.unSubscribeInnerEvent(r,E,this._onC2CMessageReadSync,this),n.unSubscribeInnerEvent(r,D,this._onC2CMessageRemindTypeSync,this),n.unSubscribeInnerEvent(r,m,this._onGroupMessageReadSync,this),n.unSubscribeInnerEvent(g,this._dispose,this)}},go=new class{init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setAllReceiveMessageOpt",context:this})}setAllReceiveMessageOpt(n){return mA(this,void 0,void 0,function*(){try{const{OuterConstant:{MSG_REMIND_ACPT_NOT_NOTE:r}}=this._core,{messageRemindType:g=r,isRepeated:u=!0}=n,{startTime:E=0,endTime:m=0}=this._calcStartAndEndTime(n),D=yield function(v){return mA(this,void 0,void 0,function*(){const{common:T}=yo.core,{startTime:P,endTime:W,isRepeated:oA,messageRemindType:EA}=v,wA={StartTime:P,EndTime:W,IsRepeated:oA,Level:EA};return T.buildAndSendPacket({servcmd:"im_msg_db_logic.ws_set_do_not_disturb",data:wA})})}({messageRemindType:this._getType(g),startTime:E,endTime:m,isRepeated:u?ls.ON:ls.OFF});return{code:0,data:{errorCode:D.ErrorCode,errorInfo:D.ErrorInfo}}}catch(r){ac("setAllReceiveMessageOpt",r)}})}_calcStartAndEndTime(n){const{startHour:r=0,startMinute:g=0,startSecond:u=0,duration:E=0,isRepeated:m=!0}=n,D=new Date,v=new Date(D.getFullYear(),D.getMonth(),D.getDate(),r,g,u),T=Math.round(v.getTime()/1e3);let P=T+E;return m&&E>=86400&&(P=T+86400),{startTime:T,endTime:P}}_getType(n){const{OuterConstant:r}=this._core;return{[r.MSG_REMIND_ACPT_AND_NOTE]:0,[r.MSG_REMIND_DISCARD]:1,[r.MSG_REMIND_ACPT_NOT_NOTE]:2}[n]}},ms=new class{init(n){this._core=n;const{helper:r,notificationCenter:g,InnerEvent:u}=n;r.registerApi({apiName:"getAllReceiveMessageOpt",context:this}),g.subscribeInnerEvent(u.MESSAGE_PUSH,g.InnerEventSubType.ALL_RECEIVE_MESSAGE_OPTION,this.onAllReceiveMsgOptionNotify,this)}onAllReceiveMsgOptionNotify(n){const r=this._handleResult(n),{notificationCenter:g,OuterEvent:{ALL_RECEIVE_MESSAGE_OPT_UPDATED:u}}=this._core;g.emitOuterEvent(u,{name:u,data:r})}getAllReceiveMessageOpt(){return mA(this,void 0,void 0,function*(){try{const n=yield function(){return mA(this,void 0,void 0,function*(){const{common:r}=yo.core,g={To_Account:r.getCurrentUserID()};return r.buildAndSendPacket({servcmd:"im_msg_db_logic.ws_get_do_not_disturb",data:g})})}();return{code:0,data:this._handleResult(n)}}catch(n){ac("getAllReceiveMessageOpt",n)}})}_handleResult(n){const{OuterConstant:r}=this._core,{MSG_REMIND_ACPT_AND_NOTE:g,MSG_REMIND_DISCARD:u,MSG_REMIND_ACPT_NOT_NOTE:E}=r,m={0:g,1:u,2:E},{Level:D,StartTime:v,EndTime:T,IsRepeated:P}=n;return{messageRemindType:m[D]||g,startTime:v,endTime:T,isRepeated:P===ls.ON}}},xo=new class{init(n){n.ssoLog.debug("ReceiveMessageOptions.init"),this._core=n,ti.init(n),ui.init(n),QA.init(n),yA.init(n),go.init(n),ms.init(n)}};const ai=n=>!St(n)&&!dg(n)&&!Js(n),xr={getConversationProfile:[{key:"conversationID",required:!0,rules:["string"],allowEmpty:!1,customValidator:n=>!ai(n)||"conversationID is invalid."}],setMessageRead:{conversationID:{required:!0,rules:["string"],allowEmpty:!1,customValidator:n=>!ai(n)||"conversationID is invalid."}},pinConversation:{conversationID:{required:!0,rules:["string"],allowEmpty:!1,customValidator:n=>!ai(n)||"conversationID is invalid."},isPinned:{required:!0,rules:["boolean"],allowEmpty:!1}},deleteConversation:[{key:"options",required:!0,rules:["string","object"],allowEmpty:!1,customValidator:n=>{const{core:{utils:{isArray:r,isObject:g,isString:u}}}=yo;if(!u(n)&&!g(n))return"options is String or Object.";if(u(n)&&ai(n))return"conversationID is invalid.";if(g(n)){if(!r(n.conversationIDList))return"conversationIDList is not Array.";if(n.conversationIDList.length===0)return"conversationIDList is empty.";if(n.conversationIDList.some(E=>{if(ai(E))return!0}))return"conversationIDList includes invalid conversationID.";if(n.clearHistoryMessage&&typeof n.clearHistoryMessage!="boolean")return"clearHistoryMessage is not Boolean."}return!0}}],setConversationDraft:{conversationID:{required:!0,rules:["string"],allowEmpty:!1,customValidator:n=>!(!St(n)&&!dg(n))||"conversationID is invalid."},draftText:{required:!0,rules:["string"],allowEmpty:!0}},setAllReceiveMessageOpt:{messageRemindType:{required:!1,rules:["string"],allowEmpty:!0},startHour:{required:!1,rules:["number"],allowEmpty:!0},startMinute:{required:!1,rules:["number"],allowEmpty:!0},startSecond:{required:!1,rules:["number"],allowEmpty:!0},duration:{required:!1,rules:["number"],allowEmpty:!0},isRepeated:{required:!1,rules:["boolean"],allowEmpty:!0}}},os={getConversationList:!0,getConversationProfile:!0,getTotalUnreadCount:!0,setMessageRead:!0,pinConversation:!0,deleteConversation:!0,setConversationDraft:!0,setMessageRemindType:!0,getAllReceiveMessageOpt:!0,setAllReceiveMessageOpt:!0};var er=new class{constructor(){this.name="Conversation"}install(n){yo.init(n),fi.init(n),xo.init(n),NA.init(n),n.helper.registerValidateConfig({auth:os,params:xr})}};const tr=new class{init(n){this.core=n}},sa="AVChatRoom",zr="AV_HISTORY_MSG",gc="GRP_COUNTER",Wu="Set",vm="Increase",Ni="Decrease",gi=0,_o=1,un=2,Is=["Type","Name","Introduction","Notification","FaceUrl","Owner_Account","CreateTime","InfoSeq","LastInfoTime","LastMsgTime","MemberNum","MaxMemberNum","ApplyJoinOption","NextMsgSeq","ShutUpAllMember","InviteJoinOption","LastRecallTime"],Cg=["Type","Name","Introduction","Notification","FaceUrl","CreateTime","Owner_Account","LastInfoTime","LastMsgTime","NextMsgSeq","MemberNum","MaxMemberNum","ApplyJoinOption","InviteJoinOption"],Jl=["Role","JoinTime","MsgFlag","MsgSeq"],yd=["Role","JoinTime","MsgSeq","MsgFlag","NameCard"],Yc=0,_r=1,_I="notStart",cu="resolved",xg="rejected",lu=10018,TI=11e3,Vc=2,zu=["Owner","Admin","Member"],Mm=["Role","JoinTime","NameCard","ShutUpUntil","OnlineStatus"],Rm=0,wm=1,_m=2,hD=4,BD=1,qM=2,QD=3,pD=4,KM=5,wT=1,Dd=0,_T=4,mD=6,TT=400,fD=300,NT={from:!0,groupID:!0,groupName:!0,to:!0},jM={from:!0,groupID:!0,groupName:!0,to:!0,type:!0},GT=2,WM=4,bT=5,kT=7,yD=8,DD=15,kQ=20,Tm=21,Nm=2600,Sd=2602,LT=2603,UT=2620,Gm=2621,SD=2623,dh=2660,FT=2661,OT=2681,bm=2683,zM=2684,vD=2685,km=2687,ZM=3122,PT=10018,xT={0:"DisableInvite",1:"NeedPermission",2:"FreeAccess"},XM=n=>n===tr.core.OuterConstant.GRP_PUBLIC,vd=n=>n===tr.core.OuterConstant.GRP_AVCHATROOM,Lm=(n,r)=>{const{isArray:g}=tr.core.utils;if(!g(n)||!g(r))return!1;let u=!1;return r.forEach(({key:E,value:m})=>{const D=n.find(v=>v.key===E);D?D.value!==m&&(D.value=m,u=!0):(n.push({key:E,value:m}),u=!0)}),u},Md=n=>{const r=[];if(!n)return r;for(let g=0,u=n.length;g{const r=[];for(let g=0,u=n.length;g0&&v.members.forEach(T=>{T.userID===this.selfInfo.userID&&D(this.selfInfo,T,["sequence"])})}updateSelfInfo(r){const{nameCard:g,joinTime:u,role:E,messageRemindType:m,readedSequence:D,excludedUnreadSequenceList:v}=r,{common:{deepMerge:T}}=tr.core;T(this.selfInfo,{nameCard:g,joinTime:u,role:E,messageRemindType:m,readedSequence:D,excludedUnreadSequenceList:v},[],["",null,void 0,0,NaN])}setSelfNameCard(r){this.selfInfo.nameCard=r}}var Wi=new class{constructor(){this._name="GroupDataHandler"}init(n){this._core=n;const{appStore:{groupStore:r}}=n;this._groupMap=r.getGroupMap()}hasLocalGroup(n){return this._groupMap.has(n)}getLocalGroup(n){return this._groupMap.get(n)}updateLocalGroup(n){const{common:{getCurrentUserID:r}}=this._core;let g;n.forEach(E=>{var m;g=E.groupID,this.hasLocalGroup(g)?(m=this.getLocalGroup(g))===null||m===void 0||m.updateGroup(E):(this._groupMap.set(g,new Zu(E)),this._clearGroupLocalMessage(g))});const u=r();for(const[,E]of this._groupMap)E.selfInfo.userID=u,E.selfInfo.role==="Owner"&&(E.ownerID=u)}deleteLocalGroup(n){this._groupMap.delete(n)}getLocalGroupList(){const{OuterConstant:{GRP_ROOM:n,GRP_LIVE:r}}=this._core;return[...this._groupMap.values()].filter(g=>{const{type:u}=g;return u!==n&&u!==r})}clearLocalGroup(){this._groupMap.clear()}emitGroupListUpdate(){const n=this.getLocalGroupList(),{OuterEvent:{GROUP_LIST_UPDATED:r},notificationCenter:g}=this._core;g.emitOuterEvent(r,{name:r,data:n})}updateConversationGroupProfile(n){const{appStore:{conversationStore:r},OuterConstant:{CONV_GROUP:g}}=this._core,u=`${g}${n}`,E=r.getConversation(u);if(E){const m=this.getLocalGroup(n);E.setProfileCompleted(),r.updateConversation(u,{groupProfile:m})}}reset(){this.clearLocalGroup()}_clearGroupLocalMessage(n){const{message:{messageHistory:r,messageDataHandler:g},OuterConstant:{CONV_GROUP:u},ssoLog:E}=this._core;E.debug("_clearGroupLocalMessage",`groupID:${n}`);const m=`${u}${n}`;r.completedHistoryConversations.delete(m),g.deleteConversationMessageList(m)}};function Fm(n,r){return mA(this,void 0,void 0,function*(){const{type:g,limit:u,offset:E,supportTopic:m=0,memberAccount:D,responseFilter:v}=n,T={Type:g,Limit:u,Offset:E,Member_Account:D,ResponseFilter:v,SupportTopic:m,NeedAppDefineData:1};return r.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_joined_group_list",data:T})})}const mn=function(n,r){return{code:0,data:n||{},successLog:r}};var $M=new class{constructor(){this._name="GetGroupList",this._pagingStatus=_I,this.PAGING_GRP_COUNT_LIMIT=200}init(n){this._core=n;const{helper:r,constants:{WORKFLOW_NAME:g,WORKFLOW_STEP:u}}=n;r.registerApi({apiName:"getGroupList",context:this}),r.registerWorkflowStep(g.SYNC_SERVER_INFO_AFTER_LOGIN,u.GROUP_LIST_SYNC,this._syncGroupList,this)}getGroupList(){return mA(this,arguments,void 0,function*(n=!1){if(n){const g=[];return yield this._pagingGetJoinedCommunityList({limit:this.PAGING_GRP_COUNT_LIMIT,offset:0,groupList:g}),Wi.updateLocalGroup(g),Wi.getLocalGroupList()}if(this._core.ssoLog.debug("getGroupList",`${this._name}.getGroupList pagingStatus:${this._pagingStatus}`),this._pagingStatus===xg||this._pagingStatus===_I)return this._syncGroupList().then(()=>{const g=Wi.getLocalGroupList();return mn({groupList:g,isSyncCompleted:this._isSyncCompleted()})}).catch(g=>{throw g});const r=Wi.getLocalGroupList();return mn({groupList:r,isSyncCompleted:this._isSyncCompleted()},{message:`return group count:${r.length}`})})}_syncGroupList(){return mA(this,void 0,void 0,function*(){this._pagingStatus===_I&&Wi.clearLocalGroup();const n=this.PAGING_GRP_COUNT_LIMIT,r=[];try{yield this._pagingGetGroupList({limit:n,offset:0,groupList:r}),this._pagingStatus=cu,this._groupListTreeShaking(r),Wi.updateLocalGroup(r);const g=Wi.getLocalGroupList();return this._core.ssoLog.debug("_syncGroupList",`${this._name}._syncGroupList ok, count:${g.length}`),Wi.emitGroupListUpdate(),g}catch(g){throw this._pagingStatus=xg,g}})}_pagingGetGroupList(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r}=this._core,{isCommunityRelay:g=!1,groupList:u}=n;let E,{limit:m,offset:D}=n;const v=[...Is];g&&(E=this._core.OuterConstant.GRP_COMMUNITY,v.push("AtInfoList"));try{const T=yield Fm({type:E,limit:m,offset:D,memberAccount:this._core.store.get("login").userId,responseFilter:{GroupBaseInfoFilter:v,SelfInfoFilter:[...Jl]}},this._core),{GroupIdList:P=[],TotalCount:W=0}=T||{},oA=this._convertGroupKey(P);u.push(...oA);const EA=D+m,wA=!(W>EA),kA=`offset:${D} limit:${m} total:${W} isCompleted:${wA} current:${u.length} isCommunityRelay:${g}`;return r.debug("_pagingGetGroupList",`${this._name}._pagingGetGroupList ok. ${kA}`),g?wA?u:(D=EA,this._pagingGetGroupList({isCommunityRelay:!0,limit:m,offset:D,groupList:u})):wA?(r.debug("_pagingGetGroupList",`${this._name}._pagingGetGroupList start to get community list`),D=0,this._pagingGetGroupList({isCommunityRelay:!0,limit:m,offset:D,groupList:u})):(D=EA,this._pagingGetGroupList({limit:m,offset:D,groupList:u}))}catch(T){if(T.ErrorCode===lu)return r.warn("_pagingGetGroupList",`${this._name}._pagingGetGroupList response size exceeds the limit, request count:${m}`),m=50,this._pagingGetGroupList({isCommunityRelay:g,limit:m,offset:D,groupList:u});if(g)return T.code===TI&&r.debug("_pagingGetGroupList",`${this._name}._pagingGetGroupList ok. community unavailable`),u;throw T}})}_pagingGetJoinedCommunityList(n){return mA(this,void 0,void 0,function*(){const{common:{getCurrentUserID:r},OuterConstant:g,ssoLog:u}=this._core,{groupList:E}=n;let{limit:m,offset:D}=n;try{const v=yield Fm({limit:m,offset:D,type:g.GRP_COMMUNITY,memberAccount:r(),supportTopic:1,responseFilter:{GroupBaseInfoFilter:[...Is],SelfInfoFilter:[...Jl]}},this._core),{GroupIdList:T=[],TotalCount:P=0}=v||{},W=this._convertGroupKey(T);E.push(...W);const oA=D+m,EA=!(P>oA),wA=`offset:${D} limit:${m} total:${P} isCompleted:${EA} current:${E.length}`;return u.debug("_pagingGetJoinedCommunityList",`${this._name}._pagingGetJoinedCommunityList ok. ${wA}`),EA?E:(D=oA,this._pagingGetJoinedCommunityList({limit:m,offset:D,groupList:E}))}catch(v){if(v.code===PT)return u.warn("_pagingGetJoinedCommunityList",`${this._name}._pagingGetJoinedCommunityList response size exceeds the limit, request count:${m}`),m=50,this._pagingGetJoinedCommunityList({limit:m,offset:D,groupList:E});throw v}})}_groupListTreeShaking(n){const r=new Map([...Wi.getLocalGroupList()]);for(let u=0,E=n.length;u{const{AtFlagList:E,AtMsgSeq:m,From_Account:D}=u;g.push({groupID:n,groupAtType:E,sequence:m,from:D})}),g}},Xu=new class{constructor(){this._name="CreateGroup"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"createGroup",context:this})}createGroup(n){return mA(this,void 0,void 0,function*(){var r;this._preCheckParams(n);const{helper:{ChatError:g}}=this._core;try{const{utils:{isEmpty:u},common:{getCurrentUserID:E},OuterConstant:{GRP_AVCHATROOM:m}}=this._core,D=yield function(oA,EA){return mA(this,void 0,void 0,function*(){const{name:wA,type:kA,groupID:xA,introduction:LA,notification:SA,avatar:OA,maxMemberNum:WA,joinOption:ue,inviteOption:le,memberList:ki,groupCustomField:Li,isSupportTopic:Yt}=oA;let Fi,hs;ki&&(Fi=ki.map(Mt=>{const{userID:UA,memberCustomField:ci}=Mt;return{Member_Account:UA,AppMemberDefinedData:ci?VE(ci):void 0}})),Li&&(hs=VE(Li));const Re={Name:wA,Type:kA,GroupId:xA,Introduction:LA,Notification:SA,FaceUrl:OA,MaxMemberCount:WA,ApplyJoinOption:ue,InviteJoinOption:le,MemberList:Fi,AppDefinedData:hs,SupportTopic:Yt,webPushFlag:1};return EA.common.buildAndSendPacket({servcmd:"group_open_http_svc.create_group",data:Re})})}(Object.assign(Object.assign({},n),{ownerID:E()}),this._core),{GroupId:v,OverJoinedGroupLimit_Account:T=[]}=D||{},P=`${this._name}.createGroup ok, type:${n.type} groupID:${v} overLimitUserIDList:${T}`;if(u(n.memberList)||u(T)||(n.memberList=(r=n.memberList)===null||r===void 0?void 0:r.filter(oA=>T.includes(oA.userID))),n.type===m)return mn({group:new Zu(Object.assign(Object.assign({},n),{groupID:v}))},{message:P});Wi.updateLocalGroup([Object.assign(Object.assign({},n),{groupID:v})]);const W=Wi.getLocalGroup(v);return this._notNeedSendCustomMessage(n)||(this._sendCustomMessage(v,n.type),Wi.emitGroupListUpdate()),mn({group:W},{message:P})}catch(u){const{errorCode:E,errorInfo:m}=u;throw new g({functionName:"createGroup",code:E,message:m,moreMessage:` groupID:${n.groupID}`})}})}_preCheckParams(n){const{type:r,groupID:g}=n,{utils:{isEmpty:u,isUndefined:E},common:{isCommunity:m}}=this._core,D=!u(g);if(!(()=>{const{GRP_PUBLIC:v,GRP_WORK:T,GRP_MEETING:P,GRP_AVCHATROOM:W,GRP_COMMUNITY:oA}=tr.core.OuterConstant;return[v,T,P,W,oA]})().includes(r))throw new this._core.helper.ChatError({code:Nm});if(!m({type:r})){if(D&&m({groupID:g}))throw new this._core.helper.ChatError({code:Sd});E(n.isSupportTopic)||(n.isSupportTopic=void 0)}if(this._canIUseMemberList(r)||E(n.memberList)||(n.memberList=void 0),this._canIUseJoinOption(r)||E(n.joinOption)||(n.joinOption=void 0),m({type:r})){if(D&&!m({groupID:g}))throw new this._core.helper.ChatError({code:Sd});n.isSupportTopic=this._canIUseTopic(n)?1:0}}_canIUseMemberList(n){return!vd(n)}_canIUseJoinOption(n){return XM(n)||this._core.common.isCommunity({type:n})}_canIUseTopic(n){const{isSupportTopic:r}=n;return r===!0}_notNeedSendCustomMessage(n){const{type:r,isSupportTopic:g}=n,{OuterConstant:{GRP_AVCHATROOM:u,GRP_COMMUNITY:E}}=this._core;return r===u||r===E&&g===1}_sendCustomMessage(n,r){var g,u,E,m,D,v;const{OuterConstant:T,common:{t:P}}=this._core;let W=P("CREATE_GROUP"),oA=Yc;r===T.GRP_COMMUNITY&&(W=P("CREATE_COMMUNITY"),oA=_r);const EA={to:n,conversationType:"GROUP",payload:{data:JSON.stringify({businessID:"group_create",content:W,cmd:oA,opUser:this._core.store.get("login").userId,version:4})}},wA=(E=(u=(g=this._core)===null||g===void 0?void 0:g.message)===null||u===void 0?void 0:u.messageFactory)===null||E===void 0?void 0:E.createCustomMessage(EA);(v=(D=(m=this._core)===null||m===void 0?void 0:m.message)===null||D===void 0?void 0:D.messageSender)===null||v===void 0||v.sendMessage(wA,{})}},rn=new class{constructor(){this._name="AttributesDataHandler",this._groupAttributesCache=new Map,this._groupAttributesCacheValuesCopy={}}init(n){this._core=n;const{helper:r,constants:g}=n;r.registerWorkflowStep(g.WORKFLOW_NAME.SYNC_SERVER_INFO_AFTER_RE_ONLINE,g.WORKFLOW_STEP.GROUP_ATTRIBUTE_CACHE_CLEAR,this.clearLocalMainSequence,this)}clearLocalMainSequence(){this._groupAttributesCache.forEach(n=>{n.localMainSequence=0})}isGroupAttributesUpdated(n){const{elements:{newGroupProfile:r}}=n,{utils:{isEmpty:g,isUndefined:u}}=this._core;return!u(r)&&!g(r.groupAttributeOption)}handleGroupAttributesUpdated(n){const{groupID:r,groupAttributeOption:g}=n,{serverMainSequence:u,groupAttributeList:E=[],operation:m}=g;this._core.ssoLog.debug("handleGroupAttributesUpdated",`${this._name}.handleGroupAttributesUpdated groupID:${r} operation:${m}`);const{utils:{isUndefined:D}}=this._core;D(m)||(this.refreshGroupAttributesCache({groupID:r,serverMainSequence:u,groupAttributeList:E,operation:m}),this.emitGroupAttributesUpdated(r))}initGroupAttributesCache(n){const{groupID:r,avChatRoomKey:g}=n;this._groupAttributesCache.set(r,{lastUpdateTime:0,localMainSequence:0,serverMainSequence:0,avChatRoomKey:g,values:new Map}),this._core.ssoLog.debug("initGroupAttributesCache",`${this._name}.initGroupAttributesCache. groupID:${r} avChatRoomKey:${g}`)}hasGroupAttributesCache(n){return this._groupAttributesCache.has(n)}getGroupAttributesCache(n){return this.hasGroupAttributesCache(n)||this.initGroupAttributesCache({groupID:n}),this._groupAttributesCache.get(n)}deleteGroupAttributesCache(n){this.hasGroupAttributesCache(n)&&this._groupAttributesCache.delete(n)}refreshGroupAttributesCache(n){const{groupID:r,serverMainSequence:g,groupAttributeList:u,operation:E}=n;if(this.hasGroupAttributesCache(r)){const m=this.getGroupAttributesCache(r),{localMainSequence:D}=m;E!==KM&&g-D!==1||(m.serverMainSequence=g,m.localMainSequence=g,m.lastUpdateTime=Date.now(),this._updateGroupAttributesCacheValues({groupAttributes:m,groupAttributeList:u,operation:E})),g-D>1&&(m.serverMainSequence=g),this._groupAttributesCache.set(r,m),this._core.ssoLog.debug("refreshGroupAttributesCache",`${this._name}.refreshGroupAttributesCache. operation:${E} localMainSequence:${D} serverMainSequence:${g}`)}}_updateGroupAttributesCacheValues(n){const{groupAttributes:r,groupAttributeList:g=[],operation:u}=n;u!==QD?u!==pD?(u===BD&&r.values.clear(),g.forEach(E=>{const{key:m,value:D,sequence:v}=E;r.values.set(m,{value:D,sequence:v})})):g.forEach(E=>{r.values.delete(E.key)}):r.values.clear()}getGroupAttributesCacheValues(n){var r;const{groupID:g,keyList:u=[]}=n,E={};if(this.hasGroupAttributesCache(g)){const{values:m}=this.getGroupAttributesCache(g);if(u.length===0){for(const D of m.keys())E[D]=((r=m.get(D))===null||r===void 0?void 0:r.value)||"";return E}return u.forEach(D=>{var v;m.has(D)&&(E[D]=((v=m.get(D))===null||v===void 0?void 0:v.value)||"")}),E}return E}saveGroupAttributesCacheValuesCopy(n){this._groupAttributesCacheValuesCopy=this.getGroupAttributesCacheValues({groupID:n})}emitGroupAttributesUpdated(n){var r,g;const{OuterConstant:{GRP_ROOM:u,GRP_LIVE:E}}=this._core,m=this.getGroupAttributesCacheValues({groupID:n}),D=this._core.appStore.groupStore.getGroup(n),{updatedKeyList:v,deletedKeyList:T}=this._computeValuesChangedData(m);v.length===0&&T.length===0||([u,E].includes(D.type)?(this._core.ssoLog.debug("RICH_STATUS_CHANGED",`${this._name}.emitRichStatusChanged update count:${v.length}, delete count:${T.length}`),this._emitEvent({name:(r=this._core)===null||r===void 0?void 0:r.OuterEvent.RICH_STATUS_CHANGED,data:{groupID:n,richStatus:m,updatedKeyList:v,deletedKeyList:T}})):(this._core.ssoLog.debug("emitGroupAttributesUpdated",`${this._name}.emitGroupAttributesUpdated update count:${v.length}, delete count:${T.length}`),this._emitEvent({name:(g=this._core)===null||g===void 0?void 0:g.OuterEvent.GROUP_ATTRIBUTES_UPDATED,data:{groupID:n,groupAttributes:m,updatedKeyList:v,deletedKeyList:T}})))}_computeValuesChangedData(n){const{utils:{isUndefined:r}}=this._core,g=[],u=[];return Object.keys(n).forEach(E=>{n[E]!==this._groupAttributesCacheValuesCopy[E]&&g.push(E)}),Object.keys(this._groupAttributesCacheValuesCopy).forEach(E=>{r(n[E])&&u.push(E)}),this._groupAttributesCacheValuesCopy={},{updatedKeyList:g,deletedKeyList:u}}_emitEvent(n){var r;(r=this._core)===null||r===void 0||r.notificationCenter.emitOuterEvent(n.name,n)}convertKeyValueMapToList(n){const r=[];return Object.keys(n).forEach(g=>{r.push({key:g,value:n[g]})}),r}reset(){this._groupAttributesCache.clear(),this._groupAttributesCacheValuesCopy={}}},hh=new class{constructor(){this._name="DismissGroup"}init(n,r){this._core=n;const{helper:g}=n;g.registerApi({apiName:"dismissGroup",context:this,matcher:()=>!r.getInstalledSubPlugins().includes(sa)})}dismissGroup(n){return mA(this,void 0,void 0,function*(){const{helper:{ChatError:r}}=this._core;try{yield function(u,E){return mA(this,void 0,void 0,function*(){const m={GroupId:u};return E.common.buildAndSendPacket({servcmd:"group_open_http_svc.destroy_group",data:m})})}(n,this._core);const{type:g}=Wi.getLocalGroup(n);return Wi.deleteLocalGroup(n),Wi.emitGroupListUpdate(),rn.deleteGroupAttributesCache(n),mn({groupID:n,type:g},{message:n})}catch(g){const{errorCode:u,errorInfo:E}=g;throw new r({functionName:"dismissGroup",code:u,message:E})}})}},Hl=new class{constructor(){this._name="GetGroupProfile"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"getGroupProfile",context:this})}getGroupProfile(n){return mA(this,void 0,void 0,function*(){const{groupID:r,groupCustomFieldFilter:g}=n,u={groupIDList:[r],responseFilter:{GroupBaseInfoFilter:[...Is],AppDefinedDataFilter_Group:g,MemberInfoFilter:[...yd]}},{helper:{ChatError:E}}=this._core;try{const m=yield this.getGroupProfileAdvance(u),{successGroupList:D,failureGroupList:v}=m;if(v.length>0)throw v[0];let T;return!Wi.hasLocalGroup(r)&&vd(D[0].type)?T=new Zu(D[0]):(Wi.updateLocalGroup(D),T=Wi.getLocalGroup(r)),T.isSupportTopic||Wi.updateConversationGroupProfile(r),mn({group:T},{message:`groupID:${r}`})}catch(m){const{code:D,message:v}=m;throw new E({functionName:"getGroupProfile",code:D,message:v})}})}getGroupProfileAdvance(n){return mA(this,void 0,void 0,function*(){const{groupIDList:r}=n,{common:{isCommunity:g}}=this._core,u=r.filter(T=>!g({groupID:T})),E=r.filter(T=>g({groupID:T}));u.length>50&&(u.length=50),E.length>50&&(E.length=50);const m=yield Promise.all([this._getGroupProfileAdvance(Object.assign(Object.assign({},n),{groupIDList:u})),this._getGroupProfileAdvance(Object.assign(Object.assign({},n),{groupIDList:E,isCommunityProfile:!0}))]),D=[],v=[];return m.forEach(T=>{D.push(...T.successGroupList),v.push(...T.failureGroupList)}),{successGroupList:D,failureGroupList:v}})}_getGroupProfileAdvance(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{isUndefined:g}}=this._core,{isCommunityProfile:u=!1}=n,E=vo(n,["isCommunityProfile"]);if(E.groupIDList.length===0)return{successGroupList:[],failureGroupList:[]};try{const m=yield function(W,oA){return mA(this,void 0,void 0,function*(){const{groupIDList:EA,responseFilter:wA}=W,kA={GroupIdList:EA,ResponseFilter:wA};return oA.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_self_member_info",data:kA})})}(E,this._core),{GroupInfo:D=[]}=m||{},v=this._convertGroupProfileKey(D),T=v.filter(W=>g(W.errorCode)||W.errorCode===0),P=v.filter(W=>W.errorCode&&W.errorCode!==0).map(W=>({code:W.errorCode,message:W.errorInfo,data:{groupID:W.groupID}}));return r.debug("_getGroupProfileAdvance",`${this._name}._getGroupProfileAdvance ok, groupID:${E.groupIDList.join(",")}`),{successGroupList:T,failureGroupList:P}}catch(m){if(u)return{successGroupList:[],failureGroupList:[]};throw m}})}_convertGroupProfileKey(n){const r=[];for(let g=0,u=n.length;g0&&u{const{Key:T,Value:P=0}=v;E.set(T,P)}),this._groupCountersMap.set(r,{lastUpdateTime:Date.now(),groupCounterSeq:u,counters:E,avChatRoomKey:m})}}initGroupCountersCache(n){const{groupID:r,avChatRoomKey:g}=n;this._groupCountersMap.set(r,{lastUpdateTime:0,groupCounterSeq:0,counters:new Map,avChatRoomKey:g})}getLocalCounters(n,r){const g={};if(!this._hasLocalGroupCounters(n))return g;const{counters:u}=this.getLocalGroupCounters(n);if(r.length>0)r.forEach(E=>{u.has(E)&&(g[E]=u.get(E))});else for(const E of u.keys())g[E]=u.get(E);return g}deleteLocalGroupCounters(n){const{groupID:r,counterList:g=[],groupCounterSeq:u}=n;if(this._hasLocalGroupCounters(r)){const{counters:E,avChatRoomKey:m}=this.getLocalGroupCounters(r);g.forEach(D=>{E.delete(D.key)}),this._groupCountersMap.set(r,{lastUpdateTime:Date.now(),groupCounterSeq:u,counters:E,avChatRoomKey:m})}}setGroupCounters(n,r){if(!this._hasLocalGroupCounters(n))return;const g=this.getLocalGroupCounters(n),{counters:u}=g;let E=!1;Object.entries(r).forEach(([m,D])=>{u.has(m)&&u.get(m)!==D&&(u.set(m,D),E=!0)}),E&&this._groupCountersMap.set(n,Object.assign(Object.assign({},g),{lastUpdateTime:Date.now(),counters:u}))}_hasLocalGroupCounters(n){return this._groupCountersMap.has(n)}reset(){this._groupCountersMap.clear()}},JE=new class{constructor(){this._name="JoinGroup"}init(n,r){this._core=n;const{helper:g}=n;g.registerApi({apiName:"joinGroup",context:this,matcher:()=>!r.getInstalledSubPlugins().includes(sa)})}joinGroup(n){return mA(this,void 0,void 0,function*(){const{groupID:r}=n,{helper:{ChatError:g},OuterConstant:u,ssoLog:E}=this._core;try{if(Wi.hasLocalGroup(r))try{return yield Hl.getGroupProfile({groupID:r}),mn({status:u.JOIN_STATUS_ALREADY_IN_GROUP,group:Wi.getLocalGroup(r)},{message:`groupID:${r} joinedStatus:${u.JOIN_STATUS_ALREADY_IN_GROUP}`})}catch{return E.warn("joinGroup",`${this._name}.joinGroup ${r} was unjoined, start to join!`),Wi.deleteLocalGroup(r),yield this._applyJoinGroup(n)}return yield this._applyJoinGroup(n)}catch(m){const{errorCode:D,errorInfo:v}=m;throw new g({functionName:"joinGroup",code:D,message:v,moreMessage:`groupID:${r}`})}})}_applyJoinGroup(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:r,helper:g,ssoLog:u}=this._core,{groupID:E}=n,m=Object.assign({},n),D=g.checkBusinessCapabilityBits(zr);D&&(m.historyMessageFlag=1);const v=yield function(SA,OA){return mA(this,void 0,void 0,function*(){const{groupID:WA,applyMessage:ue,historyMessageFlag:le}=SA,ki={GroupId:WA,ApplyMsg:ue,HugeGroupHistoryMsgFlag:le};return OA.common.buildAndSendPacket({servcmd:"group_open_http_svc.apply_join_group",data:ki})})}(m,this._core),{Type:T,JoinedStatus:P,LongPollingKey:W,StartSeq:oA,HugeGroupFlag:EA,AVChatRoomKey:wA,RspMsgList:kA=[]}=v||{},xA=`groupID:${E} joinedStatus:${P} longPollingKey:${W} startSeq:${oA} avChatRoomFlag:${EA} canGetAVChatRoomHistoryMsg:${D}, historyMessageCount:${kA.length}`;u.debug("_applyJoinGroup",`${this._name}._applyJoinGroup ok, ${xA}`);let LA=new Zu({groupID:E,type:T});if(P===r.JOIN_STATUS_WAIT_APPROVAL)return mn({status:r.JOIN_STATUS_WAIT_APPROVAL,group:LA});if(P===r.JOIN_STATUS_SUCCESS){try{LA=(yield Hl.getGroupProfile({groupID:E})).data.group}catch(SA){u.warn("_applyJoinGroup",`${this._name}._applyJoinGroup getGroupProfile failed, groupID: ${E}, errorCode:${SA?.code}`)}return this._handleJoinResult({group:LA,avChatRoomFlag:EA,longPollingKey:W,startSequence:oA,avChatRoomKey:wA,historyMessageList:kA})}throw new this._core.helper.ChatError({code:dh})})}_handleJoinResult(n){const{group:r,avChatRoomFlag:g,avChatRoomKey:u}=n;return g===1?(rn.initGroupAttributesCache({groupID:r.groupID,avChatRoomKey:u}),cc.initGroupCountersCache({groupID:r.groupID,avChatRoomKey:u}),mn(n)):(Wi.updateLocalGroup([r]),Wi.emitGroupListUpdate(),mn({status:this._core.OuterConstant.JOIN_STATUS_SUCCESS,group:r},{message:`groupID:${r.groupID}`}))}},LQ=new class{constructor(){this._name="QuitGroup"}init(n,r){this._core=n;const{helper:g}=n;g.registerApi({apiName:"quitGroup",context:this,matcher:()=>!r.getInstalledSubPlugins().includes(sa)})}quitGroup(n){return mA(this,void 0,void 0,function*(){if(!Wi.hasLocalGroup(n))throw new this._core.helper.ChatError({code:SD});const{helper:{ChatError:r}}=this._core;try{yield function(u,E){return mA(this,void 0,void 0,function*(){const m={GroupId:u};return E.common.buildAndSendPacket({servcmd:"group_open_http_svc.quit_group",data:m})})}(n,this._core);const{type:g}=Wi.getLocalGroup(n);return Wi.deleteLocalGroup(n),Wi.emitGroupListUpdate(),rn.deleteGroupAttributesCache(n),mn({groupID:n,type:g},{message:`groupID:${n}`})}catch(g){const{errorCode:u,errorInfo:E}=g;throw new r({functionName:"quitGroup",code:u,message:E,moreMessage:`groupID:${n}`})}})}},uB=new class{constructor(){this._name="SearchGroup"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"searchGroupByID",context:this})}searchGroupByID(n){return mA(this,void 0,void 0,function*(){try{const r=yield function(OA,WA){return mA(this,void 0,void 0,function*(){const ue={GroupIdList:[OA],GroupBasePublicInfoFilter:[...Cg]};return WA.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_public_info",data:ue})})}(n,this._core),{GroupInfo:g=[]}=r||{},{AppDefinedData:u=[],ApplyJoinOption:E,CreateTime:m,FaceUrl:D,Introduction:v,InviteJoinOption:T,MaxMemberNum:P,MemberNum:W,Name:oA,Owner_Account:EA,Type:wA,ErrorCode:kA,ErrorInfo:xA}=g[0];if(kA!==0)throw new this._core.helper.ChatError({code:kA,message:xA});const LA=Md(u),SA=new Zu({groupID:n,name:oA,avatar:D,introduction:v,joinOption:E,inviteOption:T,maxMemberCount:P,memberCount:W,type:wA,ownerID:EA,createTime:m,groupCustomField:LA});return mn({group:SA})}catch(r){const{errorCode:g,errorInfo:u}=r;throw new this._core.helper.ChatError({functionName:"searchGroupByID",code:g,message:u})}})}},YT=new class{constructor(){this._name="UpdateGroupProfile"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"updateGroupProfile",context:this})}updateGroupProfile(n){return mA(this,void 0,void 0,function*(){const{groupID:r}=n,{utils:{isUndefined:g,safeStringify:u},ssoLog:E,helper:m}=this._core;let D=Wi.getLocalGroup(r);if(D){const{type:v}=D;this._canIUseJoinOption(v)||g(n.joinOption)||(E.warn("updateGroupProfile",`${this._name}.updateGroupProfile groupID:${r} joinOption is unavailable for Work/Meeting/AVChatRoom`),n.joinOption=void 0)}g(n.muteAllMembers)||(n.muteAllMembers=n.muteAllMembers===!0?"On":"Off");try{return yield function(v,T){return mA(this,void 0,void 0,function*(){const{groupID:P,name:W,avatar:oA,introduction:EA,notification:wA,muteAllMembers:kA,joinOption:xA,inviteOption:LA,groupCustomField:SA}=v,OA={GroupId:P,Name:W,FaceUrl:oA,Introduction:EA,Notification:wA,ShutUpAllMember:kA,ApplyJoinOption:xA,InviteJoinOption:LA,AppDefinedData:SA?VE(SA):void 0};return T.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_base_info",data:OA})})}(n,this._core),D?(D.updateGroup(n),Wi.emitGroupListUpdate()):D=new Zu(n),mn({group:D},{message:`groupID:${r}`})}catch(v){const{errorCode:T,errorInfo:P}=v;throw new m.ChatError({code:T,message:P,moreMessage:`options:${u(n)}`})}})}_canIUseJoinOption(n){return XM(n)||this._core.common.isCommunity({type:n})}},VT=new class{constructor(){this._name="ChangeGroupOwner"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"changeGroupOwner",context:this})}changeGroupOwner(n){return mA(this,void 0,void 0,function*(){const r="changeGroupOwner",{groupID:g,newOwnerID:u}=n,E=Wi.getLocalGroup(g),{helper:m,OuterConstant:D,common:{getCurrentUserID:v}}=this._core;if(E?.type===D.GRP_AVCHATROOM)throw new m.ChatError({functionName:r,code:UT});if(u===v())throw new m.ChatError({functionName:r,code:Gm});try{return yield function(T,P){return mA(this,void 0,void 0,function*(){const{groupID:W,newOwnerID:oA}=T,EA={GroupId:W,NewOwner_Account:oA};return P.common.buildAndSendPacket({servcmd:"group_open_http_svc.change_group_owner",data:EA})})}(n,this._core),E.ownerID=u,Wi.emitGroupListUpdate(),mn({group:E})}catch(T){throw new m.ChatError({functionName:r,code:T?.errorCode,message:T?.errorInfo})}})}},UQ=new class{constructor(){this._name="GetGroupOnlineMemberCount",this._onlineMemberCountMap=new Map}init(n,r){this._core=n;const{helper:g}=n;g.registerApi({apiName:"getGroupOnlineMemberCount",context:this,matcher:()=>!r.getInstalledSubPlugins().includes(sa)})}getGroupOnlineMemberCount(n){return mA(this,void 0,void 0,function*(){const r="getGroupOnlineMemberCount";if(!Wi.hasLocalGroup(n))return mn({memberCount:0});const g=Date.now();if(this._onlineMemberCountMap.has(n)){const u=this._onlineMemberCountMap.get(n),{lastReqTime:E=0,memberCount:m=0}=u||{};if(g-E<=6e4)return mn({memberCount:m})}try{const u=yield function(D,v){return mA(this,void 0,void 0,function*(){const T={GroupId:D};return v.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_online_member_num",data:T})})}(n,this._core),{OnlineMemberNum:E=0}=u||{};this._onlineMemberCountMap.set(n,{lastReqTime:Date.now(),memberCount:E});const m=`${this._name}.${r} ok. groupID:${n} memberCount:${E}`;return mn({memberCount:E},{message:m})}catch(u){throw new this._core.helper.ChatError({functionName:r,code:u?.errorCode,message:u?.errorInfo})}})}},FQ=new class{init(n,r){n.ssoLog.debug("GroupAction.init"),$M.init(n),Xu.init(n),hh.init(n,r),JE.init(n,r),LQ.init(n,r),uB.init(n),Hl.init(n),YT.init(n),VT.init(n),UQ.init(n,r)}dismissGroup(n){return hh.dismissGroup(n)}joinGroup(n){return JE.joinGroup(n)}quitGroup(n){return LQ.quitGroup(n)}getGroupOnlineMemberCount(n){return UQ.getGroupOnlineMemberCount(n)}},AR=new class{constructor(){this._name="GetGroupApplicationList"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"getGroupApplicationList",context:this})}getGroupApplicationList(){return mA(this,void 0,void 0,function*(){const n="getGroupApplicationList";try{const r=yield Promise.all([this._getGroupApplicationList(),this._getGroupApplicationList({type:this._core.OuterConstant.GRP_COMMUNITY})]);this._core.ssoLog.debug("getGroupApplicationList",`${this._name}.${n} ok.`);const g=this._handleGroupApplicationResult([...r[0],...r[1]]);return mn({applicationList:g})}catch(r){throw new this._core.helper.ChatError({functionName:n,code:r?.errorCode,message:r?.errorInfo})}})}_getGroupApplicationList(n){return mA(this,void 0,void 0,function*(){const{type:r,startTime:g=0,limit:u=20}=n||{},{common:E}=this._core;let m;try{m=yield function(P,W){return mA(this,void 0,void 0,function*(){const{type:oA,startTime:EA,limit:wA,handleAccount:kA}=P,xA={Type:oA,StartTime:EA,Limit:wA,Handle_Account:kA};return W.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_pendency",data:xA})})}({type:r,startTime:g,limit:u,handleAccount:E.getCurrentUserID()},this._core)}catch(P){if(P?.errorCode!==11e3)throw P;m={}}const{NextStartTime:D=0,PendencyList:v=[]}=m||{};if(D===0)return v;const T=yield this._getGroupApplicationList(Object.assign(Object.assign({},n),{startTime:D}));return[...v,...T]})}_handleGroupApplicationResult(n){const r=[];return n.forEach(g=>{const u=this._convertApplicationData(g),{handled:E}=u,m=vo(u,["handled"]);E===0&&r.push(m)}),r}_convertApplicationData(n){const{Handled:r,AddTime:g,ApplyInviteMsg:u,Authentication:E,FromUserNickName:m,From_Account:D,GroupId:v,GroupName:T,PendencyType:P,To_Account:W}=n;return{handled:r,messageKey:g,applicant:D,applicantNick:m,groupID:v,groupName:T,authentication:E,applicationType:P,userID:W,note:u,addTime:g}}},eR=new class{constructor(){this._name="HandleGroupApplication"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"handleGroupApplication",context:this})}handleGroupApplication(n){return mA(this,void 0,void 0,function*(){const{application:r}=n,g=this._handleParams(n);try{r?.applicationType===Vc?yield function(E,m){return mA(this,void 0,void 0,function*(){const{groupID:D,handleAction:v,handleMessage:T,applicant:P,authentication:W,invitee:oA}=E,EA={GroupId:D,HandleMsg:v,ApprovalMsg:T,Applicant_Account:P,Authentication:W,Invited_Account:oA};return m.common.buildAndSendPacket({servcmd:"group_open_http_svc.handle_invite_join_permission_group",data:EA})})}(g,this._core):yield function(E,m){return mA(this,void 0,void 0,function*(){const{groupID:D,handleAction:v,handleMessage:T,applicant:P,authentication:W,messageKey:oA}=E,EA={GroupId:D,HandleMsg:v,ApprovalMsg:T,Applicant_Account:P,Authentication:W,MsgKey:oA};return m.common.buildAndSendPacket({servcmd:"group_open_http_svc.handle_apply_join_group",data:EA})})}(g,this._core);const u=Wi.getLocalGroup(g.groupID);return mn({group:u})}catch(u){throw new this._core.helper.ChatError({functionName:"handleGroupApplication",code:u?.errorCode,message:u?.errorInfo})}})}_handleParams(n){var r;const{handleAction:g,handleMessage:u,message:E,application:m}=n;let D,v,T,P,W;if(E){const{payload:oA}=E||{};D=oA.operatorID,v=(r=oA.groupProfile)===null||r===void 0?void 0:r.groupID,T=oA.authentication,P=oA.messageKey}else D=m?.applicant||"",v=m?.groupID||"",T=m?.authentication||"",P=m?.messageKey||0;return m?.applicationType===Vc&&(W=m.userID),{handleAction:g,handleMessage:u,applicant:D,invitee:W,groupID:v,authentication:T,messageKey:P}}},MD=new class{init(n){n.ssoLog.debug("GroupApplication.init"),AR.init(n),eR.init(n)}};let MC=class{constructor(n){this.userID="",this.avatar="",this.nick="",this.role="",this.joinTime="",this.nameCard="",this.muteUntil=0,this.memberCustomField=[],this.isOnline=!1,this.updateMember(n)}updateMember(n){const{core:{utils:{isUndefined:r},common:{deepMerge:g}}}=tr;r(n.muteTime)||(this.muteUntil=Math.floor((Date.now()+1e3*n.muteTime)/1e3)),r(n.onlineStatus)||(this.isOnline=n.onlineStatus==="Online");const u=[null,void 0,"",0,NaN];n.memberCustomField&&Lm(this.memberCustomField,n.memberCustomField),g(this,n,["memberCustomField","marks","onlineStatus","muteTime"],u)}};function EB(n,r){return mA(this,void 0,void 0,function*(){const{groupID:g,userID:u,muteTime:E,role:m,nameCard:D,memberCustomField:v}=n;let T;v&&(T=VE(v));const P={GroupId:g,Member_Account:u,ShutUpTime:E,Role:m,NameCard:D,AppMemberDefinedData:T};return r.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_member_info",data:P})})}var RD=new class{constructor(){this._name="GetGroupMemberList"}init(n,r){this._core=n;const{helper:g}=n;g.registerApi({apiName:"getGroupMemberList",context:this,matcher:()=>!r.getInstalledSubPlugins().includes(sa)})}getGroupMemberList(n){return mA(this,void 0,void 0,function*(){const r="getGroupMemberList",{groupID:g,offset:u=0,count:E=100,role:m="",filter:D=""}=n,v=Wi.getLocalGroup(g),T=E>100?100:E,P={groupID:g,offset:u,limit:T,memberRoleFilter:zu.includes(m)?[m]:void 0,memberInfoFilter:Mm};try{const W=yield function(le,ki){return mA(this,void 0,void 0,function*(){const{isCommunity:Li}=ki.common,{groupID:Yt,offset:Fi,limit:hs,memberRoleFilter:Re,memberInfoFilter:Mt}=le,UA={GroupId:Yt,Limit:hs,MemberRoleFilter:Re,MemberInfoFilter:Mt};return Li({groupID:Yt})?UA.Next=String(Fi):UA.Offset=Fi,ki.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_member_info",data:UA})})}(P,this._core),{MemberList:oA,MemberNum:EA,Next:wA}=W||{},kA=`${this._name}.${r} ok, totalMemberCount:${EA} next:${wA}`,{utils:{isArray:xA,isEmpty:LA},common:{isCommunity:SA}}=this._core;if(v&&(v.memberCount=EA),!xA(oA)||oA.length===0)return mn({memberList:[],offset:0},{message:kA});let OA=u+T;SA({groupID:g})&&(OA=LA(wA)?0:wA),oA.lengthD.userID),u=yield(r=this._core.user.userProfile)===null||r===void 0?void 0:r.getUserProfile({userIDList:g}),E=u?.data||[],m=new Map(E.map(D=>[D.userID,D]));return n.forEach(D=>{if(m.has(D.userID)){const{nick:v="",avatar:T=""}=m.get(D.userID);D.nick=v,D.avatar=T}}),n})}_generateGroupMember(n){const r=[];for(let g=0,u=n.length;g50&&(T.warn("getGroupMemberProfile",`${this._name}.${r} userIDList length:${u.length} exceeds limit 50`),u.splice(50));const P=`userIDList length:${u.length} groupID:${g}`;try{const W=yield function(kA,xA){return mA(this,void 0,void 0,function*(){const{groupID:LA,userIDList:SA,memberInfoFilter:OA,memberCustomFieldFilter:WA}=kA,ue={GroupId:LA,Member_List_Account:SA,MemberInfoFilter:OA,AppDefinedDataFilter_GroupMember:WA};return xA.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_specified_group_member_info",data:ue})})}({groupID:g,userIDList:u,memberCustomFieldFilter:E,memberInfoFilter:[...Mm]},this._core),{MemberList:oA}=W||{};if(!v(oA)||oA.length===0)return mn({memberList:[]});let EA=this._convertMemberInfo(oA);EA=yield this._getMemberAvatarAndNick(EA);const wA=this._generateGroupMember(EA);return mn({memberList:wA},{message:P})}catch(W){throw new D.ChatError({functionName:r,code:W?.errorCode,message:W?.errorInfo,moreMessage:P})}})}_convertMemberInfo(n){const r=[];for(let g=0,u=n.length;gD.userID),u=yield(r=this._core.user.userProfile)===null||r===void 0?void 0:r.getUserProfile({userIDList:g}),E=u?.data||[],m=new Map(E.map(D=>[D.userID,D]));return n.forEach(D=>{if(m.has(D.userID)){const{nick:v="",avatar:T=""}=m.get(D.userID);D.nick=v,D.avatar=T}}),n})}_generateGroupMember(n){const r=[];for(let g=0,u=n.length;g({Member_Account:v}));try{const v=yield function(wA,kA){return mA(this,void 0,void 0,function*(){const{groupID:xA,userIDList:LA}=wA,SA={GroupId:xA,MemberList:LA};return kA.common.buildAndSendPacket({servcmd:"group_open_http_svc.add_group_member",data:SA})})}({groupID:g,userIDList:D},this._core),{MemberList:T=[]}=v||{},{failureUserIDList:P,successUserIDList:W,existedUserIDList:oA,overLimitUserIDList:EA}=this._handleResult(T);return mn({failureUserIDList:P,successUserIDList:W,existedUserIDList:oA,overLimitUserIDList:EA,group:E},{message:` groupID:${g} successUserIDList:${W} failureUserIDList:${P} existedUserIDList:${oA} overLimitUserIDList:${EA}`})}catch(v){throw new m.ChatError({functionName:r,code:v?.errorCode,message:v?.errorInfo})}})}_handleResult(n){const r=[],g=[],u=[],E=[];return n.forEach(m=>{const{Result:D,Member_Account:v}=m;D===Rm?r.push(v):D===wm?g.push(v):D===_m?u.push(v):D===hD&&E.push(v)}),{failureUserIDList:r,successUserIDList:g,existedUserIDList:u,overLimitUserIDList:E}}},wd=new class{constructor(){this._name="DeleteGroupMember"}init(n,r){this._core=n;const{helper:g}=n;g.registerApi({apiName:"deleteGroupMember",context:this,matcher:()=>!r.getInstalledSubPlugins().includes(sa)})}deleteGroupMember(n){return mA(this,void 0,void 0,function*(){const r="deleteGroupMember",{groupID:g,userIDList:u}=n,E=Wi.getLocalGroup(g),{helper:m,utils:{isUndefined:D},ssoLog:v}=this._core;if(D(E))throw new m.ChatError({functionName:r,code:LT});u.length>20&&(v.warn("deleteGroupMember",`${this._name}.${r} userIDList length:${u.length} exceeds limit 20`),u.splice(20));try{return yield function(T,P){return mA(this,void 0,void 0,function*(){const{groupID:W,userIDList:oA,reason:EA}=T,wA={GroupId:W,MemberToDel_Account:oA,Reason:EA};return P.common.buildAndSendPacket({servcmd:"group_open_http_svc.delete_group_member",data:wA})})}({groupID:g,userIDList:u},this._core),mn({group:E,userIDList:u},{message:`groupID:${g} userIDList length:${u.length}`})}catch(T){throw new m.ChatError({functionName:r,code:T?.errorCode,message:T?.errorInfo})}})}},tR=new class{constructor(){this._name="SetGroupMemberMuteTime"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setGroupMemberMuteTime",context:this})}setGroupMemberMuteTime(n){return mA(this,void 0,void 0,function*(){const{helper:r}=this._core,{groupID:g,userID:u,muteTime:E}=n,m=` groupID:${g} userID:${u} muteTime:${E}`;this._preCheckSettingMuteParams(n);try{yield EB(n,this._core);const D=Wi.getLocalGroup(g),v=new MC({userID:u,muteTime:E});return mn({group:D,member:v},{message:m})}catch(D){throw new r.ChatError({functionName:"setGroupMemberMuteTime",code:D?.errorCode,message:D?.errorInfo,moreMessage:m})}})}_preCheckSettingMuteParams(n){const{userID:r}=n,{store:g,helper:u}=this._core;if(r===g.get("login").userId)throw new u.ChatError({functionName:"setGroupMemberMuteTime",code:vD})}},PQ=new class{constructor(){this._name="SetGroupMemberRole"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setGroupMemberRole",context:this})}setGroupMemberRole(n){return mA(this,void 0,void 0,function*(){const r="setGroupMemberRole",{helper:g}=this._core,{groupID:u,userID:E,role:m}=n,D=`${this._name}.${r} ok, groupID:${u} userID:${E} role:${m}`;this._preCheckSettingRoleParams(n);try{yield EB(n,this._core);const v=Wi.getLocalGroup(u),T=new MC({userID:E,role:m});return mn({group:v,member:T},{message:D})}catch(v){throw new g.ChatError({functionName:r,code:v?.errorCode,message:v?.errorInfo,moreMessage:D})}})}_preCheckSettingRoleParams(n){var r;const{groupID:g,userID:u,role:E}=n,{store:m,helper:D,OuterConstant:v,common:{isCommunity:T}}=this._core,P=Wi.getLocalGroup(g);if(((r=P?.selfInfo)===null||r===void 0?void 0:r.role)!==v.GRP_MBR_ROLE_OWNER)throw new D.ChatError({functionName:"setGroupMemberRole",code:OT});if(u===m.get("login").userId)throw new D.ChatError({functionName:"setGroupMemberRole",code:zM});const W=[...zu];if(T({groupID:g})&&W.push(v.GRP_MBR_ROLE_CUSTOM),!W.includes(E))throw new D.ChatError({functionName:"setGroupMemberRole",code:bm})}},wD=new class{constructor(){this._name="SetGroupMemberNameCard"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setGroupMemberNameCard",context:this})}setGroupMemberNameCard(n){return mA(this,void 0,void 0,function*(){var r;const g="setGroupMemberNameCard",{helper:u,common:{getCurrentUserID:E}}=this._core,{groupID:m,userID:D=E(),nameCard:v}=n,T=`${this._name}.${g} ok, groupID:${m} userID:${D} nameCard:${v}`;this._preCheckSettingNameCardParams(n);try{yield EB({groupID:m,userID:D,nameCard:v},this._core);const W=Wi.getLocalGroup(m);D===((r=W?.selfInfo)===null||r===void 0?void 0:r.userID)&&(W.updateSelfInfo({nameCard:v}),Wi.emitGroupListUpdate(),Wi.updateConversationGroupProfile(m));const oA=new MC({userID:D,nameCard:v});return mn({group:W,member:oA},{message:T})}catch(P){throw new u.ChatError({functionName:g,code:P?.errorCode,message:P?.errorInfo,moreMessage:T})}})}_preCheckSettingNameCardParams(n){const{groupID:r}=n,{helper:g}=this._core,u=Wi.getLocalGroup(r);if(vd(u?.type))throw new g.ChatError({functionName:"setGroupMemberNameCard",code:km})}},Om=new class{constructor(){this._name="SetGroupMemberCustomField"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setGroupMemberCustomField",context:this})}setGroupMemberCustomField(n){return mA(this,void 0,void 0,function*(){const r="setGroupMemberCustomField",{helper:g,common:{getCurrentUserID:u}}=this._core;this._preCheckSettingCustomFiledParams(n);const{groupID:E,userID:m=u(),memberCustomField:D}=n,v=`${this._name}.${r} ok, groupID:${E}userID:${m} memberCustomField:${JSON.stringify(D)}`;try{yield EB({groupID:E,userID:m,memberCustomField:D},this._core);const P=Wi.getLocalGroup(E),W=new MC({userID:m,memberCustomField:D});return mn({group:P,member:W},{message:v})}catch(T){throw new g.ChatError({functionName:r,code:T?.errorCode,message:T?.errorInfo,moreMessage:v})}})}_preCheckSettingCustomFiledParams(n){const{groupID:r}=n,{helper:g}=this._core,u=Wi.getLocalGroup(r);if(vd(u?.type))throw new g.ChatError({functionName:"setGroupMemberCustomField",code:km})}},iR=new class{init(n,r){n.ssoLog.debug("GroupMember.init"),RD.init(n,r),OQ.init(n),Rd.init(n),wd.init(n,r),tR.init(n),PQ.init(n),wD.init(n),Om.init(n)}getGroupMemberList(n){return RD.getGroupMemberList(n)}deleteGroupMember(n){return wd.deleteGroupMember(n)}},JT=new class{init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"getGroupCounters",context:this})}getGroupCounters(n){return mA(this,void 0,void 0,function*(){const r="getGroupCounters";try{Um(r,gc);const{groupID:g,keyList:u=[]}=n,{avChatRoomKey:E,lastUpdateTime:m}=cc.getLocalGroupCounters(g);if(!(Date.now()-m>=this._getExpireTime()))return{code:0,data:{counters:cc.getLocalCounters(g,u)}};const D=yield function(P){return mA(this,void 0,void 0,function*(){const{groupID:W,GroupCounterKeys:oA,avChatRoomKey:EA}=P,{common:wA}=tr.core,kA={GroupId:W,keyList:oA,BytesKey:EA};return wA.buildAndSendPacket({servcmd:"group_open_http_svc.get_group_counter",data:kA})})}({groupID:g,keyList:u,avChatRoomKey:E}),{GroupCounter:v=[],GroupCounterSeq:T}=D;return cc.updateLocalGroupCounters({groupID:g,counterList:v,groupCounterSeq:T}),{code:0,data:{counters:cc.getLocalCounters(g,u)}}}catch(g){vC(r,g)}})}_getExpireTime(){const{store:n,utils:{isUndefined:r}}=this._core,g=n.get("cloudConfig")||{},{grp_counter_expire_time:u}=g;return r(u)?3e4:Number(u)}},Pm=new class{init(n){const{helper:r}=n;r.registerApi({apiName:"setGroupCounters",context:this}),r.registerApi({apiName:"increaseGroupCounter",context:this}),r.registerApi({apiName:"decreaseGroupCounter",context:this})}setGroupCounters(n){return mA(this,void 0,void 0,function*(){return this._handleCounterOperation(Wu,n)})}increaseGroupCounter(n){return mA(this,void 0,void 0,function*(){return this._handleCounterOperation(vm,n)})}decreaseGroupCounter(n){return mA(this,void 0,void 0,function*(){return this._handleCounterOperation(Ni,n)})}_handleCounterOperation(n,r){return mA(this,void 0,void 0,function*(){const g=`${n}GroupCounter`;try{Um(g,gc);const{groupID:u,key:E,value:m=0}=r,{avChatRoomKey:D}=cc.getLocalGroupCounters(u),v=n===Wu?this._convertObjectToList(r.counters):[{Key:E,Value:m}],T=yield this._updateGroupCounters({groupID:u,counterList:v,avChatRoomKey:D,mode:n});return cc.setGroupCounters(u,T),{code:0,data:{counters:T}}}catch(u){vC(g,u)}})}_updateGroupCounters(n){return mA(this,void 0,void 0,function*(){const r=yield function(E){const{groupID:m,counterList:D,mode:v,avChatRoomKey:T}=E,{common:P}=tr.core,W={GroupId:m,GroupCounter:D,Mode:v,BytesKey:T};return P.buildAndSendPacket({servcmd:"group_open_http_svc.update_group_counter",data:W})}(n),{GroupCounter:g=[]}=r,u={};return g.forEach(E=>{const{Key:m,Value:D=0}=E;u[m]=D}),u})}_convertObjectToList(n){return Object.entries(n).map(([r,g])=>({Key:r,Value:g||0}))}},dB=new class{init(n){this._core=n,JT.init(n),Pm.init(n)}isGroupCounterUpdated(n){const{elements:{groupCounterInfo:r}}=n,{utils:{isEmpty:g}}=this._core;return!g(r)}handleGroupCounterUpdated(n){const{to:r,elements:{groupCounterInfo:g}}=n;g.forEach(u=>{const{type:E,groupCounterSeq:m,counterList:D=[]}=u;E!==gi&&E!==un||this._processAndNotifyCounterUpdate(r,m,D),E===_o&&cc.deleteLocalGroupCounters({groupID:r,groupCounterSeq:m,counterList:D})})}_processAndNotifyCounterUpdate(n,r,g){const{OuterEvent:u,notificationCenter:E}=this._core;cc.updateLocalGroupCounters({groupID:n,groupCounterSeq:r,counterList:g}),g.forEach(({Key:m,Value:D=0})=>{E.emitOuterEvent(u.GROUP_COUNTER_UPDATED,{name:u.GROUP_COUNTER_UPDATED,data:{groupID:n,key:m,value:D}})})}reset(){cc.reset()}},xm=new class{constructor(){this._name="InitGroupAttributes"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"initGroupAttributes",context:this})}initGroupAttributes(n){return mA(this,void 0,void 0,function*(){const{groupID:r,groupAttributes:g}=n,{serverMainSequence:u,avChatRoomKey:E}=rn.getGroupAttributesCache(r),m=rn.convertKeyValueMapToList(g);try{const D=yield function(W,oA){return mA(this,void 0,void 0,function*(){const{groupID:EA,mainSequence:wA,groupAttributeList:kA,avChatRoomKey:xA}=W,LA={GroupId:EA,AttrMainSeq:wA,GroupAttr:kA,BytesKey:xA,AttrControl:["RaceConflict"]};return oA.common.buildAndSendPacket({servcmd:"group_open_http_svc.set_group_attr",data:LA})})}({groupID:r,avChatRoomKey:E,groupAttributeList:m,mainSequence:u},this._core),{AttrMainSeq:v,GroupAttr:T}=D||{},P=T.map(W=>{const{Key:oA,seq:EA}=W;return{key:oA,value:g[oA],sequence:EA}});return rn.saveGroupAttributesCacheValuesCopy(r),rn.refreshGroupAttributesCache({groupID:r,serverMainSequence:v,groupAttributeList:P,operation:BD}),rn.emitGroupAttributesUpdated(r),mn({groupAttributes:g},{message:` groupID:${r} serverMainSequence:${v}`})}catch(D){throw new this._core.helper.ChatError({functionName:"initGroupAttributes",code:D?.errorCode,message:D?.errorInfo})}})}},HT=new class{constructor(){this._name="SetGroupAttributes"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"setGroupAttributes",context:this}),r.registerExperimentalAPI("setRichStatus",this)}setGroupAttributes(n){return mA(this,void 0,void 0,function*(){const{groupID:r,groupAttributes:g,richStatusMode:u}=n,{serverMainSequence:E,avChatRoomKey:m,values:D}=rn.getGroupAttributesCache(r),v=rn.convertKeyValueMapToList(g).map(T=>{var P;const{key:W,value:oA}=T;return{key:W,value:oA,seq:((P=D.get(T.key))===null||P===void 0?void 0:P.sequence)||0}});try{const T=yield function(EA,wA){return mA(this,void 0,void 0,function*(){const{groupID:kA,mainSequence:xA,groupAttributeList:LA,avChatRoomKey:SA,richStatusMode:OA}=EA,WA={GroupId:kA,AttrMainSeq:xA,GroupAttr:LA,BytesKey:SA,AttrControl:["RaceConflict"],AllowRoomEngineOpt:OA};return wA.common.buildAndSendPacket({servcmd:"group_open_http_svc.modify_group_attr",data:WA})})}({groupID:r,avChatRoomKey:m,groupAttributeList:v,mainSequence:E,richStatusMode:u},this._core),{AttrMainSeq:P,GroupAttr:W}=T||{},oA=W.map(EA=>{const{Key:wA,seq:kA}=EA;return{key:wA,value:g[wA],sequence:kA}});return rn.saveGroupAttributesCacheValuesCopy(r),rn.refreshGroupAttributesCache({groupID:r,serverMainSequence:P,groupAttributeList:oA,operation:qM}),rn.emitGroupAttributesUpdated(r),mn({groupAttributes:g},{message:` groupID:${r} serverMainSequence:${P}`})}catch(T){throw new this._core.helper.ChatError({functionName:"setGroupAttributes",code:T?.errorCode,message:T?.errorInfo})}})}setRichStatus(n){return mA(this,void 0,void 0,function*(){const{groupID:r,richStatus:g}=n;return this.setGroupAttributes({groupID:r,groupAttributes:g,richStatusMode:!0})})}},_D=new class{constructor(){this._name="DeleteGroupAttributes"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"deleteGroupAttributes",context:this}),r.registerExperimentalAPI("deleteRichStatus",this)}deleteGroupAttributes(n){return mA(this,void 0,void 0,function*(){const r="deleteGroupAttributes",{groupID:g,keyList:u=[],richStatusMode:E}=n;try{let m;m=u.length===0?yield this._clearGroupAttributes(g,{richStatusMode:E}):yield this._deleteGroupAttributes(g,{keyList:u,richStatusMode:E});const{resultList:D,serverMainSequence:v,operation:T,groupAttributeList:P}=m||{},W=`${this._name}.${r} ok. groupID:${g} operation: ${T}`;return rn.saveGroupAttributesCacheValuesCopy(g),rn.refreshGroupAttributesCache({groupID:g,serverMainSequence:v,groupAttributeList:P,operation:T}),rn.emitGroupAttributesUpdated(g),mn({keyList:D},{message:W})}catch(m){throw new this._core.helper.ChatError({functionName:r,code:m?.errorCode,message:m?.errorInfo})}})}deleteRichStatus(n){return mA(this,void 0,void 0,function*(){return this.deleteGroupAttributes(Object.assign(Object.assign({},n),{richStatusMode:!0}))})}_deleteGroupAttributes(n,r){return mA(this,void 0,void 0,function*(){const{serverMainSequence:g,avChatRoomKey:u,values:E}=rn.getGroupAttributesCache(n),{keyList:m,richStatusMode:D}=r,v=[],T=[];m.forEach(oA=>{if(E.has(oA)){const{sequence:EA=0}=E.get(oA)||{};T.push({key:oA,seq:EA}),v.push(oA)}});const P=yield function(oA,EA){return mA(this,void 0,void 0,function*(){const{groupID:wA,mainSequence:kA,groupAttributeList:xA,avChatRoomKey:LA,richStatusMode:SA}=oA,OA={GroupId:wA,AttrMainSeq:kA,GroupAttr:xA,BytesKey:LA,AttrControl:["RaceConflict"],AllowRoomEngineOpt:SA};return EA.common.buildAndSendPacket({servcmd:"group_open_http_svc.delete_group_attr",data:OA})})}({groupID:n,avChatRoomKey:u,groupAttributeList:T,mainSequence:g,richStatusMode:D},this._core),{AttrMainSeq:W}=P||{};return{resultList:v,serverMainSequence:W,groupAttributeList:T,operation:pD}})}_clearGroupAttributes(n,r){return mA(this,void 0,void 0,function*(){const{serverMainSequence:g,avChatRoomKey:u,values:E}=rn.getGroupAttributesCache(n),{richStatusMode:m}=r||{},D=[...E.keys()],v=yield function(P,W){return mA(this,void 0,void 0,function*(){const{groupID:oA,mainSequence:EA,avChatRoomKey:wA,richStatusMode:kA}=P,xA={GroupId:oA,AttrMainSeq:EA,BytesKey:wA,AttrControl:["RaceConflict"],AllowRoomEngineOpt:kA};return W.common.buildAndSendPacket({servcmd:"group_open_http_svc.clear_group_attr",data:xA})})}({groupID:n,avChatRoomKey:u,mainSequence:g,richStatusMode:m},this._core),{AttrMainSeq:T}=v||{};return{resultList:D,serverMainSequence:T,operation:QD}})}},TD=new class{constructor(){this._name="GetGroupAttributes"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"getGroupAttributes",context:this}),r.registerExperimentalAPI("getRichStatus",this,"getGroupAttributes")}getGroupAttributes(n){return mA(this,void 0,void 0,function*(){const{groupID:r}=n,{avChatRoomKey:g,lastUpdateTime:u,localMainSequence:E,serverMainSequence:m}=rn.getGroupAttributesCache(r),{helper:{ChatError:D}}=this._core,v=`groupID:${r} localMainSequence:${E} serverMainSequence:${m} keyList:${n.keyList}`;if(Date.now()-u>=3e4||E{const{key:oA,value:EA,seq:wA}=W;return{key:oA,value:EA,sequence:wA}});return rn.refreshGroupAttributesCache({groupID:u,serverMainSequence:v,groupAttributeList:P,operation:KM}),{serverGroupAttributeList:T}})}},xQ=new class{init(n){n.ssoLog.debug("GroupAttribute.init"),xm.init(n),HT.init(n),_D.init(n),TD.init(n),rn.init(n)}isGroupAttributesUpdated(n){return rn.isGroupAttributesUpdated(n)}handleGroupAttributesUpdated(n){const{to:r,elements:{newGroupProfile:g}}=n,{groupAttributeOption:u}=g,{serverMainSequence:E,withChangedAttributeInfo:m}=u,{localMainSequence:D}=rn.getGroupAttributesCache(r),v=E-D;if(console.log(`GroupAttribute.handleGroupAttributesUpdated groupID:${r} withChangedAttributeInfo:${m} diffSequence:${v}`),v!==0)if(rn.saveGroupAttributesCacheValuesCopy(r),m!==1||v!==1){if(rn.hasGroupAttributesCache(r)){const{avChatRoomKey:T}=rn.getGroupAttributesCache(r);TD.getGroupAttributesFromServer({groupID:r,avChatRoomKey:T}).then(()=>{rn.emitGroupAttributesUpdated(r)}).catch(()=>{})}}else rn.handleGroupAttributesUpdated({groupID:r,groupAttributeOption:u})}reset(){rn.reset()}};function HE(n,r="tips"){const{ClientSeq:g,From_Account:u,MsgClientTime:E,MsgPriority:m,MsgRandom:D,MsgSeq:v,MsgTimeStamp:T,TinyId:P,ToGroupId:W,GroupInfo:oA,MsgBody:EA}=n,wA=function(kA){const{GroupCode:xA,GroupId:LA,GroupName:SA,GroupType:OA,MsgFrom_AccountExtraInfo:WA,From_Account:ue,To_Account:le}=kA;return{groupCode:xA,groupID:LA,groupName:SA,type:OA,messageFromAccountExtraInformation:WA,from:ue,to:le}}(oA);return{clientSequence:g,from:u,clientTime:E,priority:m,random:D,sequence:v,time:T,tinyID:P,to:W,groupProfile:wA,elements:r==="tips"?$u(EA):Bh(EA)}}function $u(n){const r={};return Object.keys(n).forEach(g=>{var u,E;switch(g){case"MemberNum":r.memberCount=n[g];break;case"OpType":r.operationType=n[g];break;case"Operator_Account":r.operatorID=n[g];break;case"List_Account":r.userIDList=n[g];break;case"MsgMemberExtraInfo":r.memberInfoList=(u=n[g])===null||u===void 0?void 0:u.map(m=>ND(m));break;case"MsgOperatorMemberExtraInfo":r.operatorInfo=ND(n[g]);break;case"MsgGroupNewInfo":r.newGroupProfile=function(m){const D={};return Object.keys(m).forEach(v=>{switch(v){case"GroupIntroduction":D.introduction=m[v];break;case"GroupName":D.groupName=m[v];break;case"GroupFaceUrl":D.avatar=m[v];break;case"GroupNotification":D.notification=m[v];break;case"ApplyJoinOption":D.joinOption=m[v];break;case"InviteJoinOption":D.inviteOption=m[v];break;case"ShutupAll":D.muteAllMembers=m[v];break;case"Owner_Account":D.ownerID=m[v];break;case"GroupAttrOption":D.groupAttributeOption=function(P){const{BytesChangedKeys:W,GroupAttrSeq:oA,OpType:EA,PushChangedAttrValFlag:wA,GroupAttrInfo:kA}=P,xA=kA.map(LA=>{const{Key:SA,Val:OA,SubKeySeq:WA}=LA;return{key:SA,value:OA,sequence:WA}});return{changedKeyList:W,groupAttributeList:xA,serverMainSequence:oA,operation:EA,withChangedAttributeInfo:wA}}(m[v]);break;case"MsgAppDefinedData":D.groupCustomField=(T=m[v])==null?void 0:T.map(P=>({key:P.Key,value:P.Value}));break;case"InviteOption":D.inviteOption=xT[m[v]]||m[v]}var T}),D}(n[g]);break;case"MsgMemberInfo":r.msgMemberInfo=(E=n[g])===null||E===void 0?void 0:E.map(m=>function(D){const{ShutupTime:v,User_Account:T}=D;return{muteTime:v,userID:T}}(m));break;case"OnlineMemberInfo":r.onlineMemberInfo=function(m){const{ExpireTime:D,OnlineMemberNum:v}=m;return{expireTime:D,onlineMemberNum:v}}(n[g]);break;case"GroupCounterInfo":r.groupCounterInfo=function(m){return m.map(D=>{const{GroupCounterSeq:v,GroupCounter:T,Type:P}=D;return{type:P,groupCounterSeq:v,counterList:T}})}(n[g])}}),r}function ND(n){const{ImageUrl:r,NickName:g,Role:u,UserId:E}=n;return{avatar:r,nick:g,role:u,userID:E}}function Bh(n){const r={};return Object.keys(n).forEach(g=>{switch(g){case"MsgKey":r.messageKey=n[g];break;case"Operator_Account":r.operatorID=n[g];break;case"ReportType":r.operationType=n[g];break;case"Authentication":r.authentication=n[g];break;case"MsgFlag":r.messageRemindType=n[g];break;case"UserDefinedField":r.userDefinedField=n[g];break;case"RemarkInfo":r.remarkInfo=n[g];break;case"BanDuration":r.duration=n[g];break;case"MuteTime":r.muteTime=n[g];break;case"MsgMemberExtraInfoList":r.inviteeInfoList=(u=n[g]||[])==null?void 0:u.map(E=>{const{UserId:m,ImageUrl:D,NickName:v}=E;return{userID:m,avatar:D,nick:v}});break;case"MemberList_Account":r.inviteeList=n[g]}var u}),r}class Ym{constructor(r){this.type=tr.core.OuterConstant.MSG_GRP_TIP,this.content={},this._initContent(r)}static parseServerPushElement(r){const g=$u(r);return new Ym(g)}_initContent(r){Object.keys(r).forEach(g=>{switch(g){case"groupProfile":this._initGroupProfile(r[g]);break;case"operatorInfo":this._initOperatorInfo(r[g]);break;case"memberInfoList":case"msgMemberInfo":this._updateMemberList(r[g]);break;case"newGroupProfile":this._initNewGroupProfile(r[g]);break;case"memberExtraInfo":case"remarkInfo":case"onlineMemberInfo":break;default:this.content[g]=r[g]}}),this.content.userIDList||(this.content.userIDList=[this.content.operatorID])}_initGroupProfile(r){this.content.groupProfile={};const g=Object.keys(r);for(let u=0;u{r.forEach(u=>{g.userID===u.userID&&Object.assign(g,u)})}):this.content.memberList=r}_initNewGroupProfile(r){this.content.newGroupProfile={};const g=Object.keys(r);for(let u=0;u0&&this._handleGroupTipMessage(g),{conversationUpdateFieldList:u,messageList:g}}_emitGroupTipsEvent(n){var r;const{constants:{WORKFLOW_STEP:g}}=this._core,{messageList:u=[]}=((r=n?.result)===null||r===void 0?void 0:r[g.HANDLE_GROUP_TIPS_NOTIFICATION])||{};if(u.length>0){const{notificationCenter:E,OuterEvent:m}=this._core;E.emitOuterEvent(m.MESSAGE_RECEIVED,{name:m.MESSAGE_RECEIVED,data:u})}}_handleGroupTips(n,r=!0){const{Event:g,GroupTips:u}=n,E=new Map,m=[],D=[];for(let v=0,T=u.length;v{const{operationType:u}=g.payload;switch(u){case r.JOINED:this._handleNewMemberJoined(g);break;case r.QUITTED:this._handleMemberQuitted(g);break;case r.KICKED:this._handleMemberKicked(g);break;case r.GROUP_PROFILE_UPDATED:this._handleGroupProfileUpdated(g);break;case r.ADMIN_SET:this._handleMemberGrantAdmin(g);break;case r.ADMIN_CANCELED:this._handleMemberRevokeAdmin(g)}})}_handleNewMemberJoined(n){this._handleGroupMemberCountUpdated(n)}_handleMemberQuitted(n){this._handleGroupMemberCountUpdated(n)}_handleMemberKicked(n){this._handleGroupMemberCountUpdated(n)}_handleGroupProfileUpdated(n){var r;const{newGroupProfile:g,groupProfile:u,operatorInfo:E}=n.payload,{groupID:m}=u,D=Wi.getLocalGroup(m);Object.keys(g).forEach(T=>{switch(T){case"ownerID":this._handleGroupOwnerChanged(m,g);break;case"groupName":D.name=g[T];break;case"groupCustomField":Array.isArray(D[T])&&Array.isArray(g[T])?Lm(D[T],g[T]):D[T]=g[T];break;default:D[T]=g[T]}});const{utils:{isUndefined:v}}=this._core;v(E)||((r=D?.selfInfo)===null||r===void 0?void 0:r.userID)!==E.userID||Object.keys(E).forEach(T=>{T==="nameCard"&&D.updateSelfInfo({nameCard:E[T]}),T==="role"&&this._updateSelfRole(D,E[T])}),Wi.emitGroupListUpdate(),Wi.updateConversationGroupProfile(m)}_handleGroupOwnerChanged(n,r){const{common:g,OuterConstant:u}=this._core,E=Wi.getLocalGroup(n),m=g.getCurrentUserID(),{ownerID:D}=r;m===D&&E.updateGroup({ownerID:D,selfInfo:{role:u.GRP_MBR_ROLE_OWNER}})}_updateSelfRole(n,r){const{OuterConstant:g}=this._core;let u=g.GRP_MBR_ROLE_MEMBER;r===TT?u=g.GRP_MBR_ROLE_OWNER:r===fD&&(u=g.GRP_MBR_ROLE_ADMIN),n.updateSelfInfo({role:u})}_handleGroupMemberCountUpdated(n){const{memberCount:r,groupProfile:{groupID:g}}=n.payload,u=Wi.getLocalGroup(g),{utils:{isNumber:E}}=this._core;u&&E(r)&&u.memberCount!==r&&(u.memberCount=r,Wi.emitGroupListUpdate(),Wi.updateConversationGroupProfile(g))}_handleGroupTipsRecover(n){const{utils:{isArray:r}}=this._core,{groupTipList:g}=n?.result||{};r(g)&&g.forEach(u=>{const{messageList:E}=this._handleGroupTips({Event:u.Event,GroupTips:[u]},!1);this._handleGroupTipMessage(E)})}_handleMemberGrantAdmin(n){const{OuterConstant:r}=this._core,{groupProfile:g,userIDList:u}=n.payload,E=this._core.common.getCurrentUserID(),{groupID:m}=g,D=Wi.getLocalGroup(m);D&&u.includes(E)&&(D.updateSelfInfo({role:r.GRP_MBR_ROLE_ADMIN}),Wi.emitGroupListUpdate(),Wi.updateConversationGroupProfile(m))}_handleMemberRevokeAdmin(n){const{OuterConstant:r}=this._core,{groupProfile:g,userIDList:u}=n.payload,E=this._core.common.getCurrentUserID(),{groupID:m}=g,D=Wi.getLocalGroup(m);D&&u.includes(E)&&(D.updateSelfInfo({role:r.GRP_MBR_ROLE_MEMBER}),Wi.emitGroupListUpdate(),Wi.updateConversationGroupProfile(m))}};class YQ{constructor(r){this.type=tr.core.OuterConstant.MSG_GRP_SYS_NOTICE,this.content={},this._initContent(r)}static parseServerPushElement(r){const g=Bh(r);return new YQ(g)}_initContent(r){Object.keys(r).forEach(g=>{switch(g){case"remarkInfo":this.content.handleMessage=r[g];break;case"groupProfile":this._initGroupProfile(r[g]);break;case"memberInfoList":break;default:this.content[g]=r[g]}})}_initGroupProfile(r){this.content.groupProfile={};const g=Object.keys(r);for(let u=0;u0&&this._handleGroupSysTemMessage(g,E),g===!0&&E.length>0&&m.emitOuterEvent(D.MESSAGE_RECEIVED,{name:D.MESSAGE_RECEIVED,data:E})}_handleGroupSystemNotification(n,r){const g=[];let u={};for(let E=0;E0?[u]:[],messageList:g}}_assembleMessage(n){const{message:{messageFactory:r},OuterConstant:g,utils:{randomInt:u}}=this._core;n.flow="in",n.conversationType=g.CONV_SYSTEM,n.conversationSubType=n.groupProfile.type,n.conversationID=g.CONV_SYSTEM;const E=r.createMessage(n),m=new YQ(Object.assign(Object.assign({},n.elements),{groupProfile:Object.assign({},n.groupProfile)}));E.setElement(m),E.isSystemMessage=!0;const D=E.sequence===1&&E.random===1,v=E.sequence===2&&E.random===2;return(D||v)&&(E.sequence=u(),E.random=u(),E.generateMessageID()),E}_handleConversationOptions(n,r){const{OuterConstant:g}=this._core,u={conversationID:g.CONV_SYSTEM,unreadCount:0,type:g.CONV_SYSTEM,subType:n.conversationSubType,lastMessage:null};return r&&u.unreadCount++,u}_handleGroupSysTemMessage(n,r){n&&r.forEach(g=>{const{operationType:u}=g.payload;switch(u){case GT:this._handleGroupJoinResult(g);break;case WM:this._handleMemberKicked(g);break;case bT:this._handleGroupDismissed(g);break;case kT:this._handleGroupInvitedResult(g);break;case yD:this._handleGroupQuitResult(g);break;case kQ:this._handleMessageRemindTypeSynced(g);break;case Tm:this._handleAVChatRoomMemberBanned(g)}})}_handleGroupJoinResult(n){const{groupProfile:r}=n.payload,{groupID:g,type:u}=r,E=Wi.hasLocalGroup(g);this._core.ssoLog.debug("_handleGroupJoinResult",` groupID:${g} type:${u} hasLocalGroup:${E}`),E||vd(u)||(Wi.updateLocalGroup([Object.assign({},r)]),Wi.emitGroupListUpdate())}_handleMemberKicked(n){const{groupProfile:{groupID:r,type:g}}=n.payload;Wi.hasLocalGroup(r)&&this._deleteLocalGroup(r,g),this._updateConversationProfile(r,{unreadCount:0})}_handleGroupDismissed(n){const{groupProfile:{groupID:r,type:g}}=n.payload;Wi.hasLocalGroup(r)&&this._deleteLocalGroup(r,g),this._updateConversationProfile(r,{unreadCount:0})}_handleGroupInvitedResult(n){const{groupProfile:r}=n.payload,{groupID:g}=r,u=Wi.hasLocalGroup(g);this._core.ssoLog.debug("_handleGroupInvitedResult",` groupID:${g} hasLocalGroup:${u}`),u||Hl.getGroupProfile({groupID:g}).then(E=>{const{data:{group:m}}=E;Wi.updateLocalGroup([Object.assign({},m)]),Wi.emitGroupListUpdate()})}_handleGroupQuitResult(n){const{groupProfile:{groupID:r,type:g}}=n.payload,u=Wi.hasLocalGroup(r);this._core.ssoLog.debug("_handleGroupQuitResult",` groupID:${r} type:${g} hasLocalGroup:${u}`),u&&this._deleteLocalGroup(r,g),this._updateConversationProfile(r,{unreadCount:0})}_handleMessageRemindTypeSynced(n){const{groupProfile:{groupID:r},messageRemindType:g}=n.payload;this._updateConversationProfile(r,{messageRemindType:g})}_handleAVChatRoomMemberBanned(n){const{groupProfile:{groupID:r,type:g}}=n.payload;this._deleteLocalGroup(r,g)}_deleteLocalGroup(n,r){if(vd(r)){const{appStore:{conversationStore:g},OuterConstant:{CONV_GROUP:u}}=this._core;g.deleteConversation(`${u}${n}`)}Wi.deleteLocalGroup(n),Wi.emitGroupListUpdate()}_updateConversationProfile(n,r){const{appStore:{conversationStore:g},OuterConstant:{CONV_GROUP:u}}=this._core,E=`${u}${n}`;g.getConversation(E)&&g.updateConversation(E,r)}},GD=new class{init(n){this._core=n,n.ssoLog.debug("GroupNotificationHandler.init"),oR.init(n),sR.init(n);const{notificationCenter:r,InnerEvent:g}=n,{InnerEventSubType:u}=r;r.subscribeInnerEvent(g.MESSAGE_PUSH,u.GROUP_TIPS_NOTIFICATION,this._onNewGroupTipsNotification,this),r.subscribeInnerEvent(g.MESSAGE_PUSH,u.GROUP_SYSTEM_NOTIFICATION,this._onNewGroupSystemNotification,this),r.subscribeInnerEvent(g.DESTROY,this._dispose,this)}_onNewGroupTipsNotification(n){const{common:{workflowManager:r},constants:{WORKFLOW_NAME:g}}=this._core;r.executeWorkflow(g.RECEIVE_GROUP_TIPS_NOTIFICATION,n)}_onNewGroupSystemNotification(n){sR.onNewGroupSystemNotification(n)}_dispose(){const{notificationCenter:n,InnerEvent:r}=this._core,{InnerEventSubType:g}=n;n.unSubscribeInnerEvent(r.MESSAGE_PUSH,g.GROUP_TIPS_NOTIFICATION,this._onNewGroupTipsNotification,this),n.unSubscribeInnerEvent(r.MESSAGE_PUSH,g.GROUP_SYSTEM_NOTIFICATION,this._onNewGroupSystemNotification,this)}};const Gn={required:!0,rules:["string"],allowEmpty:!1},VQ={required:!0,rules:["number"],allowEmpty:!1},_d={required:!0,rules:["array"],allowEmpty:!1},bD={required:!0,rules:["object"],allowEmpty:!1},qT={createGroup:{name:Gn,type:Gn},dismissGroup:[Object.assign({key:"groupID"},Gn)],joinGroup:{groupID:Gn,applyMessage:{required:!1,rules:["string"],allowEmpty:!0}},quitGroup:[Object.assign({key:"groupID"},Gn)],searchGroupByID:[Object.assign({key:"groupID"},Gn)],getGroupProfile:{groupID:Gn,groupCustomFieldFilter:{required:!1,rules:["array"],allowEmpty:!0}},updateGroupProfile:{groupID:Gn,muteAllMembers:{required:!1,rules:["boolean"],allowEmpty:!1}},changeGroupOwner:{groupID:Gn,newOwnerID:Gn},getGroupOnlineMemberCount:[Object.assign({key:"groupID"},Gn)],handleGroupApplication:{handleAction:Gn},getGroupMemberList:{groupID:Gn},getGroupMemberProfile:{groupID:Gn,userIDList:_d,memberCustomFieldFilter:{required:!1,rules:["array"],allowEmpty:!0}},addGroupMember:{groupID:Gn,userIDList:_d},deleteGroupMember:{groupID:Gn,userIDList:_d},setGroupMemberMuteTime:{groupID:Gn,userID:Gn,muteTime:Object.assign(Object.assign({},VQ),{customValidator:n=>!(n<0)||"muteTime must be a non-negative number."})},setGroupMemberRole:{groupID:Gn,userID:Gn,role:Gn},setGroupMemberNameCard:{groupID:Gn,userID:{required:!1,rules:["string"],allowEmpty:!1},nameCard:Gn},setGroupMemberCustomField:{groupID:Gn,userID:{required:!1,rules:["string"],allowEmpty:!1},memberCustomField:_d},markGroupMemberList:{groupID:Gn,markType:Object.assign(Object.assign({},VQ),{customValidator:n=>!(n<1e3)||"markType must be greater than or equal to 1000."}),enableMark:{required:!0,rules:["boolean"],allowEmpty:!1},userIDList:_d},initGroupAttributes:{groupID:Gn,groupAttributes:bD},setGroupAttributes:{groupID:Gn,groupAttributes:bD},deleteGroupAttributes:{groupID:Gn,keyList:Object.assign(Object.assign({},_d),{allowEmpty:!0})},getGroupAttributes:{groupID:Gn,keyList:Object.assign(Object.assign({},_d),{allowEmpty:!0})},getGroupCounters:{groupID:Gn,keyList:{required:!1,rules:["array"],allowEmpty:!0}},setGroupCounters:{groupID:Gn,counters:bD},increaseGroupCounter:{groupID:Gn,key:Gn,value:VQ},decreaseGroupCounter:{groupID:Gn,key:Gn,value:VQ}},KT={getGroupList:!0,createGroup:!0,dismissGroup:!0,joinGroup:!0,quitGroup:!0,searchGroupByID:!0,getGroupProfile:!0,updateGroupProfile:!0,changeGroupOwner:!0,getGroupOnlineMemberCount:!0,getGroupApplicationList:!0,handleGroupApplication:!0,getGroupMemberList:!0,getGroupMemberProfile:!0,addGroupMember:!0,deleteGroupMember:!0,setGroupMemberMuteTime:!0,setGroupMemberRole:!0,setGroupMemberNameCard:!0,setGroupMemberCustomField:!0,markGroupMemberList:!0,initGroupAttributes:!0,setGroupAttributes:!0,getGroupAttributes:!0,deleteGroupAttributes:!0,getGroupCounters:!0,setGroupCounters:!0,increaseGroupCounter:!0,decreaseGroupCounter:!0};var jT=new class{constructor(){this._installedSubPlugins=[],this.groupDataHandler=Wi,this.groupAction=FQ,this.groupAttribute=xQ,this.groupMember=iR,this.groupCounter=dB,this.name="Group"}install(n,r=[]){this._core=n,tr.init(n),Wi.init(n),FQ.init(n,this),iR.init(n,this),MD.init(n),dB.init(n),xQ.init(n),GD.init(n),n.helper.registerValidateConfig({auth:KT,params:qT}),this._installSubPlugins(r);const{notificationCenter:g,InnerEvent:u}=n;g.subscribeInnerEvent(u.LOGOUT,this._reset,this),g.subscribeInnerEvent(u.DESTROY,this._dispose,this)}getInstalledSubPlugins(){return this._installedSubPlugins}_installSubPlugins(n){const{utils:{isArray:r}}=this._core;n&&r(n)&&n.forEach(g=>{var u;this._installedSubPlugins.includes(g.name)||((u=g.install)===null||u===void 0||u.call(g,this._core,this),this._installedSubPlugins.push(g.name))})}_reset(){Wi.reset(),xQ.reset(),dB.reset()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}};const CB=new class{init(n){this.core=n}},nR="AV_MBR_LIST",WT="AV_BAN_MBR",qE={NORMAL_MESSAGE:3,GROUP_TIPS_HAS_ROAMING:4,GROUP_SYSTEM_MESSAGE:5,GROUP_TIPS_HAS_NO_ROAMING:6,BROADCAST_MESSAGE:17,MESSAGE_REVOKED:20,MESSAGE_REACTION:21,LIVE_CUSTOM_DATA:100},Qh={GROUP_DISMISSED:5,QUIT_GROUP:8,AVCHATROOM_MEMBER_BANNED:21},kD=60,LD=2603,zT=2686,ZT=2688,JQ=3122;class rR{constructor(r){const{core:g,manager:u,groupID:E,getRequestParams:m,onSuccess:D,onFail:v}=r;this._name="Polling",this._core=g,this._manager=u,this._timeoutID=-1,this._isRunning=!1,this._groupID=E,this._getRequestParams=m,this._onSuccess=D,this._onFail=v}start(){this._isRunning=!0,this._request(),console.log(`${this._name}.start pollingInterval:${this._manager.getCurrentPollingInterval(this._groupID)}`)}isRunning(){return this._isRunning}_request(){return mA(this,void 0,void 0,function*(){try{const r=this._getRequestParams(this._groupID),g=yield function(E,m){return mA(this,void 0,void 0,function*(){const{longPollingKey:D,startSequence:v,startBroadcastSeq:T,simplifiedMessage:P}=E,W={Key:D,StartSeq:v,StartBroadcastSeq:T,DownsizeFlag:P,USP:1,HoldTime:90};return m.common.buildAndSendPacket({servcmd:"group_open_long_polling_http_svc.get_msg",data:W})})}(r,this._core);this._onSuccess(this._groupID,g);const u=this._manager.getCurrentPollingInterval(this._groupID);this._runNextPolling(u)}catch(r){this._onFail(this._groupID,r),this._runNextPolling(2e3)}})}_runNextPolling(r){this.isRunning()&&(this._timeoutID>-1&&clearTimeout(this._timeoutID),this._timeoutID=setTimeout(this._request.bind(this),r))}stop(){console.log(`${this._name}.stop timerID:${this._timeoutID}`),this._timeoutID>-1&&(clearTimeout(this._timeoutID),this._timeoutID=-1),this._isRunning=!1}}class ph{constructor(r){this._maxLength=r,this._map=new Map}set(r){var g;if(this._map.size>=this._maxLength){const u=((g=this._map.entries().next().value)===null||g===void 0?void 0:g[0])||"";this._map.delete(u)}this._map.set(r,1)}has(r){return this._map.has(r)}delete(r){this.has(r)&&this._map.delete(r)}clear(){this._map.clear()}}const AE=n=>n===qE.GROUP_TIPS_HAS_NO_ROAMING||n===qE.GROUP_TIPS_HAS_ROAMING,HQ=n=>n===qE.GROUP_SYSTEM_MESSAGE;function Vm(n){const r=function(g){const{E:u,MCT:E,MR:m,MP:D,MTS:v,GId:T,MS:P,CCD:W,F_Account:oA,IsSys:EA,GInf:wA,MsgBody:kA}=g,xA=vo(g,["E","MCT","MR","MP","MTS","GId","MS","CCD","F_Account","IsSys","GInf","MsgBody"]);return Object.assign({Event:u,MsgClientTime:E,MsgRandom:m,MsgPriority:D,MsgTimeStamp:v,ToGroupId:T,MsgSeq:P,CloudCustomData:W,From_Account:oA,IsSystemMsg:EA,GroupInfo:UD(wA),MsgBody:XT(kA)},xA)}(n);return function(g){const{Event:u}=g;(AE(u)||HQ(u))&&(g.From_Account=g.From_Account||"@TIM#SYSTEM"),E=u,(E===qE.BROADCAST_MESSAGE||(m=>m===qE.NORMAL_MESSAGE)(u))&&function(m){const{core:{OuterConstant:D}}=CB;m.CloudCustomData=m.CloudCustomData||"",m.MsgBody=m.MsgBody.map(v=>{if(v.MsgType===D.MSG_CUSTOM){const{content:T={}}=v;v.content=Object.assign({Data:"",Desc:"",Ext:""},T)}return v})}(g);var E;AE(u)&&function(m){const{GroupJoinType:D,MsgOperatorMemberExtraInfo:v={},MsgMemberExtraInfo:T,Operator_Account:P,List_Account:W,OpType:oA}=m.MsgBody||{};typeof D=="number"||oA!==1&&oA!==2||(m.MsgBody.GroupJoinType=oA===2?0:1),T||(m.MsgBody.MsgMemberExtraInfo=W?.map(EA=>({UserId:EA}))),oA!==1||T||(m.MsgBody.MsgMemberExtraInfo=[{UserId:v.UserId}]),m.MsgBody.MsgOperatorMemberExtraInfo=Object.assign({Operator_Account:P,ImageUrl:"",NickName:""},v)}(g),HQ(u)&&function(m){const{MsgOperatorMemberExtraInfo:D={},Operator_Account:v}=m.MsgBody||{};m.MsgBody.MsgMemberExtraInfo=Object.assign({UserId:v,ImageUrl:"",NickName:""},D),m.MsgBody=Object.assign({Authentication:"",RemarkInfo:"",MsgKey:1e3*m.MsgTimeStamp},m.MsgBody),m.MsgBody=Object.keys(m.MsgBody).filter(T=>T!=="MsgOperatorMemberExtraInfo").reduce((T,P)=>Object.assign(Object.assign({},T),{[P]:m.MsgBody[P]}),{})}(g)}(r),r}function UD(n){const r=n||{},{GN:g,GT:u,F_Hd:E,F_NN:m,F_Ll:D}=r,v=vo(r,["GN","GT","F_Hd","F_NN","F_Ll"]),T=Object.assign({GroupName:g,GroupType:u},v);return E&&(T.From_AccountHeadurl=E),m&&(T.From_AccountNick=m),D&&(T.From_AccountLevel=D),T}function XT(n){let r=n;Array.isArray(n)||(r=[n]);const g=r.map(u=>{const{O_Account:E,Opt:m,L_Account:D,RT:v,UDF:T,OpInf:P,OnlineInf:W,MsgMemberExtraInfo:oA}=u,EA=vo(u,["O_Account","Opt","L_Account","RT","UDF","OpInf","OnlineInf","MsgMemberExtraInfo"]),wA=Object.assign({Operator_Account:E,OpType:m,List_Account:D,ReportType:v,UserDefinedField:T},EA);return P&&(wA.MsgOperatorMemberExtraInfo=function(kA){const{Img:xA,NN:LA}=kA,SA=vo(kA,["Img","NN"]);return Object.assign({ImageUrl:xA,NickName:LA},SA)}(P)),oA&&(wA.MsgMemberExtraInfo=function(kA){return kA?.map(xA=>{const{Img:LA,NN:SA}=xA,OA=vo(xA,["Img","NN"]);return Object.assign({ImageUrl:LA,NickName:SA},OA)})}(oA)),W&&(wA.OnlineMemberInfo=function(kA){const{ET:xA,Num:LA}=kA;return{ExpireTime:xA,OnlineMemberNum:LA}}(W)),wA});return Array.isArray(n)?g:g[0]}var mh=new class{constructor(){this._name="MessageParser",this._sequenceList=new ph(200),this._messageIDList=new ph(100),this._broadcastMessageIDMap=new Map,this._reportMessageStackedCount=0}init(n,r){this._core=n,this._avChatRoomHandler=r}onMessageReceived(n,r,g=!1){this._sortServerMessageList({groupID:n,serverMessageList:r,isHistoryMessage:g});const u=this._handleMessageList(n,r);if(u.length===0)return;if(!g){const{appStore:{conversationStore:T},OuterConstant:{CONV_GROUP:P},common:{buildLastMessage:W}}=this._core,oA=W(u[u.length-1]);T.updateConversation(`${P}${n}`,{lastMessage:oA})}this._checkMessageStacked(u);const E=u.filter(T=>T.isModified===!0),m=u.filter(T=>T.isModified===!1),{OuterEvent:{MESSAGE_RECEIVED:D,MESSAGE_MODIFIED:v}}=this._core;E.length>0&&this._emitEvent({name:v,data:E}),m.length>0&&this._emitEvent({name:D,data:m})}_sortServerMessageList(n){const{groupID:r,serverMessageList:g,isHistoryMessage:u}=n;let E=[];this._avChatRoomHandler.isPollingSimplifiedMessage()&&!u?(g.sort((m,D)=>m.MS-D.MS),E=g.map(m=>m.MS)):(g.sort((m,D)=>m.MsgSeq-D.MsgSeq),E=g.map(m=>m.MsgSeq)),console.log(`${this._name}._sortServerMessageList groupID:${r} count:${E.length} sequenceList:${E}`),E.length=0}_handleMessageList(n,r){var g;const{message:{messageDataHandler:u,messageHelper:E}}=this._core,m=this._avChatRoomHandler.isPollingSimplifiedMessage(),D=[],v=r.length;for(let T=0;Tg===qE.MESSAGE_REVOKED)(r)?(this._handleMessageRevoked(n),null):(g=>g===qE.LIVE_CUSTOM_DATA)(r)?(this._onLiveCustomData(n),null):(g=>g===qE.MESSAGE_REACTION)(r)?null:n:(console.warn(`${this._name}.onMessageReceived unknown event:${r}`),null)}_createMessage(n){const{message:{messageFactory:r},OuterConstant:g}=this._core;let u=g.CONV_GROUP;n.elements.type===g.MSG_GRP_SYS_NOTICE&&(u=g.CONV_SYSTEM);const E=!!n.isSystemMessage,m=r.createMessage(Object.assign(Object.assign({},n),{conversationType:u,isSystemMessage:E,flow:"in"}));return m.setElement(n.elements),m}_filterDuplicateMessage(n){const{common:r}=this._core;if(!r.isUnlimitedAVChatRoom()){if(this._sequenceList.has(n.sequence))return null;this._sequenceList.set(n.sequence)}const g=this._messageIDList.has(n.ID);return g?(console.warn(`${this._name}_filterDuplicateMessageItem ID:${n.ID} has:${g}`),null):(this._messageIDList.set(n.ID),n)}_handleMessageRevoked(n){const{OuterConstant:r,OuterEvent:{MESSAGE_REVOKED:g}}=this._core,{ToGroupId:u,MsgBody:{RevokeMsgList:E},RevokerInfo:{Revoker_Account:m,Reason:D=""}}=n,v=[];E.forEach(T=>{const{TinyId:P,MsgClientTime:W,Random:oA,MsgSeq:EA}=T,wA={conversationID:`${r.CONV_GROUP}${u}`,ID:`${P}-${W}-${oA}`,revoker:m,revokeReason:D,revokerInfo:{userID:m,nick:"",avatar:""},sequence:EA};v.push(wA)}),v.length!==0&&this._emitEvent({name:g,data:v})}_onLiveCustomData(n){const{OuterEvent:{ROOM_CUSTOM_DATA_RECEIVED:r}}=this._core,{ToGroupId:g,MsgSeq:u,MsgTimeStamp:E,MsgBody:m}=n,D=m?.Content||m?.MsgContent||"";this._emitEvent({name:r,data:D}),console.log(`${this._name}._onLiveCustomData groupID:${g} sequence:${u} time:${E} data:${D}`)}_onGroupDismissed(n){this._avChatRoomHandler.reset(n)}_checkMessageStacked(n){const{length:r}=n;if(r>=100&&this._reportMessageStackedCount<5){const g=this._avChatRoomHandler.getJoinedGroups();this._core.ssoLog.info("MessageStacked",`count:${r} groupID:${g.join(",")}`),this._reportMessageStackedCount+=1}}_emitEvent(n){this._core.notificationCenter.emitOuterEvent(n.name,n)}onBroadcastMessageReceived(n){const{message:{messageHelper:r},OuterEvent:{MESSAGE_RECEIVED:g}}=this._core,u=this._avChatRoomHandler.isPollingSimplifiedMessage(),E=[],m=n.length;for(let D=0;D0&&this._emitEvent({name:g,data:E})}_updateLocalOnlineMemberCountFromTips(n){const{utils:{isEmpty:r}}=this._core,{ToGroupId:g,MsgBody:{OnlineMemberInfo:u}}=n;if(r(u))return;const{OnlineMemberNum:E=0,ExpireTime:m=kD}=u,D=Date.now();let v=this._avChatRoomHandler.getLocalOnlineMemberCount(g);r(v)?v={lastReqTime:0,lastSyncTime:0,latestUpdateTime:D,memberCount:E,expireTime:m}:(v.latestUpdateTime=D,v.memberCount=E),this._avChatRoomHandler.updateLocalOnlineMemberCount(g,v)}reset(){this._reportMessageStackedCount=0,this._sequenceList.clear(),this._messageIDList.clear(),this._broadcastMessageIDMap.clear()}};const hB=n=>{const{core:{store:r}}=CB;return(r.get("cloudConfig")||{})[n]},fh=n=>{const{core:{utils:{isUndefined:r}}}=CB;return!r(n)},qQ=()=>{const n=hB("polling_interval");return fh(n)?parseInt(n,10):300},BB=()=>{const n=hB("polling_simplified_msg");return fh(n)?parseInt(n,10):0};var aR=new class{constructor(){this._name="GetAVChatRoomOnlineMemberCount"}init(n,r){this._core=n,this._parentPlugin=r;const{helper:g}=n;g.registerApi({apiName:"getGroupOnlineMemberCount",context:this,matcher:()=>r.getInstalledSubPlugins().length>0})}getGroupOnlineMemberCount(n){return mA(this,void 0,void 0,function*(){const{appStore:{groupStore:r},OuterConstant:g}=this._core,u=r.getGroup(n);return u?u.type===g.GRP_AVCHATROOM?this._getOnlineMemberCount(n):this._parentPlugin.groupAction.getGroupOnlineMemberCount(n):{code:0,data:{memberCount:0}}})}_getOnlineMemberCount(n){return mA(this,void 0,void 0,function*(){const r="_getOnlineMemberCount",{utils:{isEmpty:g}}=this._core,u=Yg.getLocalOnlineMemberCount(n);if(g(u)||this._isExpired(n)){const{memberCount:E=0}=yield this._getOnlineMemberCountFromServer(n);return console.log(`${this._name}.${r} ok, groupID:${n} memberCount:${E} from server.`),{code:0,data:{memberCount:E}}}return console.log(`${this._name}.${r} ok, groupID:${n} memberCount:${u.memberCount} from local.`),{code:0,data:{memberCount:u.memberCount}}})}_isExpired(n){const r=Yg.getLocalOnlineMemberCount(n),g=Date.now(),u=g-r.lastSyncTime>1e3*r.expireTime,E=g-r.latestUpdateTime>1e4,m=g-r.lastReqTime>3e3;return u&&E&&m}_getOnlineMemberCountFromServer(n){return mA(this,void 0,void 0,function*(){const r="_getOnlineMemberCountFromServer";try{const g=yield function(v,T){return mA(this,void 0,void 0,function*(){const P={GroupId:v};return T.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_online_member_num",data:P})})}(n,this._core),{OnlineMemberNum:u=0,ExpireTime:E=kD}=g||{},m=Date.now(),D={lastSyncTime:m,latestUpdateTime:m,lastReqTime:m,memberCount:u,expireTime:E};return Yg.updateLocalOnlineMemberCount(n,D),{memberCount:u}}catch(g){const u=new this._core.helper.ChatError({functionName:r,code:g?.errorCode,message:g?.errorInfo});throw console.error(`${this._name}.${r} fail:`,u),u}})}},Yg=new class{constructor(){this._name="AVChatRoomHandler",this._joinedGroupMap=new Map,this._pollingRequestInfoMap=new Map,this._pollingInstanceMap=new Map,this._onlineMemberCountMap=new Map,this._pollingIntervalMap=new Map,this._pollingNoMessageCountMap=new Map,this._membersReqInfoMap=new Map,this._startBroadcastSequence=1}init(n,r){this._core=n,this._parentPlugin=r,mh.init(n,this),n.ssoLog.debug("AVChatRoomHandler.init")}onAVChatRoomSystemNotification(n){const{OuterConstant:{GRP_AVCHATROOM:r}}=this._core,{GroupTips:g=[]}=n;for(let u=0;u0&&(r=[...this._joinedGroupMap.values()].filter(g=>g.type===n)),r}handleJoinGroupResult(n){return mA(this,void 0,void 0,function*(){const{utils:{isUndefined:r},OuterConstant:{CONV_GROUP:g},apiMap:{getConversationProfile:u},OuterConstant:E}=this._core,{longPollingKey:m,group:D,historyMessageList:v=[]}=n,{groupID:T}=D;return yield this._preCheck(D),this._joinedGroupMap.set(T,D),this._parentPlugin.groupDataHandler.updateLocalGroup([D]),this._parentPlugin.groupDataHandler.emitGroupListUpdate(),u(`${g}${T}`),aR.getGroupOnlineMemberCount(T),v.length>0&&mh.onMessageReceived(T,v,!0),r(m)?{code:0,data:{status:E.JOIN_STATUS_SUCCESS,group:D}}:{code:0,data:this.startMessageLongPolling(n)}})}isGroupCounterUpdated(n){return this._parentPlugin.groupCounter.isGroupCounterUpdated(n)}handleGroupCounterUpdated(n){this._parentPlugin.groupCounter.handleGroupCounterUpdated(n)}_preCheck(n){return mA(this,void 0,void 0,function*(){const{common:r,OuterConstant:g,helper:u,apiMap:{quitGroup:E},ssoLog:m}=this._core;if(r.isUnlimitedAVChatRoom()){if(this._pollingInstanceMap.size>(()=>{const T=hB("polling_count_limit");return fh(T)&&T>0?parseInt(T,10):20})())throw new u.ChatError({code:ZT,message:"the count of longPolling exceeds the max limit"});return}if(this._joinedAVChatRoomCount()===0||n.type===g.GRP_LIVE)return;const[D,v]=this._joinedGroupMap.entries().next().value;if(v.selfInfo.role===g.GRP_MBR_ROLE_OWNER)this._parentPlugin.groupDataHandler.deleteLocalGroup(D);else try{yield E(D)}catch(T){m.debug("quitGroup",`${this._name}._preCheck quitGroup failed, groupID:${D} info:`,T)}this.reset(D)})}startMessageLongPolling(n){const{OuterConstant:r}=this._core,{longPollingKey:g,startSequence:u=1,group:E}=n,{groupID:m}=E;return this._pollingRequestInfoMap.set(m,{longPollingKey:g,startSequence:u}),this._pollingIntervalMap.set(m,qQ()),this._startPolling(m),this._reportLongPollingCount(),{status:r.JOIN_STATUS_SUCCESS,group:E}}_startPolling(n){if(this._core.ssoLog.debug("_startPolling",`${this._name}._startPolling groupID:${n}`),this._pollingInstanceMap.has(n)){const g=this._pollingInstanceMap.get(n);return void(g?.isRunning()||g==null||g.start())}const r=new rR({core:this._core,manager:this,groupID:n,getRequestParams:this._handleRequestParams.bind(this),onSuccess:this._handleSuccess.bind(this),onFail:this._handleFailure.bind(this)});r.start(),this._pollingInstanceMap.set(n,r)}_handleRequestParams(n){const{longPollingKey:r,startSequence:g}=this._pollingRequestInfoMap.get(n)||{};return n===[...this._pollingInstanceMap.keys()][0]?{longPollingKey:r,startSequence:g,startBroadcastSeq:this._startBroadcastSequence,simplifiedMessage:BB()}:{longPollingKey:r,startSequence:g,simplifiedMessage:BB()}}_handleSuccess(n,r){const{ErrorCode:g}=r;if(g!==0){const{longPollingKey:u,startSequence:E}=this._pollingRequestInfoMap.get(n)||{};return void console.warn(`${this._name}._handleSuccess groupID:${n} key:${u} startSeq:${E} errorCode:${g}`)}this._hasJoinedAVChatRoom(n)&&this._handleResponseData(n,r)}_handleResponseData(n,r){const{Key:g,NextSeq:u,NextBroadcastSeq:E,RspMsgList:m=[],RspBroadcastMsgList:D=[]}=r;if(g&&u&&this._pollingRequestInfoMap.set(n,{longPollingKey:g,startSequence:u}),E&&E>this._startBroadcastSequence&&(this._startBroadcastSequence=E),m.length>0)this._getPollingNoMessageCount(n)!==0&&(this._updatePollingNoMessageCount(n,0),this._pollingIntervalMap.set(n,qQ())),mh.onMessageReceived(n,m);else{let v=this._getPollingNoMessageCount(n);if(v+=1,this._updatePollingNoMessageCount(n,v),v===(()=>{const T=hB("polling_no_msg_count");return fh(T)?parseInt(T,10):20})()){const T=qQ()+(()=>{const P=hB("polling_interval_plus");return fh(P)?parseInt(P,10):2e3})();this._pollingIntervalMap.set(n,T)}}D.length>0&&mh.onBroadcastMessageReceived(D)}_handleFailure(n,r){const{ssoLog:g,utils:{safeStringify:u}}=this._core;g.warn("polling",`${this._name}._handleFailure groupID:${n} error: ${u(r)}`)}_joinedAVChatRoomCount(){const{OuterConstant:n}=this._core;let r=[];return this._joinedGroupMap.size>0&&(r=this.getJoinedGroups().filter(g=>g.type===n.GRP_AVCHATROOM)),r.length}_hasJoinedAVChatRoom(n){return this._joinedGroupMap.has(n)}getJoinedGroups(){return[...this._joinedGroupMap.values()]}updateLocalLiveGroup(n,r){this._joinedGroupMap.set(n,r),this._parentPlugin.groupDataHandler.updateLocalGroup([r])}handleLiveHistoryMessages(n,r){mh.onMessageReceived(n,r,!0)}isOverFrequencyLimit(n){if(!this._membersReqInfoMap.has(n))return this._membersReqInfoMap.set(n,{startTime:Date.now(),requestCount:1}),!1;let{startTime:r,requestCount:g}=this._membersReqInfoMap.get(n);const{interval:u,count:E}=(()=>{const m=hB("av_members_freq_limit");if(fh(m)){const{interval:D,count:v}=JSON.parse(m);if(v>0&&D>0)return{interval:D,count:v}}return{interval:30,count:4}})();return Date.now()-r>1e3*u?(this._membersReqInfoMap.set(n,{startTime:Date.now(),requestCount:1}),!1):(g+=1,this._membersReqInfoMap.set(n,{startTime:r,requestCount:g}),g>E)}_stopPolling(n){if(this._core.ssoLog.debug("_stopPolling",`${this._name}._stopPolling groupID:${n}`),n){const{appStore:{conversationStore:r},OuterConstant:{CONV_GROUP:g}}=this._core;r.deleteConversation(`${g}${n}`);const u=this._pollingInstanceMap.get(n);return u?.stop(),this._parentPlugin.groupDataHandler.deleteLocalGroup(n),this._pollingInstanceMap.delete(n),this._pollingRequestInfoMap.delete(n),this._joinedGroupMap.delete(n),this._onlineMemberCountMap.delete(n),this._pollingIntervalMap.delete(n),this._pollingNoMessageCountMap.delete(n),void this._membersReqInfoMap.delete(n)}for(const r of this._pollingInstanceMap.values())r?.stop();this._pollingInstanceMap.clear(),this._pollingRequestInfoMap.clear(),this._joinedGroupMap.clear(),this._onlineMemberCountMap.clear(),this._pollingIntervalMap.clear(),this._pollingNoMessageCountMap.clear(),this._membersReqInfoMap.clear()}_updatePollingNoMessageCount(n,r){this._pollingNoMessageCountMap.set(n,r)}_getPollingNoMessageCount(n){return this._pollingNoMessageCountMap.get(n)||0}_reportLongPollingCount(){const n=this._joinedGroupMap.size;if(n>1){const{common:r,OuterConstant:g,ssoLog:u}=this._core,E=r.isUnlimitedAVChatRoom()?1:0,m=[],D=[];Array.from(this._joinedGroupMap.values()).forEach(({groupID:v,type:T})=>{T===g.GRP_LIVE?D.push(v):m.push(v)}),u.info("longPollingCount",String(n),{moreMessage:`av:${m.join(",")} live:${D.join(",")} code: ${E}`,eventType:29})}}reset(n){this._stopPolling(n),this._startBroadcastSequence=1,mh.reset()}},gR=new class{init(n,r){this._core=n,this._parentPlugin=r;const{helper:g}=n;g.registerApi({apiName:"joinGroup",context:this,matcher:()=>r.getInstalledSubPlugins().length>0})}joinGroup(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:r}=this._core,g=yield this._parentPlugin.groupAction.joinGroup(n),{data:{status:u,group:{type:E}}}=g;return E===r.GRP_AVCHATROOM?u===r.JOIN_STATUS_ALREADY_IN_GROUP?g:Yg.handleJoinGroupResult(g.data):g})}},$T=new class{init(n,r){this._core=n,this._parentPlugin=r;const{helper:g}=n;g.registerApi({apiName:"quitGroup",context:this,matcher:()=>r.getInstalledSubPlugins().length>0})}quitGroup(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:r}=this._core,g=yield this._parentPlugin.groupAction.quitGroup(n),{data:{type:u}}=g;return u===r.GRP_AVCHATROOM&&Yg.reset(n),g})}},cR=new class{init(n,r){this._core=n,this._parentPlugin=r;const{helper:g}=n;g.registerApi({apiName:"dismissGroup",context:this,matcher:()=>r.getInstalledSubPlugins().length>0})}dismissGroup(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:r}=this._core,g=yield this._parentPlugin.groupAction.dismissGroup(n),{data:{type:u}}=g;return u===r.GRP_AVCHATROOM&&Yg.reset(n),g})}},Jm=new class{constructor(){this._name="GetAVChatRoomMemberList"}init(n,r){this._core=n,this._parentPlugin=r;const{helper:g}=n;g.registerApi({apiName:"getGroupMemberList",context:this,matcher:()=>r.getInstalledSubPlugins().length>0})}getGroupMemberList(n){return mA(this,void 0,void 0,function*(){const{appStore:{groupStore:r},helper:g,OuterConstant:u}=this._core,{groupID:E}=n,m=r.getGroup(E);if(m?.type===u.GRP_AVCHATROOM&&g.checkBusinessCapabilityBits(nR)){if(Yg.isOverFrequencyLimit(E))throw{code:2996,message:`Over frequency limit: get_members-${E}`};return this._getGroupMemberList(n)}return this._parentPlugin.groupMember.getGroupMemberList(n)})}_getGroupMemberList(n){return mA(this,void 0,void 0,function*(){const r="_getGroupMemberList",{helper:g}=this._core;try{const u=yield function(v,T){return mA(this,void 0,void 0,function*(){const{groupID:P,offset:W=0}=v,oA={GroupId:P,Timestamp:W};return T.common.buildAndSendPacket({servcmd:"group_open_avchatroom_http_svc.get_members",data:oA})})}(n,this._core),{MemberList:E=[],NextTimestamp:m=0}=u||{},D=this._handleMemberList(E);return console.log(`${this._name}.${r} ok, groupID:${n.groupID} count:${D.length} nextOffset:${m}`),{code:0,data:{memberList:D,offset:m}}}catch(u){const E=new g.ChatError({functionName:r,code:u?.errorCode,message:u?.errorInfo});throw console.error(`${this._name}.${r} fail:`,E),E}})}_handleMemberList(n){return n.map(r=>{const{Member_Account:g,NickName:u="",Avatar:E="",Remark:m="",JoinTime:D=0,Marks:v=[]}=r;return{userID:g,nick:u,avatar:E,remark:m,joinTime:D,marks:v,isOnline:!0}})}},Hm=new class{constructor(){this._name="DeleteAVChatRoomMember"}init(n,r){this._core=n,this._parentPlugin=r;const{helper:g}=n;g.registerApi({apiName:"deleteGroupMember",context:this,matcher:()=>r.getInstalledSubPlugins().length>0})}deleteGroupMember(n){return mA(this,void 0,void 0,function*(){const r="deleteGroupMember",{appStore:{groupStore:g},utils:{isUndefined:u},helper:E,OuterConstant:m}=this._core,{groupID:D}=n,v=g.getGroup(D);if(u(v))throw new E.ChatError({functionName:r,code:LD});if(v.type===m.GRP_AVCHATROOM){if(E.checkBusinessCapabilityBits(WT))return this._deleteGroupMember(n);throw new E.ChatError({functionName:r,code:JQ})}return this._parentPlugin.groupMember.deleteGroupMember(n)})}_deleteGroupMember(n){return mA(this,void 0,void 0,function*(){const r="_deleteGroupMember",{appStore:{groupStore:g},helper:u,ssoLog:E}=this._core,{groupID:m,duration:D=0,userIDList:v}=n;if(D===0)throw new u.ChatError({functionName:r,code:zT});try{return yield function(T,P){return mA(this,void 0,void 0,function*(){const{groupID:W,userIDList:oA,duration:EA,reason:wA}=T,kA={GroupId:W,Members_Account:oA,Duration:EA,Description:wA};return P.common.buildAndSendPacket({servcmd:"group_open_http_svc.ban_group_member",data:kA})})}(n,this._core),E.debug(r,`${this._name}.${r} ok, groupID:${m}`),{code:0,data:{group:g.getGroup(m),userIDList:v}}}catch(T){throw new u.ChatError({functionName:r,code:T?.errorCode,message:T?.errorInfo})}})}},Td=new class{constructor(){this._name="MarkAVChatRoomMember"}init(n){this._core=n;const{helper:r}=n;r.registerApi({apiName:"markGroupMemberList",context:this})}markGroupMemberList(n){return mA(this,void 0,void 0,function*(){const r="markGroupMemberList",{groupID:g,markType:u,enableMark:E,userIDList:m=[]}=n,D=this._generateRequestData(n);try{const v=yield function(oA,EA){return mA(this,void 0,void 0,function*(){const{groupID:wA,operationType:kA,memberList:xA}=oA,LA={GroupId:wA,CommandType:kA,MemberList:xA};return EA.common.buildAndSendPacket({servcmd:"group_open_avchatroom_http_svc.modify_user_info",data:LA})})}(D,this._core),{MemberList:T=[]}=v||{},{successUserIDList:P,failureUserIDList:W}=this._handleResult(T,m);return{code:0,data:{successUserIDList:P,failureUserIDList:W},successLog:{message:`${this._name}.${r} ok, groupID:${g} markType:${u} enableMark:${E} success:${P.length} fail:${W.length}`}}}catch(v){throw new this._core.helper.ChatError({functionName:r,code:v?.errorCode,message:v?.errorInfo})}})}_generateRequestData(n){const{groupID:r,markType:g,enableMark:u,userIDList:E=[]}=n,m=u===!0?1:2,D=[...E];return D.length>500&&console.warn(`${this._name}._generateRequestData, the length of userIDList cannot exceed 500`),{groupID:r,operationType:m,memberList:D.map(v=>({Member_Account:v,Marks:[g]}))}}_handleResult(n,r){const g=[],u=[];return n.length===r.length?(g.push(...r),{successUserIDList:g,failureUserIDList:u}):(r.forEach(E=>{n.find(m=>m.Member_Account===E)?g.push(E):u.push(E)}),{successUserIDList:g,failureUserIDList:u})}},lR=new class{init(n,r){n.ssoLog.debug("AVChatRoomAction.init"),gR.init(n,r),$T.init(n,r),cR.init(n,r),Jm.init(n,r),aR.init(n,r),Hm.init(n,r),Td.init(n)}},IR=new class{constructor(){this._name="LiveHandler"}init(n){this._core=n;const{helper:r,ssoLog:g}=n;r.registerExperimentalAPI("startMessageLongPolling",this),r.registerExperimentalAPI("stopMessageLongPolling",this),g.debug("LiveHandler.init")}startMessageLongPolling(n){const{common:r,utils:{isEmpty:g},OuterConstant:u,ssoLog:E}=this._core,{groupID:m,longPollingKey:D,longPollingSequence:v=1}=n;if(g(D))return E.warn("startMessageLongPolling",`${this._name}.startMessageLongPolling longPollingKey is empty.`),Promise.resolve({});Yg.hasPollingInstance(m)&&this.stopMessageLongPolling({groupID:m});const T=Yg.getJoinedLiveList(),P=r.isUnlimitedAVChatRoom();!P&&T.length>0&&this.stopMessageLongPolling({groupID:T[0].groupID}),E.debug("startMessageLongPolling",`${this._name}.startMessageLongPolling isUnlimited:${P} groupID:${m} longPollingKey:${D} longPollingSequence:${v}`);const W={groupID:m,type:u.GRP_LIVE};return Yg.updateLocalLiveGroup(m,W),this._getLiveHistoryMessages({groupID:m,longPollingKey:D,startSequence:v}),Yg.startMessageLongPolling({group:W,longPollingKey:D,startSequence:v})}stopMessageLongPolling(n){const{groupID:r}=n;return Yg.reset(r),this._core.ssoLog.debug("stopMessageLongPolling",`${this._name}.stopMessageLongPolling ok, groupID:${r}`),Promise.resolve({groupID:r})}_getLiveHistoryMessages(n){return mA(this,void 0,void 0,function*(){const{ssoLog:r}=this._core,{groupID:g}=n;try{const u=yield function(m,D){return mA(this,void 0,void 0,function*(){const{groupID:v,longPollingKey:T,startSequence:P}=m,W={GroupId:v,LongPollingKey:T,PullPreSeq:P};return D.common.buildAndSendPacket({servcmd:"group_open_http_svc.get_huge_group_msg",data:W})})}(n,this._core),{RspMsgList:E=[]}=u||{};r.debug("_getLiveHistoryMessages",`${this._name}._getLiveHistoryMessages ok, groupID:${g} count:${E.length}`),E.length>0&&Yg.handleLiveHistoryMessages(g,E)}catch(u){r.debug("_getLiveHistoryMessages",`${this._name}._getLiveHistoryMessages failed, groupID:${g} info:${u.message}`)}})}},qm=new class{constructor(){this.name="AVChatRoom"}install(n,r){this._core=n,CB.init(n),Yg.init(n,r),lR.init(n,r),IR.init(n);const{notificationCenter:g,InnerEvent:u}=n,{InnerEventSubType:E}=g;g.subscribeInnerEvent(u.MESSAGE_PUSH,E.GROUP_SYSTEM_NOTIFICATION,this._onAVChatRoomSystemNotification,this),g.subscribeInnerEvent(u.LOGOUT,this._reset,this),g.subscribeInnerEvent(u.DESTROY,this._dispose,this)}_onAVChatRoomSystemNotification(n){Yg.onAVChatRoomSystemNotification(n)}_reset(){Yg.reset()}_dispose(){this._reset();const{notificationCenter:n,InnerEvent:r}=this._core,{InnerEventSubType:g}=n;n.unSubscribeInnerEvent(r.MESSAGE_PUSH,g.GROUP_SYSTEM_NOTIFICATION,this._onAVChatRoomSystemNotification,this),n.unSubscribeInnerEvent(r.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(r.DESTROY,this._dispose,this)}};const ig=new class{init(n){this.core=n}},Km="message",QB="user",pB={OR:"or",AND:"and"},NI=20,AN=20,uR=20,yh={required:!1,rules:["array"],allowEmpty:!0,customValidator:n=>!n||!!(Array.isArray(n)&&n.length<=5)||"keywordList should be an array and length <= 5"},jm={required:!1,rules:["string"],allowEmpty:!0,customValidator:n=>!n||!![pB.OR,pB.AND].includes(n)||"keywordListMatchType should be OR or AND"},RC={required:!1,rules:["number"],allowEmpty:!0,customValidator:n=>typeof n=="number"&&n>=1&&n<=100||"count must be a number between 1 and 100"},KQ={required:!1,rules:["string"],allowEmpty:!0},ER={required:!1,rules:["array"],allowEmpty:!0,customValidator:n=>{const{OuterConstant:r}=ig.core;if(!Array.isArray(n))return"groupTypeList should be an array";const g=[r.GRP_PUBLIC,r.GRP_COMMUNITY,r.GRP_WORK,r.GRP_MEETING];let u=!1;for(let E=0;E{const{OuterConstant:r}=ig.core,g=[r.MSG_TEXT,r.MSG_IMAGE,r.MSG_AUDIO,r.MSG_FILE,r.MSG_VIDEO,r.MSG_LOCATION,r.MSG_CUSTOM,r.MSG_MERGER];let u=!1;for(let E=0;E{const{OuterConstant:r}=ig.core;return!(!n?.startsWith(r.CONV_C2C)&&!n?.startsWith(r.CONV_GROUP)&&n!==r.CONV_SYSTEM)||"conversationID is invalid"}},Wm=n=>({required:!1,rules:["number"],allowEmpty:!0,customValidator:r=>typeof r=="number"&&r>=0||`${n} should be a number >= 0';`}),FD={required:!1,rules:["string"],allowEmpty:!0,customValidator:n=>{const{OuterConstant:r}=ig.core;return!![r.GENDER_FEMALE,r.GENDER_MALE].includes(n)||"gender is invalid"}},zm={searchCloudMessages:{keywordList:yh,keywordListMatchType:jm,cursor:KQ,senderUserIDList:{required:!1,rules:["array"],allowEmpty:!0,customValidator:n=>!!(Array.isArray(n)&&n.length<=5)||"senderUserIDList should be an array and length <= 5"},messageTypeList:dR,conversationID:CR,timePosition:Wm("timePosition"),timePeriod:Wm("timePeriod")},searchCloudUsers:{keywordList:yh,keywordListMatchType:jm,cursor:KQ,count:RC,miniBirthday:Wm("miniBirthday"),maxBirthday:Wm("maxBirthday"),gender:FD},searchCloudGroupMembers:{keywordList:yh,keywordListMatchType:jm,cursor:KQ,count:RC,groupTypeList:ER,groupIDList:{required:!1,rules:["array"],allowEmpty:!0}},searchCloudGroups:{keywordList:yh,keywordListMatchType:jm,cursor:KQ,count:RC,groupTypeList:ER}},OD={searchCloudMessages:!0,searchCloudUsers:!0,searchCloudGroupMembers:!0,searchCloudGroups:!0};var PD=new class{constructor(){this.name="CloudSearch"}install(n){this._core=n,ig.init(n),n.helper.registerApi({apiName:"searchCloudMessages",context:this}),n.helper.registerApi({apiName:"searchCloudUsers",context:this}),n.helper.registerApi({apiName:"searchCloudGroupMembers",context:this}),n.helper.registerApi({apiName:"searchCloudGroups",context:this}),n.helper.registerValidateConfig({auth:OD,params:zm})}searchCloudMessages(n){return mA(this,void 0,void 0,function*(){try{const{OuterConstant:r,helper:g}=this._core,{conversationID:u,timePeriod:E,timePosition:m}=n,D=vo(n,["conversationID","timePeriod","timePosition"]),v=Object.assign({count:100},D);u&&(u.startsWith(r.CONV_C2C)?v.account=u.replace(r.CONV_C2C,""):u.startsWith(r.CONV_GROUP)&&(v.groupID=u.replace(r.CONV_GROUP,""))),this._setTimeRangeParams(v,{timePeriod:E,timePosition:m});const T=yield function(LA){return mA(this,void 0,void 0,function*(){const{count:SA,keywordList:OA,keywordListMatchType:WA,senderUserIDList:ue,messageTypeList:le,endTime:ki,startTime:Li,cursor:Yt,account:Fi,groupID:hs}=LA,Re={Count:SA,KeywordList:OA,MatchType:WA,SendUserIDList:ue,MsgTypeList:le,EndTime:ki,StartTime:Li,Cursor:Yt,PeerAccount:Fi,GroupID:hs};return ig.core.common.buildAndSendPacket({servcmd:"message_search.query",data:Re})})}(v);if(!T)return{code:0,data:{}};const{ErrorCode:P,ErrorInfo:W,TotalCount:oA,Cursor:EA="",ConversationMsgs:wA=[]}=T;if(P!==0)throw{errorCode:P,errorInfo:W};const kA=`keywordList:${n.keywordList} keywordListMatchType:${n.keywordListMatchType} cursor:${n.cursor} res: totalCount:${oA}`;return{code:0,data:{searchResultList:wA.map(LA=>{const{MsgList:SA,Count:OA,GroupID:WA,UserID:ue}=LA,le=WA?`${r.CONV_GROUP}${WA}`:`${r.CONV_C2C}${ue}`;if(this._isSearchingAllConversations(n)&&OA>1)return{conversationID:le,messageCount:OA,messageList:[]};const ki=SA.map(Li=>g.isEmpty(WA)?function(Yt,Fi){const hs=Fi.OuterConstant.CONV_C2C,Re=Fi.message.messageHelper.parseServerPushMessage(Yt),Mt=Fi.message.messageFactory.createMessage(Object.assign(Object.assign({},Re),{conversationType:hs,flow:"in"}));return Mt.setElement(Re.elements),Mt}(Li,this._core):function(Yt,Fi){const hs=Fi.OuterConstant.CONV_GROUP,Re=Fi.message.messageHelper.parseServerGroupMessage(Yt),Mt=Fi.message.messageFactory.createMessage(Object.assign(Object.assign({},Re),{conversationType:hs,flow:"in"}));return Mt.setElement(Re.elements),Mt}(Li,this._core));return{conversationID:le,messageCount:OA,messageList:ki}}),cursor:EA,totalCount:oA},successLog:{message:kA}}}catch(r){const{errorCode:g,errorInfo:u}=r||{};this._handleError({errorCode:g,errorInfo:u,searchType:Km,functionName:"searchCloudMessages"})}})}searchCloudUsers(n){return mA(this,void 0,void 0,function*(){var r;try{const{keywordListMatchType:g,count:u=AN}=n,E=vo(n,["keywordListMatchType","count"]),m=Object.assign({count:u,keywordListMatchType:g===pB.AND?1:0},E);this._setBirthdayRangeParams(m,n);const D=yield function(kA){return mA(this,void 0,void 0,function*(){const{count:xA,keywordList:LA,keywordListMatchType:SA,miniBirthday:OA,maxBirthday:WA,cursor:ue,gender:le}=kA,ki={Count:xA,Keywords:LA,KeywordMatchType:SA,Cursor:ue,UserBirthStart:OA,UserBirthEnd:WA,Gender:le};return ig.core.common.buildAndSendPacket({servcmd:"user_search.query",data:ki})})}(m);if(!D)return{error:0,data:{}};const{ErrorCode:v,ErrorInfo:T,TotalCount:P,Cursor:W="",Users:oA=[]}=D;if(v!==0)throw{errorCode:v,errorInfo:T};const EA=`keywordList:${n.keywordList} keywordListMatchType:${n.keywordListMatchType} cursor:${n.cursor} count:${n.count} res: totalCount:${P}`,wA=[];for(let kA=0,xA=oA.length;kA({tag:ue.Tag,value:ue.StrValue})),WA=(r=this._core.user.userProfile)===null||r===void 0?void 0:r.createProfile(LA,OA);wA.push(WA)}return{code:0,data:{searchResultList:wA,cursor:W,totalCount:P},successLog:{message:EA}}}catch(g){const{errorCode:u,errorInfo:E}=g||{};this._handleError({errorCode:u,errorInfo:E,searchType:QB,functionName:"searchCloudUsers"})}})}searchCloudGroupMembers(n){return mA(this,void 0,void 0,function*(){try{const{count:r=uR,keywordListMatchType:g}=n,u=vo(n,["count","keywordListMatchType"]),E=Object.assign({count:r,keywordListMatchType:g===pB.AND?1:0},u),m=yield function(wA){return mA(this,void 0,void 0,function*(){const{count:kA,keywordList:xA,keywordListMatchType:LA,groupTypeList:SA,cursor:OA,groupIDList:WA}=wA,ue={Count:kA,Keywords:xA,KeywordMatchType:LA,Cursor:OA,GroupType:SA,GroupIdList:WA};return ig.core.common.buildAndSendPacket({servcmd:"group_member_search.query",data:ue})})}(E);if(!m)return{code:0,data:{}};const{ErrorCode:D,ErrorInfo:v,GroupMembers:T=[],Cursor:P,TotalCount:W}=m;if(D!==0)throw{errorCode:D,errorInfo:v};const oA=`keywordList:${n.keywordList} keywordListMatchType:${n.keywordListMatchType} cursor:${n.cursor} count:${n.count} res: totalCount:${W}`,EA=new Map;return T.forEach(wA=>{const{GroupID:kA,GroupName:xA,GroupType:LA,GroupFaceUrl:SA,GroupMemberUserName:OA,GroupMemberUserID:WA,GroupMemberNameCard:ue,GroupMemberAvatar:le=""}=wA,ki={groupID:kA,name:xA,type:LA,avatar:SA},Li={userID:WA,nick:OA,nameCard:ue,avatar:le};if(EA.has(kA)){const Yt=EA.get(kA);Yt.memberList.push(Li),EA.set(kA,Yt)}else EA.set(kA,{groupInfo:ki,memberList:[Li]})}),{code:0,data:{searchResultList:[...EA.values()],cursor:P,totalCount:W},successLog:{message:oA}}}catch(r){const{errorCode:g,errorInfo:u}=r||{};this._handleError({errorCode:g,errorInfo:u,searchType:QB,functionName:"searchCloudGroupMembers"})}})}searchCloudGroups(n){return mA(this,void 0,void 0,function*(){try{const{count:r=NI,keywordListMatchType:g}=n,u=vo(n,["count","keywordListMatchType"]),E=Object.assign({count:r,keywordListMatchType:g===pB.AND?1:0},u),m=yield function(EA){return mA(this,void 0,void 0,function*(){const{count:wA,keywordList:kA,keywordListMatchType:xA,groupTypeList:LA,cursor:SA}=EA,OA={Count:wA,Keywords:kA,KeywordMatchType:xA,Cursor:SA,GroupType:LA};return ig.core.common.buildAndSendPacket({servcmd:"group_search.query",data:OA})})}(E);if(!m)return{code:0,data:{}};const{ErrorCode:D,ErrorInfo:v,Groups:T,Cursor:P,TotalCount:W}=m;if(D!==0)throw{errorCode:D,errorInfo:v};const oA=`keywordList:${n.keywordList} keywordListMatchType:${n.keywordListMatchType} cursor:${n.cursor} count:${n.count} res: totalCount:${W}`;return{code:0,data:{searchResultList:T?.map(EA=>function(wA){const{GroupFaceUrl:kA,GroupID:xA,GroupIntroduction:LA,GroupMemberNum:SA,GroupName:OA,GroupOwnerTinyID:WA,GroupOwnerUserID:ue,GroupOwnerUserName:le,GroupType:ki,GroupAddOption:Li,GroupInviteOption:Yt}=wA;return{avatar:kA,groupID:xA,introduction:LA,memberCount:SA,name:OA,ownerTinyID:WA,ownerID:ue,ownerNick:le,type:ki,joinOption:Li,inviteOption:Yt}}(EA))||[],cursor:P,totalCount:W},successLog:{message:oA}}}catch(r){const{errorCode:g,errorInfo:u}=r||{};this._handleError({errorCode:g,errorInfo:u,searchType:QB,functionName:"searchCloudGroups"})}})}_setTimeRangeParams(n,{timePeriod:r,timePosition:g}){r&&r>0&&(n.startTime=g&&g>0?g-r:this._core.helper.timeManager.getServerTimeSeconds()-r),n.startTime&&n.startTime<0&&(n.startTime=void 0),g&&g>0&&(n.endTime=g)}_handleError({errorCode:n,errorMessage:r,searchType:g}){const{helper:u}=this._core;let E=n;throw n===60020?E="SearchUnable":g!==Km&&n===27003?E="SearchParamsError":g!==Km&&n===60018&&(E="SearchOverLimit"),new u.ChatError({code:E,message:r})}_isSearchingAllConversations(n){return this._core.helper.isEmpty(n.conversationID)}_setBirthdayRangeParams(n,r){const{miniBirthday:g,maxBirthday:u}=r;g!==void 0&&(n.miniBirthday=g,u===void 0&&(n.maxBirthday=4294967295)),u!==void 0&&(n.maxBirthday=u)}};function Dh(n,r){return Math.round(Number(n)*Math.pow(10,r))/Math.pow(10,r)}const hR="qualityStat",xD="im-ssolog-quality-stat";var YD;(function(n){n[n.ONLINE=8]="ONLINE"})(YD||(YD={}));const Zm="networkRTT",Sh="messageE2EDelay",mB="sendMessageC2C",vh="sendMessageGroup",Mh="sendMessageGroupAV",fB="sendMessageRichMedia",yB="cosUpload",wC="messageReceivedGroup",jQ="messageReceivedGroupAVPush",WQ="messageReceivedGroupAVPull",eN={[Zm]:2,[Sh]:3,[mB]:4,[vh]:5,[Mh]:6,[fB]:7,[wC]:8,[jQ]:9,[WQ]:10,[yB]:11},BR=[mB,vh,Mh,fB,yB],Rh=[wC,jQ,WQ],DB=[Zm,Sh,mB,vh,Mh,fB,yB,wC,jQ,WQ],VD={ERR_SVR_COMM_SENSITIVE_TEXT:80001,ERR_SVR_COMM_BODY_SIZE_LIMIT:80002,OPEN_SERVICE_OVERLOAD_ERROR:60022,ERR_SVR_MSG_PKG_PARSE_FAILED:20001,ERR_SVR_MSG_INTERNAL_AUTH_FAILED:20002,ERR_SVR_MSG_INVALID_ID:20003,ERR_SVR_MSG_PUSH_DENY:20006,ERR_SVR_MSG_IN_PEER_BLACKLIST:20007,ERR_SVR_MSG_BOTH_NOT_FRIEND:20009,ERR_SVR_MSG_NOT_PEER_FRIEND:20010,ERR_SVR_MSG_NOT_SELF_FRIEND:20011,ERR_SVR_MSG_SHUTUP_DENY:20012,ERR_SVR_GROUP_INVALID_PARAMETERS:10004,ERR_SVR_GROUP_PERMISSION_DENY:10007,ERR_SVR_GROUP_NOT_FOUND:10010,ERR_SVR_GROUP_INVALID_GROUPID:10015,ERR_SVR_GROUP_REJECT_FROM_THIRDPARTY:10016,ERR_SVR_GROUP_SHUTUP_DENY:10017,MSG_SEND_FAIL:2100,OVER_FREQUENCY_LIMIT:2996},Xm="quality_stat";var zQ=new class{constructor(){this._messageStatsMap=new Map,this._userSideErrorCodes=new Set(Object.values(VD))}init(n){this._core=n,Object.values(BR).forEach(r=>{this._messageStatsMap.set(r,{totalCount:0,successCount:0,failedCountOfUserSide:0,costSum:0,costCount:0,fileSizeSum:0})})}dispatchSendStats(n){const{name:r,message:g,error:u,startTs:E}=n,{SEND_MESSAGE_STAT:m}=this._core.constants;switch(r){case m.TOTAL_COUNT:this._handleTotalCount(g);break;case m.SUCCESS_COUNT:this._handleSuccessCount(g);break;case m.FAILED_COUNT:this._handleFailedCount(g,u);break;case m.SEND_COST:this._handleSendCost(g,E)}}getStatResult(n){const r=this._messageStatsMap.get(n);if(!r||r.totalCount===0)return null;const{totalCount:g,successCount:u,failedCountOfUserSide:E}=r,m=Dh(u/g*100,2),D=u+E,v=Dh(D/g*100,2),T=this._calcAverageValue(r,n);return this._resetStat(n),{total_count:g,success_count_business:u,percent_business:m,success_count_platform:D,percent_platform:v,average_value:T}}_handleTotalCount(n){const r=this._getSendMessageSpecifiedKey(n),g=r&&this._messageStatsMap.get(r);g&&g.totalCount++}_handleSuccessCount(n){const r=this._getSendMessageSpecifiedKey(n),g=r&&this._messageStatsMap.get(r);g&&g.successCount++}_handleFailedCount(n,r){var g;const u=(g=r?.code)!==null&&g!==void 0?g:r?.errorCode;if(this._isUserSideError(u)){const E=this._getSendMessageSpecifiedKey(n),m=E&&this._messageStatsMap.get(E);m&&m.failedCountOfUserSide++}}_handleSendCost(n,r){const g=this._getSendMessageSpecifiedKey(n),u=g&&this._messageStatsMap.get(g);u&&(u.costSum+=Date.now()-r,u.costCount++)}_isUserSideError(n){return this._userSideErrorCodes.has(n)||n>=120001&&n<=13e4||n>=10100&&n<=10200}_getSendMessageSpecifiedKey(n){const{MSG_IMAGE:r,MSG_AUDIO:g,MSG_VIDEO:u,MSG_FILE:E,CONV_C2C:m,CONV_GROUP:D,GRP_AVCHATROOM:v}=this._core.OuterConstant;if([r,g,u,E].includes(n.type))return fB;if(n.conversationType===m)return mB;if(n.conversationType===D){const{groupStore:T}=this._core.appStore,P=T.getGroup(n.to);if(!P)return;const{type:W}=P;return W===v?Mh:vh}}_calcAverageValue(n,r){return n.costCount===0?0:Math.round(r===yB?1e3*n.fileSizeSum/n.costSum:n.costSum/n.costCount)}_resetStat(n){const r=this._messageStatsMap.get(n);r&&(r.totalCount=0,r.successCount=0,r.failedCountOfUserSide=0,r.costSum=0,r.costCount=0,r.fileSizeSum=0)}},ZQ=new class{constructor(){this._lastCycleStats=new Map,this._currentCycleStats=new Map}init(n){this._core=n;const{OuterEvent:r,notificationCenter:g}=n;this._initStatsMap(),g.subscribeOuterEvent(r.MESSAGE_RECEIVED,this._onMessageReceived,this)}addMessageSequence(n){const r=this._getReceivedMessageSpecifiedKey(n),{utils:{isUndefined:g},OuterConstant:{CONV_GROUP:u},ssoLog:E}=this._core;if(g(r)||!this._currentCycleStats.has(r))return void E.debug("addMessageSequence",`${hR}.addMessageSequence invalid key:${r}`);const{conversationID:m,sequence:D}=n,v=m.replace(u,""),T=this._lastCycleStats.get(r);if(T.size===0||!T.has(v))return void this._addToCurrentCycle(r,v,D);const P=T.get(v);D>P.minSeq&&D{const{sortedSequences:m,minSeq:D,maxSeq:v}=E;m.length>0&&(u+=m.length,g+=v-D+1)}),g===0?null:(this._transferCycleDataOptimized(n),{total_count:g,success_count_business:u,percent_business:Dh(u/g*100,2)})}reset(){this._lastCycleStats.clear(),this._currentCycleStats.clear()}dispose(){const{notificationCenter:n,OuterEvent:{MESSAGE_RECEIVED:r}}=this._core;n.unSubscribeOuterEvent(r,this._onMessageReceived,this),this.reset()}_initStatsMap(){Object.values(Rh).forEach(n=>{this._lastCycleStats.set(n,new Map),this._currentCycleStats.set(n,new Map)})}_onMessageReceived(n){const{data:r=[]}=n;r.forEach(g=>{this.addMessageSequence(g)})}_transferCycleDataOptimized(n){const r=this._currentCycleStats.get(n);if(!r)return;const g=new Map;r.forEach((u,E)=>{const m=u.dirty?[...u.sortedSequences].sort((D,v)=>D-v):u.sortedSequences;g.set(E,{sortedSequences:m,minSeq:u.minSeq,maxSeq:u.maxSeq,dirty:!1})}),this._lastCycleStats.set(n,g),this._currentCycleStats.set(n,new Map)}_getReceivedMessageSpecifiedKey(n){const{OuterConstant:{CONV_GROUP:r,GRP_AVCHATROOM:g}}=this._core;if(n.conversationType===r&&n?._onlineOnlyFlag!==!0){const{groupStore:u}=this._core.appStore,E=u.getGroup(n.to);if(!E)return null;const{type:m}=E;return m===g?WQ:wC}}_insertToLastCycle(n,r){r.dirty&&(r.sortedSequences.sort((u,E)=>u-E),r.dirty=!1);const g=this._findInsertPos(r.sortedSequences,n);r.sortedSequences.splice(g,0,n),r.minSeq=Math.min(r.minSeq,n),r.maxSeq=Math.max(r.maxSeq,n)}_findInsertPos(n,r){let g=0,u=n.length-1;for(;g<=u;){const E=Math.floor((g+u)/2);if(n[E]===r)return E;n[E]0&&(this._totalDelay+=g,this._totalCount++,g<=1?this._countLessThan1s++:g<=3&&this._countLessThan3s++)}getStatResult(){if(this._totalCount===0)return null;const n={total_count:this._totalCount,success_count_business:this._countLessThan1s,success_count_platform:this._countLessThan3s,percent_business:this._calculatePercentage(this._countLessThan1s,this._totalCount),percent_platform:this._calculatePercentage(this._countLessThan3s,this._totalCount),average_value:this._calculateAverageDelay(this._totalCount)};return this.reset(),n}reset(){this._totalDelay=0,this._totalCount=0,this._countLessThan1s=0,this._countLessThan3s=0}dispose(){const{notificationCenter:n,OuterEvent:{MESSAGE_RECEIVED:r}}=this._core;n.unSubscribeOuterEvent(r,this._onMessageReceived,this),this.reset()}_onMessageReceived(n){const{data:r=[]}=n,{OuterConstant:{MSG_GRP_TIP:g,MSG_GRP_SYS_NOTICE:u}}=this._core,E=[g,u];r.forEach(m=>{!E.includes(m.type)&&m.clientTime>0&&this.addMessageDelay(m.clientTime)})}_calculateAverageDelay(n){return n===0?0:Dh(this._totalDelay/n,1)}_calculatePercentage(n,r){return Dh(n/r*100,2)}},QR=new class{init(n){this.core=n}},tN=new class{constructor(){this.name="MessageQualityStat",this._reportIndex=0,this._wholePeriod=!1,this._pendingReports=[],this._failedLogsCache=new Map}install(n){this._core=n;const{helper:r,notificationCenter:g,InnerEvent:{QUALITY_STAT:u,LOGOUT:E,DESTROY:m},constants:{WORKFLOW_NAME:D,WORKFLOW_STEP:v}}=n;QR.init(n),zQ.init(n),ZQ.init(n),XQ.init(n),r.registerWorkflowStep(D.SYNC_SERVER_INFO_AFTER_LOGIN,v.QUALITY_REPORT,this.handleLoginSuccess,this),g.subscribeInnerEvent(u,this._handleQualityStat,this),g.subscribeInnerEvent(E,this._reset,this),g.subscribeInnerEvent(m,this._dispose,this)}handleLoginSuccess(){const{store:n,helper:r,utils:{isUndefined:g}}=this._core,u=n.get("cloudConfig")||{},{q_rpt_interval:E}=u,m=g(E)?12e4:Number(E);r.taskScheduler.addTask({id:Xm,intervalMs:m,callback:this.report,context:this})}report(){this._wholePeriod=!0;const n=[...DB.map(r=>{const g=this._buildQualityReportItem(r);return g?Object.assign(Object.assign({},g),{report_index:this._reportIndex,whole_period:this._wholePeriod}):null}).filter(Boolean),...this._pendingReports];this._pendingReports=[],this._needSkipReport()||this._uploadQualityReports(n)}_handleQualityStat(n){const{constants:{QUALITY_METRICS:r}}=this._core,{label:g,data:u}=n;g===r.MESSAGE_SEND_SUCCESS_RATE&&zQ.dispatchSendStats(u)}_needSkipReport(){return this._isSDKAppIDInBlacklist()&&!this._isTinyIDInWhitelist()}_isSDKAppIDInBlacklist(){const{store:n,utils:r}=this._core,g=n.get("cloudConfig")||{},u=n.get("instance")||{},{sdkAppId:E}=u,{q_rpt_sdkappid_bl:m=[]}=g;if(!r.isEmpty(m))return m.split(",").map(D=>Number(D)).includes(E)}_isTinyIDInWhitelist(){const{store:n,utils:r}=this._core,g=n.get("cloudConfig")||{},u=n.get("login")||{},E=Number(u.tinyID),{q_rpt_tinyid_wl:m=[]}=g;if(!r.isEmpty(m))return m.split(",").includes(E)}_buildQualityReportItem(n){const r=this._getStatResultByKey(n);if(r===null)return null;const g={quality_type:eN[n],timestamp:Date.now(),network_type:YD.ONLINE,extension:""};return Object.assign(Object.assign({},g),r)}_getStatResultByKey(n){switch(n){case Sh:return XQ.getStatResult();case mB:case vh:case Mh:case fB:case yB:return zQ.getStatResult(n);case wC:case jQ:case WQ:return ZQ.getStatResult(n);default:return null}}_uploadQualityReports(n){return mA(this,void 0,void 0,function*(){try{const r={header:this._core.common.getCommonHead(),quality:n};yield function(g){const{common:u,channel:E}=QR.core,m="imopenstat.tim_web_report_v2",D=u.generateSSOLogProtocolData({servcmd:m,data:g}),v=`${D.head.seq}${m}`;return E.sendPacket(D,{requestId:v})}(r),this._reportIndex++,this._wholePeriod=!1}catch(r){console.warn("doReport failed. error:",r),this._pendingReports=this._pendingReports.concat(n),this._cacheFailedLogs()}})}_cacheFailedLogs(){const n=this._pendingReports,r=`${hR}._cacheFailedLogs`;let g=[...this._failedLogsCache.get(xD)||[],...n];g.length>10&&(g=g.slice(g.length-10),console.log(`${r} logs overflow, keeping last 10 items`)),this._failedLogsCache.set(xD,g),console.log(`${r} count: ${g.length}`),this._pendingReports=[]}_reset(){const{helper:n}=this._core;n.taskScheduler.removeTask(Xm)}_dispose(){const{notificationCenter:n,InnerEvent:{QUALITY_STAT:r,LOGOUT:g,DESTROY:u}}=this._core;n.unSubscribeInnerEvent(r,this._handleQualityStat,this),n.unSubscribeInnerEvent(g,this._reset,this),n.unSubscribeInnerEvent(u,this._dispose,this),this._reset(),XQ.dispose(),ZQ.dispose()}};const hl=new class{init(n){this.core=n}};function pR(n){return mA(this,void 0,void 0,function*(){var r;const{message:g,user:u,appStore:E,constants:{OuterConstant:m}}=hl.core,D=E.conversationStore.getConversationMap();if(D.has(n)){const T=(r=D.get(n))===null||r===void 0?void 0:r.userProfile;if(T&&n.startsWith(m.CONV_C2C)){const{avatar:P,nick:W}=T;hl.core.message.messageDataHandler.updateNickAndAvatarOfSentMessage({conversationID:n,latestAvatar:P,latestNick:W,isSentByMe:!1})}}const{data:v}=(yield u.userProfile.getMyProfile())||{};if(v){const{avatar:T,nick:P}=v;g.messageDataHandler.updateNickAndAvatarOfSentMessage({conversationID:n,latestAvatar:T,latestNick:P,isSentByMe:!0})}})}function mR(n){return mA(this,void 0,void 0,function*(){const r=n.map(g=>g.revoker);try{const g=yield function(u){return mA(this,void 0,void 0,function*(){var E,m;const D=yield(E=hl.core.user.userProfile)===null||E===void 0?void 0:E.getUserProfile({userIDList:u});return D?.data?(m=D.data)===null||m===void 0?void 0:m.reduce((v,{userID:T,nick:P,avatar:W})=>(v[T]={nick:P||"",avatar:W||""},v),{}):null})}(r);g&&n.forEach(u=>{const{revoker:E}=u;g[E]&&(u.revokerInfo.nick=g[E].nick||"",u.revokerInfo.avatar=g[E].avatar||"",u.revokerInfo.userID=E)})}catch(g){console.debug(g)}})}const JD=1,fR=2,wh=20,$Q=2500,yR=1,_h=300;function Ap(n){return mA(this,void 0,void 0,function*(){var r,g;const{appStore:u,utils:{isEmpty:E},common:{getCurrentUserID:m},notificationCenter:D,OuterEvent:v,OuterConstant:{CONV_C2C:T}}=hl.core,{messageList:P,conversationID:W}=n,oA=u.conversationStore.getConversationMap();let EA=(r=oA.get(W))===null||r===void 0?void 0:r.peerReadTime;if(!EA){const kA=W.replace(T,""),xA=yield function(LA){return mA(this,void 0,void 0,function*(){const SA={To_Account:LA};return hl.core.common.buildAndSendPacket({servcmd:"openim.get_peer_read_time",data:SA})})}([kA]);if(xA){const{ReadTime:LA}=xA;EA=LA?.[0],oA.has(W)&&(oA.get(W).peerReadTime=EA)}}if(oA.has(W)){const kA=(g=oA.get(W))===null||g===void 0?void 0:g.lastMessage;E(kA)||kA.fromAccount===m()&&kA.lastTime<=EA&&!kA.isPeerRead&&(kA.isPeerRead=!0,u.conversationStore.updateConversation(W,{lastMessage:kA}))}const wA=[];P.forEach(kA=>{kA.time<=EA&&!kA.isPeerRead&&kA.flow==="out"&&(kA.isPeerRead=!0,wA.push(kA))}),wA.length>0&&D.emitOuterEvent(v.MESSAGE_READ_BY_PEER,{name:v.MESSAGE_READ_BY_PEER,data:wA})})}var DR=new class{init(n){this._core=n,n.helper.registerApi({apiName:"getMessageList",context:this}),n.helper.registerApi({apiName:"getMessageListHopping",context:this}),n.helper.registerApi({apiName:"clearHistoryMessage",context:this})}getMessageList(n){return mA(this,void 0,void 0,function*(){try{const{message:r,OuterConstant:{Direction:g,CONV_C2C:u,CONV_GROUP:E},InnerEvent:{HISTORY_MESSAGE_FETCHED:m},notificationCenter:D}=this._core,{conversationID:v,nextReqMessageID:T}=n,P=wh;if(v==="@TIM#SYSTEM")return{code:0,data:{messageList:[],isCompleted:!1,nextMessageSeq:""}};const W=this._getAvailableLocalMessagesCount({conversationID:v,nextReqMessageID:T});if(this._needFetchHistoryMessageList({conversationID:v,availableLocalMessagesCount:W,targetCount:P})){let oA=null;if(v.startsWith(E)?oA=yield r.messageHistory.getGroupRoamingMessagesByAnchor({conversationID:v,sequence:Number(T),count:P,direction:g.FORWARD,shouldMarkCompleted:!0}):v.startsWith(u)&&(oA=yield r.messageHistory.getC2CRoamingMessagesByAnchor({conversationID:v,messageID:T,count:P,direction:g.FORWARD,shouldMarkCompleted:!0})),oA){const{nextReqMessageIDFromServer:EA,hasNoMoreHistoryMessage:wA,messageList:kA}=oA,xA=r.messageDataHandler.prependLocalMessageList({messageList:kA,conversationID:v});(function(ue){const{appStore:le,message:ki,OuterConstant:Li}=hl.core,Yt=le.conversationStore.getConversation(ue),Fi=ki.messageDataHandler.getLocalMessageList(ue);if(!Yt||Fi.length===0||ue===Li.CONV_SYSTEM)return;const hs=[];for(let Mt=0;MtUA.isRevoked).length;Re=hs.length-Yt.unreadCount-Mt}else Re=hs.length-Yt.unreadCount;for(let Mt=0;Mtue.isRevoked);yield mR(SA),D.emitInnerEvent(m,xA);const OA={nextReqMessageID:wA?"":String(EA),messageList:LA,isCompleted:wA},WA=LA.map(ue=>ue.sequence);return{code:0,data:OA,successLog:{message:`conversationID: ${v} nextReqMessageID: ${T} availableLocalMessagesCount: ${W} sequenceList: ${JSON.stringify(WA)}`}}}return{code:0,data:{messageList:[],isCompleted:!1,nextReqMessageID:""}}}return{code:0,data:yield this._getMessageListFromMemory({conversationID:v,nextReqMessageID:T,count:P}),successLog:{message:`conversationID: ${v} nextReqMessageID: ${T} availableLocalMessagesCount: ${W}}`}}}catch(r){const{code:g,message:u}=r||{};throw new this._core.helper.ChatError({code:g,message:u,moreMessage:`options: ${this._core.utils.safeStringify(n)}`})}})}getMessageListHopping(n){return mA(this,void 0,void 0,function*(){var r,g;const{OuterConstant:{Direction:u,CONV_C2C:E,CONV_GROUP:m},utils:{safeStringify:D}}=this._core,{conversationID:v,sequence:T,time:P,direction:W=u.FORWARD}=n,{utils:{isEmpty:oA},message:EA,notificationCenter:wA,InnerEvent:{HISTORY_MESSAGE_FETCHED:kA}}=this._core;if(![u.BACKWARD,u.FORWARD].includes(W))throw new this._core.helper.ChatError({message:"direction must be 0 or 1",moreMessage:`options: ${D(n)}`});let{count:xA=wh}=n;xA=xA>wh?wh:xA;let LA=null;if(v.startsWith(m)){if(LA=yield EA.messageHistory.getGroupRoamingMessagesByAnchor({conversationID:v,sequence:T,count:xA,direction:W}),LA){const{nextReqMessageIDFromServer:SA,hasNoMoreHistoryMessage:OA,messageList:WA,invisibleSequenceList:ue}=LA;if(this._core.message.messageDataHandler.storeSparseMessageList(WA),wA.emitInnerEvent(kA,WA),W===u.FORWARD){const le=OA&&SA<1;return{code:0,data:{messageList:WA,isCompleted:le,nextMessageSeq:le?"":SA}}}if(W===u.BACKWARD){if(oA(WA)&&oA(ue))return{code:0,data:{messageList:[],isCompleted:!0,nextMessageSeq:""}};const le=((r=WA?.[WA.length-1])===null||r===void 0?void 0:r.sequence)||0,ki=((g=ue?.[ue.length-1])===null||g===void 0?void 0:g.sequence)||0;return{code:0,data:{messageList:WA.filter(Li=>Li.sequence>=T),isCompleted:!OA,nextMessageSeq:OA?Math.max(le,ki)+1:""}}}return{code:0,data:LA}}}else if(v.startsWith(E)&&(LA=yield EA.messageHistory.getC2CRoamingMessagesByAnchor({conversationID:v,count:xA+1,time:P,direction:W}),LA)){const{messageList:SA,lastMessageTime:OA,hasNoMoreHistoryMessage:WA}=LA;return wA.emitInnerEvent(kA,SA),WA||(W===u.FORWARD?SA.shift():SA.pop()),EA.messageDataHandler.storeSparseMessageList(SA),yield Ap({messageList:SA,conversationID:v}),{code:0,data:{messageList:SA,isCompleted:WA,nextMessageTime:WA?"":OA}}}})}clearHistoryMessage(n){return mA(this,void 0,void 0,function*(){var r;const{appStore:g,common:{ChatError:u,getCurrentUserID:E},OuterConstant:{CONV_C2C:m,CONV_GROUP:D},apiMap:v,message:T}=this._core,P=g.conversationStore.getConversation(n);if(!P)throw new u({code:$Q});const W={fromAccount:E()},{type:oA}=P;oA===m?(W.type=JD,W.toAccount=n.replace(m,"")):oA===D&&(W.type=fR,W.toGroupID=n.replace(D,""));try{return yield(r=v?.setMessageRead)===null||r===void 0?void 0:r.call(v,{conversationID:n}),(yield function(wA){return mA(this,void 0,void 0,function*(){const{fromAccount:kA,type:xA,toAccount:LA,toGroupID:SA}=wA,OA={From_Account:kA,Type:xA,To_Account:LA,ToGroupid:SA};return hl.core.common.buildAndSendPacket({servcmd:"recentcontact.clear_msg",data:OA})})}(W))&&(T.messageDataHandler.deleteConversationMessageList(n),T.messageHistory.completedHistoryConversations.delete(n),T.messageHistory.clearHistoryMessageListFetchAnchors(n),this._updateConversationLastMessage(n)),{code:0,data:{conversationID:n},successLog:{message:`convID:${n}`}}}catch(EA){const{errorCode:wA}=EA;throw new this._core.helper.ChatError({functionName:"clearHistoryMessage",code:wA,moreMessage:`convID:${n}`})}})}_updateConversationLastMessage(n){const{appStore:r}=this._core;r.conversationStore.updateConversation(n,{lastMessage:this._generateLastMessage()},{needSort:!0})}_getAvailableLocalMessagesCount({conversationID:n,nextReqMessageID:r}){const{OuterConstant:{CONV_C2C:g,CONV_GROUP:u}}=this._core,E=this._core.message.messageDataHandler.getLocalMessageList(n),{length:m}=E;if(!r)return m;let D=-1;return n?.startsWith(g)?D=E.findIndex(v=>v.ID===r):n?.startsWith(u)&&(D=E.findIndex(v=>r.includes("-")?v.ID===r:String(v.sequence)===r)),D===-1?0:D}_needFetchHistoryMessageList({conversationID:n,availableLocalMessagesCount:r,targetCount:g}){const{message:u}=this._core;return rr.startsWith(E)?EA.ID===g:String(EA.sequence)===g),W=oA>u?oA-u:0,T=oA):W=v>u?v-u:0,P.messageList=D.slice(W,oA),P.isCompleted=T<=u&&m.messageHistory.completedHistoryConversations.has(r),P.isCompleted?P.nextReqMessageID="":P.nextReqMessageID=this._generateNextReqMessageID({conversationID:r,targetIndex:W}),r.startsWith(E)&&(yield pR(r),yield Ap({messageList:P.messageList,conversationID:r})),P})}_generateNextReqMessageID({conversationID:n,targetIndex:r}){const g=this._core.message.messageDataHandler.getLocalMessageList(n);return n.startsWith("C2C")?g[r].ID:String(g[r].sequence)}_generateLastMessage(){return{lastTime:0,lastSequence:0,fromAccount:"",messageForShow:"",payload:null,type:"",isRevoked:!1,cloudCustomData:"",onlineOnlyFlag:!1,nick:"",nameCard:"",version:0,isPeerRead:!1,revoker:null}}},SB=new class{constructor(){this._lastMessageSequenceMapOnDisconnect=new Map,this._lastMessageTimeMapOnDisconnect=new Map}init(n){this._core=n;const{common:{workflowManager:r},constants:{WORKFLOW_NAME:g,WORKFLOW_STEP:u,InnerEvent:E}}=n;r.registerWorkflowStep(g.SYNC_SERVER_INFO_AFTER_RE_ONLINE,u.HISTORY_MESSAGE_RECOVER,this._syncGroupOfflineMessage,this),r.registerWorkflowStep(g.SYNC_SERVER_INFO_AFTER_RE_ONLINE,u.C2C_HISTORY_MESSAGE_RECOVER,this._syncC2COfflineMessage,this),n.notificationCenter.subscribeInnerEvent(E.SOCKET_DISCONNECTED,this._updateLastMessageSequenceMapOnDisconnect,this)}_syncGroupOfflineMessage(n){const{conversationList:r}=n?.result||{},{OuterConstant:g,utils:{isArray:u}}=this._core;if(u(r)){const E=r.filter(m=>m.type===g.CONV_GROUP&&m.groupProfile.type!==g.GRP_AVCHATROOM);return this._recoverGroupHistoryMessage(E)}}_recoverGroupHistoryMessage(n){return mA(this,void 0,void 0,function*(){const{OuterConstant:r}=this._core,g=[],u=[];return yield Promise.all(n?.map(E=>mA(this,void 0,void 0,function*(){const{groupProfile:{groupID:m}={},lastMessage:{lastSequence:D}={}}=E,v=`${r.CONV_GROUP}${m}`;let T=this._getLocalLastMessageSequence(v);this._shouldRecoverHistory({localLastMessageSequence:T,serverLastMessageSequence:D})&&(yield this._recoverGroupHistoryForConversation({conversationID:v,localLastMessageSequence:T,serverLastMessageSequence:D,groupTipList:u})),g.push(v.replace(r.CONV_GROUP,""))}))),{recoverRevokeNoticeGroupIDList:g,groupTipList:u}})}_recoverGroupHistoryForConversation(n){return mA(this,arguments,void 0,function*({conversationID:r,localLastMessageSequence:g,serverLastMessageSequence:u,groupTipList:E}){try{const{utils:{isArray:m,isObject:D,isEmpty:v},OuterEvent:T,OuterConstant:P,notificationCenter:W,message:oA,appStore:EA,common:{getMessagePreviewText:wA,buildLastMessage:kA}}=this._core,xA=u-g,LA=Math.min(20,xA),SA={},OA=yield oA.messageHistory.getGroupRoamingMessagesByAnchor({conversationID:r,sequence:g+LA,direction:P.Direction.FORWARD,count:LA}),{nextReqMessageIDFromServer:WA,hasNoMoreHistoryMessage:ue,messageList:le,serverGroupTipList:ki}=OA;m(ki)&&E.push(...ki);const Li=ue&&WA<0,Yt=[];if(m(le)&&(le.forEach(Fi=>{oA.messageReceiver.groupMessageReceiver.updateMessageProfile(Fi),Fi.from===P.CONV_SYSTEM&&(Fi.isSystemMessage=!1),oA.messageDataHandler.storeConversationMessage(Fi)&&!v(Fi.payload)&&(Yt.push(Fi),Fi._isExcludedFromLastMessage||(SA.lastMessage=kA(Fi)))}),Yt.length>0&&W.emitOuterEvent(T.MESSAGE_RECEIVED,{name:T.MESSAGE_RECEIVED,data:Yt})),!Li&&le.length>0){const Fi=le[le.length-1].sequence;yield this._recoverGroupHistoryForConversation({conversationID:r,localLastMessageSequence:Fi,serverLastMessageSequence:u,groupTipList:E})}D(SA.lastMessage)&&(SA.lastMessage.messageForShow=wA(SA.lastMessage.type,SA.lastMessage.payload),EA.conversationStore.updateConversation(r,SA))}catch(m){this._core.ssoLog.error("_recoverGroupHistoryForConversation",`Recovery failed for conversation:${r}`,{error:m})}})}_updateLastMessageSequenceMapOnDisconnect(){const{message:n}=this._core,r=n.messageDataHandler.getContinuousMessagesByConversation();for(const[g,u]of r){const E=Array.from(u.values());if(E?.length>0){const m=E[E.length-1];g.startsWith("C2C")?this._lastMessageTimeMapOnDisconnect.set(g,m.time):g.startsWith("GROUP")&&this._lastMessageSequenceMapOnDisconnect.set(g,m.sequence)}}}_getLocalLastMessageSequence(n){const{message:r}=this._core;if(this._lastMessageSequenceMapOnDisconnect.has(n))return this._lastMessageSequenceMapOnDisconnect.get(n);const g=r.messageDataHandler.getLocalMessageList(n),u=g[g.length-1];return u?.sequence}_shouldRecoverHistory(n){const{localLastMessageSequence:r,serverLastMessageSequence:g}=n;if(typeof r!="number"||typeof g!="number")return!1;const u=g-r;return g!==0&&r>0&&u>=yR&&u<_h}_syncC2COfflineMessage(n){const{conversationList:r}=n?.result||{},{OuterConstant:g,utils:{isArray:u}}=this._core;if(u(r)){const E=[];return r.forEach(m=>{m.type===g.CONV_C2C&&E.push(m)}),this._recoverC2CHistoryMessage(E)}}_recoverC2CHistoryMessage(n){return mA(this,void 0,void 0,function*(){yield Promise.all(n?.map(r=>mA(this,void 0,void 0,function*(){const{conversationID:g,lastMessage:{lastTime:u}={}}=r,E=this._getLocalLastMessageTime(g);this._shouldRecoverC2CHistory({localLastMessageTime:E,serverLastMessageTime:u})&&(yield this._recoverHistoryForC2CConversation({conversationID:g,localLastMessageTime:E,serverLastMessageTime:u}))})))})}_shouldRecoverC2CHistory(n){const{localLastMessageTime:r,serverLastMessageTime:g}=n,u=g-r;return r>0&&u>=1&&u<=600}_recoverHistoryForC2CConversation(n){return mA(this,void 0,void 0,function*(){var r;const{conversationID:g,localLastMessageTime:u,serverLastMessageTime:E}=n,{utils:{isArray:m,isObject:D,isEmpty:v,safeStringify:T},OuterEvent:P,OuterConstant:W,notificationCenter:oA,message:EA,appStore:wA,common:{getMessagePreviewText:kA,buildLastMessage:xA}}=this._core;try{const LA={},SA=yield EA.messageHistory.getC2CRoamingMessagesByAnchor({conversationID:g,direction:W.Direction.BACKWARD,time:u,count:20});if(v(SA))return;const{hasNoMoreHistoryMessage:OA,messageList:WA}=SA,ue=[];m(WA)&&(WA.forEach(ki=>{EA.messageDataHandler.storeConversationMessage(ki)&&!v(ki.payload)&&(ue.push(ki),ki._isExcludedFromLastMessage||(LA.lastMessage=xA(ki)))}),ue.length>0&&oA.emitOuterEvent(P.MESSAGE_RECEIVED,{name:P.MESSAGE_RECEIVED,data:ue}));const le=(r=WA[WA.length-1])===null||r===void 0?void 0:r.time;!OA&&le>E&&(yield this._recoverHistoryForC2CConversation({conversationID:g,localLastMessageTime:le,serverLastMessageTime:E})),D(LA.lastMessage)&&(LA.lastMessage.messageForShow=kA(LA.lastMessage.type,LA.lastMessage.payload),wA.conversationStore.updateConversation(g,LA))}catch(LA){this._core.ssoLog.error("_recoverHistoryForC2CConversation",`Recovery failed for conversation:${g} error: ${T(LA)}`)}})}_getLocalLastMessageTime(n){const{message:r}=this._core;if(this._lastMessageTimeMapOnDisconnect.has(n))return this._lastMessageTimeMapOnDisconnect.get(n);const g=r.messageDataHandler.getLocalMessageList(n),u=g[g.length-1];return u?.time}reset(){this._lastMessageSequenceMapOnDisconnect.clear(),this._lastMessageTimeMapOnDisconnect.clear()}dispose(){this.reset()}},vB=new class{constructor(){this.name="HistoryMessage"}install(n){this._core=n,hl.init(n),DR.init(n),SB.init(n),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.LOGOUT,this._reset,this),n.notificationCenter.subscribeInnerEvent(n.InnerEvent.DESTROY,this.dispose,this)}dispose(){const{notificationCenter:n,InnerEvent:r}=this._core;n.unSubscribeInnerEvent(r.LOGOUT,this._reset,this),n.unSubscribeInnerEvent(r.DESTROY,this.dispose,this),SB.dispose()}_reset(){SB.reset()}},HD=new class{init(n){this.core=n}},_C=new class{constructor(){this._reportedAtomicStoreIDs=new Set}init(n){const{helper:{registerExperimentalAPI:r}}=n;this._core=n,r("reportModalView",this),r("reportTUIFeatureUsage",this),r("reportRoomEngineEvent",this)}reportModalView(n){const{ssoLog:r,utils:{safeStringify:g,isString:u}}=this._core;try{if(!u(n))throw new Error("reportModalView data is not a string");r.createSSOLogData({method:"reportModalView",message:n,eventType:30}).end(!0)}catch(E){r.debug(`reportModalView Report failed: ${g(E)}`)}}reportTUIFeatureUsage(n){const{ssoLog:r,utils:{safeStringify:g,isEmpty:u}}=this._core,{atomicStoreID:E}=n;try{u(E)||this._reportedAtomicStoreIDs.has(E)||(this._core.ssoLog.info("reportTUIFeatureUsage",`atomicStoreID: ${n.atomicStoreID}`,{method:"reportTUIFeatureUsage",eventType:31,code:E}),this._reportedAtomicStoreIDs.add(E))}catch(m){r.debug(`reportTUIFeatureUsage Report failed: ${g(m)}`)}}reportRoomEngineEvent(n){const{utils:{safeStringify:r},ssoLog:g}=this._core;try{g.debug(`reportRoomEngineEvent Report: ${r(n)}`);const{eventId:u,eventCode:E,eventResult:m,eventMessage:D,moreMessage:v,extensionMessage:T}=n;g.createSSOLogData({method:T,code:u,message:D,eventType:30,costTime:E,uiPlatform:m,moreMessage:v}).end(!0)}catch(u){g.debug(`reportRoomEngineEvent Report failed: ${r(u)}`)}}reset(){this._reportedAtomicStoreIDs.clear()}dispose(){this.reset()}},ep=new class{constructor(){this.name="DataReport"}install(n){this._core=n;const{notificationCenter:r,InnerEvent:{LOGOUT:g,DESTROY:u}}=n;HD.init(n),_C.init(n),r.subscribeInnerEvent(g,this._reset,this),r.subscribeInnerEvent(u,this._dispose,this)}_reset(){_C.reset()}_dispose(){const{notificationCenter:n,InnerEvent:{LOGOUT:r,DESTROY:g}}=this._core;n.unSubscribeInnerEvent(r,this._reset,this),n.unSubscribeInnerEvent(g,this._dispose,this),_C.dispose()}};let $m=dr.STANDARD,MB=[];$m=dr.STANDARD,MB=[lh,dC,CC,hC,bc,tN,vB,ep,PE,Ti,er,jT,qm,PD,tu];function RB(n,r){const{operationType:g,memberInfoList:u,operatorInfo:E}=n||{};let m={};if(ts(u)?ts(E)||(m=E):g!==Gg.JOINED&&g!==Gg.KICKED&&g!==Gg.ADMIN_SET&&g!==Gg.ADMIN_CANCELED||(m=Object.assign({},u[0])),!ts(m)){const{nick:D="",avatar:v=""}=m;r.nick=D,r.avatar=v}}const tp=n=>({lastTime:n?.time||n?.lastTime||0,lastSequence:n?.sequence||n?.lastSequence||0,fromAccount:n?.from||n?.fromAccount||"",messageForShow:il(n?.type,n?.payload),payload:n?.payload||null,type:n?.type||"",isRevoked:n?.isRevoked||!1,cloudCustomData:n?.cloudCustomData||"",onlineOnlyFlag:n?._onlineOnlyFlag||!1,nick:n?.nick||"",nameCard:n?.nameCard||"",version:n?.version||0,isPeerRead:n?.isPeerRead||!1,revoker:n?.revoker||null});var ip=Object.freeze({__proto__:null,ChatError:Cs,WorkflowManager:Fs,buildAndSendPacket:lg,buildLastMessage:tp,get builtInPlugins(){return MB},checkBusinessCapabilityBits:In,deepMerge:hd,getCurrentUserID:ar,getErrorMessage:Es,getMessagePreviewText:il,isC2CConv:n=>c(n)&&n.slice(0,3)===Oa.CONV_C2C,isCommunity:ea,isGroupConv:n=>c(n)&&n.slice(0,5)===Oa.CONV_GROUP,isInternational:bl,isTopic:tl,isUnlimitedAVChatRoom:function(){var n;return!!(!((n=De.store.get("instance"))===null||n===void 0)&&n.unlimitedAVChatRoom)},liteChatInstanceMap:ma,registerInterceptor:Nc,registerValidateConfig:el,requireAuth:Ed,get sdkEdition(){return $m},setGroupTipsUserInfo:RB,t:Uu,updateGroupAtInfo:(n,r)=>{const{CONV_AT_ME:g,CONV_AT_ALL:u,CONV_AT_ALL_AT_ME:E}=Po;if(function(v,T){const{CONV_AT_ME:P,CONV_AT_ALL:W,CONV_AT_ALL_AT_ME:oA}=Po,{groupID:EA,sequence:wA}=v;let kA=!1;return ea({groupID:EA})&&T.forEach(xA=>{xA.messageSequence===wA&&(xA.atTypeArray.includes(P)&&v.groupAtType.includes(W)&&(xA.atTypeArray=[oA]),xA.atTypeArray.includes(W)&&v.groupAtType.includes(P)&&(xA.atTypeArray=[oA],xA.__random=v.__random,xA.__sequence=v.__sequence),kA=!0)}),kA}(n,r))return;let m=[...n.groupAtType];m.includes(g)&&m.includes(u)&&(m=[E]);const D={from:n.from,groupID:n.groupID,topicID:n.topicID,messageSequence:n.sequence,atTypeArray:m,__random:n.__random,__sequence:n.__sequence};r.push(D)},validateAndExecute:wr,validateParameters:hI});class Iu{constructor(){this._builtInPlugins=new Set,this._externalPlugins=new Set}static getInstance(){return Iu._instance||(Iu._instance=new Iu),Iu._instance}static setInstance(r){Iu._instance=r}installBuiltInPlugin(r){r&&this._installPlugin(r,this._builtInPlugins)}installExternalPlugin(r){r&&this._installPlugin(r,this._externalPlugins)}clear(){this._builtInPlugins=new Set,this._externalPlugins=new Set}_installPlugin(r,g){let u=[];u=C(r)?r:[r];const E=u.findIndex(D=>D?.name==="AVChatRoom"),m=E>-1?u.splice(E,1):[];u.forEach(D=>{this._isPluginInstalled(D.name)||(D&&wg(D.install)?(g.add(D.name),wg(D.getInstalledSubPlugins)?(m?.forEach(v=>g.add(v?.name)),D.install(Sr.getInstance().exposeApiForPlugin(),m)):D.install(Sr.getInstance().exposeApiForPlugin()),wg(D.handleLoginSuccess)&&this._isLoggedIn()&&D.handleLoginSuccess()):wg(D)?(g.add(D.name),D(Sr.getInstance().exposeApiForPlugin()),wg(D.handleLoginSuccess)&&this._isLoggedIn()&&D.handleLoginSuccess()):console.warn('A plugin must either be a function or an object with an "install" function.'))})}_isPluginInstalled(r){return this._builtInPlugins.has(r)||this._externalPlugins.has(r)}_isLoggedIn(){var r;return((r=De.store.get("login"))===null||r===void 0?void 0:r.isLoggedIn)===!0}}var wB=new class{constructor(){this._conversationMap=new Map}getConversationMap(){return this._conversationMap}getConversation(n){return this._conversationMap.get(n)}updateConversation(n,r,g){const{emit:u=!0,needSort:E=!1}=g||{},m=this._conversationMap.get(n);m&&!ts(r)&&(Object.keys(r).forEach(D=>{m[D]=r[D]}),u&&De.notificationCenter.emitInnerEvent(lo.CONVERSATION_UPDATED,{needSort:E}))}deleteConversation(n){this._conversationMap.has(n)&&(this._conversationMap.delete(n),De.notificationCenter.emitInnerEvent(lo.CONVERSATION_UPDATED))}},op=new class{constructor(){this._groupMap=new Map}getGroupMap(){return this._groupMap}getGroup(n){return this._groupMap.get(n)}updateGroup(n,r){const g=this._groupMap.get(n);g&&!ts(r)&&Object.keys(r).forEach(u=>{g[u]=r[u]})}},sp=new class{constructor(){this._messagesByConversation=new Map}updateMessage(n,r,g){var u;const{operation:E,updateUnreadCount:m=!0}=g,D=vo(g,["operation","updateUnreadCount"]),v=[];for(const T of r){const P=(u=this._messagesByConversation.get(n))===null||u===void 0?void 0:u.get(T);if(!P)return!1;Object.keys(D).forEach(W=>{P[W]=D[W]}),v.push(P)}return this._emitMessageStoreOperationEvent(E,{conversationID:n,messageList:v,updateUnreadCount:m}),v}getMessagesByConversation(n){var r;return[...((r=this._messagesByConversation.get(n))===null||r===void 0?void 0:r.values())||[]]}getMessages(){return this._messagesByConversation}_emitMessageStoreOperationEvent(n,r){const{conversationID:g}=r;tl(g)?De.notificationCenter.emitInnerEvent(Nu[n],r):De.notificationCenter.emitInnerEvent(n,r)}},lc=new class{constructor(){this.userProfileMap=new Map,this.friendMap=new Map}getUserProfileMap(){return this.userProfileMap}getFriendMap(){return this.friendMap}getUserProfile(n){return this.userProfileMap.get(n)}getFriend(n){return this.friendMap.get(n)}},qD=Object.freeze({__proto__:null,conversationStore:wB,groupStore:op,messageStore:sp,userStore:lc});class Sr{static getInstance(){return Sr._instance||(Sr._instance=new Sr),Sr._instance}static setInstance(r){Sr._instance=r}constructor(){this._experimentalApiMap={statTUIKeyFeatures:this.statKeyFeatureUsage.bind(this),setApplicationID:this.setApplicationID.bind(this)},this._apiHandlersMap={},this._apiMap={on:De.notificationCenter.subscribeOuterEvent.bind(De.notificationCenter),off:De.notificationCenter.unSubscribeOuterEvent.bind(De.notificationCenter),destroy:this.destroy.bind(this),callExperimentalAPI:this.callExperimentalAPI.bind(this),use:Iu.getInstance().installExternalPlugin.bind(Iu.getInstance()),registerPlugin:this.registerPlugin.bind(this),setLogLevel:this.setLogLevel.bind(this)}}registerPlugin(r){De.ssoLog.debug("registerPlugin",r)}statKeyFeatureUsage(r){De.ssoLog.debug("statTUIKeyFeatures",r)}setLogLevel(r){De.ssoLog.debug("setLogLevel",r),De.ssoLog.setLogLevel(r)}setApplicationID(r){De.store.set("instance",{applicationID:r})}getApiMap(){return this._apiMap}setApiMap(r){this._apiMap=r}registerApi(r){const{common:{timeManager:g},utils:{safeStringify:u}}=De,{apiName:E,context:m,methodName:D=E,matcher:v}=r;this._apiHandlersMap[E]||(this._apiHandlersMap[E]=[]),this._apiHandlersMap[E].push({context:m,methodName:D,matcher:v}),this._apiMap[E]&&this._apiHandlersMap[E].length!==1||(this._apiMap[E]=(...T)=>{const P=g.getServerTimeMs();let W=0;E==="login"&&(W=4),zI.includes(E)&&De.ssoLog.debug(E,`${E} start params: ${u(T)}`),wr(D,T);const oA=this._apiHandlersMap[E];for(const EA of oA)if(!EA.matcher||EA.matcher(T))try{const wA=EA.context[EA.methodName].bind(EA.context)(...T);return this._isPromiseLike(wA)?this._handleAsyncResult(wA,E,W,P):(this._reportApiSuccessLog({result:wA,apiName:E,eventType:W,startTime:P}),wA)}catch(wA){throw De.ssoLog.error(E,`${E} fail ${wA?.message||wA?.errorMessage})`,{error:wA,costTime:g.getServerTimeMs()-P,eventType:W,method:E}),wA}})}registerExperimentalAPI(r,g,u){const E=u||r;this._experimentalApiMap[r]=g[E].bind(g)}destroy(){return mA(this,void 0,void 0,function*(){var r,g;try{!((r=De.store.get("login"))===null||r===void 0)&&r.isLogin&&(yield this._apiMap.logout()),De.notificationCenter.emitInnerEvent(lo.DESTROY)}catch(u){console.debug("destroy error: ",u)}finally{De.notificationCenter.emitOuterEvent(Rr.SDK_DESTROY,{SDKAppID:(g=De.store.get("instance"))===null||g===void 0?void 0:g.sdkAppId}),ma.clear(),Iu.getInstance().clear(),Fs.getInstance().destroy(),De.destroy()}})}exposeApiForClient(){return this._apiMap}exposeApiForPlugin(){return Object.assign(Object.assign({InnerEvent:lo,InnerEventSubType:De.notificationCenter.InnerEventSubType,OuterEvent:Rr,OuterConstant:Po,SignalingEvent:Xc,helper:Object.assign(Object.assign(Object.assign({},De.utils),De.common),{registerApi:this.registerApi.bind(this),registerExperimentalAPI:this.registerExperimentalAPI.bind(this),registerInterceptor:Nc,registerValidateConfig:el,checkBusinessCapabilityBits:In,registerWorkflowStep:Fs.getInstance().registerWorkflowStep.bind(Fs.getInstance()),ChatError:Cs}),apiMap:this._apiMap},De),{constants:Object.assign(Object.assign({},$a),De.constants),common:Object.assign(Object.assign(Object.assign({},ip),De.common),{workflowManager:Fs.getInstance()}),utils:De.utils,appStore:qD})}callExperimentalAPI(r,g){return De.ssoLog.debug(`callExperimentalAPI.${r} start params: ${De.utils.safeStringify(g)}`),this._experimentalApiMap[r]?this._experimentalApiMap[r](g):(De.ssoLog.error("callExperimentalAPI",`callExperimentalAPI.${r} not found, params: ${De.utils.safeStringify(g)}`),Promise.reject(new Cs({code:pa.INVALID_OPERATION})))}_isPromiseLike(r){return r!==null&&typeof r=="object"&&typeof r.then=="function"}_handleAsyncResult(r,g,u,E){return r.then(m=>(this._reportApiSuccessLog({result:m,apiName:g,eventType:u,startTime:E}),m)).catch(m=>{throw De.ssoLog.error(g,`${g} fail ${m?.message||m?.errorMessage})`,{error:m,costTime:De.common.timeManager.getServerTimeMs()-E,eventType:u,method:g,startTime:E}),m})}_reportApiSuccessLog(r){let{result:g,apiName:u,startTime:E,eventType:m}=r;const{timeManager:D}=De.common,{successLog:{message:v,moreMessage:T}={message:"",moreMessage:""}}=g||{},P=D.getServerTimeMs();u==="login"&&(E+=D.getTimeOffsetWithServer()),zI.includes(u)&&De.ssoLog.info(u,`${u} success ${v} ${T}`,{costTime:P-E,eventType:m,message:v,moreMessage:T,startTime:E}),g?.successLog&&delete g.successLog}}class SR{constructor(){this._latestLoginAt=0,this._latestSendOnlinePresenceRequestTime=0,this._helloInterval=120,this._customLoginInfo=""}init(){const{notificationCenter:r,store:g}=De;g.set("login",{isReady:!1}),Sr.getInstance().registerApi({apiName:"login",context:this}),Sr.getInstance().registerApi({apiName:"logout",context:this}),Sr.getInstance().registerApi({apiName:"getLoginUser",context:this}),Sr.getInstance().registerApi({apiName:"isReady",context:this}),Sr.getInstance().registerApi({apiName:"getServerTime",context:this}),Sr.getInstance().registerExperimentalAPI("setCustomLoginInfo",this),r.subscribeInnerEvent(lo.RECONNECTED,this._reLogin,this),De.notificationCenter.subscribeInnerEvent(lo.DESTROY,this._dispose,this)}login(r){return mA(this,void 0,void 0,function*(){var g;const{sdkEdition:u}=De.store.get("instance")||{};try{if(this._isLoginIn())return this._createRepeatLoginResponse();if(this._isLoginFrequencyExceeded())throw new Cs({functionName:"login",code:pa.REPEAT_LOGIN});const E=yield this._performLogin(r);this._validateAfterLogin(E),this._handleLoginSuccess(E),yield this._ensureAsyncComplete(),this._updateAndEmitSDKReady(),this._latestLoginAt=0;const m=(g=De.channel.getSocketAdapter())===null||g===void 0?void 0:g.getId(),{appId:D,href:v}=De.store.get("instance")||{},{instanceID:T,customStatus:P}=E||{};return{code:0,data:E,successLog:{message:u,moreMessage:`socketID:${m} instanceID:${T} customStatus:${P} href: ${v} appId: ${D}`}}}catch(E){const{errorCode:m}=E;m!==pa.REPEAT_LOGIN&&(this._latestLoginAt=0);const D=new Cs({functionName:"login",code:m});throw console.error(D),D}})}_reLogin(){return mA(this,void 0,void 0,function*(){var r;try{if(!this._isLoginIn())return;const g=yield Lu(this._customLoginInfo);if(g){const{instanceID:u,customStatus:E}=g;De.store.set("login",{statusInstanceId:u}),Fs.getInstance().executeWorkflow(jt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,{customStatus:E,statusType:SE.USER_STATUS_ONLINE});const m=(r=De.channel.getSocketAdapter())===null||r===void 0?void 0:r.getId();De.ssoLog.info("reLogin",`socketId:${m} instanceId:${u}`)}}catch(g){console.warn(g)}})}logout(){return mA(this,arguments,void 0,function*(r=ca.USER_INITIATED){const{ssoLog:g}=De;g.debug("logout",`logout start logoutReason: ${r}`);try{yield this._performLogout(r),g.info("logout","logout success"),De.ssoLog.uploadSSOLogData()}catch(u){const{errorCode:E}=u;throw new Cs({functionName:"logout",code:E})}finally{this.handleLogoutCompleted()}return{code:0,data:{}}})}getLoginUser(){return this._isLoginIn()?ar():""}isReady(){var r;return(r=De.store.get("login"))===null||r===void 0?void 0:r.isReady}setCustomLoginInfo(r=""){this._customLoginInfo=r}handleLogoutCompleted(){this._updateAndEmitSDKNotReady(),this._reset(),Fs.getInstance().reset(),De.notificationCenter.emitInnerEvent("logout")}getServerTime(){const{timeManager:r}=De.common;return r.getServerTimeMs()}_updateAndEmitSDKReady(){De.store.set("login",{isReady:!0}),setTimeout(()=>{De.notificationCenter.emitOuterEvent(Rr.SDK_READY,{name:Rr.SDK_READY})},1)}_updateAndEmitSDKNotReady(){De.store.set("login",{isReady:!1}),De.notificationCenter.emitOuterEvent(Rr.SDK_NOT_READY,{name:Rr.SDK_NOT_READY})}_validateAfterLogin(r){const g="login";if(!r)throw new Cs({functionName:g,message:"login response is empty"});const{tinyID:u,a2Key:E}=r||{};if(!u)throw new Cs({functionName:g,code:pa.NO_TINYID});if(!E)throw new Cs({functionName:g,code:pa.NO_A2KEY})}_createRepeatLoginResponse(){var r;return{code:0,data:{actionStatus:"OK",errorCode:0,errorInfo:Es({code:"RepeatLogin",replacement1:(r=De.store.get("login"))===null||r===void 0?void 0:r.userId}),repeatLogin:!0}}}_performLogin(r){return mA(this,void 0,void 0,function*(){const{userID:g,userSig:u}=r;return De.store.set("login",{userId:g,userSig:u}),this._latestLoginAt=Date.now(),Lu(this._customLoginInfo)})}_ensureAsyncComplete(){return mA(this,void 0,void 0,function*(){yield new Promise(r=>{setTimeout(()=>r(null),1)})})}_handleLoginSuccess(r){const{timeManager:g}=De.common,{helloInterval:u,timeStamp:E,customStatus:m,purchaseBits:D}=r,v=1e3*E;g.calculateTimeOffsetWithServer(this._latestLoginAt,v),this._helloInterval=u||120,this._updateLoginStore(r),De.user.userStatus.setCustomStatus(m),Fs.getInstance().executeWorkflow(jt.SYNC_SERVER_INFO_AFTER_LOGIN,{purchaseBits:D}),De.common.taskScheduler.addTask({id:kg,intervalMs:1e3*this._helloInterval,callback:this._sendOnlinePresenceRequest,context:this})}_performLogout(r){return function(g){return mA(this,void 0,void 0,function*(){const{logoutReason:u}=g,E="im_open_status.wslogout",m=De.common.generateProtocolData({servcmd:E,data:{wslogout_type:u,isWebUniapp:0}}),D=`${m.head.seq}${E}`;return yield De.channel.sendPacket(m,{requestId:D})})}({logoutReason:r})}_updateLoginStore(r){const{a2Key:g,tinyID:u,instanceID:E,authKey:m}=r;De.store.set("login",{a2Key:g,tinyID:u,statusInstanceId:E,authKey:m,isLoggedIn:!0})}_sendOnlinePresenceRequest(){return mA(this,void 0,void 0,function*(){this._latestSendOnlinePresenceRequestTime=Date.now();try{yield function(){const r="im_open_status.wshello",g=De.common.generateProtocolData({servcmd:r,data:{isWebUniapp:0}}),u=`${g.head.seq}${r}`;return De.channel.sendPacket(g,{requestId:u})}()}catch(r){De.ssoLog.warn("_sendOnlinePresenceRequest",` error:${r.message}`)}})}_isLoginIn(){var r;return((r=De.store.get("login"))===null||r===void 0?void 0:r.isLoggedIn)===!0}_isLoginFrequencyExceeded(){return Date.now()-this._latestLoginAt<=15e3}_reset(){De.common.taskScheduler.removeTask(kg),this._helloInterval=120,this._latestSendOnlinePresenceRequestTime=0,this._latestLoginAt=0,this._customLoginInfo="",De.store.clear("login"),De.store.set("login",{isReady:!1}),De.store.set("instance",{applicationID:0})}_dispose(){this._reset();const{notificationCenter:r}=De;r.unSubscribeInnerEvent(lo.RECONNECTED,this._reLogin,this),r.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this)}}const vR={login:{userID:{required:!0,rules:["string"],allowEmpty:!1},userSig:{required:!0,rules:["string"],allowEmpty:!1}}},iN={logout:!0};class Th{constructor(){this.loginAction=new SR,this.kickedOutHandler=new ku,this.loginAction.init(),this.kickedOutHandler.init(),el({auth:iN,params:vR})}}var Zr,eE,KE;(function(n){n.CONV_C2C="C2C",n.CONV_GROUP="GROUP",n.CONV_TOPIC="TOPIC",n.CONV_SYSTEM="@TIM#SYSTEM"})(Zr||(Zr={})),function(n){n.MSG_PRIORITY_HIGH="High",n.MSG_PRIORITY_NORMAL="Normal",n.MSG_PRIORITY_LOW="Low",n.MSG_PRIORITY_LOWEST="Lowest"}(eE||(eE={})),function(n){n.MSG_TEXT="TIMTextElem",n.MSG_CUSTOM="TIMCustomElem",n.MSG_LOCATION="TIMLocationElem",n.MSG_FACE="TIMFaceElem",n.MSG_IMAGE="TIMImageElem",n.MSG_AUDIO="TIMSoundElem",n.MSG_FILE="TIMFileElem",n.MSG_VIDEO="TIMVideoFileElem",n.MSG_GRP_TIP="TIMGroupTipElem",n.MSG_GRP_SYS_NOTICE="TIMGroupSystemNoticeElem",n.MSG_MERGER="TIMRelayElem"}(KE||(KE={}));const KD={1:eE.MSG_PRIORITY_HIGH,2:eE.MSG_PRIORITY_NORMAL,3:eE.MSG_PRIORITY_LOW,4:eE.MSG_PRIORITY_LOWEST},jD=0,MR=1;var tE;(function(n){n.IN="in",n.OUT="out"})(tE||(tE={}));const RR=2,np={};function uu(n){if(!n)return 0;if(np[n]===void 0){const r=new Date,g=`3${r.getHours()}`.slice(-2),u=`0${r.getMinutes()}`.slice(-2),E=`0${r.getSeconds()}`.slice(-2);np[n]=parseInt([g,u,E,"0001"].join(""),10),console.log(`autoIncrementIndex start index:${np[n]}`)}else np[n]+=1;return np[n]}class jE{constructor(r){this.ID="",this.random=0,this.sequence=0,this.nameCard="",this.isRead=!1,this.isPeerRead=!1,this.isDeleted=!1,this.isResend=!1,this.hasRiskContent=!1,this._onlineOnlyFlag=!1,this.atUserList=[],this._groupAtInfoList=[],this.isBroadcastMessage=!1,this.priority=eE.MSG_PRIORITY_NORMAL,this._relayFlag=!1;const{clientTime:g=De.common.timeManager.getServerTimeSeconds()||0,senderTinyID:u,currentUser:E,needReadReceipt:m,isSupportExtension:D,customModerationConfigurationId:v,to:T,from:P,nick:W="",avatar:oA="",time:EA,messageControlInfo:wA,tinyID:kA,cloudCustomData:xA="",messageLifeTime:LA,messageVersion:SA=0,conversationType:OA,sequence:WA,checkResult:ue=0,isPlaceMessage:le=0,messageFlagBits:ki,receiverList:Li,isSystemMessage:Yt=!1,status:Fi=qr.SUCCESS,revokeReason:hs="",conversationSubType:Re,clientSequence:Mt,protocol:UA="JSON",revokerInfo:ci={userID:"",nick:"",avatar:""},readReceiptInfo:Os={readCount:void 0,unreadCount:void 0,isPeerRead:void 0,timestamp:0},random:Oi,groupProfile:Yr,atUserList:ji,flow:Br,isRead:Ut=!1,priority:Ft=eE.MSG_PRIORITY_NORMAL,onlineOnlyFlag:oE=!1,nameCard:Cn="",quoteInfo:Do}=r;var Bl;this.clientTime=g,this.senderTinyID=u||kA,this.needReadReceipt=m===!0||m===1,this.isSupportExtension=D===!0||D===1,this._cmConfigID=v,this.to=T,this.nick=W,this.avatar=oA,this.protocol=UA,this.random=Oi===void 0?(Bl=Bl||99999999,Math.round(Math.random()*Bl)):Oi,this.time=EA||Math.ceil(Date.now()/1e3),this._isExcludedFromLastMessage=!!wA?.excludedFromLastMessage,this._isExcludedFromUnreadCount=!!wA?.excludedFromUnreadCount,this.isModified=!!SA,this.cloudCustomData=xA,this.messageLifeTime=LA,this.from=P||null,this.sequence=WA||0,this.conversationType=OA||Zr.CONV_C2C,this.hasRiskContent=ue>1,this.version=SA,this.isPlaceMessage=le,this.isRevoked=le===2||ki===8,this.isSystemMessage=Yt,this.readReceiptInfo=Os,this.revokeReason=hs,this.revokerInfo=ci,this._receiverList=Li,this.conversationSubType=Re,this.revoker=ci?.revoker||"",this.clientSequence=Mt||WA||0,this.status=Fi,this.atUserList=ji||[],this.flow=Br,this.isRead=Ut,this.priority=Ft,this._onlineOnlyFlag=oE,this.nameCard=Cn,this.quoteInfo=Do,this.reInitialize(E),this._initC2CReadReceiptInfo(r),this._extractGroupInfo(Yr)}getElements(){return this._elements}isOnlineMessage(){return this.messageLifeTime===0}setElement(r){Array.isArray(r)?this._elements=r:this._elements=[r],this._updatePayloadAndType()}transformElementsToServerFormat(){return this._elements?Array.isArray(this._elements)?this._elements.map(r=>r.transformToServerFormat()):this._elements.transformToServerFormat():null}setRelayFlag(r){this._relayFlag=r}validateBeforeSend(){var r,g,u;return this._relayFlag?{isValid:!0}:((r=this._elements)===null||r===void 0?void 0:r.length)>0?(u=(g=this._elements[0])===null||g===void 0?void 0:g.validateBeforeSend)===null||u===void 0?void 0:u.call(g):{isValid:!1}}_updatePayloadAndType(){this._elements[0]&&(this.payload=this._elements[0].content,this.type=this._elements[0].type)}_initC2CReadReceiptInfo(r){const{readReceiptSentByPeer:g,timestamp:u=0}=r;this.conversationType===Zr.CONV_C2C&&this.needReadReceipt===!0&&(this.readReceiptInfo.isPeerRead=g===1,this.readReceiptInfo.timestamp=u)}_extractGroupInfo(r){if(!r)return;const{From_AccountNick:g,From_AccountHeadurl:u,MsgFrom_AccountExtraInfo:E,GroupType:m}=r,{NameCard:D}=E||{};typeof g=="string"&&(this.nick=g),typeof u=="string"&&(this.avatar=u),typeof D=="string"&&(this.nameCard=D),this.conversationSubType=m}reInitialize(r){r===this.from&&(this.isRead=!0),this._initSequence(r),this._concatConversationID(r),this.generateMessageID()}_concatConversationID(r){let g="";const u=this.conversationType;u!==Zr.CONV_SYSTEM?(g=u===Zr.CONV_C2C?r===this.from?this.to:this.from:this.to,this.conversationID=g?`${u}${g}`:null):this.conversationID=Zr.CONV_SYSTEM}_initSequence(r){this.clientSequence===0&&r&&(this.clientSequence=uu(r)),this.sequence===0&&this.conversationType===Zr.CONV_C2C&&(this.sequence=this.clientSequence)}generateMessageID(){this.from===Zr.CONV_SYSTEM&&(this.senderTinyID="144115198244471703"),this.ID=`${this.senderTinyID}-${this.clientTime}-${this.random}`}setIsRead(r){this.isRead=r}}class Nd{static parseServerPushElement(r){const{MsgContent:g={}}=r,{Data:u,Ext:E,Desc:m}=g;return new Nd({data:u,description:m,extension:E})}constructor(r){this.type=KE.MSG_CUSTOM;const{data:g="",description:u="",extension:E=""}=r;this.content={data:g,description:u,extension:E}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{data:E,description:m,extension:D}=u;return{MsgType:this.type,MsgContent:{Data:E,Ext:D,Desc:m}}}validateBeforeSend(){const{isEmpty:r}=De.utils,g=[this.content.data,this.content.description,this.content.extension].some(u=>!r(u));return{isValid:g,error:g?null:{message:"content can not be empty"}}}}class Gd{static parseServerPushElement(r){const{MsgContent:g={Text:""}}=r,{Text:u}=g;return new Gd({text:u})}constructor(r){this.type=Tg.MSG_TEXT,this.content={text:r.text||""}}validateBeforeSend(){var r,g;return((g=(r=this.content)===null||r===void 0?void 0:r.text)===null||g===void 0?void 0:g.length)>0?{isValid:!0}:{isValid:!1,error:{message:"content can not be empty"}}}transformToServerFormat(r){const{isMergerMessage:g=!1}=r||{},u=g?this.payload:this.content,{text:E}=u;return{MsgType:this.type,MsgContent:{Text:E}}}}var Af=new class{constructor(){this._elementClassMap={[KE.MSG_CUSTOM]:Nd,[KE.MSG_TEXT]:Gd}}init(){Sr.getInstance().registerApi({apiName:"createCustomMessage",context:this}),Sr.getInstance().registerApi({apiName:"createTextMessage",context:this})}registerElementClass(n,r){var g;(g=r).prototype!==void 0&&"constructor"in g.prototype&&(this._elementClassMap[n]=r)}getElementClass(n){return this._elementClassMap[n]}createMessage(n){const{from:r,flow:g=tE.OUT}=n,{userId:u}=De.store.get("login")||{};this._isSendByCurrentInstance({from:r,flow:g,currentUser:u})?this._updateWithSenderInfo(n):this._isMultiEndpointSyncMessage({from:r,flow:g,currentUser:u})&&(n.flow=tE.OUT);const E=Object.assign(Object.assign({},n),{currentUser:u});return new jE(E)}createCustomMessage(n){const r=ar(),g=this.createMessage(Object.assign(Object.assign({},n),{from:r})),u=this._elementClassMap[KE.MSG_CUSTOM];if(!g)return null;if(u){const E=new u(n.payload);g.setElement(E)}return g}createTextMessage(n){var r;if(!n)return null;const g=typeof n.payload=="string"?n.payload:((r=n?.payload)===null||r===void 0?void 0:r.text)||"",u=new Gd({text:g}),E=ar(),m=De.message.messageFactory.createMessage(Object.assign(Object.assign({},n),{from:E}));return m.setElement(u),m}_updateWithSenderInfo(n){var r,g;const{nick:u,avatar:E,conversationType:m,to:D}=n,{userId:v,tinyID:T}=De.store.get("login")||{},P=lc.getUserProfile(v);return n.nick=u||P?.nick||"",n.avatar=E||P?.avatar||"",n.tinyID=n.tinyID||T||"",n.from=v,n.status=qr.UNSENT,n.flow=tE.OUT,m===Oa.CONV_GROUP&&(n.nameCard=(g=(r=op.getGroup(D))===null||r===void 0?void 0:r.selfInfo)===null||g===void 0?void 0:g.nameCard),n}_isMultiEndpointSyncMessage(n){const{from:r,flow:g,currentUser:u}=n;return r===u&&g===tE.IN}_isSendByCurrentInstance(n){const{from:r,flow:g,currentUser:u}=n;return r===u&&g===tE.OUT}};const wR={PushFlag:0,Title:"",Desc:"",Ext:"",ApnsInfo:{Sound:"",BadgeMode:0,IsVoipPush:void 0,Image:"",InterruptionLevel:"active",ContentAvailable:0},AndroidInfo:{Sound:"",XiaoMiChannelID:"",OPPOChannelID:"",GoogleChannelID:"",VIVOClassification:1,VIVOCategory:"",HuaWeiCategory:"",OPPOCategory:"",HuaWeiImage:"",HonorImage:"",GoogleImage:"",HonorImportance:"",MeizuNotifyType:void 0}},bd={HonorImportance:{range:["LOW","NORMAL"],defaultValue:void 0},MeizuNotifyType:{range:[0,1],defaultValue:void 0}},WD={enableIOSBackgroundNotification:{range:[!0,!1],defaultValue:!1},interruptionLevel:{range:["passive","active","time-sensitive","critical"],defaultValue:"active"}};function _R(n,r){return Object.keys(r).forEach(g=>{const{range:u,defaultValue:E}=r[g];n[g]=u.includes(n[g])?n[g]:E}),n}function rp(n){const r=n.lastIndexOf(".");return r===-1?n:n.slice(0,r)}function TR(n){const{androidInfo:r={},androidOPPOChannelID:g=""}=n,u=r.OPPOChannelID||g,E=_R(r,bd),{sound:m="",FCMChannelID:D=""}=E,v=vo(E,["sound","FCMChannelID"]);return Object.assign(Object.assign({},v),{Sound:rp(m),OPPOChannelID:u,GoogleChannelID:D})}function NR(n){const{apnsInfo:r={},ignoreIOSBadge:g=!1,disableVoipPush:u}=n,E=_R(r,WD),{ignoreIOSBadge:m,disableVoipPush:D,enableIOSBackgroundNotification:v}=E,T=vo(E,["ignoreIOSBadge","disableVoipPush","enableIOSBackgroundNotification"]),P=m===!0||g===!0?1:0;let W;return s(u)||(W=u===!1?1:0),s(D)||(W=D===!1?1:0),Object.assign(Object.assign({},T),{BadgeMode:P,IsVoipPush:W,ContentAvailable:v?1:0})}function zD(n){return De.utils.isPlainObject(n)?{PushFlag:n.disablePush===!0?1:0,Title:n.title||"",Desc:n.description||"",Ext:n.extension||"",ApnsInfo:NR(n),AndroidInfo:TR(n)}:wR}function ef(n){const{From_AccountHeadurl:r,From_AccountNick:g,IsNeedReadReceipt:u,IsPeerRead:E,IsSyncMsg:m,MsgBody:D,MsgClientTime:v,MsgLifeTime:T,MsgRandom:P,MsgSeq:W,MsgTimeStamp:oA,SendMsgControl:EA,SupportMessageExtension:wA,TinyId:kA,MsgCheckResult:xA,CloudCustomData:LA,MsgVersion:SA,MsgFlagBits:OA,RevokerInfo:WA,InnerSdkCustomData:ue}=n;let le,{From_Account:ki,To_Account:Li}=n;if(m===1){const Yt=Li;Li=ki,ki=Yt}if(WA){const{Reason:Yt,Revoker_Account:Fi,Revoker_FromUin:hs}=WA;le={reason:Yt,revoker:Fi,revokerFromUin:hs,userID:Fi}}return{from:ki,avatar:r,nick:g,needReadReceipt:u===1,isSyncMessage:m,clientTime:v,messageLifeTime:T,random:P,sequence:W,time:oA,messageControlInfo:{excludedFromLastMessage:EA?.NoLastMsg===1,excludedFromUnreadCount:EA?.NoUnread===1},isSupportExtension:wA,to:Li,tinyID:kA,checkResult:xA,cloudCustomData:LA,revokerInfo:le,messageVersion:SA,messageFlagBits:OA,readReceiptSentByPeer:E,elements:TC(D),onlineOnlyFlag:T===0,quoteInfo:ap(ue)}}function tf(n){const{From_Account:r,MsgBody:g,MsgClientTime:u,MsgRandom:E,MsgSeq:m,MsgTimeStamp:D,To_Account:v,MsgVersion:T,CloudCustomData:P,MsgCheckResult:W}=n;return{from:r,clientTime:u,random:E,sequence:m,time:D,to:v,elements:TC(g),messageVersion:T,cloudCustomData:P,checkResult:W}}function ZD(n){const{ClientSeq:r,From_Account:g,GroupInfo:u,MsgBody:E,MsgClientTime:m,MsgRandom:D,MsgSeq:v,MsgTimeStamp:T,SendMsgControl:P,SupportMessageExtension:W,TinyId:oA,CloudCustomData:EA,MsgVersion:wA,MsgCheckResult:kA,NeedReadReceipt:xA,IsPlaceMsg:LA,RevokerInfo:SA,GroupAtInfo:OA,OnlineOnlyFlag:WA,InnerSdkCustomData:ue}=n;let le,ki=eE.MSG_PRIORITY_NORMAL;if(Object.keys(KD).includes(String(n.MsgPriority))&&(ki=KD[n.MsgPriority]),SA){const{Reason:Yt,Revoker_Account:Fi,Revoker_FromUin:hs}=SA;le={reason:Yt,revoker:Fi,revokerFromUin:hs,userID:Fi}}const Li=function(Yt){const Fi=[];return Array.isArray(Yt)&&Yt.forEach(hs=>{hs.GroupAtAllFlag===jD?Fi.push(hs.GroupAt_Account):hs.GroupAtAllFlag===MR&&Fi.push(Po.MSG_AT_ALL)}),Fi}(OA);return{clientSequence:r,from:g,groupProfile:u,clientTime:m,priority:ki,random:D,sequence:v,time:T,messageControlInfo:{excludedFromLastMessage:P?.NoLastMsg===1,excludedFromUnreadCount:P?.NoUnread===1},isSupportExtension:W,tinyID:oA,cloudCustomData:EA,messageVersion:wA,checkResult:kA,needReadReceipt:xA,isPlaceMessage:LA,revokerInfo:le,atUserList:Li,elements:TC(E),to:oN(n),onlineOnlyFlag:WA===1,quoteInfo:ap(ue)}}function oN(n){const{utils:{isEmpty:r},constants:{IS_TOPIC_MESSAGE:g}}=De,{ToGroupId:u,GroupInfo:{MillionGroupFlag:E=0,TopicId:m}={}}=n;return E!==g||r(m)?u:m}function TC(n){if(!n)return null;if(Array.isArray(n))return n.map(g=>{const u=De.message.messageFactory.getElementClass(g.MsgType);return u?.parseServerPushElement(g)});const r=De.message.messageFactory.getElementClass(n.MsgType);return r?.parseServerPushElement(n)}function XD(n){const{From_Account:r,MsgBody:g,MsgClientTime:u,MsgRandom:E,MsgSeq:m,MsgTimeStamp:D,GroupId:v,TopicId:T,MsgVersion:P,CloudCustomData:W,MsgCheckResult:oA}=n;return{from:r,clientTime:u,random:E,sequence:m,time:D,groupID:v,topicID:T,elements:TC(g),messageVersion:P,cloudCustomData:W,checkResult:oA}}function ap(n){const{utils:{isString:r,safeStringify:g},ssoLog:u}=De;if(!r(n))return null;try{const{messageID:E,messageTime:m,messageSequence:D}=JSON.parse(n).businessQuote;return{msgID:E,messageTime:m,messageSequence:D}}catch(E){return u.debug("_parseServerQuoteInfo",g(E)),null}}function gp({conversationUpdateFields:n,message:r}){const{conversationID:g,conversationType:u,conversationSubType:E,flow:m,_isExcludedFromUnreadCount:D,_isExcludedFromLastMessage:v}=r,T=v?"":tp(r),P=!D&&m===tE.IN;n.has(g)?(n.get(g).lastMessage=T,P&&n.get(g).unreadCount++):n.set(g,{conversationID:g,type:u,subType:E,unreadCount:P?1:0,lastMessage:T})}function _B(n){return n.filter(r=>{const g=!ts(r?._elements),u=r?.isPlaceMessage===1;return g||De.ssoLog.error("emptyMessageBody",`from:${r.from} to:${r.to} sequence:${r.sequence}`),g&&!u})}function TB(n){const{messageDataHandler:r}=De.message;return!r.isInMessageList(n)&&!r.isMessageSentByCurrentInstance(n)}var GR=Object.freeze({__proto__:null,autoIncrementIndex:uu,createAndroidPushInfo:TR,createApnsPushInfo:NR,createOfflinePushInfo:zD,filterValidMessages:_B,getAndroidSoundName:rp,parseServerGroupMessage:ZD,parseServerPushC2CModifyMessage:tf,parseServerPushGroupModifyMessage:XD,parseServerPushMessage:ef,parseServerPushMessageElement:TC,shouldStoreMessage:TB,updateConversationFields:gp});const{isPlainObject:bR}=De.utils;function cp(n,r={}){const{onlineUserOnly:g,messageControlInfo:u}=r;let{offlinePushInfo:E}=r;n.conversationType===Zr.CONV_C2C&&g===!0&&(E?E.disablePush=!0:E={disablePush:!0});let m="";typeof n.cloudCustomData=="string"&&n.cloudCustomData.length>0&&(m=n.cloudCustomData);const D=[];if(u&&bR(u)){const{excludedFromUnreadCount:v,excludedFromLastMessage:T,excludedFromContentModeration:P}=u;v===!0&&D.push("NoUnread"),T===!0&&D.push("NoLastMsg"),P===!0&&D.push("NoMsgCheck")}return{onlineUserOnly:g,cloudCustomData:m,messageControlInfo:D,offlinePushInfo:E}}function $D(n){const{webhookInfo:{disableCloudMessagePreHook:r=!1,disableCloudMessagePostHook:g=!1}={}}=n||{};if(!r&&!g)return;const u=[];return r&&u.push("ForbidBeforeSendMsgCallback"),g&&u.push("ForbidAfterSendMsgCallback"),u}function Nh(n,r){return mA(this,void 0,void 0,function*(){const g=n.conversationType===Zr.CONV_GROUP?function(E,m){var D;const v=cp(E,m),{onlineUserOnly:T,cloudCustomData:P,messageControlInfo:W,offlinePushInfo:oA}=v,EA=JSON.parse(JSON.stringify(E.transformElementsToServerFormat()));let wA;return C(E._receiverList)&&E._receiverList.length>0&&(wA=E._receiverList,E._receiverList.length>50&&(wA=E._receiverList.slice(0,50),console.warn("ReceiverListLimit"))),{servcmd:"group_open_http_svc.send_group_msg",data:{From_Account:(D=De.store.get("login"))===null||D===void 0?void 0:D.userId,GroupId:E.to,MsgBody:EA,CloudCustomData:P,Random:E.random,MsgPriority:E.priority,ClientSeq:E.clientSequence,GroupAtInfo:E._groupAtInfoList,OnlineOnlyFlag:T?1:0,MsgClientTime:E.clientTime,OfflinePushInfo:zD(oA),SendMsgControl:T?void 0:W,NeedReadReceipt:E.needReadReceipt===!0?1:0,To_Account:wA,SupportMessageExtension:E.isSupportExtension===!0?1:0,IsRelayMsg:E._relayFlag===!0?1:0,CustomModerationConfigID:E._cmConfigID,ForbidCallbackControl:$D(m),InnerSdkCustomData:GB(E)}}}(n,r):function(E,m){var D;const v=cp(E,m),{onlineUserOnly:T,cloudCustomData:P,messageControlInfo:W,offlinePushInfo:oA}=v,EA=T===!0?0:void 0,wA=JSON.parse(JSON.stringify(E.transformElementsToServerFormat()));return{servcmd:"openim.sendmsg",data:{From_Account:(D=De.store.get("login"))===null||D===void 0?void 0:D.userId,To_Account:E.to,MsgBody:wA,CloudCustomData:P,MsgSeq:E.sequence,MsgRandom:E.random,MsgLifeTime:EA,From_AccountNick:E.nick,From_AccountHeadurl:E.avatar,SendMsgControl:EA!==0?W:void 0,MsgClientTime:E.clientTime,IsNeedReadReceipt:E.needReadReceipt===!0?1:0,SupportMessageExtension:E.isSupportExtension===!0?1:0,IsRelayMsg:E._relayFlag===!0?1:0,CustomModerationConfigID:E._cmConfigID,OfflinePushInfo:zD(oA),ForbidCallbackControl:$D(m),InnerSdkCustomData:GB(E)}}}(n,r),u=yield lg(g);return u?{time:u.MsgTime,messageDropReason:u.MsgDropReason,sequence:u.MsgSeq}:null})}function Gh(n){return mA(this,void 0,void 0,function*(){const{from:r,to:g,version:u=0,sequence:E,random:m,time:D,type:v,cloudCustomData:T}=n,P={From_Account:r,To_Account:g,MsgVersion:u,MsgSeq:E,MsgRandom:m,MsgTime:D,MsgType:v,MsgBody:n.transformElementsToServerFormat(),CloudCustomData:T},W=yield lg({servcmd:"openim.modify_c2c_msg",data:P});if(W){const{MsgBody:oA,MsgVersion:EA,CloudCustomData:wA}=W;return{elements:TC(oA),messageVersion:EA,cloudCustomData:wA}}})}function NB(n){return mA(this,void 0,void 0,function*(){const{to:r,version:g=0,sequence:u,cloudCustomData:E}=n,m={GroupId:r,MsgVersion:g,MsgSeq:u,MsgBody:n.transformElementsToServerFormat(),CloudCustomData:E},D=yield lg({servcmd:"openim.modify_group_msg",data:m});if(D){const{MsgBody:v,MsgVersion:T,CloudCustomData:P}=D;return{elements:TC(v),messageVersion:T,cloudCustomData:P}}})}function bh(n){return mA(this,void 0,void 0,function*(){const{groupID:r,count:g,messageSequence:u,messageSequenceList:E,getType:m}=n,D={GroupId:r,ReqMsgNumber:g,WithRecalledMsg:1,Version:1,GetType:m};return u&&(D.ReqMsgSeq=u),C(E)&&E.length>0&&(D.ReqMsgSeqList=E),yield lg({servcmd:"group_open_http_svc.group_msg_get",data:D})})}function of(n){return mA(this,void 0,void 0,function*(){const{peerAccount:r,count:g,lastMessageTime:u,messageKey:E,direction:m}=n;return lg({servcmd:"openim.getroammsg",data:{Peer_Account:r,MaxCnt:g,WithRecalledMsg:1,LastMsgTime:u,MsgKey:E,GetDirection:m}})})}function GB(n){if(De.utils.isObject(n.quoteInfo)){const{msgID:r,messageSequence:g,messageTime:u}=n.quoteInfo;return JSON.stringify({businessQuote:{messageID:r,messageSequence:g,messageTime:u}})}}var AS=Object.freeze({__proto__:null,createMessagePackOptions:cp,generateForbidCallbackControl:$D,getC2CRoamingMessagesByAnchor:of,getGroupRoamingMessagesByAnchor:bh,getRoamingMessages:function(n){return mA(this,void 0,void 0,function*(){const{peerAccount:r,count:g,lastMessageTime:u,messageKey:E}=n;return(yield lg({servcmd:"openim.getroammsg",data:{Peer_Account:r,MaxCnt:g||15,LastMsgTime:u||0,MsgKey:E,GetDirection:0,WithRecalledMsg:1}}))||[]})},modifyC2CMessage:Gh,modifyGroupMessage:NB,sendMessage:Nh});const{isPlainObject:sN}=De.utils,{MSG_AUDIO:eS,MSG_FILE:tS,MSG_IMAGE:kR,MSG_VIDEO:LR,MSG_MERGER:UR}=Po;class sf{constructor(){this._sendProtocolMap=new Map}init(){Sr.getInstance().registerApi({apiName:"sendMessage",context:this,matcher:r=>![eS,tS,kR,LR,UR].includes(r[0].type)})}registerSendProtocol(r,g,u){this._sendProtocolMap.set(r,g.bind(u))}sendMessage(r,g){return mA(this,void 0,void 0,function*(){const{TOTAL_COUNT:u,SEND_COST:E,SUCCESS_COUNT:m,FAILED_COUNT:D}=Cr;if(!(r instanceof jE))throw new Cs({code:pa.MSG_INSTANCE_REQUIRED});const v=r.validateBeforeSend();if(!v.isValid){const{code:W,message:oA=""}=v.error||{};throw new Cs({code:W,message:oA})}this._reportMessageSendQuality({name:u,message:r});let T=!1;const{messageDataHandler:P}=De.message||{};try{const{messageControlInfo:W}=g||{};let oA=null;P.addRandomOfSentMessage(r.random);const EA=Date.now(),wA=this._getSendProtocol(r);if(r.conversationType===Zr.CONV_C2C?(T=g?.onlineUserOnly===!0,oA=yield wA(r,g)):r.conversationType===Zr.CONV_GROUP&&(yield this._validateBeforeSendGroupMessage(r),oA=yield wA(r,g)),oA){const{messageDropReason:kA,sequence:xA,time:LA}=oA;if(this._updateNickAndAvatarOfSentMessageByMe(r),kA&&this._logRateLimitInfo(r,xA,kA),this._reportMessageSendQuality({name:m,message:r}),this._reportMessageSendQuality({name:E,message:r,startTs:EA}),r.isResend===!0){const SA=P.findMessage(r.ID);SA&&(De.ssoLog.debug("sendMessage",`sendMessage resend ok. ID:${SA.ID}`),P.deleteConversationMessage(SA))}return r.status=qr.SUCCESS,r.time=LA,r.conversationType===Zr.CONV_GROUP&&(r.sequence=xA),T?r._onlineOnlyFlag=!0:(P.storeConversationMessage(r),this._applySentMessageControlInfo(r,W),this._emitOnlineMessageSent(r)),r.type===Tg.MSG_STREAM?{code:0,data:{message:r,streamMessageID:oA.streamMessageID}}:{code:0,data:{message:r}}}}catch(W){r.status=qr.FAIL,P.removeRandomOfSentMessage(r.random);let{errorCode:oA}=W||{},EA=W?.errorInfo||W?.message||"";throw this._hasRiskContent(oA)&&(r.hasRiskContent=!0),T||this._isRejectedByRestApi(oA)||P.storeConversationMessage(r),this._reportMessageSendQuality({name:D,message:r,error:W}),new Cs({code:oA,message:EA,data:{message:r},moreMessage:`type:${r.type} from:${r.from} to:${r.to}`})}})}_hasRiskContent(r){return r===80001||r===80004}_isRejectedByRestApi(r){return r>=10100&&r<=10200||r>=120001&&r<=13e4}_emitOnlineMessageSent(r){const g=r._isExcludedFromLastMessage?"":r,{conversationID:u,conversationType:E}=r,m=tl(u)?lo.TOPIC_NEW_MESSAGE:lo.NEW_MESSAGE;De.notificationCenter.emitInnerEvent(m,{result:{conversationUpdateFieldList:[{conversationID:u,type:E,message:r,lastMessage:g,unreadCount:0}]}})}_applySentMessageControlInfo(r,g){g&&sN(g)&&(g.excludedFromLastMessage===!0&&(r._isExcludedFromLastMessage=!0),g.excludedFromUnreadCount===!0&&(r._isExcludedFromUnreadCount=!0))}_logRateLimitInfo(r,g,u){const E=`from:${r.from} to:${r.to} sequence:${g} messageDropReason:${u}`;De.ssoLog.warn("messageDropReason",E)}_updateNickAndAvatarOfSentMessageByMe(r){const{messageDataHandler:g}=De.message||{};let u=!1;const{conversationID:E}=r,m=g.getLatestMsgSentByMe(E);if(m){const{nick:D,avatar:v}=m;D===r.nick&&v===r.avatar||(u=!0),u&&g.updateNickAndAvatarOfSentMessage({conversationID:E,latestNick:r.nick,latestAvatar:r.avatar,isSentByMe:!0})}}_validateBeforeSendGroupMessage(r){return mA(this,void 0,void 0,function*(){var g,u,E;const{to:m,from:D}=r;let v=m,T=op.getGroup(v);if(ea({groupID:v})&&T?.isSupportTopic)throw new Cs({code:pa.MSG_SEND_GRP_WITH_TOPIC_FAIL});if(tl(m)&&([v]=m.split(ga.TOPIC),T=op.getGroup(v)),!T&&typeof((g=Sr.getInstance().getApiMap())===null||g===void 0?void 0:g.getGroupProfile)=="function"){const P=yield Sr.getInstance().getApiMap().getGroupProfile({groupID:v});if(((E=(u=P?.data)===null||u===void 0?void 0:u.group)===null||E===void 0?void 0:E.type)===Po.GRP_AVCHATROOM){const W=Es({code:pa.MSG_SEND_FAIL_NOT_IN_AV,replacement1:D,replacement2:v});throw new Cs({code:pa.MSG_SEND_FAIL_NOT_IN_AV,message:W})}}return!0})}_reportMessageSendQuality(r){De.notificationCenter.emitInnerEvent(lo.QUALITY_STAT,{label:dI.MESSAGE_SEND_SUCCESS_RATE,data:r})}_getSendProtocol(r){return this._sendProtocolMap.get(r.type)||Nh}}var nN=new class{constructor(){this._sparseMessagesByConversation=new Map,this._latestMessageSentByPeerMap=new Map,this._latestMessageSentByMeMap=new Map,this._randomOfSentMessageList=new Set}init(){De.notificationCenter.subscribeInnerEvent(lo.LOGOUT,this._reset,this),De.notificationCenter.subscribeInnerEvent(lo.DESTROY,this._dispose,this)}get _messagesByConversation(){return sp.getMessages()}storeConversationMessage(n,r=!1){if(Hs)return!0;const{conversationID:g}=n;if(!g||(this._messagesByConversation.has(g)||this._messagesByConversation.set(g,new Map),this._shouldSkipStoreMessage(n,r)))return!1;const u=this._getUniqueIdOfMessage(n);return this._messagesByConversation.get(g).set(u,n),this._updateLatestMessageMap(n),!0}_updateLatestMessageMap(n){const{conversationID:r}=n;n.flow==="out"?this._setLatestMsgSentByMe(r,n):r.startsWith("C2C")&&this._setLatestMsgSentByPeer(r,n)}_shouldSkipStoreMessage(n,r){const g=this._getUniqueIdOfMessage(n),u=this._messagesByConversation.get(n.conversationID);if(u?.has(g)){const E=u?.get(g);if(!r||E?.isModified===!0)return!0}return!1}deleteConversationMessage(n){var r;const{conversationID:g=""}=n,u=this._getUniqueIdOfMessage(n);this._messagesByConversation.has(g)&&((r=this._messagesByConversation.get(g))===null||r===void 0||r.delete(u))}modifyConversationMessage(n,r){var g;if(!this._messagesByConversation.has(n)&&!this._sparseMessagesByConversation.has(n))return{isUpdated:!1,message:null};const u=this._getUniqueIdOfMessage(r),E=this._getMessageFromLocalMessage(n,u);if(E){const{messageVersion:m,elements:D,cloudCustomData:v,checkResult:T=0}=r,P=T>1;if(De.ssoLog.debug("modifyConversationMessage",`conversationToMessageMap modifyConversationMessage localVersion:${E.version} remoteVersion:${m}`),E.versionE.ID===n)||null,r)break;if(!r){const u=Array.from(this._sparseMessagesByConversation.values());for(const E of u)if(r=E.get(n)||null,r)break}return r}deleteConversationMessageList(n){this._messagesByConversation.has(n)&&(this._messagesByConversation.delete(n),this._latestMessageSentByMeMap.delete(n),this._latestMessageSentByPeerMap.delete(n)),this._sparseMessagesByConversation.has(n)&&this._sparseMessagesByConversation.delete(n)}revokeMessage({conversationID:n,sequence:r,random:g,revoker:u}){const E=this._messagesByConversation.get(n);let m=null;if(E){const D=Array.from(E.values());if(m=this._findMessageBySequenceAndRandom({messageList:D,random:g,sequence:r}),m){const v=this._getUniqueIdOfMessage(m);return sp.updateMessage(n,[v],{isRevoked:!0,revoker:u,operation:wc.revoke}),m}}if(this._sparseMessagesByConversation.has(n)){const D=Array.from(this._sparseMessagesByConversation.get(n).values());if(m=this._findMessageBySequenceAndRandom({messageList:D,random:g,sequence:r}),m)return m.isRevoked=!0,m.revoker=u,m}}_findMessageBySequenceAndRandom({messageList:n,sequence:r,random:g}){for(let u=0;u0){const D=new Map([...E,...m.entries()]);this._messagesByConversation.set(g,D),this._updateLatestMessageSentByMe(g),this._updateLatestMessageSentByPeer(g)}return u}storeSparseMessageList(n){if(n.length===0)return;const{conversationID:r}=n[0],g=n.length;this._sparseMessagesByConversation.has(r)||this._sparseMessagesByConversation.set(r,new Map);const u=this._sparseMessagesByConversation.get(r);for(let E=0;E=0;u--)if(g[u].flow==="out"){this._setLatestMsgSentByMe(n,g[u]);break}}}_updateLatestMessageSentByPeer(n){var r;const g=Array.from(((r=this._messagesByConversation.get(n))===null||r===void 0?void 0:r.values())||[]);if(g.length!==0&&n.startsWith("C2C")){for(let u=g.length-1;u>=0;u--)if(g[u].flow==="in"){this._setLatestMsgSentByPeer(n,g[u]);break}}}_getUniqueIdOfMessage(n){const{from:r,to:g,random:u,sequence:E,time:m}=n;return`${r}-${g}-${u}-${E}-${m}`}_setLatestMsgSentByPeer(n,r){this._latestMessageSentByPeerMap.set(n,r)}_setLatestMsgSentByMe(n,r){this._latestMessageSentByMeMap.set(n,r)}getLatestMsgSentByPeer(n){return this._latestMessageSentByPeerMap.get(n)}getLatestMsgSentByMe(n){return this._latestMessageSentByMeMap.get(n)}addRandomOfSentMessage(n){this._randomOfSentMessageList.add(n)}removeRandomOfSentMessage(n){this._randomOfSentMessageList.delete(n)}updateNickAndAvatarOfSentMessage(n){const{conversationID:r="",latestAvatar:g,latestNick:u,isSentByMe:E=!0}=n,m=this._messagesByConversation.get(r);if(!m)return;const D=Array.from(m.values()),v=E?"out":"in";D.forEach(T=>{const{nick:P,avatar:W,flow:oA}=T;oA===v&&(P!==u&&(T.nick=u),W!==g&&(T.avatar=g))})}isInMessageList(n){var r;const{conversationID:g}=n;if(!g||!this._messagesByConversation.has(g))return!1;const u=this._getUniqueIdOfMessage(n);return(r=this._messagesByConversation.get(g))===null||r===void 0?void 0:r.has(u)}isMessageSentByCurrentInstance(n){const{random:r}=n;return this._randomOfSentMessageList.has(r)}getContinuousMessagesByConversation(){return this._messagesByConversation}getLocalMessageList(n){const r=this._messagesByConversation.get(n);return r?[...r.values()]:[]}getSparseMessageList(n){const r=this._sparseMessagesByConversation.get(n);return r?[...r.values()]:[]}_reset(){this._messagesByConversation.clear(),this._latestMessageSentByPeerMap.clear(),this._latestMessageSentByMeMap.clear(),this._randomOfSentMessageList.clear()}_dispose(){this._reset(),De.notificationCenter.unSubscribeInnerEvent(lo.LOGOUT,this._reset,this),De.notificationCenter.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this)}};function nf(n,r){const g=wB.getConversation(n);if(g?.lastMessage){const{lastMessage:u}=g,{lastTime:E,lastSequence:m,version:D}=u,{time:v,sequence:T,messageVersion:P,elements:W,cloudCustomData:oA}=r;E===v&&m===T&&D!==P&&(u.type=W[0].type,u.payload=W[0].content,u.messageForShow=il(u.type,u.payload),u.cloudCustomData=oA,u.version=P,wB.updateConversation(n,{lastMessage:u}))}}class FR{init(){Sr.getInstance().registerApi({apiName:"modifyMessage",context:this})}modifyMessage(r){return mA(this,void 0,void 0,function*(){const{to:g,payload:u,sequence:E,conversationType:m,random:D,time:v,from:T,type:P}=r;if(this._canModifyMessageElement(P)){const W=r?._elements||[];W.length>=1&&(W[0].type=P,W[0].content=u)}try{let W=null,oA=null;if(m===Zr.CONV_C2C?W=yield Gh(r):m===Zr.CONV_GROUP&&(W=yield NB(r)),W){let EA=`${m}${g}`;return g===ar()&&m===Zr.CONV_C2C&&(EA=`${m}${T}`),oA={conversationType:m,from:T,to:g,time:v,random:D,sequence:E,elements:W?.elements,cloudCustomData:W?.cloudCustomData,messageVersion:W?.messageVersion,conversationID:EA},this._handleModifyMessageSuccess(oA),{code:0,data:{message:r},successLog:{message:`to:${g}`}}}}catch(W){const{errorCode:oA}=W||{};throw new Cs({functionName:"modifyMessage",code:oA,moreMessage:`to:${g}`})}})}_handleModifyMessageSuccess(r){const{conversationID:g}=r,{isUpdated:u,message:E}=De.message.messageDataHandler.modifyConversationMessage(g,r);u===!0&&De.notificationCenter.emitOuterEvent(Rr.MESSAGE_MODIFIED,{name:Rr.MESSAGE_MODIFIED,data:[E]}),De.notificationCenter.emitInnerEvent(lo.MESSAGE_MODIFIED,{conversationID:g,message:E}),nf(g,r)}_canModifyMessageElement(r){return[KE.MSG_TEXT,KE.MSG_CUSTOM,KE.MSG_LOCATION,KE.MSG_FACE].includes(r)}}class kh{init(){const{notificationCenter:r}=De,{InnerEventSubType:g}=r;Fs.getInstance().registerWorkflowStep(jt.RECEIVE_C2C_NEW_MESSAGE,Xt.HANDLE_C2C_NEW_MESSAGE,this._handleC2CMessagePush,this),Fs.getInstance().registerWorkflowStep(jt.RECEIVE_C2C_NEW_MESSAGE,Xt.EMIT_C2C_MESSAGE_EVENT,this._emitMessageEventsAfterReceiveNewMessage,this),Fs.getInstance().registerWorkflowStep(jt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,Xt.EMIT_C2C_MESSAGE_EVENT,this._emitMessageEventsAfterSyncUnreadMessage,this),r.subscribeInnerEvent(lo.MESSAGE_PUSH,g.C2C_REALTIME_MESSAGE,this._executeReceiverNewMessageWorkFlow,this),r.subscribeInnerEvent(lo.MESSAGE_PUSH,g.C2C_MESSAGE_MODIFIED,this._handleC2CMessageModify,this),r.subscribeInnerEvent(lo.DESTROY,this._dispose,this)}_executeReceiverNewMessageWorkFlow(r){Fs.getInstance().executeWorkflow(jt.RECEIVE_C2C_NEW_MESSAGE,r)}_handleC2CMessagePush(r){const g=r.data||{},{messageDataHandler:u}=De.message||{},E=[],m=new Map;return g.C2cMsgArray.forEach(D=>{const v=this._generateC2CMessage(D);this._updateMessageProfile(v);let T=v.isModified===1;u.isMessageSentByCurrentInstance(v)?v.isModified=T:T=!1,v._onlineOnlyFlag?u.isMessageSentByCurrentInstance(v)||E.push(v):TB(v)&&(u.storeConversationMessage(v)&&gp({conversationUpdateFields:m,message:v}),u.isMessageSentByCurrentInstance(v)&&!T||E.push(v))}),{conversationUpdateFieldList:[...m.values()],messages:E}}_emitMessageEventsAfterReceiveNewMessage(r){var g;const{messages:u=[]}=((g=r.result)===null||g===void 0?void 0:g[Xt.HANDLE_C2C_NEW_MESSAGE])||{};this._emitMessageEvents(u)}_emitMessageEventsAfterSyncUnreadMessage(r){var g;const{messages:u=[]}=((g=r.result)===null||g===void 0?void 0:g[Xt.UNREAD_MESSAGE_SYNC])||{};this._emitMessageEvents(u)}_emitMessageEvents(r){const g=r?.filter(E=>E?.isModified===!0)||[];g.length>0&&De.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:g});const u=r?.filter(E=>!E?.isModified);u.length>0&&De.notificationCenter.emitOuterEvent("onMessageReceived",{name:"onMessageReceived",data:u})}_generateC2CMessage(r){const g=Zr.CONV_C2C,u=ef(r),E=De.message.messageFactory.createMessage(Object.assign(Object.assign({},u),{conversationType:g,flow:tE.IN})),{elements:m}=u;return E.setElement(m),E}_updateMessageProfile(r){var g;const{messageDataHandler:u}=De.message||{},E=(g=De.store.get("login"))===null||g===void 0?void 0:g.userId,{from:m,nick:D,avatar:v,conversationID:T=""}=r;if(m!==E){const P=u.getLatestMsgSentByPeer(T);if(P){const{nick:W,avatar:oA}=P;s(D)||s(v)?(r.nick=c(W)?W:r.nick,r.avatar=c(oA)?oA:r.avatar):D===W&&v===oA||(u.updateNickAndAvatarOfSentMessage({conversationID:T,latestNick:D,latestAvatar:v,isSentByMe:!1}),this._updateConversationUserProfile({conversationID:T,nick:D,avatar:v}))}}else{const P=u.getLatestMsgSentByMe(T);!P||D===P.nick&&v===P.avatar||u.updateNickAndAvatarOfSentMessage({conversationID:T,latestNick:D,latestAvatar:v,isSentByMe:!0})}}_updateConversationUserProfile(r){const{conversationID:g,nick:u,avatar:E}=r,m=wB.getConversation(g),{userProfile:D={}}=m||{};D.avatar===E&&D.nick===u||wB.updateConversation(g,{userProfile:Object.assign(Object.assign({},D),{nick:u,avatar:E})})}_updateMessageListDueToModify(r){const{conversationID:g}=r,{isUpdated:u,message:E}=De.message.messageDataHandler.modifyConversationMessage(g,r);u===!0&&De.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:[E]}),De.notificationCenter.emitInnerEvent("ModifyMessageSuccess",r),nf(g,r)}_handleC2CMessageModify(r){r.C2cMsgModNotifys.forEach(g=>{var u;const E=Zr.CONV_C2C;let m=tf(g);const{to:D,from:v}=m;let T=`${E}${D}`;D===((u=De.store.get("login"))===null||u===void 0?void 0:u.userId)&&(T=`${E}${v}`),m=Object.assign({conversationType:E,conversationID:T},m),this._updateMessageListDueToModify(m)})}_dispose(){const{notificationCenter:r}=De,{InnerEventSubType:g}=r;De.notificationCenter.unSubscribeInnerEvent(lo.MESSAGE_PUSH,g.C2C_REALTIME_MESSAGE,this._handleC2CMessagePush,this),De.notificationCenter.unSubscribeInnerEvent(lo.MESSAGE_PUSH,g.C2C_MESSAGE_MODIFIED,this._handleC2CMessageModify,this),De.notificationCenter.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this)}}class Lh{init(){const{notificationCenter:r}=De,{InnerEventSubType:g}=r;Fs.getInstance().registerWorkflowStep(jt.RECEIVE_GROUP_NEW_MESSAGE,Xt.HANDLE_GROUP_NEW_MESSAGE,this._handleGroupMessagePush,this),Fs.getInstance().registerWorkflowStep(jt.RECEIVE_GROUP_NEW_MESSAGE,Xt.EMIT_GROUP_MESSAGE_EVENT,this._emitMessageEvents,this),r.subscribeInnerEvent(lo.MESSAGE_PUSH,g.GROUP_REALTIME_MESSAGE,this._executeReceiverNewMessageWorkFlow,this),r.subscribeInnerEvent(lo.MESSAGE_PUSH,g.GROUP_MESSAGE_MODIFIED,this._handleGroupMessageModify,this),r.subscribeInnerEvent(lo.DESTROY,this._dispose,this)}_executeReceiverNewMessageWorkFlow(r){this._canExecuteReceiverNewMessageWorkFlow(r)&&Fs.getInstance().executeWorkflow(jt.RECEIVE_GROUP_NEW_MESSAGE,r)}_handleGroupMessagePush(r){const g=r.data||{},{messageDataHandler:u}=De.message,E=[],m=new Map,D=g?.GroupMsgArray;return D?.forEach(v=>{if(v.GroupInfo.NotVisible===1)return;const T=this._generateGroupMessage(v);this.updateMessageProfile(T);let P=T.isModified===1;u.isMessageSentByCurrentInstance(T)?T.isModified=P:P=!1,T._onlineOnlyFlag?u.isMessageSentByCurrentInstance(T)||E.push(T):TB(T)&&u.storeConversationMessage(T)&&(E.push(T),gp({conversationUpdateFields:m,message:T}))}),{conversationUpdateFieldList:[...m.values()],messages:E}}_emitMessageEvents(r){var g;const{messages:u}=((g=r.result)===null||g===void 0?void 0:g[Xt.HANDLE_GROUP_NEW_MESSAGE])||{},E=u?.filter(D=>D?.isModified===!0)||[];E.length>0&&De.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:E});const m=u?.filter(D=>!D?.isModified)||[];m.length>0&&De.notificationCenter.emitOuterEvent("onMessageReceived",{name:"onMessageReceived",data:m})}_generateGroupMessage(r){const g=Zr.CONV_GROUP,u=ZD(r),E=De.message.messageFactory.createMessage(Object.assign(Object.assign({},u),{conversationType:g,flow:tE.IN})),{elements:m}=u;return E.setElement(m),E}updateMessageProfile(r){var g;const{messageDataHandler:u}=De.message||{},E=(g=De.store.get("login"))===null||g===void 0?void 0:g.userId,{from:m,nick:D,avatar:v,conversationID:T="",_elements:P}=r;if(m===E){const W=u.getLatestMsgSentByMe(T);!W||D===W.nick&&v===W.avatar||u.updateNickAndAvatarOfSentMessage({conversationID:T,latestNick:D,latestAvatar:v,isSentByMe:!0})}else if(m===Po.CONV_SYSTEM){const{operationType:W,memberInfoList:oA,operatorInfo:EA}=P;let wA={};if(ts(oA)?ts(EA)||(wA=EA):[Gg.JOINED,Gg.KICKED,Gg.ADMIN_SET,Gg.ADMIN_CANCELED].includes(W)&&(wA=Object.assign({},oA[0])),!ts(wA)){const{nick:kA="",avatar:xA=""}=wA;r.nick=kA,r.avatar=xA}}}_updateMessageListDueToModify(r){const{conversationID:g}=r,{isUpdated:u,message:E}=De.message.messageDataHandler.modifyConversationMessage(g,r);u===!0&&De.notificationCenter.emitOuterEvent("onMessageModified",{name:"onMessageModified",data:[E]}),nf(g,r)}_handleGroupMessageModify(r){r.GroupMsgModNotifys.forEach(g=>{const u=Zr.CONV_GROUP;let E=XD(g);const{topicID:m,groupID:D}=E,v=m||D,T=`${u}${v}`;E=Object.assign({conversationType:u,conversationID:T,to:v},E),this._updateMessageListDueToModify(E)})}_dispose(){const{notificationCenter:r}=De,{InnerEventSubType:{GROUP_REALTIME_MESSAGE:g,GROUP_MESSAGE_MODIFIED:u}}=r;r.unSubscribeInnerEvent(lo.MESSAGE_PUSH,g,this._handleGroupMessagePush,this),r.unSubscribeInnerEvent(lo.MESSAGE_PUSH,u,this._handleGroupMessageModify,this),r.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this)}_canExecuteReceiverNewMessageWorkFlow(r){var g,u;const{GroupId:E,GroupType:m}=((u=(g=r?.GroupMsgArray)===null||g===void 0?void 0:g[0])===null||u===void 0?void 0:u.GroupInfo)||{},D=m===Pa.GRP_AVCHATROOM;return!(!op.getGroup(E)&&D)}}var iS=new class{constructor(){this.c2cMessageReceiver=new kh,this.groupMessageReceiver=new Lh}init(){this.c2cMessageReceiver.init(),this.groupMessageReceiver.init()}};const OR={createCustomMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1},payload:{required:!0,rules:["object"],allowEmpty:!1},cloudCustomData:{required:!1,rules:["string"],allowEmpty:!1},priority:{required:!1,rules:["string"],allowEmpty:!1},customModerationConfigurationID:{required:!1,rules:["string"],allowEmpty:!1}},sendMessage:[{key:"message",required:!0,rules:["object"],allowEmpty:!1},{key:"options",required:!1,rules:["object"],allowEmpty:!1}],createTextMessage:{to:{required:!0,rules:["string"],allowEmpty:!1},conversationType:{required:!0,rules:["string"],allowEmpty:!1,customValidator:n=>!(!n.startsWith("C2C")&&!n.startsWith("GROUP"))||"conversationType is invalid."},payload:{required:!0,rules:["object"],allowEmpty:!1,customValidator:n=>function(r){var g;return typeof r?.text!="string"||typeof r.text=="string"&&((g=r?.text)===null||g===void 0?void 0:g.length)===0?"payload.text must be a string":!0}(n)}}},rN={createCustomMessage:!0,sendMessage:!0,modifyMessage:!0};var aN=new class{constructor(){this._historyMessageListFetchAnchors=new Map,this.completedHistoryConversations=new Set}getGroupRoamingMessagesByAnchor(n){return mA(this,void 0,void 0,function*(){try{const{conversationID:r,count:g,direction:u,sequence:E,messageSequenceList:m,shouldMarkCompleted:D=!1,getType:v}=n,T=r.replace(Oa.CONV_GROUP,""),P=[];let W=E;if(u===$c.BACKWARD){if(typeof E!="number")return{messageList:[],hasNoMoreHistoryMessage:!1,nextReqMessageIDFromServer:""};W=E+g-1}const oA=yield bh({groupID:T,count:g,messageSequence:W,messageSequenceList:m,getType:v});if(oA){const{RspMsgList:EA=[],NextReqMsgSeq:wA=0,IsFinished:kA,InvisibleMsgSeq:xA}=oA,LA=`groupID:${T} sequence:${E} reqSeq:${W} direction:${u} complete:${kA} nextSequence:${wA} remoteMsgCount:${EA.length} invisibleSequenceList:${xA}`,SA=[];for(let ue=0;ue=E),OA&&D&&this.completedHistoryConversations.add(r);const WA=_B(SA);return De.ssoLog.info("getGroupRoamingMessagesByAnchor",LA),{messageList:WA,invisibleSequenceList:xA,nextReqMessageIDFromServer:wA,hasNoMoreHistoryMessage:OA,serverGroupTipList:P}}}catch(r){const{errorCode:g,errorInfo:u}=r||{};throw new Cs({code:g,message:u})}})}clearHistoryMessageListFetchAnchors(n){this._historyMessageListFetchAnchors.delete(n)}isHistoryMessageFetchCompleted(n){return this.completedHistoryConversations.has(n)}_parseMessage(n){var r;const g=Oa.CONV_GROUP;n.Event===4&&(n.MsgBody.MsgType=Po.MSG_GRP_TIP);const u=ZD(n),E=Af.createMessage(Object.assign(Object.assign({},u),{conversationType:g,flow:"in"}));return RB(((r=u.elements)===null||r===void 0?void 0:r.content)||{},E),E.setElement(u.elements),E}getC2CRoamingMessagesByAnchor(n){return mA(this,void 0,void 0,function*(){var r;try{const{conversationID:g,count:u,messageID:E,time:m,direction:D,shouldMarkCompleted:v=!1}=n;let T=m,P="";if(!m){const EA=E?De.message.messageDataHandler.findMessage(E):null;if(T=EA?.time||0,E&&this._historyMessageListFetchAnchors.has(g)){const wA=this._historyMessageListFetchAnchors.get(g);T=wA.lastMessageTime,P=wA.messageKey}}const W=g.replace(Oa.CONV_C2C,""),oA=yield of({count:u,lastMessageTime:T,messageKey:P,peerAccount:W,direction:D});if(oA){const{MsgList:EA=[],Complete:wA,MsgKey:kA,LastMsgTime:xA}=oA;this._historyMessageListFetchAnchors.set(g,{messageKey:kA,lastMessageTime:xA});const LA=[];for(let ue=0;ue{const{tag:E,value:m}=u;E&&E.indexOf(sS)>-1?g.profileCustomField.push({key:E,value:m}):kd.has(E)&&(g[kd.get(E)]=m)}),Object.assign(Object.assign({},rf),g)}parseProfileItem(n=[]){const r=[];return n.forEach(g=>{r.push({tag:g.Tag,value:g.Value})}),r}parseProfileList(n=[]){const r=[];return n.forEach(g=>{r.push({tag:g.Tag,value:g.ValueBytes})}),r}convertParamsToProfile(n){const r=[];return Object.keys(n).forEach(g=>{g!==nS&&r.push({tag:ql[g.toUpperCase()],value:n[g]})}),n.profileCustomField&&C(n.profileCustomField)&&n.profileCustomField.forEach(g=>{r.push({tag:g.key,value:g.value})}),r}normalizeProfileFields(n){const r={},g=[];return n.forEach(u=>{const{tag:E,value:m}=u;if(E&&E.indexOf(sS)>-1&&g.push({key:E,value:m}),kd.has(E)&&m!==void 0){const D=kd.get(E);r[D]=m}}),g.length>0&&(r.profileCustomField=g),r}};const{generateProtocolData:xR}=De.common;function YR(n){return mA(this,void 0,void 0,function*(){const r="profile.portrait_get_all",g={From_Account:ar(),UserItem:[]};n.forEach(D=>{g.UserItem.push({CustomSequence:0,StandardSequence:0,To_Account:D})});const u=xR({servcmd:r,data:g}),E=`${u.head.seq}${r}`,m=yield De.channel.sendPacket(u,{requestId:E});if(m)return function(D){const{ActionStatus:v,ErrorCode:T,ErrorDisplay:P,ErrorInfo:W,UserProfileItem:oA}=D,EA=[];return oA.map(wA=>{const{To_Account:kA,CustomSequence:xA,ResultCode:LA,ResultInfo:SA,StandardSequence:OA,ProfileItem:WA}=wA,ue=iE.parseProfileItem(WA);EA.push({userId:kA,customSequence:xA,resultCode:LA,resultInfo:SA,standardSequence:OA,profileItem:ue})}),{actionStatus:v,errorCode:T,errorDisplay:P,errorInfo:W,userProfile:EA}}(m)})}function WE(n){return lc.getFriendMap().has(n)}const{isEmpty:rS}=De.utils;class af{constructor(){this._strangerProfileMap=new Map}init(){Sr.getInstance().registerApi({apiName:"getMyProfile",context:this}),Sr.getInstance().registerApi({apiName:"getUserProfile",context:this}),Sr.getInstance().registerApi({apiName:"updateMyProfile",context:this}),this.createProfile=iE.createProfile.bind(iE);const{notificationCenter:r}=De;Fs.getInstance().registerWorkflowStep(jt.SYNC_SERVER_INFO_AFTER_LOGIN,Xt.USER_PROFILE_SYNC,this.getMyProfileCacheThenServer,this),r.subscribeInnerEvent(lo.MESSAGE_PUSH,r.InnerEventSubType.PROFILE_MODIFIED,this._onProfileDataModify,this),r.subscribeInnerEvent(lo.LOGOUT,this._reset,this),r.subscribeInnerEvent(lo.DESTROY,this._dispose,this)}getMyProfile(){return mA(this,void 0,void 0,function*(){try{const r=ar(),g=yield YR([r]);if(g){const u=this._handleProfileFormResponse(g)[0];return lc.getUserProfileMap().set(r,u),{code:0,data:u}}}catch(r){const{errorCode:g,errorInfo:u}=r;throw new Cs({functionName:"getMyProfile",code:g,message:u})}})}getUserProfile(r){return mA(this,void 0,void 0,function*(){try{let{userIDList:g}=r;const{userIdListToRequest:u,profileFromCache:E}=this._filterRequestAndCacheUsers(g);if(u.length===0)return{code:0,data:E,successLog:{message:`userIDList.length:${g.length}`}};u.length>PR&&(De.ssoLog.warn("getUserProfile","userIdListToRequest.length > 1000"),u.length=PR);const{data:m,error:D}=yield this._batchFetchUserProfiles(u),v=u.length,T=m.length,P=v-T;if(E.length===0&&v===P&&!rS(D))throw D;if(C(m))return m.forEach(oA=>{WE(oA.userID)?lc.getUserProfileMap().set(oA.userID,oA):this._strangerProfileMap.set(oA.userID,oA)}),{code:0,data:m.concat(E),successLog:{message:`getUserProfile query:${v} success:${T} fail:${P} from cache:${E.length}`}}}catch(g){throw new Cs(g)}})}getMyProfileCacheThenServer(){return mA(this,void 0,void 0,function*(){const r=ar(),g=lc.getUserProfileMap().has(r);return g?{code:0,data:g}:this.getMyProfile()})}updateMyProfile(r){return mA(this,void 0,void 0,function*(){const g=ar(),u={};for(const m in r)r[m]!==void 0&&(u[m]=r[m]);const E=iE.convertParamsToProfile(u);try{yield function(P){return mA(this,void 0,void 0,function*(){const W="profile.portrait_set",oA=xR({servcmd:W,data:P}),EA=`${oA.head.seq}${W}`,wA=yield De.channel.sendPacket(oA,{requestId:EA});if(wA){const{ActionStatus:kA,ErrorCode:xA,ErrorDisplay:LA,ErrorInfo:SA}=wA;return{actionStatus:kA,errorCode:xA,errorDisplay:LA,errorInfo:SA}}})}({From_Account:g,ProfileItem:E});const D=lc.getUserProfile(g);let v;v=D?Object.assign(Object.assign({},D),u):iE.createProfile(g,E);const T=!gg(D,v,["lastUpdatedTime"]);return v.lastUpdatedTime=Date.now(),lc.getUserProfileMap().set(g,v),T&&this._emitProfileUpdated(v),{code:0,data:v,successLog:{message:`profileArray: ${De.utils.safeStringify(E)}`}}}catch(m){const{errorCode:D,errorInfo:v}=m;throw new Cs({functionName:"updateMyProfile",code:D,message:v,moreMessage:`params: ${De.utils.safeStringify(r)}`})}})}updateMyNickAndAvatar(r){return mA(this,void 0,void 0,function*(){const g=ar(),u=Date.now(),E=lc.getUserProfile(g);let m={};m=E?Object.assign(E,r):iE.createProfile(g,r),m.lastUpdatedTime=u,lc.getUserProfileMap().set(g,m)})}_onProfileDataModify(r){const g=function(m){const{Profile_Account:D,PushType:v,ProfileList:T}=m;return{userId:D,pushType:v,profileList:iE.parseProfileList(T)}}(r.ProfileDataMod[0]);if(rS(g))return;const{isProfileUpdated:u,profile:E}=this._handleProfileModified(g);u&&this._emitProfileUpdated(E)}_emitProfileUpdated(r){De.notificationCenter.emitInnerEvent(lo.PROFILE_UPDATE,{name:lo.PROFILE_UPDATE,data:[r]}),De.notificationCenter.emitOuterEvent(Rr.PROFILE_UPDATED,{name:Rr.PROFILE_UPDATED,data:[r]}),wB.updateConversation(`C2C${r?.userID}`,{userProfile:r})}_dispose(){const{notificationCenter:r}=De;r.unSubscribeInnerEvent(lo.LOGOUT,this._reset,this),r.unSubscribeInnerEvent(lo.MESSAGE_PUSH,r.InnerEventSubType.PROFILE_MODIFIED,this._onProfileDataModify,this),r.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this),this._reset()}_handleProfileModified(r){const{userId:g,profileList:u}=r,E=lc.getUserProfile(g);if(!(ar()===g||WE(g)&&E))return{isProfileUpdated:!1,profile:null};const m=iE.normalizeProfileFields(u),D=Object.keys(m).some(W=>W===nS?this._isCustomFieldChanged(E.profileCustomField,m.profileCustomField):E[W]!==m[W]);if(!D)return{isProfileUpdated:!1,profile:E};const v=Date.now(),T=Object.prototype.hasOwnProperty.call(m,nS)?this._mergeProfileCustomField(E.profileCustomField,m.profileCustomField):E.profileCustomField,P=Object.assign(Object.assign(Object.assign({},E),m),{profileCustomField:T,lastUpdatedTime:v});return lc.getUserProfileMap().set(g,P),{isProfileUpdated:D,profile:P}}_filterRequestAndCacheUsers(r){const g=[],u=[];return r.forEach(E=>{const m=lc.getUserProfileMap().has(E);WE(E)&&m?u.push(lc.getUserProfile(E)):this._isStrangerAndProfileValid(E)?u.push(this._strangerProfileMap.get(E)):g.push(E)}),{userIdListToRequest:g,profileFromCache:u}}_handleProfileFormResponse(r){const{userProfile:g}=r;if(!Array.isArray(g))return[];const u=g.filter(m=>m.userId!=="@TLS#NOT_FOUND"&&m.userId!==""&&!rS(m.profileItem)),E=Date.now();return u.map(m=>{const D=iE.createProfile(m.userId,m.profileItem);return D.lastUpdatedTime=E,D})}_isStrangerAndProfileValid(r){var g;if(!WE(r)){const{lastUpdatedTime:u=0}=this._strangerProfileMap.get(r)||{},E=((g=De.store.get("cloudConfig"))===null||g===void 0?void 0:g.stranger_profile_expiration_time)||6e5;return Date.now()-u<=E}return!1}_chunkUserIDList(r,g){return Array.from({length:Math.ceil(r.length/g)},(u,E)=>r.slice(E*g,(E+1)*g))}_batchFetchUserProfiles(r){return mA(this,void 0,void 0,function*(){const g=[],u=[];let E={};return this._chunkUserIDList(r,100).forEach(m=>{g.push(YR(m))}),(yield Promise.allSettled(g)).forEach(m=>{if(m.status==="fulfilled"){const D=m.value,v=this._handleProfileFormResponse(D);C(v)&&u.push(...v)}else if(m.status==="rejected"){const{code:D,message:v}=m.reason||{};E={errorCode:D,message:v}}}),{data:u,error:E}})}_isCustomFieldChanged(r=[],g=[]){if(!C(g)||g.length===0)return!1;if(!C(r)||r.length===0)return!0;const u=new Map(r.map(E=>[E.key,E.value]));return g.some(E=>u.get(E.key)!==E.value)}_mergeProfileCustomField(r=[],g=[]){const u=C(r)?r.map(E=>Object.assign({},E)):[];return C(g)&&g.length!==0&&g.forEach(({key:E,value:m})=>{const D=u.find(v=>v.key===E);D?D.value=m:u.push({key:E,value:m})}),u}_reset(){lc.getUserProfileMap().clear(),this._strangerProfileMap.clear()}}const gf=new Map,aS=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];for(let n=0,r=aS.length;n>(-2*m&6)):0)E="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(E);try{return decodeURIComponent(escape(g))}catch(u){return console.warn(u),""}}const{isEmpty:cN}=De.utils,{generateProtocolData:cf}=De.common;function VR(n){return mA(this,void 0,void 0,function*(){const r="im_open_status.ws_get_user_status",g=cf({servcmd:r,data:{To_Account:n}}),u=`${g.head.seq}${r}`,E=yield De.channel.sendPacket(g,{requestId:u});if(E)return function(m){const{ErrorCode:D,ErrorInfo:v,ErrorList:T=[],UserStatusList:P=[]}=m,W=P.map(EA=>{const{To_Account:wA,Status:kA,CustomStatus:xA,Detail:LA=[]}=EA;return{userID:wA,statusType:kA,customStatus:lp(xA),onlineDevices:lN(LA)}}),oA=T.map(EA=>{const{To_Account:wA,Invalid_Account:kA,ErrorCode:xA,ErrorInfo:LA}=EA;return{userID:cN(kA)?wA:kA,code:xA,message:LA}});return{errorCode:D,errorInfo:v,successUserList:W,failureUserList:oA}}(E)})}function lN(n){const r=[];return n?.forEach(g=>{const{Platform:u,Status:E}=g;E==="Online"&&r.push(u)}),r}class IN{constructor(){this._customStatus=""}init(){const{notificationCenter:r}=De;Sr.getInstance().registerApi({apiName:"getUserStatus",context:this}),Sr.getInstance().registerApi({apiName:"setSelfStatus",context:this}),Sr.getInstance().registerApi({apiName:"subscribeUserStatus",context:this}),Sr.getInstance().registerApi({apiName:"unsubscribeUserStatus",context:this}),Fs.getInstance().registerWorkflowStep(jt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,Xt.USER_STATUS_UPDATE,this._onReOnline,this),r.subscribeInnerEvent(lo.MESSAGE_PUSH,r.InnerEventSubType.USER_STATUS_UPDATE,this._onUserStatusUpdate,this),r.subscribeInnerEvent(lo.LOGOUT,this._reset,this),r.subscribeInnerEvent(lo.DESTROY,this._dispose,this)}setSelfStatus(r){return mA(this,void 0,void 0,function*(){const g=ar(),{customStatus:u}=r;try{return yield function(E){return mA(this,void 0,void 0,function*(){const m="im_open_status.ws_set_custom_status",D=cf({servcmd:m,data:{CustomStatus:E}}),v=`${D.head.seq}${m}`,T=yield De.channel.sendPacket(D,{requestId:v});if(T){const{ErrorCode:P,ErrorInfo:W}=T;return{errorCode:P,errorInfo:W}}})}(u),this._customStatus=u,{code:0,data:{userID:g,statusType:Uh,customStatus:u},successLog:{message:`customStatus: ${u}`}}}catch(E){const{errorCode:m,errorInfo:D}=E;throw new Cs({functionName:"setSelfStatus",code:m,message:D})}})}getUserStatus(r){return mA(this,void 0,void 0,function*(){const{userIDList:g=[]}=r;if(this._isOnlyMeInArray(g))return this._getMyStatus();const u=yield this._getUserStatus(g);return Object.assign(Object.assign({},u),{successLog:{message:`userIDList length: ${g.length}`}})})}setCustomStatus(r){const g=lp(r);this._customStatus=g}subscribeUserStatus(r){return mA(this,void 0,void 0,function*(){try{const{userIDList:g=[]}=r;this._checkBusinessCapabilityBits("subscribeUserStatus");const u=this._getMaxUserCount("subscribe"),E=this._sliceUserIDList(g,u),m=yield function(v){return mA(this,void 0,void 0,function*(){const{channel:T}=De,P="im_open_status.ws_status_subscribe",W=cf({servcmd:P,data:{To_Account:v}}),oA=`${W.head.seq}${P}`;return yield T.sendPacket(W,{requestId:oA})})}(E),D=this._parseResponse(m);return{code:0,data:{failureUserList:D},successLog:{message:`userID length:${g.length} failCount: ${D.length}`}}}catch(g){const{errorCode:u}=g;throw new Cs({functionName:"subscribeUserStatus",code:u})}})}unsubscribeUserStatus(r){return mA(this,void 0,void 0,function*(){try{this._checkBusinessCapabilityBits("unsubscribeUserStatus");const{userIDList:g=[]}=r,u=this._getMaxUserCount("unsubscribe"),E=this._sliceUserIDList(g,u),m=yield function(v){return mA(this,void 0,void 0,function*(){const{channel:T}=De,P="im_open_status.ws_status_unsubscribe";let W={};W=v.length===0?{UnsubscribeAll:1}:{To_Account:v};const oA=cf({servcmd:P,data:W}),EA=`${oA.head.seq}${P}`;return yield T.sendPacket(oA,{requestId:EA})})}(E),D=this._parseResponse(m);return{code:0,data:{failureUserList:D},successLog:{message:`userID length:${g.length} failCount: ${D.length}`}}}catch(g){const{errorCode:u}=g;throw new Cs({functionName:"unsubscribeUserStatus",code:u})}})}_onUserStatusUpdate(r){const{UserStatusList:g=[]}=r||{},u=g.map(E=>{const{To_Account:m,Status:D,CustomStatus:v,Platform:T}=E,P={userID:m,statusType:D,customStatus:lp(v)};return T&&(P.onlineDevices=T),P});this._emitUserStatusUpdatedEvent(u)}_onReOnline(r){const g=lp(r.data.customStatus);if(this._customStatus===g)return;this._customStatus=g;const u={userID:ar(),statusType:Uh,customStatus:g};this._emitUserStatusUpdatedEvent(u)}_emitUserStatusUpdatedEvent(r){De.notificationCenter.emitOuterEvent(Rr.USER_STATUS_UPDATED,{name:Rr.USER_STATUS_UPDATED,data:r})}_sliceUserIDList(r,g){return r.slice(0,g)}_parseResponse(r){const{ErrorList:g=[]}=r;return g.map(u=>{const{To_Account:E,Invalid_Account:m,ErrorCode:D,ErrorInfo:v}=u;return{userID:De.utils.isEmpty(m)?E:m,code:D,message:v}})}_checkBusinessCapabilityBits(r){if(!De.store.get("commercialConfig").get(gN))throw new Cs({functionName:r,code:pa.NO_USE,replacement1:r})}_getMaxUserCount(r){const g=De.store.get("cloudConfig")||{},u={query:{key:"status_query_count",default:500},subscribe:{key:"status_sub_count",default:100},unsubscribe:{key:"status_unsub_count",default:100}},{key:E,default:m}=u[r],D=g[E]||m;return parseInt(D,10)}_getMyStatus(){return{code:0,data:{successUserList:[{userID:ar(),statusType:Uh,customStatus:this._customStatus}],failureUserList:[]}}}_getUserStatus(r){return mA(this,void 0,void 0,function*(){try{this._checkBusinessCapabilityBits("getUserStatus");const g=this._getMaxUserCount("query"),u=this._sliceUserIDList(r,g),E=yield VR(u),{successUserList:m,failureUserList:D}=E||{};return{code:0,data:{successUserList:m,failureUserList:D}}}catch(g){const{errorCode:u}=g;throw new Cs({functionName:"getUserStatus",code:u})}})}_isOnlyMeInArray(r){const g=ar();return r.length===1&&r.indexOf(g)>-1}_dispose(){const{notificationCenter:r}=De;r.unSubscribeInnerEvent(lo.MESSAGE_PUSH,r.InnerEventSubType.USER_STATUS_UPDATE,this._onUserStatusUpdate,this),r.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this),r.unSubscribeInnerEvent(lo.LOGOUT,this._reset,this),this._reset()}_reset(){this._customStatus=""}}const gS={getUserProfile:{userIDList:{required:!0,rules:["array"],allowEmpty:!1}},updateMyProfile:{nick:{required:!1,rules:["string"],allowEmpty:!0},avatar:{required:!1,rules:["string"],allowEmpty:!0},gender:{required:!1,rules:["string"],allowEmpty:!0},selfSignature:{required:!1,rules:["string"],allowEmpty:!0},allowType:{required:!1,rules:["string"],allowEmpty:!0},birthday:{required:!1,rules:["number"],allowEmpty:!1},language:{required:!1,rules:["string"],allowEmpty:!0},messageSettings:{required:!1,rules:["string"],allowEmpty:!0},adminForbidType:{required:!1,rules:["string"],allowEmpty:!0},level:{required:!1,rules:["number"],allowEmpty:!1},role:{required:!1,rules:["number"],allowEmpty:!0},profileCustomField:{required:!1,rules:["array"],allowEmpty:!0,customValidator:function(n){for(const r of n){if(typeof r!="object")return"Each item in profileCustomField must be an object";if(typeof r?.key!="string")return"Each item.key in profileCustomField must be a string";if(!r?.key.startsWith(sS))return'Each item.key in profileCustomField must start with "Tag_Profile_Custom"'}return!0}}},setSelfStatus:{customStatus:{required:!0,rules:["string"],allowEmpty:!0}},getUserStatus:{userIDList:{required:!0,rules:["array"],allowEmpty:!1}},subscribeUserStatus:{userIDList:{required:!0,rules:["array"],allowEmpty:!1}},unsubscribeUserStatus:{userIDList:{required:!1,rules:["array"],allowEmpty:!0}}},uN={getMyProfile:!0,getUserProfile:!0,updateMyProfile:!0,setSelfStatus:!0,getUserStatus:!0,subscribeUserStatus:!0,unsubscribeUserStatus:!0};class EN{constructor(){this.userProfile=new af,this.userStatus=new IN,this.userProfile.init(),this.userStatus.init(),el({auth:uN,params:gS})}}function cS(n){const r=[];if(!c(n))return r;const g=n.length;if(g===0)return r;for(let u=g-1;u>=0;u--)n[u]==="1"&&r.push(2**(g-u-1));return r}var Ld,NC,Ud;(function(n){n.NOT_START="notStart",n.PENDING="pending",n.RESOLVED="resolved",n.REJECTED="rejected"})(Ld||(Ld={})),function(n){n[n.C2C=1]="C2C",n[n.GROUP=2]="GROUP"}(NC||(NC={})),function(n){n[n.C2C=8]="C2C",n[n.GROUP=2]="GROUP"}(Ud||(Ud={}));class lS{constructor(){this._name="SyncConversationHandler",this._pagingStatus=Ld.NOT_START,this._pagingTimeStamp=0,this._pagingStartIndex=0,this._pagingPinnedTimeStamp=0,this._pagingPinnedStartIndex=0}init(){const{notificationCenter:r}=De;Fs.getInstance().registerWorkflowStep(jt.SYNC_SERVER_INFO_AFTER_RE_ONLINE,Xt.CONVERSATION_RECOVER,this._syncConversationList,this),Fs.getInstance().registerWorkflowStep(jt.SYNC_SERVER_INFO_AFTER_LOGIN,Xt.CONVERSATION_LIST_SYNC,this._syncConversationListAfterLogin,this),r.subscribeInnerEvent(lo.LOGOUT,this._reset,this),r.subscribeInnerEvent(lo.DESTROY,this._dispose,this),De.ssoLog.debug(`${this._name}.init`)}isSyncCompleted(){return this._pagingStatus===Ld.RESOLVED}_syncConversationListAfterLogin(){return mA(this,void 0,void 0,function*(){return this._pagingStatus=Ld.NOT_START,this._pagingTimeStamp=0,this._pagingStartIndex=0,this._pagingPinnedTimeStamp=0,this._pagingPinnedStartIndex=0,this._syncConversationList()})}_syncConversationList(){return mA(this,void 0,void 0,function*(){const{ssoLog:r,utils:{safeStringify:g}}=De;r.debug("_syncConversationList","start");try{const u=yield this._pagingGetConversationList(!0);this._pagingStatus=Ld.RESOLVED;const{conversationList:E=[]}=u||{};return r.info("_syncConversationList",`success count:${E.length}`),u}catch(u){const E=new Cs(u);r.error("_syncConversationList",`fail ${g(u)}`,{error:E})}})}_pagingGetConversationList(r){return mA(this,void 0,void 0,function*(){try{const g=[];this._pagingStatus=Ld.PENDING;const u=yield function(oA){return mA(this,void 0,void 0,function*(){const{fromAccount:EA,pagingTimeStamp:wA,pagingStartIndex:kA,pagingPinnedTimeStamp:xA,pagingPinnedStartIndex:LA}=oA;return lg({servcmd:"recentcontact.page_get",data:{AssistFlags:31,MsgAssistFlags:15,OrderType:1,From_Account:EA,StartIndex:kA,TimeStamp:wA,TopStartIndex:LA,TopTimeStamp:xA}})})}({fromAccount:ar(),pagingTimeStamp:r?this._pagingTimeStamp:0,pagingStartIndex:r?this._pagingStartIndex:0,pagingPinnedTimeStamp:r?this._pagingPinnedTimeStamp:0,pagingPinnedStartIndex:r?this._pagingPinnedStartIndex:0}),{CompleteFlag:E,SessionItem:m=[],TimeStamp:D,StartIndex:v,TopTimeStamp:T,TopStartIndex:P}=u||{};let W=[];if(E===1&&(this._pagingStatus=Ld.RESOLVED),m.length>0&&(W=this._getConversationOptions(m),g.push(...W)),De.notificationCenter.emitInnerEvent(lo.SYNC_CONVERSATION_LIST,{conversationUpdateFieldList:W}),this._pagingTimeStamp=D,this._pagingStartIndex=v,this._pagingPinnedTimeStamp=T,this._pagingPinnedStartIndex=P,E!==1){const{conversationList:oA}=yield this._pagingGetConversationList(r);g.push(...oA)}return{conversationList:g}}catch(g){throw g}})}_getConversationOptions(r){const{utils:{isUndefined:g}}=De,u=this._convertConversationKey(r);return this._filterValidConversations(u).map(E=>(g(E.lastMsg)&&(E.lastMsg={elements:[]}),E.type===NC.C2C?this._assembleC2COption(E):this._assembleGroupOption(E)))}_filterValidConversations(r){return r.filter(({type:g,userID:u})=>g===NC.C2C&&!function(E){let m;return E.startsWith(Po.CONV_C2C)&&(m=E.replace(Po.CONV_C2C,"")),m==="@TLS#ERROR"||m==="@TLS#NOT_FOUND"}(u)||g===2)}_assembleC2COption(r){var g,u,E,m,D,v,T,P;const W=this._createUserprofile(r);return{conversationID:`${Po.CONV_C2C}${r.userID}`,type:Po.CONV_C2C,lastMessage:{lastTime:r.time,lastSequence:r.sequence,fromAccount:r.lastC2CMsgFromAccount,type:!((g=r.lastMsg)===null||g===void 0)&&g.elements[0]?(u=r.lastMsg)===null||u===void 0?void 0:u.elements[0].type:null,payload:!((E=r.lastMsg)===null||E===void 0)&&E.elements[0]?this._amendLayersOverLimitProp(r.lastMsg.elements[0].content):null,cloudCustomData:((v=(D=(m=r.lastMsg)===null||m===void 0?void 0:m.elements)===null||D===void 0?void 0:D[0])===null||v===void 0?void 0:v.cloudCustomData)||"",isRevoked:r.lastMessageFlag===Ud.C2C,onlineOnlyFlag:!1,nick:"",nameCard:"",version:0,isPeerRead:this._computeIsPeerRead(r),revoker:((P=(T=r.lastMsg)===null||T===void 0?void 0:T.revokerInfo)===null||P===void 0?void 0:P.revoker)||null},unreadCount:0,userProfile:W,peerReadTime:r.peerReadTime,isPinned:r.isPinned===1,customData:r.customMark||"",markList:cS(r.standardMark),conversationGroupList:[],remark:r.friendRemark||"",messageRemindType:this._transMsgRemindType(r.messageRemindType)}}_createUserprofile(r){var g;const{userID:u,nick:E,peerAvatar:m}=r,D=[{tag:"Tag_Profile_IM_Nick",value:E},{tag:"Tag_Profile_IM_Image",value:m}];return(g=De.user.userProfile)===null||g===void 0?void 0:g.createProfile(u,D)}_computeIsPeerRead(r){const g=ar(),{lastC2CMsgFromAccount:u,time:E,c2cPeerReadTime:m}=r;return u===g&&E<=m}_assembleGroupOption(r){var g,u,E,m,D;return{conversationID:`${Po.CONV_GROUP}${r.groupID}`,type:Po.CONV_GROUP,lastMessage:Object.assign(Object.assign({lastTime:r.time,lastSequence:r.sequence,fromAccount:r.msgGroupFromAccount},this._patchTypeAndPayload(r)),{cloudCustomData:((E=(u=(g=r.lastMsg)===null||g===void 0?void 0:g.elements)===null||u===void 0?void 0:u[0])===null||E===void 0?void 0:E.cloudCustomData)||"",isRevoked:r.lastMessageFlag===Ud.GROUP,onlineOnlyFlag:!1,nick:r.msgGroupFromNickName||"",nameCard:r.msgGroupFromCardName||"",revoker:((D=(m=r.lastMsg)===null||m===void 0?void 0:m.revokerInfo)===null||D===void 0?void 0:D.revoker)||null}),groupProfile:{groupID:r.groupID,name:r.groupNick,avatar:r.groupImage,type:r.groupType,nextMessageSeq:r.nextMessageSeq},unreadCount:this._computeGroupUnreadCount(r),peerReadTime:0,isPinned:r.isPinned===1,version:0,customData:r.customMark||"",markList:cS(r.standardMark),conversationGroupList:[],messageRemindType:this._transMsgRemindType(r.messageRemindType),subType:r.groupType}}_convertConversationKey(r){return r.map(g=>({type:g.Type,userID:g.To_Account,nick:g.C2cNick,peerAvatar:g.C2cImage,time:g.MsgTimeStamp,sequence:g.MsgSeq,lastC2CMsgFromAccount:g.LastC2cMsgFrom_Account,lastMsg:this._convertLastMsgKey(g.LastMsg),lastMessageFlag:g.LastMsgFlags,c2cPeerReadTime:g.C2cPeerReadTime,peerReadTime:g.C2cPeerReadTime,friendRemark:g.C2cRemark,isPinned:g.TopFlags,standardMark:g.StandardMark,customMark:g.CustomMark,messageRemindType:g.MsgRecvOption,groupID:g.ToAccount,groupNick:g.GroupNick,groupImage:g.GroupImage,groupType:g.GroupType,nextMessageSeq:g.GroupNextMsgSeq,msgGroupFromAccount:g.MsgGroupFrom_Account,msgGroupFromNickName:g.MsgGroupFromNickName,msgGroupFromCardName:g.MsgGroupFromCardName,unreadCount:g.UnreadMsgCount,noUnreadCount:g.GroupIgnoredUnreadSeqCount}))}_convertLastMsgKey(r){var g,u,E;const{utils:{isEmpty:m}}=De;if(m(r))return null;let D="",v=null;if(!m(r.GroupTips)){const{From_Account:T,GroupName:P}=((g=r.GroupTips)===null||g===void 0?void 0:g.GroupInfo)||{};D=Po.MSG_GRP_TIP,v=Object.assign(Object.assign({},this._parseContent(D,r.GroupTips.MsgBody)),{groupProfile:{from:T,groupName:P}})}return r.MsgBody&&(D=(u=r.MsgBody[0])===null||u===void 0?void 0:u.MsgType,v=this._parseContent(D,r.MsgBody[0])),{event:r.Event,elements:[{type:D,content:v,cloudCustomData:r.CloudCustomData}],revokerInfo:{revoker:(E=r.RevokerInfo)===null||E===void 0?void 0:E.Revoker_Account}}}_parseContent(r,g){var u;if(!g)return g;const E=De.message.messageFactory.getElementClass(r);return E?(u=E.parseServerPushElement(g))===null||u===void 0?void 0:u.content:g}_amendLayersOverLimitProp(r){const{LayersOverLimit:g}=r;return vo(r,["LayersOverLimit"]).layersOverLimit=g===1,r}_transMsgRemindType(r){let g="";return r===0?g=Po.MSG_REMIND_ACPT_AND_NOTE:r===1?g=Po.MSG_REMIND_DISCARD:r===2?g=Po.MSG_REMIND_ACPT_NOT_NOTE:r===3&&(g=Po.NOT_RECEIVE_OFFLINE_PUSH_EXCEPT_AT),g}_patchTypeAndPayload(r){var g;const{utils:{isUndefined:u}}=De,{event:E,elements:m=[]}=r.lastMsg||{};return u(E)?{type:m[0]?m[0].type:null,payload:m[0]?this._amendLayersOverLimitProp(m[0].content):null}:{type:Po.MSG_GRP_TIP,payload:((g=m?.[0])===null||g===void 0?void 0:g.content)||{}}}_computeGroupUnreadCount(r){const{unreadCount:g=0,noUnreadCount:u=0}=r,E=g-u;return E>0?E:0}_reset(){this._pagingStatus=Ld.NOT_START,this._pagingTimeStamp=0,this._pagingStartIndex=0,this._pagingPinnedTimeStamp=0,this._pagingPinnedStartIndex=0}_dispose(){this._reset();const{notificationCenter:r}=De;r.unSubscribeInnerEvent(lo.LOGOUT,this._reset,this),r.unSubscribeInnerEvent(lo.DESTROY,this._dispose,this)}}class IS{constructor(){this.syncConversationHandler=new lS,this.syncConversationHandler.init()}}console.log(`TencentCloudLiteChat.VERSION:${Aa}`);var uS={create:function(n){var r,g;const{SDKAppID:u,testEnv:E=!1,devMode:m=!1,unlimitedAVChatRoom:D=!1,scene:v="",oversea:T=!1,instance:P,disableIndependentDomain:W=!1,proxyServer:oA=""}=n;let EA=u;if(!function(kA){if(typeof kA=="number")return!0;const xA=Number(kA);return!Number.isNaN(xA)}(EA))return console.error("Create SDK instance failed. Failed to parse the SDKAppID, please check the arguments"),null;if(EA=Number(EA),ma.has(EA))return ma.get(EA);let wA=null;if(P)wA=P,wA._workflowManager&&Fs.setInstance(wA._workflowManager),wA._pluginManager&&wA._pluginManager.installBuiltInPlugin(MB),P.isReady()&&((g=(r=Fs.getInstance()).executeWorkflow)===null||g===void 0||g.call(r,jt.SYNC_SERVER_INFO_AFTER_LOGIN));else{const kA=function(){function ue(){return(65536*(1+Math.random())|0).toString(16).substring(1)}return`${ue()+ue()}${ue()}${ue()}${ue()}${ue()}${ue()}${ue()}`}();De.init({sdkAppId:EA,instanceId:kA,testEnv:E,devMode:m,unlimitedAVChatRoom:D,disableIndependentDomain:W,scene:v,oversea:T,sdkEdition:$m,version:Aa,proxyServer:oA}),Fs.getInstance().init(),De.message=new oS,De.user=new EN,De.login=new Th,De.conversation=new IS,Iu.getInstance().installBuiltInPlugin(MB),wA=Sr.getInstance().exposeApiForClient(),wA._workflowManager=Fs.getInstance(),wA._pluginManager=Iu.getInstance();const{utils:{IS_WORKER_AVAILABLE:xA,USER_AGENT:LA,getPlatformType:SA,isIOSWebView:OA}}=De,WA=`instanceID:${kA} SDKAppID:${u} platform:${HA} host:${SA()} isIOSWebView:${OA} workerAvailable:${xA} UserAgent:${LA}`;De.ssoLog.info("sdkConstruct",WA)}return ma.set(EA,wA),wA},TSignaling:Xc,EVENT:Rr,VERSION:Aa,TYPES:Po};return uS})}(uY)),uY.exports}var ksA=bsA();const ng=ZW(ksA);var EY={exports:{}},LsA=EY.exports,F8;function UsA(){return F8||(F8=1,function(t,i){(function(s,c){t.exports=c()})(LsA,function(){function s(ge,Ve){if(!(ge instanceof Ve))throw new TypeError("Cannot call a class as a function")}function c(ge,Ve){for(var Qt=0;Qt"u"&&typeof uni.requireNativePlugin=="function",KA=RA&&uni.getDeviceInfo().platform.toLocaleLowerCase()==="ios",$A=(RA&&uni.getDeviceInfo().platform.toLocaleLowerCase(),lA||tA||BA||IA||gA||RA),jA=L!==void 0&&(L.nativeModuleProxy!==void 0||L.ReactNative!==void 0),Qe=tA?qq:BA?tt:IA?swan:gA?my:lA?wx:RA?uni:{},ae=function(ge){if(N(ge)!=="object"||ge===null)return!1;var Ve=Object.getPrototypeOf(ge);if(Ve===null)return!0;for(var Qt=Ve;Object.getPrototypeOf(Qt)!==null;)Qt=Object.getPrototypeOf(Qt);return Ve===Qt};function st(ge){if(ge==null)return!0;if(typeof ge=="boolean")return!1;if(typeof ge=="number")return ge===0;if(typeof ge=="string"||typeof ge=="function"||Array.isArray(ge))return ge.length===0;if(ge instanceof Error)return ge.message==="";if(ae(ge)){for(var Ve in ge)if(Object.prototype.hasOwnProperty.call(ge,Ve))return!1;return!0}return!1}var Ct=function(){return I(function ge(){s(this,ge),this._n="WebRequest"},[{key:"request",value:function(ge,Ve){var Qt=this,Ai="".concat(this._n,".request"),Pt=ge.downloadUrl||"",ii=(ge.method||"PUT").toUpperCase(),bi=ge.url;if(console.log("%c tim-upload-plugin %c","background:#0abf5b; padding:1px; border-radius:3px; color: #fff","background:transparent","".concat(Ai," URL:").concat(bi)),ge.qs){var ao=function(Ui){var es=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"&",Ro=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"=";return st(Ui)?"":ae(Ui)?Object.keys(Ui).map(function(oo){var $t=encodeURIComponent(oo)+Ro;return Array.isArray(Ui[oo])?Ui[oo].map(function(so){return $t+encodeURIComponent(so)}).join(es):$t+encodeURIComponent(Ui[oo])}).filter(Boolean).join(es):void 0}(ge.qs);ao&&(bi+="".concat(bi.indexOf("?")===-1?"?":"&").concat(ao))}var Hi=new XMLHttpRequest;Hi.open(ii,bi,!0),Hi.responseType=ge.dataType||"text";var Vi=ge.headers||{};if(ge.uploadByIP&&(Vi=w(w({},Vi),{},{host:ge.uploadIP})),!st(Vi))for(var ws in Vi)Vi.hasOwnProperty(ws)&&ws.toLowerCase()!=="content-length"&&ws.toLowerCase()!=="user-agent"&&ws.toLowerCase()!=="origin"&&ws.toLowerCase()!=="host"&&Hi.setRequestHeader(ws,Vi[ws]);return Hi.onload=function(){if(Hi.status===200)Ve(null,Qt._xhrRes(Hi,Qt._xhrBody(Hi,Pt,ge.uploadByIP&&ge.uploadIP),Vi));else{if(ge.uploadIP&&ge.url.indexOf(ge.uploadIP)===-1)return ge.url=function(es,Ro){return es.replace(/^http(s)?:\/\/(.*?)\//,"https://".concat(Ro,"/"))}(ge.url,ge.uploadIP),ge.uploadByIP=!0,Qt.request(ge,Ve);var Ui={code:Hi.status,message:JSON.stringify(Hi.responseText)};Ve(Ui,Qt._xhrRes(Hi,Qt._xhrBody(Hi,Pt,ge.uploadByIP&&ge.uploadIP),Vi))}},Hi.onerror=function(Ui){var es=Qt._xhrBody(Hi,Pt,ge.uploadByIP&&ge.uploadIP),Ro={code:Hi.status,message:JSON.stringify(Hi.responseText)};es||Hi.statusText||Hi.status!==0||(Ui.message="CORS blocked or network error"),Ve(Ro,Qt._xhrRes(Hi,es)),Ro=null},ge.onProgress&&Hi.upload&&(Hi.upload.onprogress=function(Ui){var es=Ui.total,Ro=Ui.loaded,oo=Math.floor(100*Ro/es);ge.onProgress({total:es,loaded:Ro,percent:(oo>=100?100:oo)/100})}),Hi.send(ge.resources),Hi}},{key:"_xhrRes",value:function(ge,Ve){var Qt={};return ge.getAllResponseHeaders().trim().split(`
+`).forEach(function(Ai){if(Ai){var Pt=Ai.indexOf(":"),ii=Ai.substr(0,Pt).trim().toLowerCase(),bi=Ai.substr(Pt+1).trim();Qt[ii]=bi}}),{statusCode:ge.status,statusMessage:ge.statusText,headers:Qt,data:Ve}}},{key:"_xhrBody",value:function(ge,Ve,Qt){return ge.status===200&&Ve?{location:Ve,uploadIP:Qt}:{response:ge.responseText,uploadIP:Qt}}}])}(),We=["unknown","image","video","audio","log"],Te=["name"],ot=function(){return I(function ge(){s(this,ge)},[{key:"request",value:function(ge,Ve){var Qt=this,Ai=ge.resources,Pt=Ai===void 0?"":Ai,ii=ge.headers,bi=ii===void 0?{}:ii,ao=ge.url,Hi=ge.downloadUrl,Vi=Hi===void 0?"":Hi,ws=ao,Ui=null,es=Vi.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/),Ro=decodeURIComponent(es[3]),oo=Ro.indexOf("?")>-1?Ro.split("?")[0]:Ro,$t={key:ge.fileKey?ge.fileKey:oo,success_action_status:200,"Content-Type":""},so={};if(KA){var Ri=ao.split("?sign=");if(Ri.length>1){var Qs=Ri[1];ws="".concat(Ri[0],"?sign=").concat(encodeURIComponent("".concat(Qs))),so.sign=decodeURIComponent(Qs),so.signature=decodeURIComponent(Qs)}}var HA={url:ws,header:bi,name:"file",filePath:Pt,formData:w(w({},$t),so),timeout:ge.timeout||3e5};if(gA){var Ie=HA;Ie.name,HA=w(w({},function(Ye,Lt){if(Ye==null)return{};var at,Et,ei=function(Le,$e){if(Le==null)return{};var Tt={};for(var Gt in Le)if({}.hasOwnProperty.call(Le,Gt)){if($e.includes(Gt))continue;Tt[Gt]=Le[Gt]}return Tt}(Ye,Lt);if(Object.getOwnPropertySymbols){var Jt=Object.getOwnPropertySymbols(Ye);for(Et=0;Et=3e4&&(this.systemClockOffset=ao-bi,Ve=!0)}else Math.floor(ge.statusCode/100)===5&&(Ve=!0)}return Ve}}],[{key:"getVersion",value:function(){return"1.4.3"}}])}()})}(EY)),EY.exports}var FsA=UsA();const OsA=ZW(FsA);/**
* @vue/shared v3.5.13
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
-**//*! #__NO_SIDE_EFFECTS__ */function DW(t){const i=Object.create(null);for(const r of t.split(","))i[r]=1;return r=>r in i}const Da={},H_=[],RQ=()=>{},XoA=()=>!1,$Y=t=>t.charCodeAt(0)===111&&t.charCodeAt(1)===110&&(t.charCodeAt(2)>122||t.charCodeAt(2)<97),SW=t=>t.startsWith("onUpdate:"),sI=Object.assign,MW=(t,i)=>{const r=t.indexOf(i);r>-1&&t.splice(r,1)},$oA=Object.prototype.hasOwnProperty,Wr=(t,i)=>$oA.call(t,i),Ms=Array.isArray,q_=t=>AV(t)==="[object Map]",B6=t=>AV(t)==="[object Set]",$s=t=>typeof t=="function",fg=t=>typeof t=="string",Cm=t=>typeof t=="symbol",Na=t=>t!==null&&typeof t=="object",Q6=t=>(Na(t)||$s(t))&&$s(t.then)&&$s(t.catch),p6=Object.prototype.toString,AV=t=>p6.call(t),AsA=t=>AV(t).slice(8,-1),m6=t=>AV(t)==="[object Object]",vW=t=>fg(t)&&t!=="NaN"&&t[0]!=="-"&&""+parseInt(t,10)===t,jL=DW(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),eV=t=>{const i=Object.create(null);return r=>i[r]||(i[r]=t(r))},esA=/-(\w)/g,sh=eV(t=>t.replace(esA,(i,r)=>r?r.toUpperCase():"")),tsA=/\B([A-Z])/g,rD=eV(t=>t.replace(tsA,"-$1").toLowerCase()),tV=eV(t=>t.charAt(0).toUpperCase()+t.slice(1)),Dj=eV(t=>t?`on${tV(t)}`:""),Wy=(t,i)=>!Object.is(t,i),X1=(t,...i)=>{for(let r=0;r{Object.defineProperty(t,i,{configurable:!0,enumerable:!1,writable:l,value:r})},p3=t=>{const i=parseFloat(t);return isNaN(i)?t:i},isA=t=>{const i=fg(t)?Number(t):NaN;return isNaN(i)?t:i};let a8;const iV=()=>a8||(a8=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Br(t){if(Ms(t)){const i={};for(let r=0;r{if(r){const l=r.split(ssA);l.length>1&&(i[l[0].trim()]=l[1].trim())}}),i}function qi(t){let i="";if(fg(t))i=t;else if(Ms(t))for(let r=0;r!!(t&&t.__v_isRef===!0),ii=t=>fg(t)?t:t==null?"":Ms(t)||Na(t)&&(t.toString===p6||!$s(t.toString))?D6(t)?ii(t.value):JSON.stringify(t,S6,2):String(t),S6=(t,i)=>D6(i)?S6(t,i.value):q_(i)?{[`Map(${i.size})`]:[...i.entries()].reduce((r,[l,I],h)=>(r[Sj(l,h)+" =>"]=I,r),{})}:B6(i)?{[`Set(${i.size})`]:[...i.values()].map(r=>Sj(r))}:Cm(i)?Sj(i):Na(i)&&!Ms(i)&&!m6(i)?String(i):i,Sj=(t,i="")=>{var r;return Cm(t)?`Symbol(${(r=t.description)!=null?r:i})`:t};/**
+**//*! #__NO_SIDE_EFFECTS__ */function XW(t){const i=Object.create(null);for(const s of t.split(","))i[s]=1;return s=>s in i}const wa={},AT=[],NQ=()=>{},PsA=()=>!1,pV=t=>t.charCodeAt(0)===111&&t.charCodeAt(1)===110&&(t.charCodeAt(2)>122||t.charCodeAt(2)<97),$W=t=>t.startsWith("onUpdate:"),cI=Object.assign,A4=(t,i)=>{const s=t.indexOf(i);s>-1&&t.splice(s,1)},xsA=Object.prototype.hasOwnProperty,$r=(t,i)=>xsA.call(t,i),ks=Array.isArray,eT=t=>mV(t)==="[object Map]",X6=t=>mV(t)==="[object Set]",cn=t=>typeof t=="function",Dg=t=>typeof t=="string",mm=t=>typeof t=="symbol",La=t=>t!==null&&typeof t=="object",$6=t=>(La(t)||cn(t))&&cn(t.then)&&cn(t.catch),A9=Object.prototype.toString,mV=t=>A9.call(t),YsA=t=>mV(t).slice(8,-1),e9=t=>mV(t)==="[object Object]",e4=t=>Dg(t)&&t!=="NaN"&&t[0]!=="-"&&""+parseInt(t,10)===t,rU=XW(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),fV=t=>{const i=Object.create(null);return s=>i[s]||(i[s]=t(s))},VsA=/-(\w)/g,gh=fV(t=>t.replace(VsA,(i,s)=>s?s.toUpperCase():"")),JsA=/\B([A-Z])/g,ED=fV(t=>t.replace(JsA,"-$1").toLowerCase()),yV=fV(t=>t.charAt(0).toUpperCase()+t.slice(1)),qj=fV(t=>t?`on${yV(t)}`:""),Xy=(t,i)=>!Object.is(t,i),dY=(t,...i)=>{for(let s=0;s{Object.defineProperty(t,i,{configurable:!0,enumerable:!1,writable:c,value:s})},J3=t=>{const i=parseFloat(t);return isNaN(i)?t:i},HsA=t=>{const i=Dg(t)?Number(t):NaN;return isNaN(i)?t:i};let O8;const DV=()=>O8||(O8=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function lr(t){if(ks(t)){const i={};for(let s=0;s{if(s){const c=s.split(KsA);c.length>1&&(i[c[0].trim()]=c[1].trim())}}),i}function Pi(t){let i="";if(Dg(t))i=t;else if(ks(t))for(let s=0;s!!(t&&t.__v_isRef===!0),ft=t=>Dg(t)?t:t==null?"":ks(t)||La(t)&&(t.toString===A9||!cn(t.toString))?o9(t)?ft(t.value):JSON.stringify(t,s9,2):String(t),s9=(t,i)=>o9(i)?s9(t,i.value):eT(i)?{[`Map(${i.size})`]:[...i.entries()].reduce((s,[c,I],C)=>(s[Kj(c,C)+" =>"]=I,s),{})}:X6(i)?{[`Set(${i.size})`]:[...i.values()].map(s=>Kj(s))}:mm(i)?Kj(i):La(i)&&!ks(i)&&!e9(i)?String(i):i,Kj=(t,i="")=>{var s;return mm(t)?`Symbol(${(s=t.description)!=null?s:i})`:t};/**
* @vue/reactivity v3.5.13
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
-**/let iC;class lsA{constructor(i=!1){this.detached=i,this._active=!0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=iC,!i&&iC&&(this.index=(iC.scopes||(iC.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let i,r;if(this.scopes)for(i=0,r=this.scopes.length;i0)return;if(zL){let i=zL;for(zL=void 0;i;){const r=i.next;i.next=void 0,i.flags&=-9,i=r}}let t;for(;WL;){let i=WL;for(WL=void 0;i;){const r=i.next;if(i.next=void 0,i.flags&=-9,i.flags&1)try{i.trigger()}catch(l){t||(t=l)}i=r}}if(t)throw t}function w6(t){for(let i=t.deps;i;i=i.nextDep)i.version=-1,i.prevActiveLink=i.dep.activeLink,i.dep.activeLink=i}function _6(t){let i,r=t.depsTail,l=r;for(;l;){const I=l.prevDep;l.version===-1?(l===r&&(r=I),_W(l),usA(l)):i=l,l.dep.activeLink=l.prevActiveLink,l.prevActiveLink=void 0,l=I}t.deps=i,t.depsTail=r}function m3(t){for(let i=t.deps;i;i=i.nextDep)if(i.dep.version!==i.version||i.dep.computed&&(T6(i.dep.computed)||i.dep.version!==i.version))return!0;return!!t._dirty}function T6(t){if(t.flags&4&&!(t.flags&16)||(t.flags&=-17,t.globalVersion===dU))return;t.globalVersion=dU;const i=t.dep;if(t.flags|=2,i.version>0&&!t.isSSR&&t.deps&&!m3(t)){t.flags&=-3;return}const r=_a,l=sB;_a=t,sB=!0;try{w6(t);const I=t.fn(t._value);(i.version===0||Wy(I,t._value))&&(t._value=I,i.version++)}catch(I){throw i.version++,I}finally{_a=r,sB=l,_6(t),t.flags&=-3}}function _W(t,i=!1){const{dep:r,prevSub:l,nextSub:I}=t;if(l&&(l.nextSub=I,t.prevSub=void 0),I&&(I.prevSub=l,t.nextSub=void 0),r.subs===t&&(r.subs=l,!l&&r.computed)){r.computed.flags&=-5;for(let h=r.computed.deps;h;h=h.nextDep)_W(h,!0)}!i&&!--r.sc&&r.map&&r.map.delete(r.key)}function usA(t){const{prevDep:i,nextDep:r}=t;i&&(i.nextDep=r,t.prevDep=void 0),r&&(r.prevDep=i,t.nextDep=void 0)}let sB=!0;const N6=[];function aD(){N6.push(sB),sB=!1}function gD(){const t=N6.pop();sB=t===void 0?!0:t}function g8(t){const{cleanup:i}=t;if(t.cleanup=void 0,i){const r=_a;_a=void 0;try{i()}finally{_a=r}}}let dU=0;class EsA{constructor(i,r){this.sub=i,this.dep=r,this.version=r.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class TW{constructor(i){this.computed=i,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0}track(i){if(!_a||!sB||_a===this.computed)return;let r=this.activeLink;if(r===void 0||r.sub!==_a)r=this.activeLink=new EsA(_a,this),_a.deps?(r.prevDep=_a.depsTail,_a.depsTail.nextDep=r,_a.depsTail=r):_a.deps=_a.depsTail=r,G6(r);else if(r.version===-1&&(r.version=this.version,r.nextDep)){const l=r.nextDep;l.prevDep=r.prevDep,r.prevDep&&(r.prevDep.nextDep=l),r.prevDep=_a.depsTail,r.nextDep=void 0,_a.depsTail.nextDep=r,_a.depsTail=r,_a.deps===r&&(_a.deps=l)}return r}trigger(i){this.version++,dU++,this.notify(i)}notify(i){RW();try{for(let r=this.subs;r;r=r.prevSub)r.sub.notify()&&r.sub.dep.notify()}finally{wW()}}}function G6(t){if(t.dep.sc++,t.sub.flags&4){const i=t.dep.computed;if(i&&!t.dep.subs){i.flags|=20;for(let l=i.deps;l;l=l.nextDep)G6(l)}const r=t.dep.subs;r!==t&&(t.prevSub=r,r&&(r.nextSub=t)),t.dep.subs=t}}const CY=new WeakMap,Qv=Symbol(""),f3=Symbol(""),CU=Symbol("");function pu(t,i,r){if(sB&&_a){let l=CY.get(t);l||CY.set(t,l=new Map);let I=l.get(r);I||(l.set(r,I=new TW),I.map=l,I.key=r),I.track()}}function lm(t,i,r,l,I,h){const f=CY.get(t);if(!f){dU++;return}const w=_=>{_&&_.trigger()};if(RW(),i==="clear")f.forEach(w);else{const _=Ms(t),b=_&&vW(r);if(_&&r==="length"){const U=Number(l);f.forEach((j,IA)=>{(IA==="length"||IA===CU||!Cm(IA)&&IA>=U)&&w(j)})}else switch((r!==void 0||f.has(void 0))&&w(f.get(r)),b&&w(f.get(CU)),i){case"add":_?b&&w(f.get("length")):(w(f.get(Qv)),q_(t)&&w(f.get(f3)));break;case"delete":_||(w(f.get(Qv)),q_(t)&&w(f.get(f3)));break;case"set":q_(t)&&w(f.get(Qv));break}}wW()}function dsA(t,i){const r=CY.get(t);return r&&r.get(i)}function f_(t){const i=Gr(t);return i===t?i:(pu(i,"iterate",CU),th(t)?i:i.map(mu))}function oV(t){return pu(t=Gr(t),"iterate",CU),t}const CsA={__proto__:null,[Symbol.iterator](){return vj(this,Symbol.iterator,mu)},concat(...t){return f_(this).concat(...t.map(i=>Ms(i)?f_(i):i))},entries(){return vj(this,"entries",t=>(t[1]=mu(t[1]),t))},every(t,i){return im(this,"every",t,i,void 0,arguments)},filter(t,i){return im(this,"filter",t,i,r=>r.map(mu),arguments)},find(t,i){return im(this,"find",t,i,mu,arguments)},findIndex(t,i){return im(this,"findIndex",t,i,void 0,arguments)},findLast(t,i){return im(this,"findLast",t,i,mu,arguments)},findLastIndex(t,i){return im(this,"findLastIndex",t,i,void 0,arguments)},forEach(t,i){return im(this,"forEach",t,i,void 0,arguments)},includes(...t){return Rj(this,"includes",t)},indexOf(...t){return Rj(this,"indexOf",t)},join(t){return f_(this).join(t)},lastIndexOf(...t){return Rj(this,"lastIndexOf",t)},map(t,i){return im(this,"map",t,i,void 0,arguments)},pop(){return QL(this,"pop")},push(...t){return QL(this,"push",t)},reduce(t,...i){return c8(this,"reduce",t,i)},reduceRight(t,...i){return c8(this,"reduceRight",t,i)},shift(){return QL(this,"shift")},some(t,i){return im(this,"some",t,i,void 0,arguments)},splice(...t){return QL(this,"splice",t)},toReversed(){return f_(this).toReversed()},toSorted(t){return f_(this).toSorted(t)},toSpliced(...t){return f_(this).toSpliced(...t)},unshift(...t){return QL(this,"unshift",t)},values(){return vj(this,"values",mu)}};function vj(t,i,r){const l=oV(t),I=l[i]();return l!==t&&!th(t)&&(I._next=I.next,I.next=()=>{const h=I._next();return h.value&&(h.value=r(h.value)),h}),I}const hsA=Array.prototype;function im(t,i,r,l,I,h){const f=oV(t),w=f!==t&&!th(t),_=f[i];if(_!==hsA[i]){const j=_.apply(t,h);return w?mu(j):j}let b=r;f!==t&&(w?b=function(j,IA){return r.call(this,mu(j),IA,t)}:r.length>2&&(b=function(j,IA){return r.call(this,j,IA,t)}));const U=_.call(f,b,l);return w&&I?I(U):U}function c8(t,i,r,l){const I=oV(t);let h=r;return I!==t&&(th(t)?r.length>3&&(h=function(f,w,_){return r.call(this,f,w,_,t)}):h=function(f,w,_){return r.call(this,f,mu(w),_,t)}),I[i](h,...l)}function Rj(t,i,r){const l=Gr(t);pu(l,"iterate",CU);const I=l[i](...r);return(I===-1||I===!1)&&bW(r[0])?(r[0]=Gr(r[0]),l[i](...r)):I}function QL(t,i,r=[]){aD(),RW();const l=Gr(t)[i].apply(t,r);return wW(),gD(),l}const BsA=DW("__proto__,__v_isRef,__isVue"),b6=new Set(Object.getOwnPropertyNames(Symbol).filter(t=>t!=="arguments"&&t!=="caller").map(t=>Symbol[t]).filter(Cm));function QsA(t){Cm(t)||(t=String(t));const i=Gr(this);return pu(i,"has",t),i.hasOwnProperty(t)}class k6{constructor(i=!1,r=!1){this._isReadonly=i,this._isShallow=r}get(i,r,l){if(r==="__v_skip")return i.__v_skip;const I=this._isReadonly,h=this._isShallow;if(r==="__v_isReactive")return!I;if(r==="__v_isReadonly")return I;if(r==="__v_isShallow")return h;if(r==="__v_raw")return l===(I?h?wsA:O6:h?F6:U6).get(i)||Object.getPrototypeOf(i)===Object.getPrototypeOf(l)?i:void 0;const f=Ms(i);if(!I){let _;if(f&&(_=CsA[r]))return _;if(r==="hasOwnProperty")return QsA}const w=Reflect.get(i,r,iI(i)?i:l);return(Cm(r)?b6.has(r):BsA(r))||(I||pu(i,"get",r),h)?w:iI(w)?f&&vW(r)?w:w.value:Na(w)?I?PI(w):dv(w):w}}class L6 extends k6{constructor(i=!1){super(!1,i)}set(i,r,l,I){let h=i[r];if(!this._isShallow){const _=Tv(h);if(!th(l)&&!Tv(l)&&(h=Gr(h),l=Gr(l)),!Ms(i)&&iI(h)&&!iI(l))return _?!1:(h.value=l,!0)}const f=Ms(i)&&vW(r)?Number(r)t,_1=t=>Reflect.getPrototypeOf(t);function DsA(t,i,r){return function(...l){const I=this.__v_raw,h=Gr(I),f=q_(h),w=t==="entries"||t===Symbol.iterator&&f,_=t==="keys"&&f,b=I[t](...l),U=r?y3:i?D3:mu;return!i&&pu(h,"iterate",_?f3:Qv),{next(){const{value:j,done:IA}=b.next();return IA?{value:j,done:IA}:{value:w?[U(j[0]),U(j[1])]:U(j),done:IA}},[Symbol.iterator](){return this}}}}function T1(t){return function(...i){return t==="delete"?!1:t==="clear"?void 0:this}}function SsA(t,i){const r={get(I){const h=this.__v_raw,f=Gr(h),w=Gr(I);t||(Wy(I,w)&&pu(f,"get",I),pu(f,"get",w));const{has:_}=_1(f),b=i?y3:t?D3:mu;if(_.call(f,I))return b(h.get(I));if(_.call(f,w))return b(h.get(w));h!==f&&h.get(I)},get size(){const I=this.__v_raw;return!t&&pu(Gr(I),"iterate",Qv),Reflect.get(I,"size",I)},has(I){const h=this.__v_raw,f=Gr(h),w=Gr(I);return t||(Wy(I,w)&&pu(f,"has",I),pu(f,"has",w)),I===w?h.has(I):h.has(I)||h.has(w)},forEach(I,h){const f=this,w=f.__v_raw,_=Gr(w),b=i?y3:t?D3:mu;return!t&&pu(_,"iterate",Qv),w.forEach((U,j)=>I.call(h,b(U),b(j),f))}};return sI(r,t?{add:T1("add"),set:T1("set"),delete:T1("delete"),clear:T1("clear")}:{add(I){!i&&!th(I)&&!Tv(I)&&(I=Gr(I));const h=Gr(this);return _1(h).has.call(h,I)||(h.add(I),lm(h,"add",I,I)),this},set(I,h){!i&&!th(h)&&!Tv(h)&&(h=Gr(h));const f=Gr(this),{has:w,get:_}=_1(f);let b=w.call(f,I);b||(I=Gr(I),b=w.call(f,I));const U=_.call(f,I);return f.set(I,h),b?Wy(h,U)&&lm(f,"set",I,h):lm(f,"add",I,h),this},delete(I){const h=Gr(this),{has:f,get:w}=_1(h);let _=f.call(h,I);_||(I=Gr(I),_=f.call(h,I)),w&&w.call(h,I);const b=h.delete(I);return _&&lm(h,"delete",I,void 0),b},clear(){const I=Gr(this),h=I.size!==0,f=I.clear();return h&&lm(I,"clear",void 0,void 0),f}}),["keys","values","entries",Symbol.iterator].forEach(I=>{r[I]=DsA(I,t,i)}),r}function NW(t,i){const r=SsA(t,i);return(l,I,h)=>I==="__v_isReactive"?!t:I==="__v_isReadonly"?t:I==="__v_raw"?l:Reflect.get(Wr(r,I)&&I in l?r:l,I,h)}const MsA={get:NW(!1,!1)},vsA={get:NW(!1,!0)},RsA={get:NW(!0,!1)};const U6=new WeakMap,F6=new WeakMap,O6=new WeakMap,wsA=new WeakMap;function _sA(t){switch(t){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function TsA(t){return t.__v_skip||!Object.isExtensible(t)?0:_sA(AsA(t))}function dv(t){return Tv(t)?t:GW(t,!1,msA,MsA,U6)}function NsA(t){return GW(t,!1,ysA,vsA,F6)}function PI(t){return GW(t,!0,fsA,RsA,O6)}function GW(t,i,r,l,I){if(!Na(t)||t.__v_raw&&!(i&&t.__v_isReactive))return t;const h=I.get(t);if(h)return h;const f=TsA(t);if(f===0)return t;const w=new Proxy(t,f===2?l:r);return I.set(t,w),w}function K_(t){return Tv(t)?K_(t.__v_raw):!!(t&&t.__v_isReactive)}function Tv(t){return!!(t&&t.__v_isReadonly)}function th(t){return!!(t&&t.__v_isShallow)}function bW(t){return t?!!t.__v_raw:!1}function Gr(t){const i=t&&t.__v_raw;return i?Gr(i):t}function GsA(t){return!Wr(t,"__v_skip")&&Object.isExtensible(t)&&f6(t,"__v_skip",!0),t}const mu=t=>Na(t)?dv(t):t,D3=t=>Na(t)?PI(t):t;function iI(t){return t?t.__v_isRef===!0:!1}function We(t){return bsA(t,!1)}function bsA(t,i){return iI(t)?t:new ksA(t,i)}class ksA{constructor(i,r){this.dep=new TW,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=r?i:Gr(i),this._value=r?i:mu(i),this.__v_isShallow=r}get value(){return this.dep.track(),this._value}set value(i){const r=this._rawValue,l=this.__v_isShallow||th(i)||Tv(i);i=l?i:Gr(i),Wy(i,r)&&(this._rawValue=i,this._value=l?i:mu(i),this.dep.trigger())}}function aA(t){return iI(t)?t.value:t}const LsA={get:(t,i,r)=>i==="__v_raw"?t:aA(Reflect.get(t,i,r)),set:(t,i,r,l)=>{const I=t[i];return iI(I)&&!iI(r)?(I.value=r,!0):Reflect.set(t,i,r,l)}};function P6(t){return K_(t)?t:new Proxy(t,LsA)}function Gs(t){const i=Ms(t)?new Array(t.length):{};for(const r in t)i[r]=x6(t,r);return i}class UsA{constructor(i,r,l){this._object=i,this._key=r,this._defaultValue=l,this.__v_isRef=!0,this._value=void 0}get value(){const i=this._object[this._key];return this._value=i===void 0?this._defaultValue:i}set value(i){this._object[this._key]=i}get dep(){return dsA(Gr(this._object),this._key)}}class FsA{constructor(i){this._getter=i,this.__v_isRef=!0,this.__v_isReadonly=!0,this._value=void 0}get value(){return this._value=this._getter()}}function wj(t,i,r){return iI(t)?t:$s(t)?new FsA(t):Na(t)&&arguments.length>1?x6(t,i,r):We(t)}function x6(t,i,r){const l=t[i];return iI(l)?l:new UsA(t,i,r)}class OsA{constructor(i,r,l){this.fn=i,this.setter=r,this._value=void 0,this.dep=new TW(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=dU-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!r,this.isSSR=l}notify(){if(this.flags|=16,!(this.flags&8)&&_a!==this)return R6(this,!0),!0}get value(){const i=this.dep.track();return T6(this),i&&(i.version=this.dep.version),this._value}set value(i){this.setter&&this.setter(i)}}function PsA(t,i,r=!1){let l,I;return $s(t)?l=t:(l=t.get,I=t.set),new OsA(l,I,r)}const N1={},hY=new WeakMap;let av;function xsA(t,i=!1,r=av){if(r){let l=hY.get(r);l||hY.set(r,l=[]),l.push(t)}}function YsA(t,i,r=Da){const{immediate:l,deep:I,once:h,scheduler:f,augmentJob:w,call:_}=r,b=de=>I?de:th(de)||I===!1||I===0?Im(de,1):Im(de);let U,j,IA,nA,mA=!1,lA=!1;if(iI(t)?(j=()=>t.value,mA=th(t)):K_(t)?(j=()=>b(t),mA=!0):Ms(t)?(lA=!0,mA=t.some(de=>K_(de)||th(de)),j=()=>t.map(de=>{if(iI(de))return de.value;if(K_(de))return b(de);if($s(de))return _?_(de,2):de()})):$s(t)?i?j=_?()=>_(t,2):t:j=()=>{if(IA){aD();try{IA()}finally{gD()}}const de=av;av=U;try{return _?_(t,3,[nA]):t(nA)}finally{av=de}}:j=RQ,i&&I){const de=j,Pe=I===!0?1/0:I;j=()=>Im(de(),Pe)}const cA=IsA(),TA=()=>{U.stop(),cA&&cA.active&&MW(cA.effects,U)};if(h&&i){const de=i;i=(...Pe)=>{de(...Pe),TA()}}let WA=lA?new Array(t.length).fill(N1):N1;const Ee=de=>{if(!(!(U.flags&1)||!U.dirty&&!de))if(i){const Pe=U.run();if(I||mA||(lA?Pe.some((pe,gt)=>Wy(pe,WA[gt])):Wy(Pe,WA))){IA&&IA();const pe=av;av=U;try{const gt=[Pe,WA===N1?void 0:lA&&WA[0]===N1?[]:WA,nA];_?_(i,3,gt):i(...gt),WA=Pe}finally{av=pe}}}else U.run()};return w&&w(Ee),U=new M6(j),U.scheduler=f?()=>f(Ee,!1):Ee,nA=de=>xsA(de,!1,U),IA=U.onStop=()=>{const de=hY.get(U);if(de){if(_)_(de,4);else for(const Pe of de)Pe();hY.delete(U)}},i?l?Ee(!0):WA=U.run():f?f(Ee.bind(null,!0),!0):U.run(),TA.pause=U.pause.bind(U),TA.resume=U.resume.bind(U),TA.stop=TA,TA}function Im(t,i=1/0,r){if(i<=0||!Na(t)||t.__v_skip||(r=r||new Set,r.has(t)))return t;if(r.add(t),i--,iI(t))Im(t.value,i,r);else if(Ms(t))for(let l=0;l{Im(l,i,r)});else if(m6(t)){for(const l in t)Im(t[l],i,r);for(const l of Object.getOwnPropertySymbols(t))Object.prototype.propertyIsEnumerable.call(t,l)&&Im(t[l],i,r)}return t}/**
+**/let oC;class $sA{constructor(i=!1){this.detached=i,this._active=!0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=oC,!i&&oC&&(this.index=(oC.scopes||(oC.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let i,s;if(this.scopes)for(i=0,s=this.scopes.length;i0)return;if(gU){let i=gU;for(gU=void 0;i;){const s=i.next;i.next=void 0,i.flags&=-9,i=s}}let t;for(;aU;){let i=aU;for(aU=void 0;i;){const s=i.next;if(i.next=void 0,i.flags&=-9,i.flags&1)try{i.trigger()}catch(c){t||(t=c)}i=s}}if(t)throw t}function g9(t){for(let i=t.deps;i;i=i.nextDep)i.version=-1,i.prevActiveLink=i.dep.activeLink,i.dep.activeLink=i}function c9(t){let i,s=t.depsTail,c=s;for(;c;){const I=c.prevDep;c.version===-1?(c===s&&(s=I),o4(c),enA(c)):i=c,c.dep.activeLink=c.prevActiveLink,c.prevActiveLink=void 0,c=I}t.deps=i,t.depsTail=s}function H3(t){for(let i=t.deps;i;i=i.nextDep)if(i.dep.version!==i.version||i.dep.computed&&(l9(i.dep.computed)||i.dep.version!==i.version))return!0;return!!t._dirty}function l9(t){if(t.flags&4&&!(t.flags&16)||(t.flags&=-17,t.globalVersion===RU))return;t.globalVersion=RU;const i=t.dep;if(t.flags|=2,i.version>0&&!t.isSSR&&t.deps&&!H3(t)){t.flags&=-3;return}const s=ka,c=aB;ka=t,aB=!0;try{g9(t);const I=t.fn(t._value);(i.version===0||Xy(I,t._value))&&(t._value=I,i.version++)}catch(I){throw i.version++,I}finally{ka=s,aB=c,c9(t),t.flags&=-3}}function o4(t,i=!1){const{dep:s,prevSub:c,nextSub:I}=t;if(c&&(c.nextSub=I,t.prevSub=void 0),I&&(I.prevSub=c,t.nextSub=void 0),s.subs===t&&(s.subs=c,!c&&s.computed)){s.computed.flags&=-5;for(let C=s.computed.deps;C;C=C.nextDep)o4(C,!0)}!i&&!--s.sc&&s.map&&s.map.delete(s.key)}function enA(t){const{prevDep:i,nextDep:s}=t;i&&(i.nextDep=s,t.prevDep=void 0),s&&(s.prevDep=i,t.nextDep=void 0)}let aB=!0;const I9=[];function dD(){I9.push(aB),aB=!1}function CD(){const t=I9.pop();aB=t===void 0?!0:t}function P8(t){const{cleanup:i}=t;if(t.cleanup=void 0,i){const s=ka;ka=void 0;try{i()}finally{ka=s}}}let RU=0;class tnA{constructor(i,s){this.sub=i,this.dep=s,this.version=s.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class s4{constructor(i){this.computed=i,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0}track(i){if(!ka||!aB||ka===this.computed)return;let s=this.activeLink;if(s===void 0||s.sub!==ka)s=this.activeLink=new tnA(ka,this),ka.deps?(s.prevDep=ka.depsTail,ka.depsTail.nextDep=s,ka.depsTail=s):ka.deps=ka.depsTail=s,u9(s);else if(s.version===-1&&(s.version=this.version,s.nextDep)){const c=s.nextDep;c.prevDep=s.prevDep,s.prevDep&&(s.prevDep.nextDep=c),s.prevDep=ka.depsTail,s.nextDep=void 0,ka.depsTail.nextDep=s,ka.depsTail=s,ka.deps===s&&(ka.deps=c)}return s}trigger(i){this.version++,RU++,this.notify(i)}notify(i){t4();try{for(let s=this.subs;s;s=s.prevSub)s.sub.notify()&&s.sub.dep.notify()}finally{i4()}}}function u9(t){if(t.dep.sc++,t.sub.flags&4){const i=t.dep.computed;if(i&&!t.dep.subs){i.flags|=20;for(let c=i.deps;c;c=c.nextDep)u9(c)}const s=t.dep.subs;s!==t&&(t.prevSub=s,s&&(s.nextSub=t)),t.dep.subs=t}}const GY=new WeakMap,MM=Symbol(""),q3=Symbol(""),wU=Symbol("");function Du(t,i,s){if(aB&&ka){let c=GY.get(t);c||GY.set(t,c=new Map);let I=c.get(s);I||(c.set(s,I=new s4),I.map=c,I.key=s),I.track()}}function dm(t,i,s,c,I,C){const f=GY.get(t);if(!f){RU++;return}const w=_=>{_&&_.trigger()};if(t4(),i==="clear")f.forEach(w);else{const _=ks(t),N=_&&e4(s);if(_&&s==="length"){const L=Number(c);f.forEach((q,lA)=>{(lA==="length"||lA===wU||!mm(lA)&&lA>=L)&&w(q)})}else switch((s!==void 0||f.has(void 0))&&w(f.get(s)),N&&w(f.get(wU)),i){case"add":_?N&&w(f.get("length")):(w(f.get(MM)),eT(t)&&w(f.get(q3)));break;case"delete":_||(w(f.get(MM)),eT(t)&&w(f.get(q3)));break;case"set":eT(t)&&w(f.get(MM));break}}i4()}function inA(t,i){const s=GY.get(t);return s&&s.get(i)}function __(t){const i=Lr(t);return i===t?i:(Du(i,"iterate",wU),nh(t)?i:i.map(Su))}function SV(t){return Du(t=Lr(t),"iterate",wU),t}const onA={__proto__:null,[Symbol.iterator](){return Wj(this,Symbol.iterator,Su)},concat(...t){return __(this).concat(...t.map(i=>ks(i)?__(i):i))},entries(){return Wj(this,"entries",t=>(t[1]=Su(t[1]),t))},every(t,i){return rm(this,"every",t,i,void 0,arguments)},filter(t,i){return rm(this,"filter",t,i,s=>s.map(Su),arguments)},find(t,i){return rm(this,"find",t,i,Su,arguments)},findIndex(t,i){return rm(this,"findIndex",t,i,void 0,arguments)},findLast(t,i){return rm(this,"findLast",t,i,Su,arguments)},findLastIndex(t,i){return rm(this,"findLastIndex",t,i,void 0,arguments)},forEach(t,i){return rm(this,"forEach",t,i,void 0,arguments)},includes(...t){return zj(this,"includes",t)},indexOf(...t){return zj(this,"indexOf",t)},join(t){return __(this).join(t)},lastIndexOf(...t){return zj(this,"lastIndexOf",t)},map(t,i){return rm(this,"map",t,i,void 0,arguments)},pop(){return _L(this,"pop")},push(...t){return _L(this,"push",t)},reduce(t,...i){return x8(this,"reduce",t,i)},reduceRight(t,...i){return x8(this,"reduceRight",t,i)},shift(){return _L(this,"shift")},some(t,i){return rm(this,"some",t,i,void 0,arguments)},splice(...t){return _L(this,"splice",t)},toReversed(){return __(this).toReversed()},toSorted(t){return __(this).toSorted(t)},toSpliced(...t){return __(this).toSpliced(...t)},unshift(...t){return _L(this,"unshift",t)},values(){return Wj(this,"values",Su)}};function Wj(t,i,s){const c=SV(t),I=c[i]();return c!==t&&!nh(t)&&(I._next=I.next,I.next=()=>{const C=I._next();return C.value&&(C.value=s(C.value)),C}),I}const snA=Array.prototype;function rm(t,i,s,c,I,C){const f=SV(t),w=f!==t&&!nh(t),_=f[i];if(_!==snA[i]){const q=_.apply(t,C);return w?Su(q):q}let N=s;f!==t&&(w?N=function(q,lA){return s.call(this,Su(q),lA,t)}:s.length>2&&(N=function(q,lA){return s.call(this,q,lA,t)}));const L=_.call(f,N,c);return w&&I?I(L):L}function x8(t,i,s,c){const I=SV(t);let C=s;return I!==t&&(nh(t)?s.length>3&&(C=function(f,w,_){return s.call(this,f,w,_,t)}):C=function(f,w,_){return s.call(this,f,Su(w),_,t)}),I[i](C,...c)}function zj(t,i,s){const c=Lr(t);Du(c,"iterate",wU);const I=c[i](...s);return(I===-1||I===!1)&&a4(s[0])?(s[0]=Lr(s[0]),c[i](...s)):I}function _L(t,i,s=[]){dD(),t4();const c=Lr(t)[i].apply(t,s);return i4(),CD(),c}const nnA=XW("__proto__,__v_isRef,__isVue"),E9=new Set(Object.getOwnPropertyNames(Symbol).filter(t=>t!=="arguments"&&t!=="caller").map(t=>Symbol[t]).filter(mm));function rnA(t){mm(t)||(t=String(t));const i=Lr(this);return Du(i,"has",t),i.hasOwnProperty(t)}class d9{constructor(i=!1,s=!1){this._isReadonly=i,this._isShallow=s}get(i,s,c){if(s==="__v_skip")return i.__v_skip;const I=this._isReadonly,C=this._isShallow;if(s==="__v_isReactive")return!I;if(s==="__v_isReadonly")return I;if(s==="__v_isShallow")return C;if(s==="__v_raw")return c===(I?C?hnA:Q9:C?B9:h9).get(i)||Object.getPrototypeOf(i)===Object.getPrototypeOf(c)?i:void 0;const f=ks(i);if(!I){let _;if(f&&(_=onA[s]))return _;if(s==="hasOwnProperty")return rnA}const w=Reflect.get(i,s,aI(i)?i:c);return(mm(s)?E9.has(s):nnA(s))||(I||Du(i,"get",s),C)?w:aI(w)?f&&e4(s)?w:w.value:La(w)?I?Qc(w):fM(w):w}}class C9 extends d9{constructor(i=!1){super(!1,i)}set(i,s,c,I){let C=i[s];if(!this._isShallow){const _=OM(C);if(!nh(c)&&!OM(c)&&(C=Lr(C),c=Lr(c)),!ks(i)&&aI(C)&&!aI(c))return _?!1:(C.value=c,!0)}const f=ks(i)&&e4(s)?Number(s)t,H1=t=>Reflect.getPrototypeOf(t);function InA(t,i,s){return function(...c){const I=this.__v_raw,C=Lr(I),f=eT(C),w=t==="entries"||t===Symbol.iterator&&f,_=t==="keys"&&f,N=I[t](...c),L=s?K3:i?j3:Su;return!i&&Du(C,"iterate",_?q3:MM),{next(){const{value:q,done:lA}=N.next();return lA?{value:q,done:lA}:{value:w?[L(q[0]),L(q[1])]:L(q),done:lA}},[Symbol.iterator](){return this}}}}function q1(t){return function(...i){return t==="delete"?!1:t==="clear"?void 0:this}}function unA(t,i){const s={get(I){const C=this.__v_raw,f=Lr(C),w=Lr(I);t||(Xy(I,w)&&Du(f,"get",I),Du(f,"get",w));const{has:_}=H1(f),N=i?K3:t?j3:Su;if(_.call(f,I))return N(C.get(I));if(_.call(f,w))return N(C.get(w));C!==f&&C.get(I)},get size(){const I=this.__v_raw;return!t&&Du(Lr(I),"iterate",MM),Reflect.get(I,"size",I)},has(I){const C=this.__v_raw,f=Lr(C),w=Lr(I);return t||(Xy(I,w)&&Du(f,"has",I),Du(f,"has",w)),I===w?C.has(I):C.has(I)||C.has(w)},forEach(I,C){const f=this,w=f.__v_raw,_=Lr(w),N=i?K3:t?j3:Su;return!t&&Du(_,"iterate",MM),w.forEach((L,q)=>I.call(C,N(L),N(q),f))}};return cI(s,t?{add:q1("add"),set:q1("set"),delete:q1("delete"),clear:q1("clear")}:{add(I){!i&&!nh(I)&&!OM(I)&&(I=Lr(I));const C=Lr(this);return H1(C).has.call(C,I)||(C.add(I),dm(C,"add",I,I)),this},set(I,C){!i&&!nh(C)&&!OM(C)&&(C=Lr(C));const f=Lr(this),{has:w,get:_}=H1(f);let N=w.call(f,I);N||(I=Lr(I),N=w.call(f,I));const L=_.call(f,I);return f.set(I,C),N?Xy(C,L)&&dm(f,"set",I,C):dm(f,"add",I,C),this},delete(I){const C=Lr(this),{has:f,get:w}=H1(C);let _=f.call(C,I);_||(I=Lr(I),_=f.call(C,I)),w&&w.call(C,I);const N=C.delete(I);return _&&dm(C,"delete",I,void 0),N},clear(){const I=Lr(this),C=I.size!==0,f=I.clear();return C&&dm(I,"clear",void 0,void 0),f}}),["keys","values","entries",Symbol.iterator].forEach(I=>{s[I]=InA(I,t,i)}),s}function n4(t,i){const s=unA(t,i);return(c,I,C)=>I==="__v_isReactive"?!t:I==="__v_isReadonly"?t:I==="__v_raw"?c:Reflect.get($r(s,I)&&I in c?s:c,I,C)}const EnA={get:n4(!1,!1)},dnA={get:n4(!1,!0)},CnA={get:n4(!0,!1)};const h9=new WeakMap,B9=new WeakMap,Q9=new WeakMap,hnA=new WeakMap;function BnA(t){switch(t){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function QnA(t){return t.__v_skip||!Object.isExtensible(t)?0:BnA(YsA(t))}function fM(t){return OM(t)?t:r4(t,!1,gnA,EnA,h9)}function pnA(t){return r4(t,!1,lnA,dnA,B9)}function Qc(t){return r4(t,!0,cnA,CnA,Q9)}function r4(t,i,s,c,I){if(!La(t)||t.__v_raw&&!(i&&t.__v_isReactive))return t;const C=I.get(t);if(C)return C;const f=QnA(t);if(f===0)return t;const w=new Proxy(t,f===2?c:s);return I.set(t,w),w}function tT(t){return OM(t)?tT(t.__v_raw):!!(t&&t.__v_isReactive)}function OM(t){return!!(t&&t.__v_isReadonly)}function nh(t){return!!(t&&t.__v_isShallow)}function a4(t){return t?!!t.__v_raw:!1}function Lr(t){const i=t&&t.__v_raw;return i?Lr(i):t}function mnA(t){return!$r(t,"__v_skip")&&Object.isExtensible(t)&&t9(t,"__v_skip",!0),t}const Su=t=>La(t)?fM(t):t,j3=t=>La(t)?Qc(t):t;function aI(t){return t?t.__v_isRef===!0:!1}function Ge(t){return fnA(t,!1)}function fnA(t,i){return aI(t)?t:new ynA(t,i)}class ynA{constructor(i,s){this.dep=new s4,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=s?i:Lr(i),this._value=s?i:Su(i),this.__v_isShallow=s}get value(){return this.dep.track(),this._value}set value(i){const s=this._rawValue,c=this.__v_isShallow||nh(i)||OM(i);i=c?i:Lr(i),Xy(i,s)&&(this._rawValue=i,this._value=c?i:Su(i),this.dep.trigger())}}function aA(t){return aI(t)?t.value:t}const DnA={get:(t,i,s)=>i==="__v_raw"?t:aA(Reflect.get(t,i,s)),set:(t,i,s,c)=>{const I=t[i];return aI(I)&&!aI(s)?(I.value=s,!0):Reflect.set(t,i,s,c)}};function p9(t){return tT(t)?t:new Proxy(t,DnA)}function Ys(t){const i=ks(t)?new Array(t.length):{};for(const s in t)i[s]=m9(t,s);return i}class SnA{constructor(i,s,c){this._object=i,this._key=s,this._defaultValue=c,this.__v_isRef=!0,this._value=void 0}get value(){const i=this._object[this._key];return this._value=i===void 0?this._defaultValue:i}set value(i){this._object[this._key]=i}get dep(){return inA(Lr(this._object),this._key)}}class vnA{constructor(i){this._getter=i,this.__v_isRef=!0,this.__v_isReadonly=!0,this._value=void 0}get value(){return this._value=this._getter()}}function Zj(t,i,s){return aI(t)?t:cn(t)?new vnA(t):La(t)&&arguments.length>1?m9(t,i,s):Ge(t)}function m9(t,i,s){const c=t[i];return aI(c)?c:new SnA(t,i,s)}class MnA{constructor(i,s,c){this.fn=i,this.setter=s,this._value=void 0,this.dep=new s4(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=RU-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!s,this.isSSR=c}notify(){if(this.flags|=16,!(this.flags&8)&&ka!==this)return a9(this,!0),!0}get value(){const i=this.dep.track();return l9(this),i&&(i.version=this.dep.version),this._value}set value(i){this.setter&&this.setter(i)}}function RnA(t,i,s=!1){let c,I;return cn(t)?c=t:(c=t.get,I=t.set),new MnA(c,I,s)}const K1={},bY=new WeakMap;let dM;function wnA(t,i=!1,s=dM){if(s){let c=bY.get(s);c||bY.set(s,c=[]),c.push(t)}}function _nA(t,i,s=wa){const{immediate:c,deep:I,once:C,scheduler:f,augmentJob:w,call:_}=s,N=jA=>I?jA:nh(jA)||I===!1||I===0?Cm(jA,1):Cm(jA);let L,q,lA,tA,BA=!1,IA=!1;if(aI(t)?(q=()=>t.value,BA=nh(t)):tT(t)?(q=()=>N(t),BA=!0):ks(t)?(IA=!0,BA=t.some(jA=>tT(jA)||nh(jA)),q=()=>t.map(jA=>{if(aI(jA))return jA.value;if(tT(jA))return N(jA);if(cn(jA))return _?_(jA,2):jA()})):cn(t)?i?q=_?()=>_(t,2):t:q=()=>{if(lA){dD();try{lA()}finally{CD()}}const jA=dM;dM=L;try{return _?_(t,3,[tA]):t(tA)}finally{dM=jA}}:q=NQ,i&&I){const jA=q,Qe=I===!0?1/0:I;q=()=>Cm(jA(),Qe)}const gA=AnA(),RA=()=>{L.stop(),gA&&gA.active&&A4(gA.effects,L)};if(C&&i){const jA=i;i=(...Qe)=>{jA(...Qe),RA()}}let KA=IA?new Array(t.length).fill(K1):K1;const $A=jA=>{if(!(!(L.flags&1)||!L.dirty&&!jA))if(i){const Qe=L.run();if(I||BA||(IA?Qe.some((ae,st)=>Xy(ae,KA[st])):Xy(Qe,KA))){lA&&lA();const ae=dM;dM=L;try{const st=[Qe,KA===K1?void 0:IA&&KA[0]===K1?[]:KA,tA];_?_(i,3,st):i(...st),KA=Qe}finally{dM=ae}}}else L.run()};return w&&w($A),L=new n9(q),L.scheduler=f?()=>f($A,!1):$A,tA=jA=>wnA(jA,!1,L),lA=L.onStop=()=>{const jA=bY.get(L);if(jA){if(_)_(jA,4);else for(const Qe of jA)Qe();bY.delete(L)}},i?c?$A(!0):KA=L.run():f?f($A.bind(null,!0),!0):L.run(),RA.pause=L.pause.bind(L),RA.resume=L.resume.bind(L),RA.stop=RA,RA}function Cm(t,i=1/0,s){if(i<=0||!La(t)||t.__v_skip||(s=s||new Set,s.has(t)))return t;if(s.add(t),i--,aI(t))Cm(t.value,i,s);else if(ks(t))for(let c=0;c{Cm(c,i,s)});else if(e9(t)){for(const c in t)Cm(t[c],i,s);for(const c of Object.getOwnPropertySymbols(t))Object.prototype.propertyIsEnumerable.call(t,c)&&Cm(t[c],i,s)}return t}/**
* @vue/runtime-core v3.5.13
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
-**/function LU(t,i,r,l){try{return l?t(...l):t()}catch(I){sV(I,i,r)}}function rB(t,i,r,l){if($s(t)){const I=LU(t,i,r,l);return I&&Q6(I)&&I.catch(h=>{sV(h,i,r)}),I}if(Ms(t)){const I=[];for(let h=0;h>>1,I=pE[l],h=hU(I);h=hU(r)?pE.push(t):pE.splice(JsA(i),0,t),t.flags|=1,V6()}}function V6(){BY||(BY=Y6.then(H6))}function HsA(t){Ms(t)?j_.push(...t):Ly&&t.id===-1?Ly.splice(v_+1,0,t):t.flags&1||(j_.push(t),t.flags|=1),V6()}function l8(t,i,r=QQ+1){for(;rhU(r)-hU(l));if(j_.length=0,Ly){Ly.push(...i);return}for(Ly=i,v_=0;v_t.id==null?t.flags&2?-1:1/0:t.id;function H6(t){try{for(QQ=0;QQ{l._d&&S8(-1);const h=QY(i);let f;try{f=t(...I)}finally{QY(h),l._d&&S8(1)}return f};return l._n=!0,l._c=!0,l._d=!0,l}function Ta(t,i){if(tI===null)return t;const r=lV(tI),l=t.dirs||(t.dirs=[]);for(let I=0;It.__isTeleport,ZL=t=>t&&(t.disabled||t.disabled===""),I8=t=>t&&(t.defer||t.defer===""),u8=t=>typeof SVGElement<"u"&&t instanceof SVGElement,E8=t=>typeof MathMLElement=="function"&&t instanceof MathMLElement,S3=(t,i)=>{const r=t&&t.to;return fg(r)?i?i(r):null:r},j6={name:"Teleport",__isTeleport:!0,process(t,i,r,l,I,h,f,w,_,b){const{mc:U,pc:j,pbc:IA,o:{insert:nA,querySelector:mA,createText:lA,createComment:cA}}=b,TA=ZL(i.props);let{shapeFlag:WA,children:Ee,dynamicChildren:de}=i;if(t==null){const Pe=i.el=lA(""),pe=i.anchor=lA("");nA(Pe,r,l),nA(pe,r,l);const gt=(ze,Dt)=>{WA&16&&(I&&I.isCE&&(I.ce._teleportTarget=ze),U(Ee,ze,Dt,I,h,f,w,_))},pt=()=>{const ze=i.target=S3(i.props,mA),Dt=W6(ze,i,lA,nA);ze&&(f!=="svg"&&u8(ze)?f="svg":f!=="mathml"&&E8(ze)&&(f="mathml"),TA||(gt(ze,Dt),$1(i,!1)))};TA&&(gt(r,pe),$1(i,!0)),I8(i.props)?BE(()=>{pt(),i.el.__isMounted=!0},h):pt()}else{if(I8(i.props)&&!t.el.__isMounted){BE(()=>{j6.process(t,i,r,l,I,h,f,w,_,b),delete t.el.__isMounted},h);return}i.el=t.el,i.targetStart=t.targetStart;const Pe=i.anchor=t.anchor,pe=i.target=t.target,gt=i.targetAnchor=t.targetAnchor,pt=ZL(t.props),ze=pt?r:pe,Dt=pt?Pe:gt;if(f==="svg"||u8(pe)?f="svg":(f==="mathml"||E8(pe))&&(f="mathml"),de?(IA(t.dynamicChildren,de,ze,I,h,f,w),UW(t,i,!0)):_||j(t,i,ze,Dt,I,h,f,w,!1),TA)pt?i.props&&t.props&&i.props.to!==t.props.to&&(i.props.to=t.props.to):G1(i,r,Pe,b,1);else if((i.props&&i.props.to)!==(t.props&&t.props.to)){const Kt=i.target=S3(i.props,mA);Kt&&G1(i,Kt,null,b,0)}else pt&&G1(i,pe,gt,b,1);$1(i,TA)}},remove(t,i,r,{um:l,o:{remove:I}},h){const{shapeFlag:f,children:w,anchor:_,targetStart:b,targetAnchor:U,target:j,props:IA}=t;if(j&&(I(b),I(U)),h&&I(_),f&16){const nA=h||!ZL(IA);for(let mA=0;mA{t.isMounted=!0}),i9(()=>{t.isUnmounting=!0}),t}const JC=[Function,Array],z6={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:JC,onEnter:JC,onAfterEnter:JC,onEnterCancelled:JC,onBeforeLeave:JC,onLeave:JC,onAfterLeave:JC,onLeaveCancelled:JC,onBeforeAppear:JC,onAppear:JC,onAfterAppear:JC,onAppearCancelled:JC},Z6=t=>{const i=t.subTree;return i.component?Z6(i.component):i},WsA={name:"BaseTransition",props:z6,setup(t,{slots:i}){const r=HnA(),l=jsA();return()=>{const I=i.default&&A9(i.default(),!0);if(!I||!I.length)return;const h=X6(I),f=Gr(t),{mode:w}=f;if(l.isLeaving)return _j(h);const _=d8(h);if(!_)return _j(h);let b=M3(_,f,l,r,j=>b=j);_.type!==mE&&BU(_,b);let U=r.subTree&&d8(r.subTree);if(U&&U.type!==mE&&!cv(_,U)&&Z6(r).type!==mE){let j=M3(U,f,l,r);if(BU(U,j),w==="out-in"&&_.type!==mE)return l.isLeaving=!0,j.afterLeave=()=>{l.isLeaving=!1,r.job.flags&8||r.update(),delete j.afterLeave,U=void 0},_j(h);w==="in-out"&&_.type!==mE?j.delayLeave=(IA,nA,mA)=>{const lA=$6(l,U);lA[String(U.key)]=U,IA[Uy]=()=>{nA(),IA[Uy]=void 0,delete b.delayedLeave,U=void 0},b.delayedLeave=()=>{mA(),delete b.delayedLeave,U=void 0}}:U=void 0}else U&&(U=void 0);return h}}};function X6(t){let i=t[0];if(t.length>1){for(const r of t)if(r.type!==mE){i=r;break}}return i}const zsA=WsA;function $6(t,i){const{leavingVNodes:r}=t;let l=r.get(i.type);return l||(l=Object.create(null),r.set(i.type,l)),l}function M3(t,i,r,l,I){const{appear:h,mode:f,persisted:w=!1,onBeforeEnter:_,onEnter:b,onAfterEnter:U,onEnterCancelled:j,onBeforeLeave:IA,onLeave:nA,onAfterLeave:mA,onLeaveCancelled:lA,onBeforeAppear:cA,onAppear:TA,onAfterAppear:WA,onAppearCancelled:Ee}=i,de=String(t.key),Pe=$6(r,t),pe=(ze,Dt)=>{ze&&rB(ze,l,9,Dt)},gt=(ze,Dt)=>{const Kt=Dt[1];pe(ze,Dt),Ms(ze)?ze.every(ut=>ut.length<=1)&&Kt():ze.length<=1&&Kt()},pt={mode:f,persisted:w,beforeEnter(ze){let Dt=_;if(!r.isMounted)if(h)Dt=cA||_;else return;ze[Uy]&&ze[Uy](!0);const Kt=Pe[de];Kt&&cv(t,Kt)&&Kt.el[Uy]&&Kt.el[Uy](),pe(Dt,[ze])},enter(ze){let Dt=b,Kt=U,ut=j;if(!r.isMounted)if(h)Dt=TA||b,Kt=WA||U,ut=Ee||j;else return;let ge=!1;const XA=ze[b1]=_e=>{ge||(ge=!0,_e?pe(ut,[ze]):pe(Kt,[ze]),pt.delayedLeave&&pt.delayedLeave(),ze[b1]=void 0)};Dt?gt(Dt,[ze,XA]):XA()},leave(ze,Dt){const Kt=String(t.key);if(ze[b1]&&ze[b1](!0),r.isUnmounting)return Dt();pe(IA,[ze]);let ut=!1;const ge=ze[Uy]=XA=>{ut||(ut=!0,Dt(),XA?pe(lA,[ze]):pe(mA,[ze]),ze[Uy]=void 0,Pe[Kt]===t&&delete Pe[Kt])};Pe[Kt]=t,nA?gt(nA,[ze,ge]):ge()},clone(ze){const Dt=M3(ze,i,r,l,I);return I&&I(Dt),Dt}};return pt}function _j(t){if(rV(t))return t=eD(t),t.children=null,t}function d8(t){if(!rV(t))return K6(t.type)&&t.children?X6(t.children):t;const{shapeFlag:i,children:r}=t;if(r){if(i&16)return r[0];if(i&32&&$s(r.default))return r.default()}}function BU(t,i){t.shapeFlag&6&&t.component?(t.transition=i,BU(t.component.subTree,i)):t.shapeFlag&128?(t.ssContent.transition=i.clone(t.ssContent),t.ssFallback.transition=i.clone(t.ssFallback)):t.transition=i}function A9(t,i=!1,r){let l=[],I=0;for(let h=0;h1)for(let h=0;hpY(mA,i&&(Ms(i)?i[lA]:i),r,l,I));return}if(W_(l)&&!I){l.shapeFlag&512&&l.type.__asyncResolved&&l.component.subTree.component&&pY(t,i,r,l.component.subTree);return}const h=l.shapeFlag&4?lV(l.component):l.el,f=I?null:h,{i:w,r:_}=t,b=i&&i.r,U=w.refs===Da?w.refs={}:w.refs,j=w.setupState,IA=Gr(j),nA=j===Da?()=>!1:mA=>Wr(IA,mA);if(b!=null&&b!==_&&(fg(b)?(U[b]=null,nA(b)&&(j[b]=null)):iI(b)&&(b.value=null)),$s(_))LU(_,w,12,[f,U]);else{const mA=fg(_),lA=iI(_);if(mA||lA){const cA=()=>{if(t.f){const TA=mA?nA(_)?j[_]:U[_]:_.value;I?Ms(TA)&&MW(TA,h):Ms(TA)?TA.includes(h)||TA.push(h):mA?(U[_]=[h],nA(_)&&(j[_]=U[_])):(_.value=[h],t.k&&(U[t.k]=_.value))}else mA?(U[_]=f,nA(_)&&(j[_]=f)):lA&&(_.value=f,t.k&&(U[t.k]=f))};f?(cA.id=-1,BE(cA,r)):cA()}}}iV().requestIdleCallback;iV().cancelIdleCallback;const W_=t=>!!t.type.__asyncLoader,rV=t=>t.type.__isKeepAlive;function ZsA(t,i){t9(t,"a",i)}function XsA(t,i){t9(t,"da",i)}function t9(t,i,r=xI){const l=t.__wdc||(t.__wdc=()=>{let I=r;for(;I;){if(I.isDeactivated)return;I=I.parent}return t()});if(aV(i,l,r),r){let I=r.parent;for(;I&&I.parent;)rV(I.parent.vnode)&&$sA(l,i,r,I),I=I.parent}}function $sA(t,i,r,l){const I=aV(i,t,l,!0);Kg(()=>{MW(l[i],I)},r)}function aV(t,i,r=xI,l=!1){if(r){const I=r[t]||(r[t]=[]),h=i.__weh||(i.__weh=(...f)=>{aD();const w=UU(r),_=rB(i,r,t,f);return w(),gD(),_});return l?I.unshift(h):I.push(h),h}}const hm=t=>(i,r=xI)=>{(!mU||t==="sp")&&aV(t,(...l)=>i(...l),r)},AnA=hm("bm"),hc=hm("m"),enA=hm("bu"),tnA=hm("u"),i9=hm("bum"),Kg=hm("um"),inA=hm("sp"),onA=hm("rtg"),snA=hm("rtc");function nnA(t,i=xI){aV("ec",t,i)}const rnA="components";function anA(t,i){return cnA(rnA,t,!0,i)||t}const gnA=Symbol.for("v-ndc");function cnA(t,i,r=!0,l=!1){const I=tI||xI;if(I){const h=I.type;{const w=znA(h,!1);if(w&&(w===i||w===sh(i)||w===tV(sh(i))))return h}const f=C8(I[t]||h[t],i)||C8(I.appContext[t],i);return!f&&l?h:f}}function C8(t,i){return t&&(t[i]||t[sh(i)]||t[tV(sh(i))])}function yE(t,i,r,l){let I;const h=r,f=Ms(t);if(f||fg(t)){const w=f&&K_(t);let _=!1;w&&(_=!th(t),t=oV(t)),I=new Array(t.length);for(let b=0,U=t.length;bi(w,_,void 0,h));else{const w=Object.keys(t);I=new Array(w.length);for(let _=0,b=w.length;_pU(i)?!(i.type===mE||i.type===vr&&!o9(i.children)):!0)?t:null}const v3=t=>t?y9(t)?lV(t):v3(t.parent):null,XL=sI(Object.create(null),{$:t=>t,$el:t=>t.vnode.el,$data:t=>t.data,$props:t=>t.props,$attrs:t=>t.attrs,$slots:t=>t.slots,$refs:t=>t.refs,$parent:t=>v3(t.parent),$root:t=>v3(t.root),$host:t=>t.ce,$emit:t=>t.emit,$options:t=>n9(t),$forceUpdate:t=>t.f||(t.f=()=>{kW(t.update)}),$nextTick:t=>t.n||(t.n=Vy.bind(t.proxy)),$watch:t=>TnA.bind(t)}),Tj=(t,i)=>t!==Da&&!t.__isScriptSetup&&Wr(t,i),lnA={get({_:t},i){if(i==="__v_skip")return!0;const{ctx:r,setupState:l,data:I,props:h,accessCache:f,type:w,appContext:_}=t;let b;if(i[0]!=="$"){const nA=f[i];if(nA!==void 0)switch(nA){case 1:return l[i];case 2:return I[i];case 4:return r[i];case 3:return h[i]}else{if(Tj(l,i))return f[i]=1,l[i];if(I!==Da&&Wr(I,i))return f[i]=2,I[i];if((b=t.propsOptions[0])&&Wr(b,i))return f[i]=3,h[i];if(r!==Da&&Wr(r,i))return f[i]=4,r[i];R3&&(f[i]=0)}}const U=XL[i];let j,IA;if(U)return i==="$attrs"&&pu(t.attrs,"get",""),U(t);if((j=w.__cssModules)&&(j=j[i]))return j;if(r!==Da&&Wr(r,i))return f[i]=4,r[i];if(IA=_.config.globalProperties,Wr(IA,i))return IA[i]},set({_:t},i,r){const{data:l,setupState:I,ctx:h}=t;return Tj(I,i)?(I[i]=r,!0):l!==Da&&Wr(l,i)?(l[i]=r,!0):Wr(t.props,i)||i[0]==="$"&&i.slice(1)in t?!1:(h[i]=r,!0)},has({_:{data:t,setupState:i,accessCache:r,ctx:l,appContext:I,propsOptions:h}},f){let w;return!!r[f]||t!==Da&&Wr(t,f)||Tj(i,f)||(w=h[0])&&Wr(w,f)||Wr(l,f)||Wr(XL,f)||Wr(I.config.globalProperties,f)},defineProperty(t,i,r){return r.get!=null?t._.accessCache[i]=0:Wr(r,"value")&&this.set(t,i,r.value,null),Reflect.defineProperty(t,i,r)}};function h8(t){return Ms(t)?t.reduce((i,r)=>(i[r]=null,i),{}):t}let R3=!0;function InA(t){const i=n9(t),r=t.proxy,l=t.ctx;R3=!1,i.beforeCreate&&B8(i.beforeCreate,t,"bc");const{data:I,computed:h,methods:f,watch:w,provide:_,inject:b,created:U,beforeMount:j,mounted:IA,beforeUpdate:nA,updated:mA,activated:lA,deactivated:cA,beforeDestroy:TA,beforeUnmount:WA,destroyed:Ee,unmounted:de,render:Pe,renderTracked:pe,renderTriggered:gt,errorCaptured:pt,serverPrefetch:ze,expose:Dt,inheritAttrs:Kt,components:ut,directives:ge,filters:XA}=i;if(b&&unA(b,l,null),f)for(const Ut in f){const gi=f[Ut];$s(gi)&&(l[Ut]=gi.bind(r))}if(I){const Ut=I.call(r,r);Na(Ut)&&(t.data=dv(Ut))}if(R3=!0,h)for(const Ut in h){const gi=h[Ut],Fi=$s(gi)?gi.bind(r,r):$s(gi.get)?gi.get.bind(r,r):RQ,To=!$s(gi)&&$s(gi.set)?gi.set.bind(r):RQ,io=wt({get:Fi,set:To});Object.defineProperty(l,Ut,{enumerable:!0,configurable:!0,get:()=>io.value,set:Eo=>io.value=Eo})}if(w)for(const Ut in w)s9(w[Ut],l,r,Ut);if(_){const Ut=$s(_)?_.call(r):_;Reflect.ownKeys(Ut).forEach(gi=>{cd(gi,Ut[gi])})}U&&B8(U,t,"c");function je(Ut,gi){Ms(gi)?gi.forEach(Fi=>Ut(Fi.bind(r))):gi&&Ut(gi.bind(r))}if(je(AnA,j),je(hc,IA),je(enA,nA),je(tnA,mA),je(ZsA,lA),je(XsA,cA),je(nnA,pt),je(snA,pe),je(onA,gt),je(i9,WA),je(Kg,de),je(inA,ze),Ms(Dt))if(Dt.length){const Ut=t.exposed||(t.exposed={});Dt.forEach(gi=>{Object.defineProperty(Ut,gi,{get:()=>r[gi],set:Fi=>r[gi]=Fi})})}else t.exposed||(t.exposed={});Pe&&t.render===RQ&&(t.render=Pe),Kt!=null&&(t.inheritAttrs=Kt),ut&&(t.components=ut),ge&&(t.directives=ge),ze&&e9(t)}function unA(t,i,r=RQ){Ms(t)&&(t=w3(t));for(const l in t){const I=t[l];let h;Na(I)?"default"in I?h=JI(I.from||l,I.default,!0):h=JI(I.from||l):h=JI(I),iI(h)?Object.defineProperty(i,l,{enumerable:!0,configurable:!0,get:()=>h.value,set:f=>h.value=f}):i[l]=h}}function B8(t,i,r){rB(Ms(t)?t.map(l=>l.bind(i.proxy)):t.bind(i.proxy),i,r)}function s9(t,i,r,l){let I=l.includes(".")?B9(r,l):()=>r[l];if(fg(t)){const h=i[t];$s(h)&&br(I,h)}else if($s(t))br(I,t.bind(r));else if(Na(t))if(Ms(t))t.forEach(h=>s9(h,i,r,l));else{const h=$s(t.handler)?t.handler.bind(r):i[t.handler];$s(h)&&br(I,h,t)}}function n9(t){const i=t.type,{mixins:r,extends:l}=i,{mixins:I,optionsCache:h,config:{optionMergeStrategies:f}}=t.appContext,w=h.get(i);let _;return w?_=w:!I.length&&!r&&!l?_=i:(_={},I.length&&I.forEach(b=>mY(_,b,f,!0)),mY(_,i,f)),Na(i)&&h.set(i,_),_}function mY(t,i,r,l=!1){const{mixins:I,extends:h}=i;h&&mY(t,h,r,!0),I&&I.forEach(f=>mY(t,f,r,!0));for(const f in i)if(!(l&&f==="expose")){const w=EnA[f]||r&&r[f];t[f]=w?w(t[f],i[f]):i[f]}return t}const EnA={data:Q8,props:p8,emits:p8,methods:wL,computed:wL,beforeCreate:dE,created:dE,beforeMount:dE,mounted:dE,beforeUpdate:dE,updated:dE,beforeDestroy:dE,beforeUnmount:dE,destroyed:dE,unmounted:dE,activated:dE,deactivated:dE,errorCaptured:dE,serverPrefetch:dE,components:wL,directives:wL,watch:CnA,provide:Q8,inject:dnA};function Q8(t,i){return i?t?function(){return sI($s(t)?t.call(this,this):t,$s(i)?i.call(this,this):i)}:i:t}function dnA(t,i){return wL(w3(t),w3(i))}function w3(t){if(Ms(t)){const i={};for(let r=0;r1)return r&&$s(i)?i.call(l&&l.proxy):i}}const a9={},g9=()=>Object.create(a9),c9=t=>Object.getPrototypeOf(t)===a9;function QnA(t,i,r,l=!1){const I={},h=g9();t.propsDefaults=Object.create(null),l9(t,i,I,h);for(const f in t.propsOptions[0])f in I||(I[f]=void 0);r?t.props=l?I:NsA(I):t.type.props?t.props=I:t.props=h,t.attrs=h}function pnA(t,i,r,l){const{props:I,attrs:h,vnode:{patchFlag:f}}=t,w=Gr(I),[_]=t.propsOptions;let b=!1;if((l||f>0)&&!(f&16)){if(f&8){const U=t.vnode.dynamicProps;for(let j=0;j{_=!0;const[IA,nA]=I9(j,i,!0);sI(f,IA),nA&&w.push(...nA)};!r&&i.mixins.length&&i.mixins.forEach(U),t.extends&&U(t.extends),t.mixins&&t.mixins.forEach(U)}if(!h&&!_)return Na(t)&&l.set(t,H_),H_;if(Ms(h))for(let U=0;Ut[0]==="_"||t==="$stable",LW=t=>Ms(t)?t.map(fQ):[fQ(t)],fnA=(t,i,r)=>{if(i._n)return i;const l=Li((...I)=>LW(i(...I)),r);return l._c=!1,l},E9=(t,i,r)=>{const l=t._ctx;for(const I in t){if(u9(I))continue;const h=t[I];if($s(h))i[I]=fnA(I,h,l);else if(h!=null){const f=LW(h);i[I]=()=>f}}},d9=(t,i)=>{const r=LW(i);t.slots.default=()=>r},C9=(t,i,r)=>{for(const l in i)(r||l!=="_")&&(t[l]=i[l])},ynA=(t,i,r)=>{const l=t.slots=g9();if(t.vnode.shapeFlag&32){const I=i._;I?(C9(l,i,r),r&&f6(l,"_",I,!0)):E9(i,l)}else i&&d9(t,i)},DnA=(t,i,r)=>{const{vnode:l,slots:I}=t;let h=!0,f=Da;if(l.shapeFlag&32){const w=i._;w?r&&w===1?h=!1:C9(I,i,r):(h=!i.$stable,E9(i,I)),f=i}else i&&(d9(t,i),f={default:1});if(h)for(const w in I)!u9(w)&&f[w]==null&&delete I[w]},BE=FnA;function SnA(t){return MnA(t)}function MnA(t,i){const r=iV();r.__VUE__=!0;const{insert:l,remove:I,patchProp:h,createElement:f,createText:w,createComment:_,setText:b,setElementText:U,parentNode:j,nextSibling:IA,setScopeId:nA=RQ,insertStaticContent:mA}=t,lA=(HA,le,Ve,Ft=null,nt=null,It=null,Ai=void 0,ei=null,ke=!!le.dynamicChildren)=>{if(HA===le)return;HA&&!cv(HA,le)&&(Ft=Ao(HA),Eo(HA,nt,It,!0),HA=null),le.patchFlag===-2&&(ke=!1,le.dynamicChildren=null);const{type:Ze,ref:vt,shapeFlag:_t}=le;switch(Ze){case cV:cA(HA,le,Ve,Ft);break;case mE:TA(HA,le,Ve,Ft);break;case Gj:HA==null&&WA(le,Ve,Ft,Ai);break;case vr:ut(HA,le,Ve,Ft,nt,It,Ai,ei,ke);break;default:_t&1?Pe(HA,le,Ve,Ft,nt,It,Ai,ei,ke):_t&6?ge(HA,le,Ve,Ft,nt,It,Ai,ei,ke):(_t&64||_t&128)&&Ze.process(HA,le,Ve,Ft,nt,It,Ai,ei,ke,bi)}vt!=null&&nt&&pY(vt,HA&&HA.ref,It,le||HA,!le)},cA=(HA,le,Ve,Ft)=>{if(HA==null)l(le.el=w(le.children),Ve,Ft);else{const nt=le.el=HA.el;le.children!==HA.children&&b(nt,le.children)}},TA=(HA,le,Ve,Ft)=>{HA==null?l(le.el=_(le.children||""),Ve,Ft):le.el=HA.el},WA=(HA,le,Ve,Ft)=>{[HA.el,HA.anchor]=mA(HA.children,le,Ve,Ft,HA.el,HA.anchor)},Ee=({el:HA,anchor:le},Ve,Ft)=>{let nt;for(;HA&&HA!==le;)nt=IA(HA),l(HA,Ve,Ft),HA=nt;l(le,Ve,Ft)},de=({el:HA,anchor:le})=>{let Ve;for(;HA&&HA!==le;)Ve=IA(HA),I(HA),HA=Ve;I(le)},Pe=(HA,le,Ve,Ft,nt,It,Ai,ei,ke)=>{le.type==="svg"?Ai="svg":le.type==="math"&&(Ai="mathml"),HA==null?pe(le,Ve,Ft,nt,It,Ai,ei,ke):ze(HA,le,nt,It,Ai,ei,ke)},pe=(HA,le,Ve,Ft,nt,It,Ai,ei)=>{let ke,Ze;const{props:vt,shapeFlag:_t,transition:Oi,dirs:po}=HA;if(ke=HA.el=f(HA.type,It,vt&&vt.is,vt),_t&8?U(ke,HA.children):_t&16&&pt(HA.children,ke,null,Ft,nt,Nj(HA,It),Ai,ei),po&&ev(HA,null,Ft,"created"),gt(ke,HA,HA.scopeId,Ai,Ft),vt){for(const so in vt)so!=="value"&&!jL(so)&&h(ke,so,null,vt[so],It,Ft);"value"in vt&&h(ke,"value",null,vt.value,It),(Ze=vt.onVnodeBeforeMount)&&BQ(Ze,Ft,HA)}po&&ev(HA,null,Ft,"beforeMount");const No=vnA(nt,Oi);No&&Oi.beforeEnter(ke),l(ke,le,Ve),((Ze=vt&&vt.onVnodeMounted)||No||po)&&BE(()=>{Ze&&BQ(Ze,Ft,HA),No&&Oi.enter(ke),po&&ev(HA,null,Ft,"mounted")},nt)},gt=(HA,le,Ve,Ft,nt)=>{if(Ve&&nA(HA,Ve),Ft)for(let It=0;It{for(let Ze=ke;Ze{const ei=le.el=HA.el;let{patchFlag:ke,dynamicChildren:Ze,dirs:vt}=le;ke|=HA.patchFlag&16;const _t=HA.props||Da,Oi=le.props||Da;let po;if(Ve&&tv(Ve,!1),(po=Oi.onVnodeBeforeUpdate)&&BQ(po,Ve,le,HA),vt&&ev(le,HA,Ve,"beforeUpdate"),Ve&&tv(Ve,!0),(_t.innerHTML&&Oi.innerHTML==null||_t.textContent&&Oi.textContent==null)&&U(ei,""),Ze?Dt(HA.dynamicChildren,Ze,ei,Ve,Ft,Nj(le,nt),It):Ai||gi(HA,le,ei,null,Ve,Ft,Nj(le,nt),It,!1),ke>0){if(ke&16)Kt(ei,_t,Oi,Ve,nt);else if(ke&2&&_t.class!==Oi.class&&h(ei,"class",null,Oi.class,nt),ke&4&&h(ei,"style",_t.style,Oi.style,nt),ke&8){const No=le.dynamicProps;for(let so=0;so{po&&BQ(po,Ve,le,HA),vt&&ev(le,HA,Ve,"updated")},Ft)},Dt=(HA,le,Ve,Ft,nt,It,Ai)=>{for(let ei=0;ei{if(le!==Ve){if(le!==Da)for(const It in le)!jL(It)&&!(It in Ve)&&h(HA,It,le[It],null,nt,Ft);for(const It in Ve){if(jL(It))continue;const Ai=Ve[It],ei=le[It];Ai!==ei&&It!=="value"&&h(HA,It,ei,Ai,nt,Ft)}"value"in Ve&&h(HA,"value",le.value,Ve.value,nt)}},ut=(HA,le,Ve,Ft,nt,It,Ai,ei,ke)=>{const Ze=le.el=HA?HA.el:w(""),vt=le.anchor=HA?HA.anchor:w("");let{patchFlag:_t,dynamicChildren:Oi,slotScopeIds:po}=le;po&&(ei=ei?ei.concat(po):po),HA==null?(l(Ze,Ve,Ft),l(vt,Ve,Ft),pt(le.children||[],Ve,vt,nt,It,Ai,ei,ke)):_t>0&&_t&64&&Oi&&HA.dynamicChildren?(Dt(HA.dynamicChildren,Oi,Ve,nt,It,Ai,ei),(le.key!=null||nt&&le===nt.subTree)&&UW(HA,le,!0)):gi(HA,le,Ve,vt,nt,It,Ai,ei,ke)},ge=(HA,le,Ve,Ft,nt,It,Ai,ei,ke)=>{le.slotScopeIds=ei,HA==null?le.shapeFlag&512?nt.ctx.activate(le,Ve,Ft,Ai,ke):XA(le,Ve,Ft,nt,It,Ai,ke):_e(HA,le,ke)},XA=(HA,le,Ve,Ft,nt,It,Ai)=>{const ei=HA.component=JnA(HA,Ft,nt);if(rV(HA)&&(ei.ctx.renderer=bi),qnA(ei,!1,Ai),ei.asyncDep){if(nt&&nt.registerDep(ei,je,Ai),!HA.el){const ke=ei.subTree=bt(mE);TA(null,ke,le,Ve)}}else je(ei,HA,le,Ve,nt,It,Ai)},_e=(HA,le,Ve)=>{const Ft=le.component=HA.component;if(LnA(HA,le,Ve))if(Ft.asyncDep&&!Ft.asyncResolved){Ut(Ft,le,Ve);return}else Ft.next=le,Ft.update();else le.el=HA.el,Ft.vnode=le},je=(HA,le,Ve,Ft,nt,It,Ai)=>{const ei=()=>{if(HA.isMounted){let{next:_t,bu:Oi,u:po,parent:No,vnode:so}=HA;{const an=h9(HA);if(an){_t&&(_t.el=so.el,Ut(HA,_t,Ai)),an.asyncDep.then(()=>{HA.isUnmounted||ei()});return}}let Go=_t,An;tv(HA,!1),_t?(_t.el=so.el,Ut(HA,_t,Ai)):_t=so,Oi&&X1(Oi),(An=_t.props&&_t.props.onVnodeBeforeUpdate)&&BQ(An,No,_t,so),tv(HA,!0);const rn=y8(HA),Es=HA.subTree;HA.subTree=rn,lA(Es,rn,j(Es.el),Ao(Es),HA,nt,It),_t.el=rn.el,Go===null&&UnA(HA,rn.el),po&&BE(po,nt),(An=_t.props&&_t.props.onVnodeUpdated)&&BE(()=>BQ(An,No,_t,so),nt)}else{let _t;const{el:Oi,props:po}=le,{bm:No,m:so,parent:Go,root:An,type:rn}=HA,Es=W_(le);tv(HA,!1),No&&X1(No),!Es&&(_t=po&&po.onVnodeBeforeMount)&&BQ(_t,Go,le),tv(HA,!0);{An.ce&&An.ce._injectChildStyle(rn);const an=HA.subTree=y8(HA);lA(null,an,Ve,Ft,HA,nt,It),le.el=an.el}if(so&&BE(so,nt),!Es&&(_t=po&&po.onVnodeMounted)){const an=le;BE(()=>BQ(_t,Go,an),nt)}(le.shapeFlag&256||Go&&W_(Go.vnode)&&Go.vnode.shapeFlag&256)&&HA.a&&BE(HA.a,nt),HA.isMounted=!0,le=Ve=Ft=null}};HA.scope.on();const ke=HA.effect=new M6(ei);HA.scope.off();const Ze=HA.update=ke.run.bind(ke),vt=HA.job=ke.runIfDirty.bind(ke);vt.i=HA,vt.id=HA.uid,ke.scheduler=()=>kW(vt),tv(HA,!0),Ze()},Ut=(HA,le,Ve)=>{le.component=HA;const Ft=HA.vnode.props;HA.vnode=le,HA.next=null,pnA(HA,le.props,Ft,Ve),DnA(HA,le.children,Ve),aD(),l8(HA),gD()},gi=(HA,le,Ve,Ft,nt,It,Ai,ei,ke=!1)=>{const Ze=HA&&HA.children,vt=HA?HA.shapeFlag:0,_t=le.children,{patchFlag:Oi,shapeFlag:po}=le;if(Oi>0){if(Oi&128){To(Ze,_t,Ve,Ft,nt,It,Ai,ei,ke);return}else if(Oi&256){Fi(Ze,_t,Ve,Ft,nt,It,Ai,ei,ke);return}}po&8?(vt&16&&jo(Ze,nt,It),_t!==Ze&&U(Ve,_t)):vt&16?po&16?To(Ze,_t,Ve,Ft,nt,It,Ai,ei,ke):jo(Ze,nt,It,!0):(vt&8&&U(Ve,""),po&16&&pt(_t,Ve,Ft,nt,It,Ai,ei,ke))},Fi=(HA,le,Ve,Ft,nt,It,Ai,ei,ke)=>{HA=HA||H_,le=le||H_;const Ze=HA.length,vt=le.length,_t=Math.min(Ze,vt);let Oi;for(Oi=0;Oi<_t;Oi++){const po=le[Oi]=ke?Fy(le[Oi]):fQ(le[Oi]);lA(HA[Oi],po,Ve,null,nt,It,Ai,ei,ke)}Ze>vt?jo(HA,nt,It,!0,!1,_t):pt(le,Ve,Ft,nt,It,Ai,ei,ke,_t)},To=(HA,le,Ve,Ft,nt,It,Ai,ei,ke)=>{let Ze=0;const vt=le.length;let _t=HA.length-1,Oi=vt-1;for(;Ze<=_t&&Ze<=Oi;){const po=HA[Ze],No=le[Ze]=ke?Fy(le[Ze]):fQ(le[Ze]);if(cv(po,No))lA(po,No,Ve,null,nt,It,Ai,ei,ke);else break;Ze++}for(;Ze<=_t&&Ze<=Oi;){const po=HA[_t],No=le[Oi]=ke?Fy(le[Oi]):fQ(le[Oi]);if(cv(po,No))lA(po,No,Ve,null,nt,It,Ai,ei,ke);else break;_t--,Oi--}if(Ze>_t){if(Ze<=Oi){const po=Oi+1,No=poOi)for(;Ze<=_t;)Eo(HA[Ze],nt,It,!0),Ze++;else{const po=Ze,No=Ze,so=new Map;for(Ze=No;Ze<=Oi;Ze++){const Jn=le[Ze]=ke?Fy(le[Ze]):fQ(le[Ze]);Jn.key!=null&&so.set(Jn.key,Ze)}let Go,An=0;const rn=Oi-No+1;let Es=!1,an=0;const Do=new Array(rn);for(Ze=0;Ze=rn){Eo(Jn,nt,It,!0);continue}let Qr;if(Jn.key!=null)Qr=so.get(Jn.key);else for(Go=No;Go<=Oi;Go++)if(Do[Go-No]===0&&cv(Jn,le[Go])){Qr=Go;break}Qr===void 0?Eo(Jn,nt,It,!0):(Do[Qr-No]=Ze+1,Qr>=an?an=Qr:Es=!0,lA(Jn,le[Qr],Ve,null,nt,It,Ai,ei,ke),An++)}const pA=Es?RnA(Do):H_;for(Go=pA.length-1,Ze=rn-1;Ze>=0;Ze--){const Jn=No+Ze,Qr=le[Jn],ds=Jn+1{const{el:It,type:Ai,transition:ei,children:ke,shapeFlag:Ze}=HA;if(Ze&6){io(HA.component.subTree,le,Ve,Ft);return}if(Ze&128){HA.suspense.move(le,Ve,Ft);return}if(Ze&64){Ai.move(HA,le,Ve,bi);return}if(Ai===vr){l(It,le,Ve);for(let _t=0;_tei.enter(It),nt);else{const{leave:_t,delayLeave:Oi,afterLeave:po}=ei,No=()=>l(It,le,Ve),so=()=>{_t(It,()=>{No(),po&&po()})};Oi?Oi(It,No,so):so()}else l(It,le,Ve)},Eo=(HA,le,Ve,Ft=!1,nt=!1)=>{const{type:It,props:Ai,ref:ei,children:ke,dynamicChildren:Ze,shapeFlag:vt,patchFlag:_t,dirs:Oi,cacheIndex:po}=HA;if(_t===-2&&(nt=!1),ei!=null&&pY(ei,null,Ve,HA,!0),po!=null&&(le.renderCache[po]=void 0),vt&256){le.ctx.deactivate(HA);return}const No=vt&1&&Oi,so=!W_(HA);let Go;if(so&&(Go=Ai&&Ai.onVnodeBeforeUnmount)&&BQ(Go,le,HA),vt&6)ns(HA.component,Ve,Ft);else{if(vt&128){HA.suspense.unmount(Ve,Ft);return}No&&ev(HA,null,le,"beforeUnmount"),vt&64?HA.type.remove(HA,le,Ve,bi,Ft):Ze&&!Ze.hasOnce&&(It!==vr||_t>0&&_t&64)?jo(Ze,le,Ve,!1,!0):(It===vr&&_t&384||!nt&&vt&16)&&jo(ke,le,Ve),Ft&&Vs(HA)}(so&&(Go=Ai&&Ai.onVnodeUnmounted)||No)&&BE(()=>{Go&&BQ(Go,le,HA),No&&ev(HA,null,le,"unmounted")},Ve)},Vs=HA=>{const{type:le,el:Ve,anchor:Ft,transition:nt}=HA;if(le===vr){ki(Ve,Ft);return}if(le===Gj){de(HA);return}const It=()=>{I(Ve),nt&&!nt.persisted&&nt.afterLeave&&nt.afterLeave()};if(HA.shapeFlag&1&&nt&&!nt.persisted){const{leave:Ai,delayLeave:ei}=nt,ke=()=>Ai(Ve,It);ei?ei(HA.el,It,ke):ke()}else It()},ki=(HA,le)=>{let Ve;for(;HA!==le;)Ve=IA(HA),I(HA),HA=Ve;I(le)},ns=(HA,le,Ve)=>{const{bum:Ft,scope:nt,job:It,subTree:Ai,um:ei,m:ke,a:Ze}=HA;f8(ke),f8(Ze),Ft&&X1(Ft),nt.stop(),It&&(It.flags|=8,Eo(Ai,HA,le,Ve)),ei&&BE(ei,le),BE(()=>{HA.isUnmounted=!0},le),le&&le.pendingBranch&&!le.isUnmounted&&HA.asyncDep&&!HA.asyncResolved&&HA.suspenseId===le.pendingId&&(le.deps--,le.deps===0&&le.resolve())},jo=(HA,le,Ve,Ft=!1,nt=!1,It=0)=>{for(let Ai=It;Ai{if(HA.shapeFlag&6)return Ao(HA.component.subTree);if(HA.shapeFlag&128)return HA.suspense.next();const le=IA(HA.anchor||HA.el),Ve=le&&le[q6];return Ve?IA(Ve):le};let zt=!1;const oo=(HA,le,Ve)=>{HA==null?le._vnode&&Eo(le._vnode,null,null,!0):lA(le._vnode||null,HA,le,null,null,null,Ve),le._vnode=HA,zt||(zt=!0,l8(),J6(),zt=!1)},bi={p:lA,um:Eo,m:io,r:Vs,mt:XA,mc:pt,pc:gi,pbc:Dt,n:Ao,o:t};return{render:oo,hydrate:void 0,createApp:BnA(oo)}}function Nj({type:t,props:i},r){return r==="svg"&&t==="foreignObject"||r==="mathml"&&t==="annotation-xml"&&i&&i.encoding&&i.encoding.includes("html")?void 0:r}function tv({effect:t,job:i},r){r?(t.flags|=32,i.flags|=4):(t.flags&=-33,i.flags&=-5)}function vnA(t,i){return(!t||t&&!t.pendingBranch)&&i&&!i.persisted}function UW(t,i,r=!1){const l=t.children,I=i.children;if(Ms(l)&&Ms(I))for(let h=0;h>1,t[r[w]]0&&(i[l]=r[h-1]),r[h]=l)}}for(h=r.length,f=r[h-1];h-- >0;)r[h]=f,f=i[f];return r}function h9(t){const i=t.subTree.component;if(i)return i.asyncDep&&!i.asyncResolved?i:h9(i)}function f8(t){if(t)for(let i=0;iJI(wnA);function ET(t,i){return FW(t,null,i)}function br(t,i,r){return FW(t,i,r)}function FW(t,i,r=Da){const{immediate:l,deep:I,flush:h,once:f}=r,w=sI({},r),_=i&&l||!i&&h!=="post";let b;if(mU){if(h==="sync"){const nA=_nA();b=nA.__watcherHandles||(nA.__watcherHandles=[])}else if(!_){const nA=()=>{};return nA.stop=RQ,nA.resume=RQ,nA.pause=RQ,nA}}const U=xI;w.call=(nA,mA,lA)=>rB(nA,U,mA,lA);let j=!1;h==="post"?w.scheduler=nA=>{BE(nA,U&&U.suspense)}:h!=="sync"&&(j=!0,w.scheduler=(nA,mA)=>{mA?nA():kW(nA)}),w.augmentJob=nA=>{i&&(nA.flags|=4),j&&(nA.flags|=2,U&&(nA.id=U.uid,nA.i=U))};const IA=YsA(t,i,w);return mU&&(b?b.push(IA):_&&IA()),IA}function TnA(t,i,r){const l=this.proxy,I=fg(t)?t.includes(".")?B9(l,t):()=>l[t]:t.bind(l,l);let h;$s(i)?h=i:(h=i.handler,r=i);const f=UU(this),w=FW(I,h.bind(l),r);return f(),w}function B9(t,i){const r=i.split(".");return()=>{let l=t;for(let I=0;Ii==="modelValue"||i==="model-value"?t.modelModifiers:t[`${i}Modifiers`]||t[`${sh(i)}Modifiers`]||t[`${rD(i)}Modifiers`];function GnA(t,i,...r){if(t.isUnmounted)return;const l=t.vnode.props||Da;let I=r;const h=i.startsWith("update:"),f=h&&NnA(l,i.slice(7));f&&(f.trim&&(I=r.map(U=>fg(U)?U.trim():U)),f.number&&(I=r.map(p3)));let w,_=l[w=Dj(i)]||l[w=Dj(sh(i))];!_&&h&&(_=l[w=Dj(rD(i))]),_&&rB(_,t,6,I);const b=l[w+"Once"];if(b){if(!t.emitted)t.emitted={};else if(t.emitted[w])return;t.emitted[w]=!0,rB(b,t,6,I)}}function Q9(t,i,r=!1){const l=i.emitsCache,I=l.get(t);if(I!==void 0)return I;const h=t.emits;let f={},w=!1;if(!$s(t)){const _=b=>{const U=Q9(b,i,!0);U&&(w=!0,sI(f,U))};!r&&i.mixins.length&&i.mixins.forEach(_),t.extends&&_(t.extends),t.mixins&&t.mixins.forEach(_)}return!h&&!w?(Na(t)&&l.set(t,null),null):(Ms(h)?h.forEach(_=>f[_]=null):sI(f,h),Na(t)&&l.set(t,f),f)}function gV(t,i){return!t||!$Y(i)?!1:(i=i.slice(2).replace(/Once$/,""),Wr(t,i[0].toLowerCase()+i.slice(1))||Wr(t,rD(i))||Wr(t,i))}function y8(t){const{type:i,vnode:r,proxy:l,withProxy:I,propsOptions:[h],slots:f,attrs:w,emit:_,render:b,renderCache:U,props:j,data:IA,setupState:nA,ctx:mA,inheritAttrs:lA}=t,cA=QY(t);let TA,WA;try{if(r.shapeFlag&4){const de=I||l,Pe=de;TA=fQ(b.call(Pe,de,U,j,nA,IA,mA)),WA=w}else{const de=i;TA=fQ(de.length>1?de(j,{attrs:w,slots:f,emit:_}):de(j,null)),WA=i.props?w:bnA(w)}}catch(de){$L.length=0,sV(de,t,1),TA=bt(mE)}let Ee=TA;if(WA&&lA!==!1){const de=Object.keys(WA),{shapeFlag:Pe}=Ee;de.length&&Pe&7&&(h&&de.some(SW)&&(WA=knA(WA,h)),Ee=eD(Ee,WA,!1,!0))}return r.dirs&&(Ee=eD(Ee,null,!1,!0),Ee.dirs=Ee.dirs?Ee.dirs.concat(r.dirs):r.dirs),r.transition&&BU(Ee,r.transition),TA=Ee,QY(cA),TA}const bnA=t=>{let i;for(const r in t)(r==="class"||r==="style"||$Y(r))&&((i||(i={}))[r]=t[r]);return i},knA=(t,i)=>{const r={};for(const l in t)(!SW(l)||!(l.slice(9)in i))&&(r[l]=t[l]);return r};function LnA(t,i,r){const{props:l,children:I,component:h}=t,{props:f,children:w,patchFlag:_}=i,b=h.emitsOptions;if(i.dirs||i.transition)return!0;if(r&&_>=0){if(_&1024)return!0;if(_&16)return l?D8(l,f,b):!!f;if(_&8){const U=i.dynamicProps;for(let j=0;jt.__isSuspense;function FnA(t,i){i&&i.pendingBranch?Ms(t)?i.effects.push(...t):i.effects.push(t):HsA(t)}const vr=Symbol.for("v-fgt"),cV=Symbol.for("v-txt"),mE=Symbol.for("v-cmt"),Gj=Symbol.for("v-stc"),$L=[];let oC=null;function oe(t=!1){$L.push(oC=t?null:[])}function OnA(){$L.pop(),oC=$L[$L.length-1]||null}let QU=1;function S8(t,i=!1){QU+=t,t<0&&oC&&i&&(oC.hasOnce=!0)}function m9(t){return t.dynamicChildren=QU>0?oC||H_:null,OnA(),QU>0&&oC&&oC.push(t),t}function $e(t,i,r,l,I,h){return m9(re(t,i,r,l,I,h,!0))}function Qi(t,i,r,l,I){return m9(bt(t,i,r,l,I,!0))}function pU(t){return t?t.__v_isVNode===!0:!1}function cv(t,i){return t.type===i.type&&t.key===i.key}const f9=({key:t})=>t??null,AY=({ref:t,ref_key:i,ref_for:r})=>(typeof t=="number"&&(t=""+t),t!=null?fg(t)||iI(t)||$s(t)?{i:tI,r:t,k:i,f:!!r}:t:null);function re(t,i=null,r=null,l=0,I=null,h=t===vr?0:1,f=!1,w=!1){const _={__v_isVNode:!0,__v_skip:!0,type:t,props:i,key:i&&f9(i),ref:i&&AY(i),scopeId:nV,slotScopeIds:null,children:r,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:h,patchFlag:l,dynamicProps:I,dynamicChildren:null,appContext:null,ctx:tI};return w?(OW(_,r),h&128&&t.normalize(_)):r&&(_.shapeFlag|=fg(r)?8:16),QU>0&&!f&&oC&&(_.patchFlag>0||h&6)&&_.patchFlag!==32&&oC.push(_),_}const bt=PnA;function PnA(t,i=null,r=null,l=0,I=null,h=!1){if((!t||t===gnA)&&(t=mE),pU(t)){const w=eD(t,i,!0);return r&&OW(w,r),QU>0&&!h&&oC&&(w.shapeFlag&6?oC[oC.indexOf(t)]=w:oC.push(w)),w.patchFlag=-2,w}if(ZnA(t)&&(t=t.__vccOpts),i){i=xnA(i);let{class:w,style:_}=i;w&&!fg(w)&&(i.class=qi(w)),Na(_)&&(bW(_)&&!Ms(_)&&(_=sI({},_)),i.style=Br(_))}const f=fg(t)?1:p9(t)?128:K6(t)?64:Na(t)?4:$s(t)?2:0;return re(t,i,r,l,I,f,h,!0)}function xnA(t){return t?bW(t)||c9(t)?sI({},t):t:null}function eD(t,i,r=!1,l=!1){const{props:I,ref:h,patchFlag:f,children:w,transition:_}=t,b=i?T3(I||{},i):I,U={__v_isVNode:!0,__v_skip:!0,type:t.type,props:b,key:b&&f9(b),ref:i&&i.ref?r&&h?Ms(h)?h.concat(AY(i)):[h,AY(i)]:AY(i):h,scopeId:t.scopeId,slotScopeIds:t.slotScopeIds,children:w,target:t.target,targetStart:t.targetStart,targetAnchor:t.targetAnchor,staticCount:t.staticCount,shapeFlag:t.shapeFlag,patchFlag:i&&t.type!==vr?f===-1?16:f|16:f,dynamicProps:t.dynamicProps,dynamicChildren:t.dynamicChildren,appContext:t.appContext,dirs:t.dirs,transition:_,component:t.component,suspense:t.suspense,ssContent:t.ssContent&&eD(t.ssContent),ssFallback:t.ssFallback&&eD(t.ssFallback),el:t.el,anchor:t.anchor,ctx:t.ctx,ce:t.ce};return _&&l&&BU(U,_.clone(U)),U}function Ia(t=" ",i=0){return bt(cV,null,t,i)}function Wt(t="",i=!1){return i?(oe(),Qi(mE,null,t)):bt(mE,null,t)}function fQ(t){return t==null||typeof t=="boolean"?bt(mE):Ms(t)?bt(vr,null,t.slice()):pU(t)?Fy(t):bt(cV,null,String(t))}function Fy(t){return t.el===null&&t.patchFlag!==-1||t.memo?t:eD(t)}function OW(t,i){let r=0;const{shapeFlag:l}=t;if(i==null)i=null;else if(Ms(i))r=16;else if(typeof i=="object")if(l&65){const I=i.default;I&&(I._c&&(I._d=!1),OW(t,I()),I._c&&(I._d=!0));return}else{r=32;const I=i._;!I&&!c9(i)?i._ctx=tI:I===3&&tI&&(tI.slots._===1?i._=1:(i._=2,t.patchFlag|=1024))}else $s(i)?(i={default:i,_ctx:tI},r=32):(i=String(i),l&64?(r=16,i=[Ia(i)]):r=8);t.children=i,t.shapeFlag|=r}function T3(...t){const i={};for(let r=0;r