# SearchResults 组件自定义文档

## 概述

SearchResults 是搜索结果展示组件，负责渲染和管理不同类型的搜索结果。组件支持用户、群组、消息等多种搜索类型的结果展示，提供三种显示模式（迷你、标准、嵌入式）以适配不同的使用场景。具备加载状态管理、空结果提示、分页加载、错误处理等完整功能，同时支持自定义各种子组件，为用户提供灵活且完整的搜索结果浏览体验。

## Props 配置表格

| 字段 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| results | `Map<SearchType, SearchResult<SearchType>>` | - | 搜索结果数据，按类型分组的结果集合 |
| isLoading | `boolean` | - | 是否正在加载搜索结果 |
| error | `Error \| null` | - | 搜索过程中的错误信息 |
| keyword | `string` | - | 当前搜索关键词 |
| typeLabels | `Record<SearchType, string>` | - | 搜索类型的显示标签映射 |
| onLoadMore | `(type: SearchType) => void` | - | 加载更多结果的回调函数 |
| onResultItemClick | `(data: SearchResultItem, type: SearchType) => void` | - | 搜索结果项点击回调 |
| SearchResultsPresearch | `React.ComponentType` | - | 搜索前占位符组件 |
| SearchResultsLoading | `React.ComponentType` | `Loading` | 加载状态组件 |
| SearchResultsEmpty | `React.ComponentType` | `EmptyResult` | 空结果占位符组件 |
| SearchResultItem | `React.ComponentType<ResultItemProps<SearchType>>` | `DefaultSearchResultsItem` | 自定义搜索结果项组件 |
| variant | `VariantType` | `VariantType.STANDARD` | 组件显示模式 |
| searchType | `SearchType \| 'all'` | `'all'` | 当前搜索类型筛选 |

## Props 详解

### results

type: `Map<SearchType, SearchResult<SearchType>>`

results 用于提供按类型分组的搜索结果数据，每种类型包含结果列表、总数、分页信息等，默认值为 `-`。

### isLoading

type: `boolean`

isLoading 用于指示是否正在加载搜索结果，控制加载状态的显示，默认值为 `-`。

### error

type: `Error | null`

error 用于传递搜索过程中发生的错误信息，组件会显示错误提示，默认值为 `-`。

### keyword

type: `string`

keyword 用于指定当前搜索关键词，组件根据关键词状态决定显示内容，默认值为 `-`。

### typeLabels

type: `Record<SearchType, string>`

typeLabels 用于定义各搜索类型的显示标签，用于界面上的类型标题展示，默认值为 `-`。

### onLoadMore

type: `(type: SearchType) => void`

onLoadMore 用于处理加载更多结果的请求，当用户点击加载更多按钮时触发，默认值为 `-`。

#### Example1: 基础分页加载

