Migrate frontend realtime messaging to SSE.
Switch service integrations and screen/store consumers from websocket events to SSE, and ignore generated dist-web artifacts. Made-with: Cursor
This commit is contained in:
@@ -117,8 +117,8 @@ const GroupInfoScreen: React.FC = () => {
|
||||
|
||||
// 并行加载群组信息和成员列表
|
||||
const [groupData, membersData] = await Promise.all([
|
||||
groupManager.getGroup(groupId),
|
||||
groupManager.getMembers(groupId, 1, 100),
|
||||
groupManager.getGroup(groupId, true),
|
||||
groupManager.getMembers(groupId, 1, 100, true),
|
||||
]);
|
||||
|
||||
setGroup(groupData);
|
||||
|
||||
@@ -92,11 +92,16 @@ const GroupMembersScreen: React.FC = () => {
|
||||
const isAdmin = currentMember?.role === 'admin' || isOwner;
|
||||
|
||||
// 加载成员列表
|
||||
const loadMembers = useCallback(async (pageNum: number = 1, refresh: boolean = false) => {
|
||||
const loadMembers = useCallback(
|
||||
async (
|
||||
pageNum: number = 1,
|
||||
refresh: boolean = false,
|
||||
forceRefresh: boolean = false
|
||||
) => {
|
||||
if (!hasMore && !refresh) return;
|
||||
|
||||
try {
|
||||
const response = await groupManager.getMembers(groupId, pageNum, 50);
|
||||
const response = await groupManager.getMembers(groupId, pageNum, 50, forceRefresh);
|
||||
|
||||
if (refresh) {
|
||||
setMembers(response.list);
|
||||
@@ -121,14 +126,14 @@ const GroupMembersScreen: React.FC = () => {
|
||||
|
||||
// 初始加载
|
||||
useEffect(() => {
|
||||
loadMembers(1, true);
|
||||
loadMembers(1, true, true);
|
||||
}, [groupId]);
|
||||
|
||||
// 下拉刷新
|
||||
const onRefresh = useCallback(() => {
|
||||
setRefreshing(true);
|
||||
setHasMore(true);
|
||||
loadMembers(1, true);
|
||||
loadMembers(1, true, true);
|
||||
}, [loadMembers]);
|
||||
|
||||
// 加载更多
|
||||
@@ -246,6 +251,8 @@ const GroupMembersScreen: React.FC = () => {
|
||||
}
|
||||
return m;
|
||||
}));
|
||||
// 强制刷新远端状态,避免命中旧缓存导致解禁后仍显示禁言
|
||||
await loadMembers(1, true, true);
|
||||
|
||||
setActionModalVisible(false);
|
||||
Alert.alert('成功', `已${actionText}`);
|
||||
|
||||
@@ -72,9 +72,10 @@ const truncateDisplayName = (name: string, maxLength: number = MAX_CONVERSATION_
|
||||
*/
|
||||
const AsyncMessagePreview: React.FC<{
|
||||
segments?: MessageSegment[];
|
||||
status?: string;
|
||||
isGroupChat?: boolean;
|
||||
senderName?: string;
|
||||
}> = ({ segments, isGroupChat, senderName }) => {
|
||||
}> = ({ segments, status, isGroupChat, senderName }) => {
|
||||
const [displayText, setDisplayText] = useState<string>('');
|
||||
const isMountedRef = useRef(true);
|
||||
|
||||
@@ -82,6 +83,13 @@ const AsyncMessagePreview: React.FC<{
|
||||
isMountedRef.current = true;
|
||||
|
||||
const loadPreview = async () => {
|
||||
if (status === 'recalled') {
|
||||
if (isMountedRef.current) {
|
||||
setDisplayText('消息已撤回');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const initialText = extractTextFromSegments(segments);
|
||||
if (isMountedRef.current) {
|
||||
setDisplayText(initialText);
|
||||
@@ -112,7 +120,7 @@ const AsyncMessagePreview: React.FC<{
|
||||
return () => {
|
||||
isMountedRef.current = false;
|
||||
};
|
||||
}, [segments]);
|
||||
}, [segments, status]);
|
||||
|
||||
if (!displayText) return null;
|
||||
|
||||
@@ -556,6 +564,7 @@ export const MessageListScreen: React.FC = () => {
|
||||
) : (
|
||||
<AsyncMessagePreview
|
||||
segments={item.last_message?.segments}
|
||||
status={item.last_message?.status}
|
||||
isGroupChat={isGroupChat}
|
||||
senderName={getSenderName()}
|
||||
/>
|
||||
|
||||
@@ -27,9 +27,6 @@ import { uploadService } from '../../../../services/uploadService';
|
||||
import { ApiError } from '../../../../services/api';
|
||||
// 【新架构】使用 MessageManager
|
||||
import { useChat, useGroupTyping, useGroupMuted, messageManager } from '../../../../stores';
|
||||
import {
|
||||
websocketService,
|
||||
} from '../../../../services/websocketService';
|
||||
import { groupService } from '../../../../services/groupService';
|
||||
import { userManager } from '../../../../stores/userManager';
|
||||
import { groupManager } from '../../../../stores/groupManager';
|
||||
@@ -728,14 +725,7 @@ export const useChatScreen = () => {
|
||||
const segments = buildTextSegments(trimmedText, replyingTo);
|
||||
|
||||
if (isGroupChat && routeGroupId) {
|
||||
// 群聊消息发送
|
||||
websocketService.sendGroupChatMessage({
|
||||
conversationId: conversationId,
|
||||
groupId: routeGroupId,
|
||||
segments: segments,
|
||||
mentionUsers: selectedMentions.length > 0 ? selectedMentions : undefined,
|
||||
mentionAll: mentionAll || undefined,
|
||||
});
|
||||
await messageService.sendMessageByAction('group', conversationId, segments);
|
||||
|
||||
setInputText('');
|
||||
setSelectedMentions([]);
|
||||
@@ -790,12 +780,7 @@ export const useChatScreen = () => {
|
||||
const segments = buildImageSegments(uploadResult.url, uploadResult.url, undefined, undefined, replyingTo);
|
||||
|
||||
if (isGroupChat && routeGroupId) {
|
||||
websocketService.sendGroupChatMessage({
|
||||
conversationId: conversationId,
|
||||
groupId: routeGroupId,
|
||||
mediaUrl: uploadResult.url,
|
||||
segments: segments,
|
||||
});
|
||||
await messageService.sendMessageByAction('group', conversationId, segments);
|
||||
setReplyingTo(null);
|
||||
} else {
|
||||
// 【新架构】私聊图片通过 MessageManager 发送
|
||||
@@ -922,12 +907,7 @@ export const useChatScreen = () => {
|
||||
const segments = buildImageSegments(stickerUrl, stickerUrl, undefined, undefined, replyingTo);
|
||||
|
||||
if (isGroupChat && routeGroupId) {
|
||||
websocketService.sendGroupChatMessage({
|
||||
conversationId: conversationId,
|
||||
groupId: routeGroupId,
|
||||
mediaUrl: stickerUrl,
|
||||
segments: segments,
|
||||
});
|
||||
await messageService.sendMessageByAction('group', conversationId, segments);
|
||||
setReplyingTo(null);
|
||||
} else {
|
||||
// 【新架构】私聊表情通过 MessageManager 发送
|
||||
@@ -983,7 +963,7 @@ export const useChatScreen = () => {
|
||||
const handleRecall = useCallback(async (messageId: string) => {
|
||||
try {
|
||||
if (isGroupChat && routeGroupId) {
|
||||
websocketService.sendGroupRecall(routeGroupId, conversationId!, messageId);
|
||||
await messageService.recallMessage(messageId);
|
||||
} else {
|
||||
await messageService.recallMessage(messageId);
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
|
||||
<Text style={styles.senderName}>{item.sender?.nickname || item.sender?.username}</Text>
|
||||
)}
|
||||
<Text style={[styles.messageText, isMe ? styles.messageTextMe : styles.messageTextOther]}>
|
||||
{extractTextFromSegments(item.segments)}
|
||||
{item.status === 'recalled' ? '消息已撤回' : extractTextFromSegments(item.segments)}
|
||||
</Text>
|
||||
</View>
|
||||
{isMe && (
|
||||
|
||||
Reference in New Issue
Block a user