fix: 空评论列表 500,并完善撤回审计与角色说明
空切片 JSON 统一为数组;撤回保留正文供站长阅读,成员侧居中提示与重新编辑;头像支持拖放;角色弹窗补全职责说明并汇入封禁。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
} from "@/lib/api";
|
||||
import { realtime, RT_CHAT_UNREAD, RT_CHAT_MEMBERSHIP } from "@/lib/realtime";
|
||||
import type { RtChatUnreadData, RtChatMembershipData } from "@/lib/realtime";
|
||||
import { onDocumentVisible } from "@/lib/visibilityReconcile";
|
||||
import { toast } from "@/lib/toast";
|
||||
import Avatar from "@/components/Avatar";
|
||||
import ContextMenu, { type CtxMenuItem } from "@/components/ContextMenu";
|
||||
@@ -114,28 +115,35 @@ export default function ChatShell({
|
||||
setRooms(sortRooms(initialRooms));
|
||||
}, [initialRooms]);
|
||||
|
||||
const refreshRooms = useCallback(async () => {
|
||||
const roomsInFlight = useRef(false);
|
||||
const lastRoomsFetchAt = useRef(0);
|
||||
|
||||
const refreshRooms = useCallback(async (opts?: { force?: boolean }) => {
|
||||
const now = Date.now();
|
||||
if (!opts?.force) {
|
||||
if (roomsInFlight.current) return;
|
||||
// 切房/回前台可合并;建群、被邀请等走 force
|
||||
if (now - lastRoomsFetchAt.current < 2_000) return;
|
||||
}
|
||||
roomsInFlight.current = true;
|
||||
lastRoomsFetchAt.current = now;
|
||||
try {
|
||||
const res = await apiListChatRooms(1, 50, "", "joined");
|
||||
setRooms(sortRooms(res.rooms || []));
|
||||
} catch {
|
||||
// 静默
|
||||
} finally {
|
||||
roomsInFlight.current = false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 每次进入消息壳都用 HTTP 拉最新排序(避免首页 Link 预取/路由缓存导致新消息会话不置顶)
|
||||
// 进入消息壳 / 切会话:HTTP 拉最新排序(避开预取缓存)
|
||||
useEffect(() => {
|
||||
refreshRooms();
|
||||
void refreshRooms();
|
||||
}, [refreshRooms, activeRoomId]);
|
||||
|
||||
// 从其他标签页切回时也对账一次
|
||||
useEffect(() => {
|
||||
const onVisible = () => {
|
||||
if (document.visibilityState === "visible") refreshRooms();
|
||||
};
|
||||
document.addEventListener("visibilitychange", onVisible);
|
||||
return () => document.removeEventListener("visibilitychange", onVisible);
|
||||
}, [refreshRooms]);
|
||||
// 从其他标签页切回时对账(10s 限频 + 上方 2s 合并)
|
||||
useEffect(() => onDocumentVisible(() => void refreshRooms()), [refreshRooms]);
|
||||
|
||||
// 实时未读:更新侧栏角标与预览,按置顶规则重排(不盲目置顶到最前)
|
||||
useEffect(() => {
|
||||
@@ -145,7 +153,7 @@ export default function ChatShell({
|
||||
setRooms((prev) => {
|
||||
const idx = prev.findIndex((r) => r.id === data.room_id);
|
||||
if (idx < 0) {
|
||||
refreshRooms();
|
||||
void refreshRooms({ force: true });
|
||||
return prev;
|
||||
}
|
||||
const next = [...prev];
|
||||
@@ -179,7 +187,7 @@ export default function ChatShell({
|
||||
const off = realtime.on<RtChatMembershipData>(RT_CHAT_MEMBERSHIP, (data) => {
|
||||
if (!data) return;
|
||||
if (data.status === "invited" || data.status === "dissolved" || data.status === "kicked") {
|
||||
refreshRooms();
|
||||
void refreshRooms({ force: true });
|
||||
}
|
||||
});
|
||||
return off;
|
||||
@@ -230,7 +238,7 @@ export default function ChatShell({
|
||||
setQuery("");
|
||||
setUserHits([]);
|
||||
router.push(`/chat/${room.id}`);
|
||||
refreshRooms();
|
||||
void refreshRooms({ force: true });
|
||||
} catch (e) {
|
||||
toast(e instanceof Error ? e.message : "无法发起私聊");
|
||||
}
|
||||
@@ -524,7 +532,7 @@ export default function ChatShell({
|
||||
setShowCreate(false);
|
||||
toast("群已创建", "ok");
|
||||
router.push(`/chat/${id}`);
|
||||
refreshRooms();
|
||||
void refreshRooms({ force: true });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user