# MessageList 组件自定义文档

## 概述

MessageList 是一个功能强大的聊天消息列表组件，提供了完整的消息展示、交互和自定义功能。该组件支持消息分组、已读回执、消息操作、滚动控制等核心聊天功能，同时提供了丰富的自定义选项来满足不同的业务需求。

## Props 配置

| 字段 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `alignment` | `'left' \| 'right' \| 'two-sided'` | `'two-sided'` | 消息对齐方式。`left`: 所有消息左对齐；`right`: 所有消息右对齐；`two-sided`: 发送消息右对齐，接收消息左对齐 |
| `enableReadReceipt` | `boolean` | `false` | 是否启用已读回执功能 |
| `messageActionList` | `IMessageAction[]` | `undefined` | 自定义消息操作列表，如复制、撤回、删除等 |
| `messageAggregationTime` | `number` | `300` (5分钟) | 消息聚合时间间隔（秒），相同发送者在此时间内的连续消息会被聚合显示 |
| `filter` | `(message: IMessageModel) => boolean` | `undefined` | 消息过滤函数，用于控制哪些消息需要显示 |
| `className` | `string` | `undefined` | 自定义 CSS 类名 |
| `style` | `React.CSSProperties` | `undefined` | 自定义内联样式 |
| `Message` | `React.ComponentType` | `Message` | 自定义消息组件 |
| `MessageTimeDivider` | `React.ComponentType` | `MessageTimeDivider` | 自定义时间分隔线组件 |
| `LocalNoticeMessage` | `React.ComponentType` | `null` | 自定义本地通知消息组件 |

### IMessageAction 接口说明

```typescript
interface IMessageAction {
  key: 'copy' | 'recall' | 'quote' | 'forward' | 'delete' | string;
  label?: string;
  icon?: React.ReactNode;
  onClick?: (message: IMessageModel) => void;
  visible?: ((message: IMessageModel) => boolean) | boolean;
  component?: React.ComponentType<{ message: IMessageModel }>;
  className?: string;
  style?: React.CSSProperties;
}
```

## 自定义功能详解

### alignment

type: `'left' | 'right' | 'two-sided'`

alignment 用于设置消息对齐方式，支持 `left`、`right`、`two-sided` 三种模式。默认值为 `'two-sided'`。

- `two-sided`: 非本人的消息位于左侧，本人的消息位于右侧
- `left`: 所有消息位于左侧
- `right`: 所有消息位于右侧

### enableReadReceipt

type: `boolean`

enableReadReceipt 用于设置是否开启单条消息已读回执功能，默认值为 `false`。

### messageActionList

type: `IMessageAction[]`

messageActionList 用于设置消息操作列表，如复制、撤回、删除等操作，默认值为完整的消息操作列表 `['copy', 'recall', 'quote', 'forward', 'delete']`。

```tsx
interface IMessageAction {
  key: 'copy' | 'recall' | 'quote' | 'forward' | 'delete' | string;
  label?: string;
  icon?: React.ReactNode;
  onClick?: (message: IMessageModel) => void;
  visible?: ((message: IMessageModel) => boolean) | boolean;
  component?: React.ComponentType<{ message: IMessageModel }>;
  style?: React.CSSProperties;
}
```

可以使用 `useMessageAction` 获取完整的消息操作列表，然后根据需要进行自定义。

#### Example1: 变更消息操作列表的顺序

假设按照 `forward`、`copy`、`recall`、`quote`、`delete` 的顺序显示消息操作列表。

```tsx
import { Chat, MessageList, useMessageActions } from '@tencentcloud/chat-uikit-react';

const App = () => {
  const actions = useMessageActions(['forward', 'copy', 'recall', 'quote', 'delete']);
  return (
    <Chat>
      <MessageList messageActionList={actions} />
    </Chat>
  );
}
```

#### Example2: 仅展示部分消息操作

假设仅展示 `forward`、`copy`、`recall` 三个操作。

```tsx
import { Chat, MessageList, useMessageActions } from '@tencentcloud/chat-uikit-react';

const App = () => {
  const actions = useMessageActions(['forward', 'copy', 'recall']);
  return (
    <Chat>
      <MessageList messageActionList={actions} />
    </Chat>
  );
}

```

#### Example3: 自定义消息操作的样式

下面是一个自定义撤回操作的示例：

1. 将标签修改为'撤回 ⚠️'
2. 将颜色修改为橙色
3. 只有文本消息可以撤回


```tsx
import TUIChatEngine from '@tencentcloud/chat-uikit-engine';
import { Chat, MessageList, useMessageActions } from '@tencentcloud/chat-uikit-react';

const ChatApp = () => {
  const actions = useMessageActions(['copy', {
    key: 'recall',
    label: 'Recall ⚠️',
    style: {
      color: 'orange'
    },
    visible: (message) => message.type === TUIChatEngine.TYPES.MSG_TEXT,
  }, 'quote', 'forward', 'delete']);

  return (
    <Chat>
      <MessageList messageActionList={actions} />
    </Chat>
  );
}
```

#### Example4: 新增自定义消息操作

假设需要自定义消息操作，如仅其他人发送的消息可以标记'喜欢'，且插入在'撤回'操作之后。

