群成员格子改回独立"移出"格子,点击打开成员列表,不再是逐头像角标+直接移出
用户再次纠正:不要在每个可移出成员的头像上单独加角标、点击直接弹确认移出;而是 像"+邀请"一样,做一个独立的"-移出"格子(同款虚线方块,仅 isAdmin 可见),点击后 打开"查看全部"成员列表,真正的移出操作留在列表里已有的那一行按钮上。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
05ee23aefa
commit
2427a3782c
@@ -12,7 +12,6 @@ import { GroupAnnouncementModal } from '@/features/groups/GroupAnnouncementModal
|
|||||||
import { GroupFilesModal } from '@/features/groups/GroupFilesModal';
|
import { GroupFilesModal } from '@/features/groups/GroupFilesModal';
|
||||||
import { GroupMembersModal } from '@/features/groups/GroupMembersModal';
|
import { GroupMembersModal } from '@/features/groups/GroupMembersModal';
|
||||||
import {
|
import {
|
||||||
canRemoveMember,
|
|
||||||
disbandGroup,
|
disbandGroup,
|
||||||
getGroup,
|
getGroup,
|
||||||
getMyGroupProfile,
|
getMyGroupProfile,
|
||||||
@@ -20,7 +19,6 @@ import {
|
|||||||
getGroupSettings,
|
getGroupSettings,
|
||||||
getGroupSummary,
|
getGroupSummary,
|
||||||
leaveGroup,
|
leaveGroup,
|
||||||
removeGroupMember,
|
|
||||||
updateGroup,
|
updateGroup,
|
||||||
updateGroupMemberSettings,
|
updateGroupMemberSettings,
|
||||||
updateMyGroupNickname,
|
updateMyGroupNickname,
|
||||||
@@ -73,27 +71,6 @@ function RoleCorner({ role }: { role: GroupMember['role'] }) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Corner "-" badge for a removable member's avatar in the compact grid -- the "outside the avatar,
|
|
||||||
* like the +邀请 tile" treatment (explicit user correction: a text "移出" link inside a member ROW is
|
|
||||||
* the full-list modal's job, not this grid's). Opposite corner from RoleCorner (top-right, not
|
|
||||||
* top-left) because both can legitimately apply to the same avatar at once -- an owner removing an
|
|
||||||
* admin still needs the "管" tag AND this badge on one avatar. */
|
|
||||||
function RemoveBadge({ pending, onRemove }: { pending: boolean; onRemove: () => void }) {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
disabled={pending}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
onRemove();
|
|
||||||
}}
|
|
||||||
aria-label="移出群聊"
|
|
||||||
className="absolute -right-1 -top-1 z-10 grid h-4 w-4 place-items-center rounded-full bg-danger-text text-white shadow-sm disabled:opacity-60 md:h-[18px] md:w-[18px]"
|
|
||||||
>
|
|
||||||
<Icon name="remove" className="text-[10px]" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* README §4.4's 群聊设置 detail rail (group-owner/admin/member view). Sibling of DetailColumn.tsx
|
* README §4.4's 群聊设置 detail rail (group-owner/admin/member view). Sibling of DetailColumn.tsx
|
||||||
@@ -207,19 +184,6 @@ export function GroupDetailColumn({ topicId, peerName, onClose, onOpenHistory }:
|
|||||||
onError: (err) => showError(err, '群名保存失败'),
|
onError: (err) => showError(err, '群名保存失败'),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Drives the corner "-" badge on the compact member grid below -- same removeGroupMember call and
|
|
||||||
// same invalidation keys as GroupMembersModal's own remove button (canRemoveMember is now shared
|
|
||||||
// from lib/api/groups.ts so the two surfaces can't drift on who's eligible to remove whom).
|
|
||||||
const removeMutation = useMutation({
|
|
||||||
mutationFn: (userId: string) => removeGroupMember(topicId, userId),
|
|
||||||
onSuccess: () => {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['group-members', topicId] });
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['group-members-preview', topicId] });
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['group', topicId] });
|
|
||||||
},
|
|
||||||
onError: (err) => showError(err, '移出失败,请重试'),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Both mutations call forgetTopic() the instant their own REST call succeeds, rather than waiting
|
// Both mutations call forgetTopic() the instant their own REST call succeeds, rather than waiting
|
||||||
// on the async native/`group.dissolved` gone-signal that normally follows a group actually going
|
// on the async native/`group.dissolved` gone-signal that normally follows a group actually going
|
||||||
// away -- real, user-reported bugs fixed by this: (1) the chat list kept showing a broken stale
|
// away -- real, user-reported bugs fixed by this: (1) the chat list kept showing a broken stale
|
||||||
@@ -409,17 +373,6 @@ export function GroupDetailColumn({ topicId, peerName, onClose, onOpenHistory }:
|
|||||||
className="h-11 w-11 rounded-lg text-sm md:h-10 md:w-10"
|
className="h-11 w-11 rounded-lg text-sm md:h-10 md:w-10"
|
||||||
/>
|
/>
|
||||||
<RoleCorner role={m.role} />
|
<RoleCorner role={m.role} />
|
||||||
{canRemoveMember(myUserId, myRole || 'member', m) ? (
|
|
||||||
<RemoveBadge
|
|
||||||
pending={removeMutation.isPending && removeMutation.variables === m.user_id}
|
|
||||||
onRemove={async () => {
|
|
||||||
const label = m.display_name || m.user_id;
|
|
||||||
if (await requestConfirm({ message: `确定将"${label}"移出群聊吗?`, danger: true })) {
|
|
||||||
removeMutation.mutate(m.user_id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<span className="w-full truncate text-center text-[11px] text-text-secondary">{m.display_name || m.user_id}</span>
|
<span className="w-full truncate text-center text-[11px] text-text-secondary">{m.display_name || m.user_id}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -437,6 +390,20 @@ export function GroupDetailColumn({ topicId, peerName, onClose, onOpenHistory }:
|
|||||||
<span className="text-[11px] text-text-secondary">邀请</span>
|
<span className="text-[11px] text-text-secondary">邀请</span>
|
||||||
</button>
|
</button>
|
||||||
) : null}
|
) : null}
|
||||||
|
{isAdmin ? (
|
||||||
|
// Sibling tile to "+邀请" right above -- same dashed-square treatment, mirrored icon.
|
||||||
|
// A single standalone entry point into the plain member list (not a per-avatar corner
|
||||||
|
// badge, and not a direct remove action) -- the actual "移出" control already lives on
|
||||||
|
// each removable row inside that list. Explicit user correction after a first attempt
|
||||||
|
// put a "-" badge on every removable avatar's own corner: that read as "many separate
|
||||||
|
// remove buttons" when the intent was one "+"-shaped entry point, mirroring "+邀请".
|
||||||
|
<button type="button" onClick={() => setOpenModal('members')} className="flex flex-col items-center gap-1">
|
||||||
|
<span className="grid h-11 w-11 place-items-center rounded-lg border border-dashed border-[#c5cad2] text-text-tertiary-3 md:h-10 md:w-10">
|
||||||
|
<Icon name="remove" className="text-[18px]" />
|
||||||
|
</span>
|
||||||
|
<span className="text-[11px] text-text-secondary">移出</span>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onClick={() => setOpenModal('members')} className="mt-2 flex justify-center py-1 text-[13px] text-accent md:hidden">
|
<button type="button" onClick={() => setOpenModal('members')} className="mt-2 flex justify-center py-1 text-[13px] text-accent md:hidden">
|
||||||
查看全部成员 ({memberCount})
|
查看全部成员 ({memberCount})
|
||||||
|
|||||||
Reference in New Issue
Block a user