修复codereview复核确认的多选/转发/收藏页/资料页等前端bug

- 多选模式下Drafty链接、名片消息不再意外触发跳转/开新标签页
- 语音/视频消息在多选模式下点击可正常冒泡选中该行
- 转发排除未确认/发送失败消息,识别uncertain转发结果并单独提示
- 群文件"更多操作"菜单竞态、群成员移出状态竞态
- 收藏页链接卡片new URL()崩溃点加防御,并给登录后应用区域加错误边界
- 个人资料页乐观锁版本冲突时清空草稿避免静默覆盖并发修改

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-09-27 16:47:32 +08:00
co-authored by Claude Sonnet 5
parent e3eed8bdd4
commit 9abae5030b
10 changed files with 142 additions and 27 deletions
+13 -1
View File
@@ -144,7 +144,19 @@ function FavoriteCard({ item, selectMode, selected, onToggle }: { item: Favorite
// Only show a second line when it says something the title line doesn't already -- a
// hostname alongside a real title/url is useful, but repeating `text` under itself when
// that's ALSO what the title line fell back to would just be the same line twice.
const subtitle = item.snapshot.url ? new URL(item.snapshot.url).hostname : title === text ? '' : text;
// `new URL()` throws on anything that isn't a well-formed absolute URL -- `url` can come from
// another client's own Drafty implementation or the backend's own extraction logic (docs/
// IM-前后端对接文档.md §7.6), neither of which this codebase controls the shape of. A single
// malformed value here must not crash the whole render (there's no error boundary around this
// list short of react-router's own default one, which would replace the entire logged-in UI).
let subtitle = title === text ? '' : text;
if (item.snapshot.url) {
try {
subtitle = new URL(item.snapshot.url).hostname;
} catch {
// fall through to the plain-text fallback computed above
}
}
return (
<div className="flex items-start gap-3">
{item.snapshot.thumbnail_file_id ? (