```tsx
import { useMessageAction } from '@tencentcloud/chat-uikit-react';
import { yourApi } from '@/api/yourApi';

const customActions = {
  key: 'like',
  label: 'Like',
  icon: <span>👍</span>,
  style: {
    color: '#E53888',
  },
  visible: (message) => message.flow === 'in',
  onClick: (message) => {
    yourApi.likeMessage(message.ID);
  }
}

function ChatApp() {
  const actions = useMessageAction(['forward', 'copy', 'recall', customActions, 'quote', 'delete']);
  return <MessageList messageActionList={actions} />;
}
```

### messageAggregationTime

type: `number`

messageAggregationTime 用于设置消息聚合时间间隔，将相同发送者的连续消息聚合显示，默认值为 `300`（秒）。

### filter

type: `(message: IMessageModel) => boolean`

filter 用于设置消息过滤函数，控制哪些消息需要显示，默认值为 `undefined`。

#### Example: 过滤掉机器人发送的错误消息

```tsx
import { MessageList } from '@/components/MessageList';
import TUIChatEngine from '@tencentcloud/chat-uikit-engine';

const messageFilter = (message) => {
  // 过滤掉发送者昵称包含 '_robot' 且内容包含 'operation-failed' 的文本消息
  if (
    message.nick?.includes('_robot') 
    && message.type === TUIChatEngine.TYPES.MSG_TEXT
    && message.payload?.text?.includes('operation-failed')
  ) {
    return false;
  }
  return true;
};

function ChatApp() {
  return <MessageList filter={messageFilter} />;
}
```

### className

type: `string`

className 用于设置根容器自定义 CSS 类名，默认值为 `undefined`。

### style

type: `React.CSSProperties`

style 用于设置根容器自定义内联样式，默认值为 `undefined`。

### Message

type: `React.ComponentType`

Message 用于设置自定义消息组件，替换默认的消息渲染组件，默认值为内置的 `Message` 组件。

#### Example: 自定义 CUSTOM 消息点击跳转的消息组件

```tsx
import TUIChatEngine from '@tencentcloud/chat-uikit-engine';
import { Chat, MessageList, Message } from '@tencentcloud/chat-uikit-react';

function CustomMessage(props) {
  const { message } = props;

  if (message.type === TUIChatEngine.TYPES.MSG_CUSTOM) {
    const { businessID, ...restData } = JSON.parse(message.payload.data);
    if (businessID === 'text_link') {
      return (
        <div>
          <div>{restData.text}</div>
          <a href={restData.link}>
            跳转到外部网址 {restData.link}
          </a>
        </div>
      );
    }
  } else {
    // 其他消息类型使用默认消息组件
    return <Message {...props} />;
  }
}

function ChatApp() {
  return (
    <Chat>
      <MessageList Message={CustomMessage} />
    </Chat>
  );
}
```

### MessageTimeDivider

type: `React.ComponentType`

MessageTimeDivider 用于设置自定义时间分隔线组件，默认值为内置的 `MessageTimeDivider` 组件。

#### Example: 区分工作时间的时间分隔线

```tsx
import { Chat, MessageList, MessageTimeDivider } from '@tencentcloud/chat-uikit-react';

const BusinessTimeDivider: typeof MessageTimeDivider = ({ prevMessage, currentMessage }) => {
  if (!prevMessage || !currentMessage) return null;
  
  // 对于即将渲染的每一条消息获取当前消息和上一消息的时间，并转换为日期对象，判断是否跨天或间隔超过4小时
  const currentTime = new Date(currentMessage.time * 1000);
  const prevTime = new Date(prevMessage.time * 1000);
  
  // 跨天或间隔超过4小时才显示
  const shouldShow = currentTime.toDateString() !== prevTime.toDateString() ||
                    (currentTime.getTime() - prevTime.getTime()) > 4 * 60 * 60 * 1000;
  
  if (!shouldShow) return null;
  
  // 判断工作时间 (9:00-18:00, 周一到周五)
  const isWorkingTime = () => {
    const hour = currentTime.getHours();
    const day = currentTime.getDay();
    return day >= 1 && day <= 5 && hour >= 9 && hour <= 18;
  };
  
  const timeLabel = isWorkingTime() ? '工作时间' : '非工作时间';
  const timeColor = isWorkingTime() ? '#52c41a' : '#faad14';
  
  return (
    <div style={{ textAlign: 'center', margin: '16px 0' }}>
      <span style={{
        backgroundColor: timeColor,
        color: 'white',
        padding: '2px 8px',
        borderRadius: '12px',
        marginRight: '8px'
      }}>
        {timeLabel}
      </span>
      {currentTime.toLocaleString()}
    </div>
  );
};

function ChatApp() {
  return (
    <Chat>
      <MessageList MessageTimeDivider={BusinessTimeDivider} />
    </Chat>
  );
}
```

## 总结

MessageList 组件提供了完整的消息列表功能和丰富的自定义选项。通过合理配置 Props 和自定义组件，您可以创建出符合业务需求的聊天界面。建议在实际使用中根据具体场景选择合适的配置，并注意性能优化和用户体验的平衡。 