```tsx
import { SearchResults, SearchType } from 'tuikit-atomicx-react';
import { useState } from 'react';

function BasicPaginationExample() {
  const [results, setResults] = useState(new Map());
  const [isLoading, setIsLoading] = useState(false);
  const [currentPage, setCurrentPage] = useState(new Map([
    [SearchType.USER, 1],
    [SearchType.GROUP, 1],
    [SearchType.MESSAGE, 1]
  ]));

  const handleLoadMore = async (type: SearchType) => {
    setIsLoading(true);
    
    try {
      const nextPage = (currentPage.get(type) || 1) + 1;
      
      // 模拟API调用
      const newResults = await fetchSearchResults(type, nextPage);
      
      // 合并新结果到现有结果
      setResults(prev => {
        const newMap = new Map(prev);
        const existingResult = newMap.get(type);
        
        if (existingResult) {
          newMap.set(type, {
            ...existingResult,
            resultList: [...existingResult.resultList, ...newResults.resultList],
            hasMore: newResults.hasMore,
            cursor: newResults.cursor
          });
        }
        
        return newMap;
      });
      
      // 更新页码
      setCurrentPage(prev => new Map(prev).set(type, nextPage));
      
      console.log(`${getTypeLabel(type)} 第${nextPage}页加载完成`);
    } catch (error) {
      console.error('加载更多失败:', error);
    } finally {
      setIsLoading(false);
    }
  };

  const fetchSearchResults = async (type: SearchType, page: number) => {
    // 模拟异步请求
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    return {
      resultList: generateMockResults(type, 10),
      hasMore: page < 5, // 假设最多5页
      cursor: `page_${page}`,
      totalCount: 50
    };
  };

  const generateMockResults = (type: SearchType, count: number) => {
    return Array.from({ length: count }, (_, index) => ({
      id: `${type}_${Date.now()}_${index}`,
      name: `${getTypeLabel(type)} ${index + 1}`,
      type: type
    }));
  };

  const getTypeLabel = (type: SearchType) => {
    const labels = {
      [SearchType.USER]: '用户',
      [SearchType.GROUP]: '群组',
      [SearchType.MESSAGE]: '消息'
    };
    return labels[type] || '未知';
  };

  const typeLabels = {
    [SearchType.USER]: '用户',
    [SearchType.GROUP]: '群组',
    [SearchType.MESSAGE]: '消息'
  };

  return (
    <div style={{ padding: '20px' }}>
      <SearchResults
        results={results}
        isLoading={isLoading}
        keyword="搜索关键词"
        typeLabels={typeLabels}
        onLoadMore={handleLoadMore}
        onResultItemClick={(data, type) => {
          console.log('点击结果:', data, type);
        }}
      />
      
      {/* 分页状态显示 */}
      <div style={{ marginTop: '16px', fontSize: '12px', color: '#666' }}>
        <h4>当前分页状态:</h4>
        {Array.from(currentPage.entries()).map(([type, page]) => (
          <div key={type}>
            {getTypeLabel(type)}: 第 {page} 页
          </div>
        ))}
      </div>
    </div>
  );
}
```

#### Example2: 智能加载与缓存管理

