feat(navigation): add profile stack navigator and fix API endpoints

- Add ProfileStackNavigatorComponent with full navigation stack (Profile, Settings, EditProfile, AccountSecurity, MyPosts, Bookmarks, NotificationSettings, BlockedUsers)
- Add null checks for response data in authService login, register, and refreshToken methods
- Fix postService API routes to use correct endpoints (/posts instead of /posts/cursor)
- Remove completed cursor pagination design document
This commit is contained in:
lafay
2026-03-21 01:36:40 +08:00
parent 8a0aea1c59
commit 97c7762f2b
5 changed files with 118 additions and 1153 deletions

View File

@@ -5,6 +5,6 @@ dist
dist-web dist-web
dist-android dist-android
dist-android-update.zip dist-android-update.zip
android android
screenshots screenshots
*.log *.log

File diff suppressed because it is too large Load Diff

View File

@@ -40,8 +40,21 @@ export type ScheduleStackParamList = {
CourseDetail: { course: any; relatedCourses?: any[] }; CourseDetail: { course: any; relatedCourses?: any[] };
}; };
// Profile Stack 类型定义
export type ProfileStackParamList = {
Profile: undefined;
Settings: undefined;
EditProfile: undefined;
AccountSecurity: undefined;
MyPosts: undefined;
Bookmarks: undefined;
NotificationSettings: undefined;
BlockedUsers: undefined;
};
// ==================== Stack Navigators ==================== // ==================== Stack Navigators ====================
const ScheduleStack = createNativeStackNavigator<ScheduleStackParamList>(); const ScheduleStack = createNativeStackNavigator<ScheduleStackParamList>();
const ProfileStack = createNativeStackNavigator<ProfileStackParamList>();
// ==================== 常量 ==================== // ==================== 常量 ====================
const TAB_BAR_HEIGHT = 64; const TAB_BAR_HEIGHT = 64;
@@ -80,6 +93,84 @@ function ScheduleStackNavigatorComponent() {
); );
} }
/**
* Profile Stack Navigator 组件
*/
function ProfileStackNavigatorComponent() {
return (
<ProfileStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: colors.background.paper,
},
headerTintColor: colors.text.primary,
headerTitleStyle: {
fontWeight: '600',
},
headerBackTitle: '',
headerShadowVisible: false,
}}
>
<ProfileStack.Screen
name="Profile"
component={ProfileScreen}
options={{
headerShown: false,
}}
/>
<ProfileStack.Screen
name="Settings"
component={SettingsScreen}
options={{
title: '设置',
}}
/>
<ProfileStack.Screen
name="EditProfile"
component={EditProfileScreen}
options={{
title: '编辑资料',
}}
/>
<ProfileStack.Screen
name="AccountSecurity"
component={AccountSecurityScreen}
options={{
title: '账号安全',
}}
/>
<ProfileStack.Screen
name="MyPosts"
component={ProfileScreen}
options={{
title: '我的帖子',
}}
/>
<ProfileStack.Screen
name="Bookmarks"
component={ProfileScreen}
options={{
title: '收藏',
}}
/>
<ProfileStack.Screen
name="NotificationSettings"
component={NotificationSettingsScreen}
options={{
title: '通知设置',
}}
/>
<ProfileStack.Screen
name="BlockedUsers"
component={BlockedUsersScreen}
options={{
title: '黑名单',
}}
/>
</ProfileStack.Navigator>
);
}
/** /**
* 主组件SimpleMobileTabNavigator * 主组件SimpleMobileTabNavigator
*/ */
@@ -108,7 +199,7 @@ export function SimpleMobileTabNavigator() {
case 'ScheduleTab': case 'ScheduleTab':
return <ScheduleStackNavigatorComponent />; return <ScheduleStackNavigatorComponent />;
case 'ProfileTab': case 'ProfileTab':
return <ProfileScreen />; return <ProfileStackNavigatorComponent />;
default: default:
return <HomeScreen />; return <HomeScreen />;
} }

View File

