修复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
+14 -4
View File
@@ -31,15 +31,25 @@ import { openUserCard } from '@/stores/userCard';
/** Distinct from a regular Drafty-rendered bubble -- see `contactCardContentOf`'s own doc comment
* for why this is dispatched by `head['x-im-type']` rather than a Drafty style tag. Tapping opens
* the real profile page, the one thing a contact-card message is fundamentally for. */
function ContactCardBubble({ content }: { content: ContactCardContent }) {
function ContactCardBubble({ content, locked }: { content: ContactCardContent; locked?: boolean }) {
const name = content.display_name || content.public_account || content.user_id;
return (
<Link to={`/contacts/${content.user_id}`} className="flex w-[220px] items-center gap-3 no-underline">
const inner = (
<>
<Avatar id={content.user_id} name={name} avatarFileId={content.avatar_file_id} className="h-11 w-11 flex-none rounded-lg text-base" />
<span className="flex min-w-0 flex-col">
<span className="truncate text-sm font-medium text-text-body">{name}</span>
{content.public_account ? <span className="truncate text-xs text-text-tertiary-2">ID: {content.public_account}</span> : null}
</span>
</>
);
// `locked` (selectMode): same reasoning as the avatar/@mention buttons elsewhere in this file --
// a tap must only toggle the row, not navigate away and lose whatever's already been picked.
if (locked) {
return <div className="flex w-[220px] items-center gap-3">{inner}</div>;
}
return (
<Link to={`/contacts/${content.user_id}`} className="flex w-[220px] items-center gap-3 no-underline">
{inner}
</Link>
);
}
@@ -236,7 +246,7 @@ export function MessageRow({
{callResult.text}
</span>
) : contactCard ? (
<ContactCardBubble content={contactCard} />
<ContactCardBubble content={contactCard} locked={selectMode} />
) : mobileAttachment ? (
mobileAttachment.kind === 'image' ? (
<ImageAttachment data={mobileAttachment} locked={selectMode} />