# ContactList 组件

## 概述

ContactList 是一个高度可配置的联系人列表组件，基于 `useContactListState` 状态管理实现。该组件支持好友列表、群组列表、黑名单和申请管理，提供分组折叠、搜索过滤、自定义渲染等核心功能，适用于即时通讯、社交应用等场景的联系人管理界面。

## Props 配置表格

| 字段 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `activeContactItem` | `ContactGroupItem \| undefined` | `undefined` | 当前激活的联系人项 |
| `enableSearch` | `boolean` | `true` | 是否启用搜索功能 |
| `groupConfig` | `Partial<Record<ContactItemType, CustomGroupConfig>>` | `{}` | 自定义分组配置 |
| `className` | `string` | `undefined` | 自定义 CSS 类名 |
| `style` | `React.CSSProperties` | `undefined` | 自定义内联样式 |
| `searchPlaceholder` | `string` | `t('ContactList.search_contacts')` | 搜索框占位符文本 |
| `emptyText` | `string` | `t('ContactList.no_contacts')` | 空状态提示文本 |
| `ContactItem` | `React.ComponentType<ContactListItemProps> \| undefined` | `ContactListItem` | 自定义联系人项组件 |
| `ContactSearchComponent` | `React.ComponentType<ContactSearchProps> \| undefined` | `ContactSearch` | 自定义搜索组件 |
| `GroupHeader` | `React.ComponentType<ContactGroupHeaderProps> \| undefined` | 默认分组头 | 自定义分组头部组件 |
| `PlaceholderEmptyList` | `React.ReactNode \| undefined` | 默认空状态 | 自定义空状态组件 |
| `onContactItemClick` | `(item: ContactGroupItem) => void` | `undefined` | 联系人项点击事件 |
| `onFriendApplicationAction` | `(action: 'accept' \| 'refuse', application: FriendApplication) => void` | `undefined` | 好友申请操作事件 |
| `onGroupApplicationAction` | `(action: 'accept' \| 'refuse', application: GroupApplication) => void` | `undefined` | 群组申请操作事件 |

## 自定义功能详解

### activeContactItem

type: `ContactGroupItem | undefined`

activeContactItem 用于标识当前选中的联系人项，支持高亮显示选中状态，默认值为 `undefined`。

#### Example1: 基础选中状态管理

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroupItem } from 'tuikit-atomicx-react';

function ContactListWithSelection() {
  // 管理当前选中的联系人
  const [selectedContact, setSelectedContact] = useState<ContactGroupItem | undefined>();

  const handleContactClick = (item: ContactGroupItem) => {
    setSelectedContact(item);
    console.log('选中联系人:', item.data.nick || item.data.name);
  };

  return (
    <ContactList
      activeContactItem={selectedContact}
      onContactItemClick={handleContactClick}
    />
  );
}
```

#### Example2: 与路由状态同步

```tsx
import React from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroupItem } from 'tuikit-atomicx-react';

function ContactListWithRouting() {
  const { contactId, contactType } = useParams();
  const navigate = useNavigate();

  // 根据路由参数构建激活项
  const activeContactItem: ContactGroupItem | undefined = contactId ? {
    type: contactType as ContactItemType,
    data: { userID: contactId } as ContactItem
  } : undefined;

  const handleContactClick = (item: ContactGroupItem) => {
    // 点击联系人时更新路由
    navigate(`/contacts/${item.type}/${item.data.userID || item.data.groupID}`);
  };

  return (
    <ContactList
      activeContactItem={activeContactItem}
      onContactItemClick={handleContactClick}
    />
  );
}
```

### enableSearch

type: `boolean`

enableSearch 用于控制是否显示搜索功能，默认值为 `true`。

#### Example1: 禁用搜索功能

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function ContactListWithoutSearch() {
  return (
    <ContactList
      enableSearch={false}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 条件性显示搜索

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function ConditionalSearchContactList() {
  const [showSearch, setShowSearch] = useState(true);
  const [contactCount, setContactCount] = useState(0);

  // 当联系人数量较少时隐藏搜索框
  const shouldShowSearch = showSearch && contactCount > 10;

  return (
    <div>
      <button onClick={() => setShowSearch(!showSearch)}>
        {showSearch ? '隐藏搜索' : '显示搜索'}
      </button>
      
      <ContactList
        enableSearch={shouldShowSearch}
        onContactItemClick={(item) => {
          console.log('联系人点击:', item);
        }}
      />
    </div>
  );
}
```

