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

@@ -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 {