fix(web): 隐藏文件助手入口,修复自聊天详情栏错误操作

后端目前没有支持文件助手所需的配额/分类等能力,只是把它当作
普通话题处理;与其做一个功能不全的界面,先从导航栏、会话列表
置顶区、通讯录固定入口、设置页移动端快捷入口中移除该入口。slf
话题现在按普通会话行为处理(排序、未读计数均不再特殊处理)。

同时修复 DetailColumn 对自聊天(slf)显示语音/视频通话、备注、
拉黑、举报、删除好友等对自己无意义操作的问题,改为仅显示适用
的发消息/查找聊天记录/置顶/免打扰/清空聊天记录等项。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-09-09 23:35:58 +08:00
co-authored by Claude Sonnet 5
parent 3065e232be
commit 9271a0a9c1
6 changed files with 97 additions and 98 deletions
+58 -39
View File
@@ -70,10 +70,19 @@ export function DetailColumn({ topicId, peerName, onClose, onOpenHistory }: Deta
setErrorToast('');
}, [topicId]);
// `slf` (self-chat, e.g. opened via a chat-list row once it has real history -- there is no
// "文件助手" entry point pointing at it anymore, see ChatListColumn.tsx's PINNED_ENTRIES doc
// comment) isn't a friend and isn't really "someone else" at all -- getUserProfile('slf') has no
// real user to look up, and every friend-only action below (remark/block/report/delete friend)
// is nonsensical pointed at yourself. Gated out entirely rather than left to silently no-op or
// error, confirmed live: this used to render "加入黑名单"/"投诉举报"/"删除好友" for your own notes
// to yourself.
const isSelf = topicId === 'slf';
const friendsQuery = useQuery({ queryKey: ['friends'], queryFn: () => fetchAllPages((cursor) => getFriends('', cursor)) });
const friend = friendsQuery.data?.find((f) => f.user_id === topicId);
const profileQuery = useQuery({ queryKey: ['user-profile', topicId], queryFn: () => getUserProfile(topicId) });
const profileQuery = useQuery({ queryKey: ['user-profile', topicId], queryFn: () => getUserProfile(topicId), enabled: !isSelf });
const idLine = [profileQuery.data?.public_account && `ID:${profileQuery.data.public_account}`, profileQuery.data?.region]
.filter(Boolean)
.join(' · ');
@@ -160,28 +169,32 @@ export function DetailColumn({ topicId, peerName, onClose, onOpenHistory }: Deta
<Icon name="chat_bubble_outline" className="text-[20px]" />
<span className="text-xs text-text-secondary">发消息</span>
</button>
<button
type="button"
disabled={profileQuery.data?.capabilities?.can_call === false}
onClick={() => {
if (useCallStore.getState().phase === 'idle') useCallStore.getState().startCall(topicId, peerName, 'audio');
}}
className="flex w-19 flex-col items-center gap-1 rounded-[10px] bg-surface-rail py-2.5 text-accent disabled:opacity-50"
>
<Icon name="call" className="text-[20px]" />
<span className="text-xs text-text-secondary">语音</span>
</button>
<button
type="button"
disabled={profileQuery.data?.capabilities?.can_call === false}
onClick={() => {
if (useCallStore.getState().phase === 'idle') useCallStore.getState().startCall(topicId, peerName, 'video');
}}
className="flex w-19 flex-col items-center gap-1 rounded-[10px] bg-surface-rail py-2.5 text-accent disabled:opacity-50"
>
<Icon name="videocam" className="text-[20px]" />
<span className="text-xs text-text-secondary">视频</span>
</button>
{isSelf ? null : (
<>
<button
type="button"
disabled={profileQuery.data?.capabilities?.can_call === false}
onClick={() => {
if (useCallStore.getState().phase === 'idle') useCallStore.getState().startCall(topicId, peerName, 'audio');
}}
className="flex w-19 flex-col items-center gap-1 rounded-[10px] bg-surface-rail py-2.5 text-accent disabled:opacity-50"
>
<Icon name="call" className="text-[20px]" />
<span className="text-xs text-text-secondary">语音</span>
</button>
<button
type="button"
disabled={profileQuery.data?.capabilities?.can_call === false}
onClick={() => {
if (useCallStore.getState().phase === 'idle') useCallStore.getState().startCall(topicId, peerName, 'video');
}}
className="flex w-19 flex-col items-center gap-1 rounded-[10px] bg-surface-rail py-2.5 text-accent disabled:opacity-50"
>
<Icon name="videocam" className="text-[20px]" />
<span className="text-xs text-text-secondary">视频</span>
</button>
</>
)}
</div>
</div>
@@ -208,7 +221,7 @@ export function DetailColumn({ topicId, peerName, onClose, onOpenHistory }: Deta
</div>
<div className="flex flex-col border-b border-border-list-item px-5 text-sm">
{remarkEditing ? (
{isSelf ? null : remarkEditing ? (
<div className="flex items-center gap-2 py-3">
<span className="flex-none text-text-body">备注</span>
<input
@@ -254,10 +267,12 @@ export function DetailColumn({ topicId, peerName, onClose, onOpenHistory }: Deta
onChange={() => updateSettings.mutate({ mute_notifications: !settingsQuery.data?.mute_notifications })}
/>
</div>
<div className="flex items-center justify-between py-3">
<span className="text-text-body">加入黑名单</span>
<Toggle checked={isBlocked} disabled={blockMutation.isPending} onChange={() => blockMutation.mutate(!isBlocked)} />
</div>
{isSelf ? null : (
<div className="flex items-center justify-between py-3">
<span className="text-text-body">加入黑名单</span>
<Toggle checked={isBlocked} disabled={blockMutation.isPending} onChange={() => blockMutation.mutate(!isBlocked)} />
</div>
)}
</div>
<div className="flex flex-col px-5 pb-2 text-sm">
@@ -265,19 +280,23 @@ export function DetailColumn({ topicId, peerName, onClose, onOpenHistory }: Deta
<span className="text-text-body">清空聊天记录</span>
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
</button>
<button type="button" onClick={reportAbuse} className="flex items-center justify-between py-3 text-left">
<span className="text-text-body">投诉举报</span>
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
</button>
{isSelf ? null : (
<button type="button" onClick={reportAbuse} className="flex items-center justify-between py-3 text-left">
<span className="text-text-body">投诉举报</span>
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
</button>
)}
</div>
<button
type="button"
onClick={startDeleteFriend}
className="mx-5 my-4 h-10 flex-none rounded-lg border border-danger-border-soft text-sm text-danger-text"
>
删除好友
</button>
{isSelf ? null : (
<button
type="button"
onClick={startDeleteFriend}
className="mx-5 my-4 h-10 flex-none rounded-lg border border-danger-border-soft text-sm text-danger-text"
>
删除好友
</button>
)}
<Toast message={errorToast} variant="error" onDone={() => setErrorToast('')} />
</aside>