refactor(App, navigation): migrate to Expo Router and clean up navigation structure
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 4m27s
Frontend CI / ota-android (push) Successful in 11m6s
Frontend CI / build-android-apk (push) Successful in 1h16m45s

- Updated App entry point to utilize Expo Router, simplifying the navigation setup.
- Removed legacy navigation components and services to streamline the codebase.
- Adjusted package.json to reflect the new entry point and updated dependencies for compatibility.
- Enhanced overall application structure by consolidating navigation logic and improving maintainability.
This commit is contained in:
lafay
2026-03-24 14:21:31 +08:00
parent b91e78c921
commit 2ddb9cadd8
111 changed files with 1829 additions and 3214 deletions

View File

@@ -11,8 +11,15 @@
import { AppState, AppStateStatus, Platform } from 'react-native';
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';
import * as Haptics from 'expo-haptics';
import { sseService } from './sseService';
import {
triggerVibration,
vibrateOnMessage,
setVibrationConfig,
getVibrationConfig,
setVibrationEnabled,
} from './messageVibrationService';
export { triggerVibration, vibrateOnMessage, setVibrationConfig, getVibrationConfig, setVibrationEnabled };
// 后台任务名称
const BACKGROUND_FETCH_TASK = 'background-fetch-keepalive';
@@ -21,27 +28,8 @@ const REALTIME_KEEPALIVE_TASK = 'realtime-keepalive';
// 后台任务间隔Android 最小 15 分钟iOS 最小 15 分钟)
const BACKGROUND_INTERVAL = 15; // 15 分钟
// 震动配置
interface VibrationConfig {
enabled: boolean; // 是否启用震动
onChatMessage: boolean; // 私聊消息震动
onGroupMessage: boolean; // 群聊消息震动
onNotification: boolean; // 系统通知震动
style: Haptics.ImpactFeedbackStyle; // 震动样式
}
// 默认震动配置
const defaultVibrationConfig: VibrationConfig = {
enabled: true,
onChatMessage: true,
onGroupMessage: true,
onNotification: true,
style: Haptics.ImpactFeedbackStyle.Light,
};
// 后台服务状态
let isInitialized = false;
let vibrationConfig: VibrationConfig = { ...defaultVibrationConfig };
let appStateSubscription: any = null;
// 定义后台任务
@@ -73,96 +61,13 @@ TaskManager.defineTask(REALTIME_KEEPALIVE_TASK, async () => {
}
});
/**
* 触发震动反馈
* @param type 震动类型
*/
export async function triggerVibration(
type: 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error' = 'light'
): Promise<void> {
if (!vibrationConfig.enabled) {
return;
}
try {
switch (type) {
case 'light':
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
break;
case 'medium':
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
break;
case 'heavy':
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
break;
case 'success':
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
break;
case 'warning':
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
break;
case 'error':
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
break;
}
} catch (error) {
console.error('[BackgroundService] 震动反馈失败:', error);
}
}
/**
* 收到消息时触发震动
* @param messageType 消息类型
*/
export async function vibrateOnMessage(messageType: 'chat' | 'group_message' | 'notification'): Promise<void> {
if (!vibrationConfig.enabled) {
return;
}
switch (messageType) {
case 'chat':
if (vibrationConfig.onChatMessage) {
await triggerVibration('light');
}
break;
case 'group_message':
if (vibrationConfig.onGroupMessage) {
await triggerVibration('light');
}
break;
case 'notification':
if (vibrationConfig.onNotification) {
await triggerVibration('medium');
}
break;
}
}
/**
* 配置震动设置
*/
export function setVibrationConfig(config: Partial<VibrationConfig>): void {
vibrationConfig = { ...vibrationConfig, ...config };
}
/**
* 获取当前震动配置
*/
export function getVibrationConfig(): VibrationConfig {
return { ...vibrationConfig };
}
/**
* 启用/禁用震动
*/
export function setVibrationEnabled(enabled: boolean): void {
vibrationConfig.enabled = enabled;
}
/**
* 注册后台任务
*/
async function registerBackgroundTasks(): Promise<void> {
if (Platform.OS === 'web') {
return;
}
try {
// 检查是否已注册
const isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_FETCH_TASK);
@@ -192,6 +97,9 @@ async function registerBackgroundTasks(): Promise<void> {
* 取消后台任务
*/
async function unregisterBackgroundTasks(): Promise<void> {
if (Platform.OS === 'web') {
return;
}
try {
await BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK);
await BackgroundFetch.unregisterTaskAsync(REALTIME_KEEPALIVE_TASK);
@@ -227,6 +135,12 @@ export async function initBackgroundService(): Promise<boolean> {
return true;
}
if (Platform.OS === 'web') {
setupAppStateListener();
isInitialized = true;
return true;
}
try {
// 检查后台任务状态
const status = await BackgroundFetch.getStatusAsync();
@@ -275,6 +189,13 @@ export async function checkBackgroundStatus(): Promise<{
isInitialized: boolean;
registeredTasks: string[];
}> {
if (Platform.OS === 'web') {
return {
isAvailable: false,
isInitialized,
registeredTasks: [],
};
}
const status = await BackgroundFetch.getStatusAsync();
const registeredTasks = await TaskManager.getRegisteredTasksAsync();

View File

@@ -27,6 +27,54 @@ import {
CursorPaginationResponse,
} from '../types/dto';
function asGroupId(raw: unknown): string {
return String(raw);
}
function normalizeGroup(g: GroupResponse): GroupResponse {
return { ...g, id: asGroupId(g.id) };
}
function normalizeMember(m: GroupMemberResponse): GroupMemberResponse {
return { ...m, group_id: asGroupId(m.group_id) };
}
function normalizeAnnouncement(a: GroupAnnouncementResponse): GroupAnnouncementResponse {
return { ...a, group_id: asGroupId(a.group_id) };
}
function normalizeGroupListResponse(r: GroupListResponse): GroupListResponse {
return { ...r, list: r.list.map(normalizeGroup) };
}
function normalizeMemberListResponse(r: GroupMemberListResponse): GroupMemberListResponse {
return { ...r, list: r.list.map(normalizeMember) };
}
function normalizeAnnouncementListResponse(
r: GroupAnnouncementListResponse
): GroupAnnouncementListResponse {
return { ...r, list: r.list.map(normalizeAnnouncement) };
}
function normalizeGroupCursor(
r: CursorPaginationResponse<GroupResponse>
): CursorPaginationResponse<GroupResponse> {
return { ...r, list: r.list.map(normalizeGroup) };
}
function normalizeMemberCursor(
r: CursorPaginationResponse<GroupMemberResponse>
): CursorPaginationResponse<GroupMemberResponse> {
return { ...r, list: r.list.map(normalizeMember) };
}
function normalizeAnnouncementCursor(
r: CursorPaginationResponse<GroupAnnouncementResponse>
): CursorPaginationResponse<GroupAnnouncementResponse> {
return { ...r, list: r.list.map(normalizeAnnouncement) };
}
// 群组服务类(纯 API 层)
// SQLite/内存缓存编排由 groupManager 统一处理
class GroupService {
@@ -35,27 +83,27 @@ class GroupService {
page,
page_size: pageSize,
});
return response.data;
return normalizeGroupListResponse(response.data);
}
async fetchGroupFromApi(id: number | string): Promise<GroupResponse> {
const response = await api.get<GroupResponse>(`/groups/${encodeURIComponent(String(id))}`);
return response.data;
async fetchGroupFromApi(id: string): Promise<GroupResponse> {
const response = await api.get<GroupResponse>(`/groups/${encodeURIComponent(id)}`);
return normalizeGroup(response.data);
}
async fetchMembersFromApi(
groupId: number | string,
groupId: string,
page = 1,
pageSize = 50
): Promise<GroupMemberListResponse> {
const response = await api.get<GroupMemberListResponse>(
`/groups/${encodeURIComponent(String(groupId))}/members`,
`/groups/${encodeURIComponent(groupId)}/members`,
{
page,
page_size: pageSize,
}
);
return response.data;
return normalizeMemberListResponse(response.data);
}
// ==================== 群组管理 ====================
@@ -66,7 +114,7 @@ class GroupService {
*/
async createGroup(data: CreateGroupRequest): Promise<GroupResponse> {
const response = await api.post<GroupResponse>('/groups', data);
return response.data;
return normalizeGroup(response.data);
}
/**
@@ -81,7 +129,7 @@ class GroupService {
* 获取群组详情
* GET /api/v1/groups/:id
*/
async getGroup(id: number | string): Promise<GroupResponse> {
async getGroup(id: string): Promise<GroupResponse> {
return this.fetchGroupFromApi(id);
}
@@ -89,27 +137,30 @@ class GroupService {
* 获取当前用户在群组中的成员信息
* GET /api/v1/groups/:id/me
*/
async getMyMemberInfo(groupId: number | string): Promise<MyMemberInfoResponse> {
async getMyMemberInfo(groupId: string): Promise<MyMemberInfoResponse> {
const response = await api.get<MyMemberInfoResponse>(
`/groups/${encodeURIComponent(String(groupId))}/me`
`/groups/${encodeURIComponent(groupId)}/me`
);
return response.data;
return {
...response.data,
member: normalizeMember(response.data.member),
};
}
/**
* 解散群组
* DELETE /api/v1/groups/:id
*/
async dissolveGroup(id: number | string): Promise<void> {
await api.delete(`/groups/${encodeURIComponent(String(id))}`);
async dissolveGroup(id: string): Promise<void> {
await api.delete(`/groups/${encodeURIComponent(id)}`);
}
/**
* 转让群主
* POST /api/v1/groups/:id/transfer
*/
async transferOwner(id: number | string, data: TransferOwnerRequest): Promise<void> {
await api.post(`/groups/${encodeURIComponent(String(id))}/transfer`, data);
async transferOwner(id: string, data: TransferOwnerRequest): Promise<void> {
await api.post(`/groups/${encodeURIComponent(id)}/transfer`, data);
}
// ==================== 成员管理 ====================
@@ -118,25 +169,25 @@ class GroupService {
* 邀请成员加入群组
* POST /api/v1/groups/:id/invitations
*/
async inviteMembers(groupId: number | string, data: InviteMembersRequest): Promise<void> {
await api.post(`/groups/${encodeURIComponent(String(groupId))}/invitations`, data);
async inviteMembers(groupId: string, data: InviteMembersRequest): Promise<void> {
await api.post(`/groups/${encodeURIComponent(groupId)}/invitations`, data);
}
/**
* 申请加入群组
* POST /api/v1/groups/:id/join-requests
*/
async joinGroup(groupId: number | string): Promise<void> {
await api.post(`/groups/${encodeURIComponent(String(groupId))}/join-requests`);
async joinGroup(groupId: string): Promise<void> {
await api.post(`/groups/${encodeURIComponent(groupId)}/join-requests`);
}
/**
* 响应群邀请/申请
* POST /api/v1/groups/:id/join-requests/respond
*/
async respondInvite(groupId: number | string, data: HandleGroupRequestAction): Promise<void> {
async respondInvite(groupId: string, data: HandleGroupRequestAction): Promise<void> {
await api.post(
`/groups/${encodeURIComponent(String(groupId))}/join-requests/respond`,
`/groups/${encodeURIComponent(groupId)}/join-requests/respond`,
data
);
}
@@ -145,9 +196,9 @@ class GroupService {
* 审批主动加群申请
* POST /api/v1/groups/:id/join-requests/handle
*/
async reviewJoinRequest(groupId: number | string, data: HandleGroupRequestAction): Promise<void> {
async reviewJoinRequest(groupId: string, data: HandleGroupRequestAction): Promise<void> {
await api.post(
`/groups/${encodeURIComponent(String(groupId))}/join-requests/handle`,
`/groups/${encodeURIComponent(groupId)}/join-requests/handle`,
data
);
}
@@ -156,15 +207,15 @@ class GroupService {
* 退出群组
* POST /api/v1/groups/:id/leave
*/
async leaveGroup(groupId: number | string): Promise<void> {
await api.post(`/groups/${encodeURIComponent(String(groupId))}/leave`);
async leaveGroup(groupId: string): Promise<void> {
await api.post(`/groups/${encodeURIComponent(groupId)}/leave`);
}
/**
* 获取群组成员列表
* GET /api/v1/groups/:id/members
*/
async getMembers(groupId: number | string, page = 1, pageSize = 50): Promise<GroupMemberListResponse> {
async getMembers(groupId: string, page = 1, pageSize = 50): Promise<GroupMemberListResponse> {
return this.fetchMembersFromApi(groupId, page, pageSize);
}
@@ -172,8 +223,8 @@ class GroupService {
* 移除群成员(踢人)
* POST /api/v1/groups/:id/members/kick
*/
async removeMember(groupId: number | string, userId: string): Promise<void> {
await api.post(`/groups/${encodeURIComponent(String(groupId))}/members/kick`, {
async removeMember(groupId: string, userId: string): Promise<void> {
await api.post(`/groups/${encodeURIComponent(groupId)}/members/kick`, {
user_id: userId,
reject_add_request: false,
});
@@ -184,12 +235,12 @@ class GroupService {
* PUT /api/v1/groups/:id/members/:user_id/admin
*/
async setMemberRole(
groupId: number | string,
groupId: string,
userId: string,
data: SetRoleRequest
): Promise<void> {
await api.put(
`/groups/${encodeURIComponent(String(groupId))}/members/${encodeURIComponent(userId)}/admin`,
`/groups/${encodeURIComponent(groupId)}/members/${encodeURIComponent(userId)}/admin`,
{
enable: data.role === 'admin',
}
@@ -200,8 +251,8 @@ class GroupService {
* 设置群昵称
* PUT /api/v1/groups/:id/members/me/nickname
*/
async setNickname(groupId: number | string, data: SetNicknameRequest): Promise<void> {
await api.put(`/groups/${encodeURIComponent(String(groupId))}/members/me/nickname`, data);
async setNickname(groupId: string, data: SetNicknameRequest): Promise<void> {
await api.put(`/groups/${encodeURIComponent(groupId)}/members/me/nickname`, data);
}
/**
@@ -212,11 +263,11 @@ class GroupService {
* @param duration 禁言时长0表示解除禁言
*/
async muteMember(
groupId: number | string,
groupId: string,
userId: string,
duration: number = 0
): Promise<void> {
await api.post(`/groups/${encodeURIComponent(String(groupId))}/members/ban`, {
await api.post(`/groups/${encodeURIComponent(groupId)}/members/ban`, {
user_id: userId,
duration: duration,
});
@@ -228,8 +279,8 @@ class GroupService {
* 设置全员禁言
* PUT /api/v1/groups/:id/ban
*/
async setMuteAll(groupId: number | string, data: SetMuteAllRequest): Promise<void> {
await api.put(`/groups/${encodeURIComponent(String(groupId))}/ban`, {
async setMuteAll(groupId: string, data: SetMuteAllRequest): Promise<void> {
await api.put(`/groups/${encodeURIComponent(groupId)}/ban`, {
enable: data.mute_all,
});
}
@@ -238,16 +289,16 @@ class GroupService {
* 设置加群方式
* PUT /api/v1/groups/:id/join-type
*/
async setJoinType(groupId: number | string, data: SetJoinTypeRequest): Promise<void> {
await api.put(`/groups/${encodeURIComponent(String(groupId))}/join-type`, data);
async setJoinType(groupId: string, data: SetJoinTypeRequest): Promise<void> {
await api.put(`/groups/${encodeURIComponent(groupId)}/join-type`, data);
}
/**
* 设置群名称
* PUT /api/v1/groups/:id/name
*/
async setGroupName(groupId: number | string, groupName: string): Promise<void> {
await api.put(`/groups/${encodeURIComponent(String(groupId))}/name`, {
async setGroupName(groupId: string, groupName: string): Promise<void> {
await api.put(`/groups/${encodeURIComponent(groupId)}/name`, {
group_name: groupName,
});
}
@@ -256,14 +307,14 @@ class GroupService {
* 设置群头像
* PUT /api/v1/groups/:id/avatar
*/
async setGroupAvatar(groupId: number | string, avatarUrl: string): Promise<GroupResponse> {
async setGroupAvatar(groupId: string, avatarUrl: string): Promise<GroupResponse> {
const response = await api.put<GroupResponse>(
`/groups/${encodeURIComponent(String(groupId))}/avatar`,
`/groups/${encodeURIComponent(groupId)}/avatar`,
{
avatar: avatarUrl,
}
);
return response.data;
return normalizeGroup(response.data);
}
// ==================== 群公告 ====================
@@ -273,14 +324,14 @@ class GroupService {
* POST /api/v1/groups/:id/announcements
*/
async createAnnouncement(
groupId: number | string,
groupId: string,
data: CreateAnnouncementRequest
): Promise<GroupAnnouncementResponse> {
const response = await api.post<GroupAnnouncementResponse>(
`/groups/${encodeURIComponent(String(groupId))}/announcements`,
`/groups/${encodeURIComponent(groupId)}/announcements`,
data
);
return response.data;
return normalizeAnnouncement(response.data);
}
/**
@@ -288,19 +339,19 @@ class GroupService {
* GET /api/v1/groups/:id/announcements
*/
async getAnnouncements(
groupId: number | string,
groupId: string,
page = 1,
pageSize = 20
): Promise<GroupAnnouncementListResponse> {
try {
const response = await api.get<GroupAnnouncementListResponse>(
`/groups/${encodeURIComponent(String(groupId))}/announcements`,
`/groups/${encodeURIComponent(groupId)}/announcements`,
{
page,
page_size: pageSize,
}
);
return response.data;
return normalizeAnnouncementListResponse(response.data);
} catch (error) {
console.error('获取群公告列表失败:', error);
return {
@@ -317,9 +368,9 @@ class GroupService {
* 删除群公告
* DELETE /api/v1/groups/:id/announcements/:announcement_id
*/
async deleteAnnouncement(groupId: number | string, announcementId: number): Promise<void> {
async deleteAnnouncement(groupId: string, announcementId: number): Promise<void> {
await api.delete(
`/groups/${encodeURIComponent(String(groupId))}/announcements/${encodeURIComponent(String(announcementId))}`
`/groups/${encodeURIComponent(groupId)}/announcements/${encodeURIComponent(String(announcementId))}`
);
}
@@ -335,7 +386,7 @@ class GroupService {
): Promise<CursorPaginationResponse<GroupResponse>> {
try {
const response = await api.get<CursorPaginationResponse<GroupResponse>>('/groups/cursor', params);
return response.data;
return normalizeGroupCursor(response.data);
} catch (error) {
console.error('获取群组列表失败:', error);
return {
@@ -354,15 +405,15 @@ class GroupService {
* @param params 游标分页请求参数
*/
async getGroupMembersCursor(
groupId: number | string,
groupId: string,
params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<GroupMemberResponse>> {
try {
const response = await api.get<CursorPaginationResponse<GroupMemberResponse>>(
`/groups/${encodeURIComponent(String(groupId))}/members/cursor`,
`/groups/${encodeURIComponent(groupId)}/members/cursor`,
params
);
return response.data;
return normalizeMemberCursor(response.data);
} catch (error) {
console.error('获取群组成员列表失败:', error);
return {
@@ -381,15 +432,15 @@ class GroupService {
* @param params 游标分页请求参数
*/
async getGroupAnnouncementsCursor(
groupId: number | string,
groupId: string,
params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<GroupAnnouncementResponse>> {
try {
const response = await api.get<CursorPaginationResponse<GroupAnnouncementResponse>>(
`/groups/${encodeURIComponent(String(groupId))}/announcements/cursor`,
`/groups/${encodeURIComponent(groupId)}/announcements/cursor`,
params
);
return response.data;
return normalizeAnnouncementCursor(response.data);
} catch (error) {
console.error('获取群公告列表失败:', error);
return {

View File

@@ -0,0 +1,88 @@
import * as Haptics from 'expo-haptics';
interface VibrationConfig {
enabled: boolean;
onChatMessage: boolean;
onGroupMessage: boolean;
onNotification: boolean;
style: Haptics.ImpactFeedbackStyle;
}
const defaultVibrationConfig: VibrationConfig = {
enabled: true,
onChatMessage: true,
onGroupMessage: true,
onNotification: true,
style: Haptics.ImpactFeedbackStyle.Light,
};
let vibrationConfig: VibrationConfig = { ...defaultVibrationConfig };
export async function triggerVibration(
type: 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error' = 'light'
): Promise<void> {
if (!vibrationConfig.enabled) {
return;
}
try {
switch (type) {
case 'light':
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
break;
case 'medium':
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
break;
case 'heavy':
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
break;
case 'success':
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
break;
case 'warning':
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
break;
case 'error':
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
break;
}
} catch (error) {
console.error('[VibrationService] 震动反馈失败:', error);
}
}
export async function vibrateOnMessage(messageType: 'chat' | 'group_message' | 'notification'): Promise<void> {
if (!vibrationConfig.enabled) {
return;
}
switch (messageType) {
case 'chat':
if (vibrationConfig.onChatMessage) {
await triggerVibration('light');
}
break;
case 'group_message':
if (vibrationConfig.onGroupMessage) {
await triggerVibration('light');
}
break;
case 'notification':
if (vibrationConfig.onNotification) {
await triggerVibration('medium');
}
break;
}
}
export function setVibrationConfig(config: Partial<VibrationConfig>): void {
vibrationConfig = { ...vibrationConfig, ...config };
}
export function getVibrationConfig(): VibrationConfig {
return { ...vibrationConfig };
}
export function setVibrationEnabled(enabled: boolean): void {
vibrationConfig.enabled = enabled;
}

View File

@@ -4,7 +4,7 @@ import EventSource from 'react-native-sse';
import { api, SSE_URL } from './api';
import { MessageCategory, SystemMessageType, SystemMessageExtraData, MessageSegment } from '../types/dto';
import { systemNotificationService } from './systemNotificationService';
import { vibrateOnMessage } from './backgroundService';
import { vibrateOnMessage } from './messageVibrationService';
export type WSMessageType =
| 'chat'
@@ -62,7 +62,7 @@ export interface WSRecallMessage {
export interface WSNotificationMessage {
type: 'notification';
id: number | string;
id: string;
sender_id?: string;
receiver_id?: string;
content: string;
@@ -74,7 +74,7 @@ export interface WSNotificationMessage {
export interface WSAnnouncementMessage {
type: 'announcement';
id: number | string;
id: string;
sender_id?: string;
receiver_id?: string;
content: string;
@@ -86,7 +86,7 @@ export interface WSAnnouncementMessage {
export interface WSGroupMentionMessage {
type: 'group_mention';
group_id: number | string;
group_id: string;
conversation_id: string;
message_id: string;
from_user_id: string;
@@ -98,7 +98,7 @@ export interface WSGroupMentionMessage {
export interface WSGroupChatMessage {
type: 'group_message';
conversation_id: string;
group_id: number | string;
group_id: string;
id: string;
sender_id: string;
seq: number;
@@ -108,7 +108,7 @@ export interface WSGroupChatMessage {
export interface WSGroupTypingMessage {
type: 'group_typing';
group_id: number | string;
group_id: string;
user_id: string;
is_typing: boolean;
}
@@ -118,7 +118,7 @@ export type GroupNoticeType = 'member_join' | 'member_leave' | 'member_removed'
export interface WSGroupNoticeMessage {
type: 'group_notice';
notice_type: GroupNoticeType;
group_id: number | string;
group_id: string;
data: {
user_id?: string;
operator_id?: string;
@@ -132,7 +132,7 @@ export interface WSGroupNoticeMessage {
export interface WSGroupReadMessage {
type: 'group_read';
group_id: number | string;
group_id: string;
conversation_id: string;
user_id: string;
seq: number;
@@ -140,7 +140,7 @@ export interface WSGroupReadMessage {
export interface WSGroupRecallMessage {
type: 'group_recall';
group_id: number | string;
group_id: string;
conversation_id: string;
message_id: string;
}
@@ -271,7 +271,7 @@ class SSEService {
const gm: WSGroupChatMessage = {
type: 'group_message',
conversation_id: m.conversation_id,
group_id: m.group_id || '',
group_id: String(m.group_id ?? ''),
id: m.id,
sender_id: m.sender_id,
seq: Number(m.seq || 0),
@@ -301,7 +301,7 @@ class SSEService {
if (detailType === 'group') {
const m: WSGroupReadMessage = {
type: 'group_read',
group_id: payload.group_id || '',
group_id: String(payload.group_id ?? ''),
conversation_id: payload.conversation_id,
user_id: payload.user_id,
seq: Number(payload.seq || 0),
@@ -324,7 +324,7 @@ class SSEService {
if (detailType === 'group') {
const m: WSGroupTypingMessage = {
type: 'group_typing',
group_id: payload.group_id || '',
group_id: String(payload.group_id ?? ''),
user_id: payload.user_id,
is_typing: payload.is_typing !== false,
};
@@ -346,7 +346,7 @@ class SSEService {
if (detailType === 'group') {
const m: WSGroupRecallMessage = {
type: 'group_recall',
group_id: payload.group_id || '',
group_id: String(payload.group_id ?? ''),
conversation_id: payload.conversation_id,
message_id: payload.message_id,
};
@@ -366,7 +366,7 @@ class SSEService {
const m: WSGroupNoticeMessage = {
type: 'group_notice',
notice_type: payload.notice_type,
group_id: payload.group_id,
group_id: String(payload.group_id ?? ''),
data: payload.data || {},
timestamp: payload.timestamp || Date.now(),
message_id: payload.message_id,
@@ -379,7 +379,7 @@ class SSEService {
if (eventName === 'system_notification') {
const m: WSNotificationMessage = {
type: 'notification',
id: payload.id || '',
id: String(payload.id ?? ''),
content: payload.content || '',
created_at: payload.created_at || new Date().toISOString(),
};