Add ability to search messages within a specific conversation. This includes: - New `MessageSearchScreen` for displaying search results. - `MessageRepository.searchByConversation` to query messages by keyword and conversation ID. - Integration of search entry points in `GroupInfoScreen` and `PrivateChatInfoScreen`. - Support for scrolling to a specific message sequence (`scrollToSeq`) when navigating from search results. - Enhanced `HighlightText` component to support custom highlight styles. feat(message): implement message search functionality
242 lines
6.4 KiB
TypeScript
242 lines
6.4 KiB
TypeScript
/**
|
|
* Expo Router 路径构建(单一事实来源,避免魔法字符串散落)
|
|
*/
|
|
import type { SystemMessageResponse } from '../types/dto';
|
|
import { routePayloadCache } from '../stores';
|
|
|
|
export function hrefPostDetail(postId: string, scrollToComments?: boolean): string {
|
|
const q = scrollToComments ? '?scrollToComments=1' : '';
|
|
return `/post/${encodeURIComponent(postId)}${q}`;
|
|
}
|
|
|
|
export function hrefUserProfile(userId: string): string {
|
|
return `/user/${encodeURIComponent(userId)}`;
|
|
}
|
|
|
|
export function hrefHome(): string {
|
|
return '/home';
|
|
}
|
|
|
|
export function hrefHomeSearch(): string {
|
|
return '/home/search';
|
|
}
|
|
|
|
export function hrefMessages(): string {
|
|
return '/messages';
|
|
}
|
|
|
|
export function hrefNotifications(): string {
|
|
return '/messages/notifications';
|
|
}
|
|
|
|
export function hrefApps(): string {
|
|
return '/apps';
|
|
}
|
|
|
|
export function hrefSchedule(): string {
|
|
return '/apps/schedule';
|
|
}
|
|
|
|
export function hrefScheduleCourse(courseId: string): string {
|
|
return `/apps/schedule/course?courseId=${encodeURIComponent(courseId)}`;
|
|
}
|
|
|
|
export function hrefProfileSettings(): string {
|
|
return '/profile/settings';
|
|
}
|
|
|
|
export function hrefProfileEdit(): string {
|
|
return '/profile/edit-profile';
|
|
}
|
|
|
|
export function hrefProfileSecurity(): string {
|
|
return '/profile/account-security';
|
|
}
|
|
|
|
export function hrefProfileNotifications(): string {
|
|
return '/profile/notification-settings';
|
|
}
|
|
|
|
export function hrefProfileBlocked(): string {
|
|
return '/profile/blocked-users';
|
|
}
|
|
|
|
export function hrefProfileChatSettings(): string {
|
|
return '/profile/chat-settings';
|
|
}
|
|
|
|
export function hrefProfileMyPosts(): string {
|
|
return '/profile/my-posts';
|
|
}
|
|
|
|
export function hrefProfileBookmarks(): string {
|
|
return '/profile/bookmarks';
|
|
}
|
|
|
|
export function hrefCreatePost(mode?: 'create' | 'edit', postId?: string): string {
|
|
if (mode === 'edit' && postId) {
|
|
return `/posts/create?mode=edit&postId=${encodeURIComponent(postId)}`;
|
|
}
|
|
return '/posts/create';
|
|
}
|
|
|
|
export function hrefChat(params: {
|
|
conversationId: string;
|
|
userId?: string;
|
|
isGroupChat?: boolean;
|
|
groupId?: string;
|
|
groupName?: string;
|
|
groupAvatar?: string;
|
|
scrollToSeq?: number;
|
|
}): string {
|
|
const { conversationId, userId, isGroupChat, groupId, groupName, groupAvatar, scrollToSeq } = params;
|
|
const q = new URLSearchParams();
|
|
if (userId) q.set('userId', userId);
|
|
if (isGroupChat) q.set('isGroupChat', '1');
|
|
if (groupId != null && groupId !== '') q.set('groupId', String(groupId));
|
|
if (groupName) q.set('groupName', groupName);
|
|
if (groupAvatar) q.set('groupAvatar', groupAvatar);
|
|
if (scrollToSeq != null) q.set('scrollToSeq', String(scrollToSeq));
|
|
const qs = q.toString();
|
|
return `/chat/${encodeURIComponent(conversationId)}${qs ? `?${qs}` : ''}`;
|
|
}
|
|
|
|
export function hrefFollowList(userId: string, type: 'following' | 'followers'): string {
|
|
return `/users/${encodeURIComponent(userId)}/${type}`;
|
|
}
|
|
|
|
export function hrefGroupCreate(): string {
|
|
return '/group/create';
|
|
}
|
|
|
|
export function hrefGroupJoin(): string {
|
|
return '/group/join';
|
|
}
|
|
|
|
export function hrefGroupInfo(groupId: string, conversationId?: string): string {
|
|
const base = `/group/${encodeURIComponent(groupId)}`;
|
|
if (!conversationId) return base;
|
|
return `${base}?conversationId=${encodeURIComponent(conversationId)}`;
|
|
}
|
|
|
|
export function hrefGroupMembers(groupId: string): string {
|
|
return `/group/${encodeURIComponent(groupId)}/members`;
|
|
}
|
|
|
|
export function hrefGroupRequestDetail(message: SystemMessageResponse): string {
|
|
routePayloadCache.stashSystemMessage(message);
|
|
return `/group/request?messageId=${encodeURIComponent(message.id)}`;
|
|
}
|
|
|
|
export function hrefGroupInviteDetail(message: SystemMessageResponse): string {
|
|
routePayloadCache.stashSystemMessage(message);
|
|
return `/group/invite?messageId=${encodeURIComponent(message.id)}`;
|
|
}
|
|
|
|
export function hrefMessageSearch(params: {
|
|
conversationId: string;
|
|
conversationName?: string;
|
|
isGroupChat?: boolean;
|
|
}): string {
|
|
const q = new URLSearchParams({
|
|
conversationId: params.conversationId,
|
|
});
|
|
if (params.conversationName) q.set('conversationName', params.conversationName);
|
|
if (params.isGroupChat) q.set('isGroupChat', '1');
|
|
return `/chat/message-search?${q.toString()}`;
|
|
}
|
|
|
|
export function hrefPrivateChatInfo(params: {
|
|
conversationId: string;
|
|
userId: string;
|
|
userName?: string;
|
|
userAvatar?: string | null;
|
|
}): string {
|
|
const q = new URLSearchParams({
|
|
conversationId: params.conversationId,
|
|
userId: params.userId,
|
|
});
|
|
if (params.userName) q.set('userName', params.userName);
|
|
if (params.userAvatar != null) q.set('userAvatar', params.userAvatar ?? '');
|
|
return `/chat/private-info?${q.toString()}`;
|
|
}
|
|
|
|
export function hrefQrLoginConfirm(sessionId: string): string {
|
|
return `/qrcode/login/${encodeURIComponent(sessionId)}`;
|
|
}
|
|
|
|
export function hrefAuthLogin(): string {
|
|
return '/login';
|
|
}
|
|
|
|
export function hrefAuthRegister(): string {
|
|
return '/register';
|
|
}
|
|
|
|
export function hrefAuthForgot(): string {
|
|
return '/forgot-password';
|
|
}
|
|
|
|
export function hrefAuthWelcome(): string {
|
|
return '/welcome';
|
|
}
|
|
|
|
// ==================== Materials (学习资料) ====================
|
|
|
|
export function hrefMaterials(): string {
|
|
return '/apps/materials';
|
|
}
|
|
|
|
export function hrefMaterialSubject(subjectId: string): string {
|
|
return `/apps/materials/subject?subjectId=${encodeURIComponent(subjectId)}`;
|
|
}
|
|
|
|
export function hrefMaterialDetail(materialId: string): string {
|
|
return `/apps/materials/detail?materialId=${encodeURIComponent(materialId)}`;
|
|
}
|
|
|
|
// ==================== Profile Settings (设置相关) ====================
|
|
|
|
export function hrefProfileAbout(): string {
|
|
return '/profile/about';
|
|
}
|
|
|
|
export function hrefProfileTerms(): string {
|
|
return '/terms';
|
|
}
|
|
|
|
export function hrefProfilePrivacy(): string {
|
|
return '/privacy';
|
|
}
|
|
|
|
export function hrefProfileVerification(): string {
|
|
return '/profile/verification';
|
|
}
|
|
|
|
export function hrefVerificationGuide(): string {
|
|
return '/verification-guide';
|
|
}
|
|
|
|
export function hrefVerificationForm(identity?: string): string {
|
|
if (identity) {
|
|
return `/verification-form?identity=${encodeURIComponent(identity)}`;
|
|
}
|
|
return '/verification-form';
|
|
}
|
|
|
|
export function hrefProfileDataStorage(): string {
|
|
return '/profile/data-storage';
|
|
}
|
|
|
|
export function hrefProfilePrivacySettings(): string {
|
|
return '/profile/privacy-settings';
|
|
}
|
|
|
|
export function hrefProfileDeletion(): string {
|
|
return '/profile/account-deletion';
|
|
}
|
|
|
|
export function hrefEditTrade(tradeId: string): string {
|
|
return `/trade/edit/${encodeURIComponent(tradeId)}`;
|
|
}
|