```tsx
import { SearchResults, SearchType } from 'tuikit-atomicx-react';
import { useState, useCallback, useRef } from 'react';

interface CacheItem {
  data: any[];
  timestamp: number;
  hasMore: boolean;
}

function SmartLoadingExample() {
  const [results, setResults] = useState(new Map());
  const [isLoading, setIsLoading] = useState(false);
  const [loadingTypes, setLoadingTypes] = useState(new Set<SearchType>());
  const cacheRef = useRef(new Map<string, CacheItem>());
  const loadingRef = useRef(new Set<string>());

  const handleLoadMore = useCallback(async (type: SearchType) => {
    const cacheKey = `${type}_more`;
    
    // 防止重复请求
    if (loadingRef.current.has(cacheKey)) {
      console.log('请求进行中，跳过重复请求');
      return;
    }

    // 检查缓存
    const cached = cacheRef.current.get(cacheKey);
    const now = Date.now();
    if (cached && (now - cached.timestamp < 30000)) { // 30秒缓存
      console.log('使用缓存数据');
      appendResults(type, cached.data, cached.hasMore);
      return;
    }

    loadingRef.current.add(cacheKey);
    setLoadingTypes(prev => new Set(prev).add(type));
    
    try {
      const currentResult = results.get(type);
      const currentCount = currentResult?.resultList.length || 0;
      
      // 智能批量大小：根据类型和当前结果数量调整
      const batchSize = getBatchSize(type, currentCount);
      
      const newData = await fetchMoreResults(type, currentCount, batchSize);
      
      // 更新缓存
      cacheRef.current.set(cacheKey, {
        data: newData.resultList,
        timestamp: now,
        hasMore: newData.hasMore
      });
      
      appendResults(type, newData.resultList, newData.hasMore);
      
      // 记录加载统计
      logLoadingStats(type, newData.resultList.length, currentCount + newData.resultList.length);
      
    } catch (error) {
      console.error(`加载更多${getTypeLabel(type)}失败:`, error);
      // 可以显示错误提示
    } finally {
      loadingRef.current.delete(cacheKey);
      setLoadingTypes(prev => {
        const newSet = new Set(prev);
        newSet.delete(type);
        return newSet;
      });
    }
  }, [results]);

  const getBatchSize = (type: SearchType, currentCount: number): number => {
    // 根据类型和当前数量智能调整批量大小
    const baseSizes = {
      [SearchType.USER]: 20,
      [SearchType.GROUP]: 15,
      [SearchType.MESSAGE]: 10
    };
    
    const baseSize = baseSizes[type] || 10;
    
    // 随着数据增多，减少批量大小以提高响应速度
    if (currentCount > 100) return Math.max(5, Math.floor(baseSize * 0.5));
    if (currentCount > 50) return Math.max(8, Math.floor(baseSize * 0.7));
    
    return baseSize;
  };

  const fetchMoreResults = async (type: SearchType, offset: number, limit: number) => {
    // 模拟网络延迟
    const delay = Math.random() * 1000 + 500;
    await new Promise(resolve => setTimeout(resolve, delay));
    
    // 模拟偶发错误
    if (Math.random() < 0.1) {
      throw new Error('网络请求失败');
    }
    
    const mockResults = Array.from({ length: limit }, (_, index) => ({
      id: `${type}_${offset + index}`,
      name: `${getTypeLabel(type)} ${offset + index + 1}`,
      avatar: `https://example.com/avatar_${offset + index}.jpg`,
      type: type,
      timestamp: Date.now() - Math.random() * 86400000 // 随机时间戳
    }));
    
    return {
      resultList: mockResults,
      hasMore: offset + limit < 200, // 假设总共200条数据
      totalCount: 200
    };
  };

  const appendResults = (type: SearchType, newData: any[], hasMore: boolean) => {
    setResults(prev => {
      const newMap = new Map(prev);
      const existingResult = newMap.get(type);
      
      if (existingResult) {
        newMap.set(type, {
          ...existingResult,
          resultList: [...existingResult.resultList, ...newData],
          hasMore: hasMore
        });
      } else {
        newMap.set(type, {
          resultList: newData,
          hasMore: hasMore,
          totalCount: newData.length
        });
      }
      
      return newMap;
    });
  };

  const logLoadingStats = (type: SearchType, newCount: number, totalCount: number) => {
    console.log(`📊 加载统计 - ${getTypeLabel(type)}: 新增${newCount}条，总计${totalCount}条`);
  };

  const getTypeLabel = (type: SearchType) => {
    const labels = {
      [SearchType.USER]: '用户',
      [SearchType.GROUP]: '群组',
      [SearchType.MESSAGE]: '消息'
    };
    return labels[type] || '未知';
  };

  const typeLabels = {
    [SearchType.USER]: '用户',
    [SearchType.GROUP]: '群组',
    [SearchType.MESSAGE]: '消息'
  };

  return (
    <div style={{ padding: '20px' }}>
      <SearchResults
        results={results}
        isLoading={loadingTypes.size > 0}
        keyword="智能搜索"
        typeLabels={typeLabels}
        onLoadMore={handleLoadMore}
        onResultItemClick={(data, type) => {
          console.log('点击结果:', data, type);
        }}
      />
      
      {/* 加载状态指示器 */}
      {loadingTypes.size > 0 && (
        <div style={{
          position: 'fixed',
          top: '20px',
          right: '20px',
          padding: '8px 12px',
          backgroundColor: '#007AFF',
          color: 'white',
          borderRadius: '4px',
          fontSize: '12px'
        }}>
          正在加载: {Array.from(loadingTypes).map(getTypeLabel).join(', ')}
        </div>
      )}
      
      {/* 缓存状态 */}
      <div style={{ marginTop: '16px', fontSize: '12px', color: '#666' }}>
        <h4>缓存状态:</h4>
        <div>缓存项数: {cacheRef.current.size}</div>
        <div>进行中请求: {loadingRef.current.size}</div>
      </div>
    </div>
  );
}
```

### onResultItemClick

type: `(data: SearchResultItem, type: SearchType) => void`

onResultItemClick 用于处理搜索结果项的点击事件，接收点击的数据和类型参数，默认值为 `-`。

#### Example1: 基础结果点击处理

```tsx
import { SearchResults, SearchType } from 'tuikit-atomicx-react';
import { useState } from 'react';