### groupConfig

type: `Partial<Record<ContactItemType, CustomGroupConfig>>`

groupConfig 用于自定义分组配置，包括标题、显示顺序、隐藏状态等，默认值为 `{}`。

#### Example1: 自定义分组标题

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import { ContactItemType } from 'tuikit-atomicx-react';

function CustomGroupTitlesContactList() {
  const groupConfig = {
    [ContactItemType.FRIEND]: {
      title: '我的好友',
      order: 1
    },
    [ContactItemType.GROUP]: {
      title: '我的群组',
      order: 2
    },
    [ContactItemType.FRIEND_REQUEST]: {
      title: '好友申请',
      order: 0
    }
  };

  return (
    <ContactList
      groupConfig={groupConfig}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 隐藏特定分组

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import { ContactItemType } from 'tuikit-atomicx-react';

function HiddenGroupsContactList() {
  const groupConfig = {
    [ContactItemType.BLACK]: {
      title: '黑名单',
      hidden: true // 隐藏黑名单分组
    },
    [ContactItemType.GROUP_REQUEST]: {
      title: '群组申请',
      hidden: true // 隐藏群组申请分组
    }
  };

  return (
    <ContactList
      groupConfig={groupConfig}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example3: 企业级分组配置

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import { ContactItemType } from 'tuikit-atomicx-react';

function EnterpriseContactList() {
  const groupConfig = {
    [ContactItemType.FRIEND]: {
      title: '企业通讯录',
      order: 1
    },
    [ContactItemType.GROUP]: {
      title: '工作群组',
      order: 2
    },
    [ContactItemType.FRIEND_REQUEST]: {
      title: '待处理申请',
      order: 0
    },
    [ContactItemType.GROUP_REQUEST]: {
      title: '群组邀请',
      order: 1
    },
    [ContactItemType.BLACK]: {
      title: '已屏蔽',
      order: 3,
      hidden: false
    }
  };

  return (
    <ContactList
      groupConfig={groupConfig}
      onContactItemClick={(item) => {
        console.log('企业联系人点击:', item);
      }}
    />
  );
}
```

### className

type: `string`

className 用于添加自定义 CSS 类名，默认值为 `undefined`。

#### Example1: 基础样式定制

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import './CustomContactList.scss';

function StyledContactList() {
  return (
    <ContactList
      className="custom-contact-list"
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 主题样式切换

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function ThemedContactList() {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');

  const getThemeClass = () => {
    return theme === 'dark' ? 'contact-list-dark' : 'contact-list-light';
  };

  return (
    <div>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        切换主题
      </button>
      
      <ContactList
        className={`contact-list ${getThemeClass()}`}
        onContactItemClick={(item) => {
          console.log('联系人点击:', item);
        }}
      />
    </div>
  );
}
```

### style

type: `React.CSSProperties`

style 用于添加自定义内联样式，默认值为 `undefined`。

#### Example1: 固定高度布局

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function FixedHeightContactList() {
  return (
    <ContactList
      style={{
        height: '400px',
        border: '1px solid #e0e0e0',
        borderRadius: '8px'
      }}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 响应式布局

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function ResponsiveContactList() {
  return (
    <ContactList
      style={{
        height: '100vh',
        maxWidth: '300px',
        minWidth: '250px',
        flex: '0 0 auto'
      }}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

### searchPlaceholder

type: `string`

searchPlaceholder 用于设置搜索框的占位符文本，默认值为国际化文本 `t('ContactList.search_contacts')`。

#### Example1: 自定义搜索提示

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function CustomSearchPlaceholder() {
  return (
    <ContactList
      searchPlaceholder="搜索好友、群组或群成员..."
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 多语言搜索提示

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function MultiLanguageSearch() {
  const [language, setLanguage] = React.useState<'zh' | 'en'>('zh');

  const getSearchPlaceholder = () => {
    return language === 'zh' 
      ? '搜索联系人...' 
      : 'Search contacts...';
  };

  return (
    <div>
      <button onClick={() => setLanguage(language === 'zh' ? 'en' : 'zh')}>
        切换语言
      </button>
      
      <ContactList
        searchPlaceholder={getSearchPlaceholder()}
        onContactItemClick={(item) => {
          console.log('联系人点击:', item);
        }}
      />
    </div>
  );
}
```

### emptyText

type: `string`

emptyText 用于设置空状态时的提示文本，默认值为国际化文本 `t('ContactList.no_contacts')`。

#### Example1: 自定义空状态提示

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function CustomEmptyText() {
  return (
    <ContactList
      emptyText="暂无联系人数据，请先添加好友或加入群组"
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 动态空状态提示

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';

function DynamicEmptyText() {
  const [isLoading, setIsLoading] = useState(false);

  const getEmptyText = () => {
    if (isLoading) {
      return '正在加载联系人数据...';
    }
    return '暂无联系人，点击右上角添加按钮开始添加';
  };

  return (
    <div>
      <button onClick={() => setIsLoading(!isLoading)}>
        {isLoading ? '停止加载' : '开始加载'}
      </button>
      
      <ContactList
        emptyText={getEmptyText()}
        onContactItemClick={(item) => {
          console.log('联系人点击:', item);
        }}
      />
    </div>
  );
}
```

### ContactItem

type: `React.ComponentType<ContactListItemProps> | undefined`

ContactItem 用于自定义联系人项的渲染组件，默认值为内置的 `ContactListItem` 组件。

#### Example1: 简化版联系人项

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactListItemProps } from 'tuikit-atomicx-react';

const SimpleContactItem: React.FC<ContactListItemProps> = ({ 
  contactItem, 
  onClick, 
  activeContactItem 
}) => {
  const isActive = activeContactItem?.data.userID === contactItem.data.userID;
  
  return (
    <div
      className={`simple-contact-item ${isActive ? 'active' : ''}`}
      onClick={() => onClick?.(contactItem.type, contactItem.data)}
      style={{
        padding: '8px 12px',
        borderBottom: '1px solid #f0f0f0',
        cursor: 'pointer',
        backgroundColor: isActive ? '#e6f7ff' : 'transparent'
      }}
    >
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <img
          src={contactItem.data.avatar}
          alt="avatar"
          style={{
            width: '32px',
            height: '32px',
            borderRadius: '50%',
            marginRight: '8px'
          }}
        />
        <span>{contactItem.data.nick || contactItem.data.name}</span>
      </div>
    </div>
  );
};

function ContactListWithSimpleItems() {
  return (
    <ContactList
      ContactItem={SimpleContactItem}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 企业级联系人项

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactListItemProps } from 'tuikit-atomicx-react';

const EnterpriseContactItem: React.FC<ContactListItemProps> = ({ 
  contactItem, 
  onClick, 
  activeContactItem 
}) => {
  const isActive = activeContactItem?.data.userID === contactItem.data.userID;
  
  const getStatusIcon = () => {
    // 根据联系人状态返回不同的图标
    if ('onlineStatus' in contactItem.data) {
      return contactItem.data.onlineStatus === 'online' ? '🟢' : '⚪';
    }
    return '⚪';
  };

  const getDepartment = () => {
    // 企业场景下的部门信息
    if ('department' in contactItem.data) {
      return contactItem.data.department;
    }
    return '';
  };

  return (
    <div
      className={`enterprise-contact-item ${isActive ? 'active' : ''}`}
      onClick={() => onClick?.(contactItem.type, contactItem.data)}
      style={{
        padding: '12px 16px',
        borderBottom: '1px solid #f0f0f0',
        cursor: 'pointer',
        backgroundColor: isActive ? '#f0f8ff' : 'transparent',
        transition: 'background-color 0.2s'
      }}
    >
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', alignItems: 'center', flex: 1 }}>
          <img
            src={contactItem.data.avatar}
            alt="avatar"
            style={{
              width: '40px',
              height: '40px',
              borderRadius: '50%',
              marginRight: '12px'
            }}
          />
          <div style={{ flex: 1 }}>
            <div style={{ fontWeight: 'bold', fontSize: '14px' }}>
              {contactItem.data.nick || contactItem.data.name}
            </div>
            {getDepartment() && (
              <div style={{ fontSize: '12px', color: '#666' }}>
                {getDepartment()}
              </div>
            )}
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
          <span>{getStatusIcon()}</span>
          {contactItem.type === 'friendRequest' && (
            <span style={{ 
              backgroundColor: '#ff4d4f', 
              color: 'white', 
              padding: '2px 6px', 
              borderRadius: '10px', 
              fontSize: '12px' 
            }}>
              新
            </span>
          )}
        </div>
      </div>
    </div>
  );
};

function EnterpriseContactList() {
  return (
    <ContactList
      ContactItem={EnterpriseContactItem}
      onContactItemClick={(item) => {
        console.log('企业联系人点击:', item);
      }}
    />
  );
}
```

### ContactSearchComponent

type: `React.ComponentType<ContactSearchProps> | undefined`

ContactSearchComponent 用于自定义搜索组件的渲染，默认值为内置的 `ContactSearch` 组件。

#### Example1: 简化搜索框

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactSearchProps } from 'tuikit-atomicx-react';

const SimpleSearch: React.FC<ContactSearchProps> = ({ 
  placeholder, 
  onResultClick,
  onKeywordChange 
}) => {
  const [keyword, setKeyword] = useState('');

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setKeyword(value);
    onKeywordChange?.(value);
  };

  return (
    <div style={{ padding: '12px', borderBottom: '1px solid #e0e0e0' }}>
      <input
        type="text"
        value={keyword}
        onChange={handleChange}
        placeholder={placeholder}
        style={{
          width: '100%',
          padding: '8px 12px',
          border: '1px solid #d9d9d9',
          borderRadius: '6px',
          fontSize: '14px'
        }}
      />
    </div>
  );
};

function ContactListWithSimpleSearch() {
  return (
    <ContactList
      ContactSearchComponent={SimpleSearch}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 高级搜索组件

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactSearchProps } from 'tuikit-atomicx-react';

const AdvancedSearch: React.FC<ContactSearchProps> = ({ 
  placeholder, 
  onResultClick,
  onKeywordChange 
}) => {
  const [keyword, setKeyword] = useState('');
  const [searchType, setSearchType] = useState<'all' | 'friend' | 'group'>('all');

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setKeyword(value);
    onKeywordChange?.(value);
  };

  const handleTypeChange = (type: 'all' | 'friend' | 'group') => {
    setSearchType(type);
    // 这里可以触发特定类型的搜索
  };

  return (
    <div style={{ padding: '12px', borderBottom: '1px solid #e0e0e0' }}>
      <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>
        <button
          onClick={() => handleTypeChange('all')}
          style={{
            padding: '4px 8px',
            border: '1px solid #d9d9d9',
            borderRadius: '4px',
            backgroundColor: searchType === 'all' ? '#1890ff' : 'white',
            color: searchType === 'all' ? 'white' : '#333',
            cursor: 'pointer'
          }}
        >
          全部
        </button>
        <button
          onClick={() => handleTypeChange('friend')}
          style={{
            padding: '4px 8px',
            border: '1px solid #d9d9d9',
            borderRadius: '4px',
            backgroundColor: searchType === 'friend' ? '#1890ff' : 'white',
            color: searchType === 'friend' ? 'white' : '#333',
            cursor: 'pointer'
          }}
        >
          好友
        </button>
        <button
          onClick={() => handleTypeChange('group')}
          style={{
            padding: '4px 8px',
            border: '1px solid #d9d9d9',
            borderRadius: '4px',
            backgroundColor: searchType === 'group' ? '#1890ff' : 'white',
            color: searchType === 'group' ? 'white' : '#333',
            cursor: 'pointer'
          }}
        >
          群组
        </button>
      </div>
      
      <input
        type="text"
        value={keyword}
        onChange={handleChange}
        placeholder={placeholder}
        style={{
          width: '100%',
          padding: '8px 12px',
          border: '1px solid #d9d9d9',
          borderRadius: '6px',
          fontSize: '14px'
        }}
      />
    </div>
  );
};

function ContactListWithAdvancedSearch() {
  return (
    <ContactList
      ContactSearchComponent={AdvancedSearch}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

### GroupHeader

type: `React.ComponentType<ContactGroupHeaderProps> | undefined`

GroupHeader 用于自定义分组头部的渲染组件，默认值为内置的分组头部组件。

#### Example1: 简化分组头部

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroup } from 'tuikit-atomicx-react';

const SimpleGroupHeader: React.FC<ContactGroupHeaderProps> = ({ data, onClick }) => {
  return (
    <div
      style={{
        padding: '8px 12px',
        backgroundColor: '#f5f5f5',
        borderBottom: '1px solid #e0e0e0',
        fontSize: '14px',
        fontWeight: 'bold'
      }}
      onClick={onClick}
    >
      {data.title} ({data.items.length})
    </div>
  );
};

function ContactListWithSimpleHeaders() {
  return (
    <ContactList
      GroupHeader={SimpleGroupHeader}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 可折叠分组头部

```tsx
import React, { useState } from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroup } from 'tuikit-atomicx-react';

const CollapsibleGroupHeader: React.FC<ContactGroupHeaderProps> = ({ data, onClick }) => {
  const [isExpanded, setIsExpanded] = useState(true);

  const toggleExpanded = () => {
    setIsExpanded(!isExpanded);
    onClick();
  };

  return (
    <div
      style={{
        padding: '12px 16px',
        backgroundColor: '#fafafa',
        borderBottom: '1px solid #e0e0e0',
        cursor: 'pointer',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'space-between'
      }}
      onClick={toggleExpanded}
    >
      <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
        <span style={{ fontSize: '16px' }}>
          {isExpanded ? '▼' : '▶'}
        </span>
        <span style={{ fontSize: '14px', fontWeight: 'bold' }}>
          {data.title}
        </span>
        <span style={{ fontSize: '12px', color: '#666' }}>
          ({data.items.length})
        </span>
      </div>
      
      {data.unreadCount && data.unreadCount > 0 && (
        <span style={{
          backgroundColor: '#ff4d4f',
          color: 'white',
          padding: '2px 6px',
          borderRadius: '10px',
          fontSize: '12px'
        }}>
          {data.unreadCount > 99 ? '99+' : data.unreadCount}
        </span>
      )}
    </div>
  );
};

function ContactListWithCollapsibleHeaders() {
  return (
    <ContactList
      GroupHeader={CollapsibleGroupHeader}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

### PlaceholderEmptyList

type: `React.ReactNode | undefined`

PlaceholderEmptyList 用于自定义空状态时的渲染内容，默认值为内置的空状态组件。

#### Example1: 自定义空状态

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

const CustomEmptyState = () => {
  return (
    <div style={{
      textAlign: 'center',
      padding: '40px 20px',
      color: '#999'
    }}>
      <div style={{ fontSize: '48px', marginBottom: '16px' }}>👥</div>
      <div style={{ fontSize: '16px', marginBottom: '8px' }}>
        暂无联系人
      </div>
      <div style={{ fontSize: '14px' }}>
        点击右上角按钮添加好友或加入群组
      </div>
    </div>
  );
};

function ContactListWithCustomEmpty() {
  return (
    <ContactList
      PlaceholderEmptyList={<CustomEmptyState />}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

#### Example2: 带操作按钮的空状态

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';

const EmptyStateWithActions = () => {
  const handleAddFriend = () => {
    console.log('添加好友');
  };

  const handleJoinGroup = () => {
    console.log('加入群组');
  };

  return (
    <div style={{
      textAlign: 'center',
      padding: '40px 20px',
      color: '#999'
    }}>
      <div style={{ fontSize: '48px', marginBottom: '16px' }}>📞</div>
      <div style={{ fontSize: '16px', marginBottom: '16px' }}>
        开始添加联系人
      </div>
      <div style={{ fontSize: '14px', marginBottom: '24px' }}>
        添加好友或加入群组开始聊天
      </div>
      
      <div style={{ display: 'flex', gap: '12px', justifyContent: 'center' }}>
        <button
          onClick={handleAddFriend}
          style={{
            padding: '8px 16px',
            border: '1px solid #1890ff',
            borderRadius: '6px',
            backgroundColor: '#1890ff',
            color: 'white',
            cursor: 'pointer'
          }}
        >
          添加好友
        </button>
        <button
          onClick={handleJoinGroup}
          style={{
            padding: '8px 16px',
            border: '1px solid #d9d9d9',
            borderRadius: '6px',
            backgroundColor: 'white',
            color: '#333',
            cursor: 'pointer'
          }}
        >
          加入群组
        </button>
      </div>
    </div>
  );
};

function ContactListWithActionEmpty() {
  return (
    <ContactList
      PlaceholderEmptyList={<EmptyStateWithActions />}
      onContactItemClick={(item) => {
        console.log('联系人点击:', item);
      }}
    />
  );
}
```

### onContactItemClick

type: `(item: ContactGroupItem) => void`

onContactItemClick 用于处理联系人项点击事件，默认值为 `undefined`。

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

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroupItem } from 'tuikit-atomicx-react';

function BasicClickHandler() {
  const handleContactClick = (item: ContactGroupItem) => {
    console.log('联系人点击:', {
      type: item.type,
      data: item.data
    });
  };

  return (
    <ContactList
      onContactItemClick={handleContactClick}
    />
  );
}
```

#### Example2: 根据类型处理点击

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroupItem } from 'tuikit-atomicx-react';
import { ContactItemType } from 'tuikit-atomicx-react';

function TypedClickHandler() {
  const handleContactClick = (item: ContactGroupItem) => {
    switch (item.type) {
      case ContactItemType.FRIEND:
        console.log('好友点击:', item.data);
        // 打开好友聊天窗口
        break;
      case ContactItemType.GROUP:
        console.log('群组点击:', item.data);
        // 打开群组聊天窗口
        break;
      case ContactItemType.FRIEND_REQUEST:
        console.log('好友申请点击:', item.data);
        // 打开好友申请详情
        break;
      case ContactItemType.GROUP_REQUEST:
        console.log('群组申请点击:', item.data);
        // 打开群组申请详情
        break;
      default:
        console.log('其他类型点击:', item);
    }
  };

  return (
    <ContactList
      onContactItemClick={handleContactClick}
    />
  );
}
```

#### Example3: 带确认的点击处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { ContactGroupItem } from 'tuikit-atomicx-react';

function ConfirmedClickHandler() {
  const handleContactClick = (item: ContactGroupItem) => {
    // 检查是否需要确认
    if (item.type === 'black') {
      const confirmed = window.confirm('确定要查看黑名单用户吗？');
      if (!confirmed) {
        return;
      }
    }

    // 执行点击操作
    console.log('确认后执行:', item);
    
    // 这里可以添加路由跳转或其他操作
    // navigate(`/chat/${item.type}/${item.data.userID || item.data.groupID}`);
  };

  return (
    <ContactList
      onContactItemClick={handleContactClick}
    />
  );
}
```

### onFriendApplicationAction

type: `(action: 'accept' | 'refuse', application: FriendApplication) => void`

onFriendApplicationAction 用于处理好友申请的操作事件，默认值为 `undefined`。

#### Example1: 基础申请处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { FriendApplication } from 'tuikit-atomicx-react';

function BasicFriendApplicationHandler() {
  const handleFriendApplication = (action: 'accept' | 'refuse', application: FriendApplication) => {
    console.log('好友申请操作:', {
      action,
      userID: application.userID,
      nick: application.nick,
      wording: application.wording
    });
  };

  return (
    <ContactList
      onFriendApplicationAction={handleFriendApplication}
    />
  );
}
```

#### Example2: 带确认的申请处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { FriendApplication } from 'tuikit-atomicx-react';

function ConfirmedFriendApplicationHandler() {
  const handleFriendApplication = (action: 'accept' | 'refuse', application: FriendApplication) => {
    const actionText = action === 'accept' ? '接受' : '拒绝';
    const confirmed = window.confirm(
      `确定要${actionText}来自 "${application.nick}" 的好友申请吗？`
    );

    if (!confirmed) {
      return;
    }

    // 执行申请操作
    console.log('执行好友申请操作:', {
      action,
      userID: application.userID,
      nick: application.nick
    });

    // 这里可以调用 API 处理申请
    // if (action === 'accept') {
    //   acceptFriendApplication(application.userID);
    // } else {
    //   refuseFriendApplication(application.userID);
    // }
  };

  return (
    <ContactList
      onFriendApplicationAction={handleFriendApplication}
    />
  );
}
```

#### Example3: 企业级申请处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { FriendApplication } from 'tuikit-atomicx-react';

function EnterpriseFriendApplicationHandler() {
  const handleFriendApplication = (action: 'accept' | 'refuse', application: FriendApplication) => {
    // 记录操作日志
    const logData = {
      timestamp: new Date().toISOString(),
      action,
      userID: application.userID,
      nick: application.nick,
      source: application.source,
      wording: application.wording
    };

    console.log('企业级好友申请处理:', logData);

    // 发送操作通知
    if (action === 'accept') {
      console.log('发送接受通知给:', application.userID);
    } else {
      console.log('发送拒绝通知给:', application.userID);
    }

    // 更新本地状态
    // updateFriendApplicationStatus(application.userID, action);
  };

  return (
    <ContactList
      onFriendApplicationAction={handleFriendApplication}
    />
  );
}
```

### onGroupApplicationAction

type: `(action: 'accept' | 'refuse', application: GroupApplication) => void`

onGroupApplicationAction 用于处理群组申请的操作事件，默认值为 `undefined`。

#### Example1: 基础群组申请处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { GroupApplication } from 'tuikit-atomicx-react';

function BasicGroupApplicationHandler() {
  const handleGroupApplication = (action: 'accept' | 'refuse', application: GroupApplication) => {
    console.log('群组申请操作:', {
      action,
      groupID: application.groupID,
      groupName: application.groupName,
      applicant: application.applicant,
      note: application.note
    });
  };

  return (
    <ContactList
      onGroupApplicationAction={handleGroupApplication}
    />
  );
}
```

#### Example2: 带权限检查的群组申请处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { GroupApplication } from 'tuikit-atomicx-react';

function PermissionCheckedGroupApplicationHandler() {
  const handleGroupApplication = (action: 'accept' | 'refuse', application: GroupApplication) => {
    // 检查用户权限
    const hasPermission = checkGroupPermission(application.groupID, 'manageApplications');
    
    if (!hasPermission) {
      alert('您没有权限处理此群组申请');
      return;
    }

    const actionText = action === 'accept' ? '接受' : '拒绝';
    const confirmed = window.confirm(
      `确定要${actionText}用户 "${application.applicantNick}" 加入群组 "${application.groupName}" 的申请吗？`
    );

    if (!confirmed) {
      return;
    }

    // 执行群组申请操作
    console.log('执行群组申请操作:', {
      action,
      groupID: application.groupID,
      applicant: application.applicant
    });
  };

  // 模拟权限检查函数
  const checkGroupPermission = (groupID: string, permission: string) => {
    // 这里应该调用实际的权限检查逻辑
    return true;
  };

  return (
    <ContactList
      onGroupApplicationAction={handleGroupApplication}
    />
  );
}
```

#### Example3: 企业级群组申请处理

```tsx
import React from 'react';
import { ContactList } from 'tuikit-atomicx-react';
import type { GroupApplication } from 'tuikit-atomicx-react';

function EnterpriseGroupApplicationHandler() {
  const handleGroupApplication = (action: 'accept' | 'refuse', application: GroupApplication) => {
    // 记录操作日志
    const logData = {
      timestamp: new Date().toISOString(),
      action,
      groupID: application.groupID,
      groupName: application.groupName,
      applicant: application.applicant,
      applicantNick: application.applicantNick,
      applicationType: application.applicationType,
      note: application.note
    };

    console.log('企业级群组申请处理:', logData);

    // 发送操作通知
    if (action === 'accept') {
      console.log('发送接受通知给申请人:', application.applicant);
      console.log('发送群组更新通知给群成员');
    } else {
      console.log('发送拒绝通知给申请人:', application.applicant);
    }

    // 更新群组统计信息
    // updateGroupStatistics(application.groupID, action);

    // 记录审计日志
    // logAuditTrail('groupApplication', action, application);
  };

  return (
    <ContactList
      onGroupApplicationAction={handleGroupApplication}
    />
  );
}
```

## 总结

ContactList 组件提供了丰富的自定义能力，通过合理的 props 配置可以满足不同业务场景的需求。从简单的联系人展示到复杂的企业级应用，组件都能提供良好的扩展性和灵活性。建议根据实际业务需求选择合适的自定义配置，避免过度定制导致维护成本增加。 