fix(chat): 发送后切会话不再误标未读,管理端撤回实时同步到对话页
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -48,6 +48,7 @@ import { canOverseeChat } from "@/lib/roles";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { scrollBehavior } from "@/lib/motion";
|
||||
import Avatar from "@/components/Avatar";
|
||||
import AutolinkText from "@/components/AutolinkText";
|
||||
import ConfirmDialog from "@/components/ConfirmDialog";
|
||||
import ContextMenu, { type CtxMenuItem } from "@/components/ContextMenu";
|
||||
|
||||
@@ -56,10 +57,11 @@ const MARK_READ_GAP_MS = 2_000;
|
||||
const markReadInflight = new Set<number>();
|
||||
const markReadLastAt = new Map<number, number>();
|
||||
|
||||
function requestMarkChatRead(roomId: number): void {
|
||||
function requestMarkChatRead(roomId: number, opts?: { force?: boolean }): void {
|
||||
const now = Date.now();
|
||||
const last = markReadLastAt.get(roomId) || 0;
|
||||
if (markReadInflight.has(roomId) || now - last < MARK_READ_GAP_MS) return;
|
||||
if (markReadInflight.has(roomId)) return;
|
||||
if (!opts?.force && now - last < MARK_READ_GAP_MS) return;
|
||||
markReadInflight.add(roomId);
|
||||
markReadLastAt.set(roomId, now);
|
||||
apiMarkChatRead(roomId, 0)
|
||||
@@ -235,6 +237,17 @@ function highlightMentions(content: string, members: ChatRoomMember[]) {
|
||||
return parts;
|
||||
}
|
||||
|
||||
/** 消息正文:URL 自动识别 + @提及;外链新开跟随站点策略 */
|
||||
function renderChatContent(content: string, members: ChatRoomMember[]) {
|
||||
return (
|
||||
<AutolinkText
|
||||
text={content}
|
||||
forceNewTab
|
||||
renderText={(seg) => <>{highlightMentions(seg, members)}</>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/** 输入区镜像层:已确认的 @ 显示为飞书风 token */
|
||||
function renderComposerMirror(content: string, tokens: Set<string>) {
|
||||
if (!content) return null;
|
||||
@@ -405,10 +418,13 @@ export default function ChatRoomClient({
|
||||
}
|
||||
}, [roomId, canView]);
|
||||
|
||||
const markReadToLatest = useCallback(() => {
|
||||
if (!isRealMember) return;
|
||||
requestMarkChatRead(roomId);
|
||||
}, [roomId, isRealMember]);
|
||||
const markReadToLatest = useCallback(
|
||||
(opts?: { force?: boolean }) => {
|
||||
if (!isRealMember) return;
|
||||
requestMarkChatRead(roomId, opts);
|
||||
},
|
||||
[roomId, isRealMember]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canView) return;
|
||||
@@ -563,7 +579,11 @@ export default function ChatRoomClient({
|
||||
return [...prev, message];
|
||||
});
|
||||
requestAnimationFrame(() => scrollToBottom(true));
|
||||
markReadToLatest();
|
||||
// 发送成功立刻同步侧栏预览,并强制推进已读(避开进房 MarkRead 的 2s 节流)
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("j13-chat-sent", { detail: { roomId, message } })
|
||||
);
|
||||
markReadToLatest({ force: true });
|
||||
} catch (e) {
|
||||
setContent(prevContent);
|
||||
setMentionTokens(prevTokens);
|
||||
@@ -1196,7 +1216,7 @@ export default function ChatRoomClient({
|
||||
已撤回
|
||||
</div>
|
||||
<div style={{ color: "var(--ink-2)" }}>
|
||||
{highlightMentions(m.content, members)}
|
||||
{renderChatContent(m.content, members)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1291,7 +1311,7 @@ export default function ChatRoomClient({
|
||||
{m.reply_snap}
|
||||
</button>
|
||||
)}
|
||||
{highlightMentions(m.content, members)}
|
||||
{renderChatContent(m.content, members)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user