function BasicResultClickExample() {
  const [selectedItem, setSelectedItem] = useState<any>(null);
  const [clickHistory, setClickHistory] = useState<Array<{
    data: any;
    type: SearchType;
    timestamp: number;
  }>>([]);

  const handleResultClick = (data: any, type: SearchType) => {
    // 记录点击历史
    const clickRecord = {
      data,
      type,
      timestamp: Date.now()
    };
    
    setClickHistory(prev => [clickRecord, ...prev.slice(0, 9)]);
    setSelectedItem({ data, type });
    
    // 根据类型执行不同的操作
    switch (type) {
      case SearchType.USER:
        handleUserClick(data);
        break;
      case SearchType.GROUP:
        handleGroupClick(data);
        break;
      case SearchType.MESSAGE:
        handleMessageClick(data);
        break;
      case SearchType.CHAT_MESSAGE:
        handleChatMessageClick(data);
        break;
    }
  };

  const handleUserClick = (userData: any) => {
    console.log('点击用户:', userData);
    // 导航到用户详情页或发起私聊
    // router.push(`/user/${userData.profile?.userID}`);
  };

  const handleGroupClick = (groupData: any) => {
    console.log('点击群组:', groupData);
    // 显示群组信息或申请加入
    // showGroupInfo(groupData.groupInfo?.groupID);
  };

  const handleMessageClick = (messageData: any) => {
    console.log('点击消息:', messageData);
    // 跳转到对应的会话
    // openConversation(messageData.conversation?.conversationID);
  };

  const handleChatMessageClick = (chatMessageData: any) => {
    console.log('点击聊天消息:', chatMessageData);
    // 定位到具体消息
    // locateToMessage(chatMessageData.ID);
  };

  // 模拟搜索结果数据
  const mockResults = new Map([
    [SearchType.USER, {
      resultList: [
        {
          profile: {
            userID: 'user1',
            nick: '张三',
            avatar: 'https://example.com/avatar1.jpg'
          }
        }
      ],
      hasMore: false,
      totalCount: 1
    }],
    [SearchType.GROUP, {
      resultList: [
        {
          groupInfo: {
            groupID: 'group1',
            name: '技术交流群',
            avatar: 'https://example.com/group1.jpg'
          }
        }
      ],
      hasMore: false,
      totalCount: 1
    }]
  ]);

  const typeLabels = {
    [SearchType.USER]: '用户',
    [SearchType.GROUP]: '群组',
    [SearchType.MESSAGE]: '消息'
  };

  return (
    <div style={{ padding: '20px' }}>
      <SearchResults
        results={mockResults}
        isLoading={false}
        keyword="测试"
        typeLabels={typeLabels}
        onResultItemClick={handleResultClick}
      />
      
      {/* 选中项显示 */}
      {selectedItem && (
        <div style={{
          marginTop: '16px',
          padding: '12px',
          backgroundColor: '#f0f8ff',
          borderRadius: '4px',
          border: '1px solid #e0e0e0'
        }}>
          <h4 style={{ margin: '0 0 8px 0', fontSize: '14px' }}>当前选中:</h4>
          <div style={{ fontSize: '12px' }}>
            类型: {typeLabels[selectedItem.type]} | 
            数据: {JSON.stringify(selectedItem.data, null, 2)}
          </div>
        </div>
      )}
      
      {/* 点击历史 */}
      {clickHistory.length > 0 && (
        <div style={{ marginTop: '16px' }}>
          <h4 style={{ fontSize: '14px', margin: '0 0 8px 0' }}>点击历史:</h4>
          {clickHistory.map((record, index) => (
            <div key={index} style={{
              fontSize: '12px',
              padding: '4px 8px',
              backgroundColor: '#f5f5f5',
              marginBottom: '4px',
              borderRadius: '4px'
            }}>
              {new Date(record.timestamp).toLocaleTimeString()} - 
              {typeLabels[record.type]}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
```

#### Example2: 高级点击处理与业务逻辑

```tsx
import { SearchResults, SearchType } from 'tuikit-atomicx-react';
import { useState, useCallback } from 'react';

interface BusinessContext {
  currentUserId: string;
  permissions: {
    canViewUserProfile: boolean;
    canJoinGroup: boolean;
    canViewMessages: boolean;
  };
  analytics: {
    trackUserClick: (userId: string) => void;
    trackGroupClick: (groupId: string) => void;
    trackMessageClick: (messageId: string) => void;
  };
}

function AdvancedResultClickExample() {
  const [businessContext] = useState<BusinessContext>({
    currentUserId: 'current_user_123',
    permissions: {
      canViewUserProfile: true,
      canJoinGroup: true,
      canViewMessages: true
    },
    analytics: {
      trackUserClick: (userId) => console.log('📊 用户点击追踪:', userId),
      trackGroupClick: (groupId) => console.log('📊 群组点击追踪:', groupId),
      trackMessageClick: (messageId) => console.log('📊 消息点击追踪:', messageId)
    }
  });

  const [operationLog, setOperationLog] = useState<string[]>([]);
  const [showModal, setShowModal] = useState<{
    visible: boolean;
    type: string;
    data: any;
  }>({ visible: false, type: '', data: null });

  const logOperation = useCallback((message: string) => {
    setOperationLog(prev => [
      `${new Date().toLocaleTimeString()}: ${message}`,
      ...prev.slice(0, 9)
    ]);
  }, []);

  const handleAdvancedResultClick = async (data: any, type: SearchType) => {
    try {
      // 权限检查
      if (!checkPermission(type)) {
        logOperation(`权限不足，无法访问${getTypeLabel(type)}`);
        return;
      }

      // 业务逻辑处理
      switch (type) {
        case SearchType.USER:
          await handleAdvancedUserClick(data);
          break;
        case SearchType.GROUP:
          await handleAdvancedGroupClick(data);
          break;
        case SearchType.MESSAGE:
          await handleAdvancedMessageClick(data);
          break;
        case SearchType.CHAT_MESSAGE:
          await handleAdvancedChatMessageClick(data);
          break;
      }
    } catch (error) {
      logOperation(`操作失败: ${error.message}`);
    }
  };

  const checkPermission = (type: SearchType): boolean => {
    const { permissions } = businessContext;
    switch (type) {
      case SearchType.USER:
        return permissions.canViewUserProfile;
      case SearchType.GROUP:
        return permissions.canJoinGroup;
      case SearchType.MESSAGE:
      case SearchType.CHAT_MESSAGE:
        return permissions.canViewMessages;
      default:
        return false;
    }
  };

  const handleAdvancedUserClick = async (userData: any) => {
    const { profile } = userData;
    const { currentUserId, analytics } = businessContext;

    // 防止点击自己
    if (profile.userID === currentUserId) {
      logOperation('不能点击自己的用户信息');
      return;
    }

    // 分析追踪
    analytics.trackUserClick(profile.userID);
    
    logOperation(`正在加载用户资料: ${profile.nick || profile.userID}`);
    
    // 模拟加载用户详细信息
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 显示用户详情模态框
    setShowModal({
      visible: true,
      type: 'user',
      data: {
        ...userData,
        // 模拟获取的额外信息
        lastOnline: new Date(Date.now() - Math.random() * 86400000),
        mutualFriends: Math.floor(Math.random() * 20),
        isOnline: Math.random() > 0.5
      }
    });
    
    logOperation(`用户资料加载完成: ${profile.nick || profile.userID}`);
  };

  const handleAdvancedGroupClick = async (groupData: any) => {
    const { groupInfo } = groupData;
    const { analytics } = businessContext;

    analytics.trackGroupClick(groupInfo.groupID);
    
    logOperation(`正在检查群组状态: ${groupInfo.name || groupInfo.groupID}`);
    
    // 模拟检查群组状态
    await new Promise(resolve => setTimeout(resolve, 300));
    
    const groupStatus = {
      isMember: Math.random() > 0.7,
      needApproval: Math.random() > 0.5,
      memberCount: Math.floor(Math.random() * 500) + 50,
      maxMembers: 500
    };

    if (groupStatus.isMember) {
      logOperation('您已经是该群组成员，正在打开群聊...');
      // 打开群聊界面
    } else if (groupStatus.memberCount >= groupStatus.maxMembers) {
      logOperation('群组已满，无法申请加入');
    } else {
      setShowModal({
        visible: true,
        type: 'group',
        data: { ...groupData, status: groupStatus }
      });
      logOperation(`群组信息加载完成，${groupStatus.needApproval ? '需要' : '无需'}管理员审批`);
    }
  };

  const handleAdvancedMessageClick = async (messageData: any) => {
    const { conversation } = messageData;
    const { analytics } = businessContext;

    analytics.trackMessageClick(conversation.conversationID);
    
    logOperation(`正在打开会话: ${conversation.conversationID}`);
    
    // 模拟会话加载
    await new Promise(resolve => setTimeout(resolve, 200));
    
    logOperation('会话已打开，正在定位到相关消息...');
  };

  const handleAdvancedChatMessageClick = async (chatMessageData: any) => {
    const { analytics } = businessContext;

    analytics.trackMessageClick(chatMessageData.ID);
    
    logOperation(`正在定位到消息: ${chatMessageData.ID}`);
    
    // 模拟消息定位
    await new Promise(resolve => setTimeout(resolve, 100));
    
    logOperation('消息定位完成');
  };

  const getTypeLabel = (type: SearchType) => {
    const labels = {
      [SearchType.USER]: '用户',
      [SearchType.GROUP]: '群组',
      [SearchType.MESSAGE]: '消息',
      [SearchType.CHAT_MESSAGE]: '聊天消息'
    };
    return labels[type] || '未知';
  };

  const closeModal = () => {
    setShowModal({ visible: false, type: '', data: null });
  };

  // 模拟数据
  const mockResults = new Map([
    [SearchType.USER, {
      resultList: [
        {
          profile: {
            userID: 'user1',
            nick: '李四',
            avatar: 'https://example.com/avatar1.jpg'
          }
        }
      ],
      hasMore: false,
      totalCount: 1
    }]
  ]);

  const typeLabels = {
    [SearchType.USER]: '用户',
    [SearchType.GROUP]: '群组',
    [SearchType.MESSAGE]: '消息'
  };

  return (
    <div style={{ padding: '20px' }}>
      <SearchResults
        results={mockResults}
        isLoading={false}
        keyword="高级搜索"
        typeLabels={typeLabels}
        onResultItemClick={handleAdvancedResultClick}
      />

      {/* 操作日志 */}
      {operationLog.length > 0 && (
        <div style={{ marginTop: '16px' }}>
          <h4 style={{ fontSize: '14px', margin: '0 0 8px 0' }}>操作日志:</h4>
          {operationLog.map((log, index) => (
            <div key={index} style={{
              fontSize: '12px',
              padding: '4px 8px',
              backgroundColor: '#f8f9fa',
              marginBottom: '2px',
              borderLeft: '3px solid #007AFF',
              borderRadius: '2px'
            }}>
              {log}
            </div>
          ))}
        </div>
      )}

      {/* 模态框 */}
      {showModal.visible && (
        <div style={{
          position: 'fixed',
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          backgroundColor: 'rgba(0,0,0,0.5)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          zIndex: 1000
        }}>
          <div style={{
            backgroundColor: 'white',
            padding: '20px',
            borderRadius: '8px',
            maxWidth: '400px',
            width: '90%'
          }}>
            <h3 style={{ margin: '0 0 16px 0' }}>
              {showModal.type === 'user' ? '用户详情' : '群组信息'}
            </h3>
            <pre style={{ fontSize: '12px', backgroundColor: '#f5f5f5', padding: '8px' }}>
              {JSON.stringify(showModal.data, null, 2)}
            </pre>
            <button
              onClick={closeModal}
              style={{
                marginTop: '16px',
                padding: '8px 16px',
                backgroundColor: '#007AFF',
                color: 'white',
                border: 'none',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              关闭
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
```

### SearchResultsPresearch

type: `React.ComponentType`

SearchResultsPresearch 用于自定义搜索前的占位符组件，在用户未输入关键词时显示，默认值为 `-`。

#### Example1: 自定义搜索建议组件

```tsx
import { SearchResults } from 'tuikit-atomicx-react';
import { useState } from 'react';

const CustomPresearchComponent = () => {
  const [recentSearches] = useState([
    '用户管理', '群组设置', '消息记录', '权限配置'
  ]);
  
  const [hotSearches] = useState([
    '最新功能', '使用教程', '常见问题', '技术支持'
  ]);

  const handleSearchClick = (keyword: string) => {
    console.log('点击搜索建议:', keyword);
    // 这里可以触发搜索逻辑
  };

  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <div style={{ marginBottom: '24px' }}>
        <svg width="64" height="64" viewBox="0 0 64 64" fill="none">
          <circle cx="32" cy="32" r="30" fill="#f0f8ff" stroke="#007AFF" strokeWidth="2"/>
          <path d="M26 26l12 12M38 26l-12 12" stroke="#007AFF" strokeWidth="2"/>
        </svg>
      </div>
      
      <h3 style={{ margin: '0 0 8px 0', color: '#333' }}>开始搜索</h3>
      <p style={{ margin: '0 0 24px 0', color: '#666', fontSize: '14px' }}>
        输入关键词搜索用户、群组或消息
      </p>
      
      {/* 最近搜索 */}
      {recentSearches.length > 0 && (
        <div style={{ marginBottom: '20px' }}>
          <h4 style={{ margin: '0 0 8px 0', fontSize: '14px', color: '#333' }}>
            最近搜索
          </h4>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', justifyContent: 'center' }}>
            {recentSearches.map((keyword, index) => (
              <span
                key={index}
                onClick={() => handleSearchClick(keyword)}
                style={{
                  padding: '4px 12px',
                  backgroundColor: '#e3f2fd',
                  color: '#1976d2',
                  borderRadius: '16px',
                  fontSize: '12px',
                  cursor: 'pointer',
                  transition: 'background-color 0.2s'
                }}
                onMouseEnter={(e) => {
                  e.currentTarget.style.backgroundColor = '#bbdefb';
                }}
                onMouseLeave={(e) => {
                  e.currentTarget.style.backgroundColor = '#e3f2fd';
                }}
              >
                {keyword}
              </span>
            ))}
          </div>
        </div>
      )}
      
      {/* 热门搜索 */}
      <div>
        <h4 style={{ margin: '0 0 8px 0', fontSize: '14px', color: '#333' }}>
          热门搜索
        </h4>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', justifyContent: 'center' }}>
          {hotSearches.map((keyword, index) => (
            <span
              key={index}
              onClick={() => handleSearchClick(keyword)}
              style={{
                padding: '4px 12px',
                backgroundColor: '#fff3e0',
                color: '#f57c00',
                borderRadius: '16px',
                fontSize: '12px',
                cursor: 'pointer',
                transition: 'background-color 0.2s'
              }}
              onMouseEnter={(e) => {
                e.currentTarget.style.backgroundColor = '#ffe0b2';
              }}
              onMouseLeave={(e) => {
                e.currentTarget.style.backgroundColor = '#fff3e0';
              }}
            >
              🔥 {keyword}
            </span>
          ))}
        </div>
      </div>
    </div>
  );
};

function PresearchExample() {
  const [keyword, setKeyword] = useState('');

  return (
    <div style={{ padding: '20px' }}>
      <input
        type="text"
        value={keyword}
        onChange={(e) => setKeyword(e.target.value)}
        placeholder="输入搜索关键词..."
        style={{
          width: '100%',
          padding: '8px 12px',
          border: '1px solid #ddd',
          borderRadius: '4px',
          marginBottom: '16px'
        }}
      />
      
      <SearchResults
        results={new Map()}
        isLoading={false}
        keyword={keyword}
        typeLabels={{}}
        SearchResultsPresearch={CustomPresearchComponent}
      />
    </div>
  );
}
```

### SearchResultsLoading

type: `React.ComponentType`

SearchResultsLoading 用于自定义加载状态组件，在搜索进行中时显示，默认值为 `Loading`。

### SearchResultsEmpty

type: `React.ComponentType`

SearchResultsEmpty 用于自定义空结果占位符组件，在搜索无结果时显示，默认值为 `EmptyResult`。

### SearchResultItem

type: `React.ComponentType<ResultItemProps<SearchType>>`

SearchResultItem 用于自定义单个搜索结果项的展示组件，默认值为 `DefaultSearchResultsItem`。

### variant

type: `VariantType`

variant 用于指定组件的显示模式，支持迷你、标准、嵌入式三种模式，默认值为 `VariantType.STANDARD`。

### searchType

type: `SearchType | 'all'`

searchType 用于指定当前搜索类型筛选，控制显示哪些类型的结果，默认值为 `'all'`。 