@@ -150,6 +150,9 @@ class AuthService {
async login(data: LoginRequest): Promise<AuthResponse> { async login(data: LoginRequest): Promise<AuthResponse> {
const response = await api.post<AuthResponse>('/auth/login', data); const response = await api.post<AuthResponse>('/auth/login', data);
if (!response.data) {
throw new Error('登录响应数据为空');
}
if (response.data.token) { if (response.data.token) {
await api.setToken(response.data.token); await api.setToken(response.data.token);
} }
@@ -165,6 +168,9 @@ class AuthService {
async register(data: RegisterRequest): Promise<AuthResponse> { async register(data: RegisterRequest): Promise<AuthResponse> {
const response = await api.post<AuthResponse>('/auth/register', data); const response = await api.post<AuthResponse>('/auth/register', data);
if (!response.data) {
throw new Error('注册响应数据为空');
}
if (response.data.token) { if (response.data.token) {
await api.setToken(response.data.token); await api.setToken(response.data.token);
} }
@@ -233,6 +239,9 @@ class AuthService {
try { try {
const response = await api.post<RefreshTokenResponse>('/auth/refresh'); const response = await api.post<RefreshTokenResponse>('/auth/refresh');
if (!response.data) {
return null;
}
if (response.data.token) { if (response.data.token) {
await api.setToken(response.data.token); await api.setToken(response.data.token);
} }

View File

@@ -287,19 +287,17 @@ class PostService {
/** /**
* 获取帖子列表(游标分页) * 获取帖子列表(游标分页)
* GET /api/v1/posts/cursor * GET /api/v1/posts
* @param params 游标分页请求参数(包含 post_type 可选recommend, follow, hot, latest * @param params 游标分页请求参数(包含 post_type 可选recommend, follow, hot, latest
*/ */
async getPostsCursor( async getPostsCursor(
params: CursorPaginationRequest = {} params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<Post>> { ): Promise<CursorPaginationResponse<Post>> {
try { try {
const response = await api.get<CursorPaginationResponse<Post>>('/posts/cursor', { const response = await api.get<CursorPaginationResponse<Post>>('/posts', {
params: { cursor: params.cursor,
cursor: params.cursor, page_size: params.page_size,
page_size: params.page_size, post_type: params.post_type,
post_type: params.post_type,
},
}); });
return response.data; return response.data;
} catch (error) { } catch (error) {
@@ -315,7 +313,7 @@ class PostService {
/** /**
* 搜索帖子(游标分页) * 搜索帖子(游标分页)
* GET /api/v1/posts/search/cursor * GET /api/v1/posts/search
* @param query 搜索关键词 * @param query 搜索关键词
* @param params 游标分页请求参数 * @param params 游标分页请求参数
*/ */
@@ -324,11 +322,9 @@ class PostService {
params: CursorPaginationRequest = {} params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<Post>> { ): Promise<CursorPaginationResponse<Post>> {
try { try {
const response = await api.get<CursorPaginationResponse<Post>>('/posts/search/cursor', { const response = await api.get<CursorPaginationResponse<Post>>('/posts/search', {
params: { ...params,
...params, keyword: query,
keyword: query,
},
}); });
return response.data; return response.data;
} catch (error) { } catch (error) {
@@ -344,7 +340,7 @@ class PostService {
/** /**
* 获取用户帖子列表(游标分页) * 获取用户帖子列表(游标分页)
* GET /api/v1/users/:id/posts/cursor * GET /api/v1/users/:id/posts
* @param userId 用户ID * @param userId 用户ID
* @param params 游标分页请求参数 * @param params 游标分页请求参数
*/ */
@@ -354,8 +350,8 @@ class PostService {
): Promise<CursorPaginationResponse<Post>> { ): Promise<CursorPaginationResponse<Post>> {
try { try {
const response = await api.get<CursorPaginationResponse<Post>>( const response = await api.get<CursorPaginationResponse<Post>>(
`/users/${userId}/posts/cursor`, `/users/${userId}/posts`,
{ params } params
); );
return response.data; return response.data;
} catch (error) { } catch (error) {