# Комментарии

- Human documentation: [https://docs.univer.ai/ru-RU/guides/sheets/features/comments](https://docs.univer.ai/ru-RU/guides/sheets/features/comments)

- Agent Markdown: [https://docs.univer.ai/ru-RU/guides/sheets/features/comments.md](https://docs.univer.ai/ru-RU/guides/sheets/features/comments.md)

- Requested language: `ru-RU`

- Content language: `ru-RU`

- Documentation version: `1.2.0`

- Source: [sheets/features/comments.ru-RU.mdx](https://github.com/dream-num/documentation/blob/dev/content/guides/sheets/features/comments.ru-RU.mdx)

---

#### Package metadata

```json
{
  "mobile": true,
  "preset": [
    {
      "client": "@univerjs/preset-sheets-thread-comment",
      "locale": "@univerjs/preset-sheets-thread-comment/locales/en-US",
      "style": "@univerjs/preset-sheets-thread-comment/lib/index.css"
    }
  ],
  "plugins": [
    {
      "client": "@univerjs/thread-comment"
    },
    {
      "client": "@univerjs/thread-comment-ui",
      "locale": "@univerjs/thread-comment-ui/locale/en-US",
      "style": "@univerjs/thread-comment-ui/lib/index.css"
    },
    {
      "client": "@univerjs/sheets-thread-comment",
      "facade": "@univerjs/sheets-thread-comment/facade"
    },
    {
      "client": "@univerjs/sheets-thread-comment-ui",
      "locale": "@univerjs/sheets-thread-comment-ui/locale/en-US",
      "style": "@univerjs/sheets-thread-comment-ui/lib/index.css"
    }
  ],
  "server": "optional"
}
```

Комментарии позволяют пользователям оставлять в документах сообщения и ответы, упрощая общение и совместную работу в команде.

## Режим плагинов

### Установка

#### npm

```bash
npm install @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

#### pnpm

```bash
pnpm add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

#### yarn

```bash
yarn add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

#### bun

```bash
bun add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

### Использование

```typescript
import { LocaleType, mergeLocales, Univer } from '@univerjs/core'
import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment' // [!code ++]
import { UniverSheetsThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment-ui' // [!code ++]
import SheetsThreadCommentUIEnUS from '@univerjs/sheets-thread-comment-ui/locale/en-US' // [!code ++]
import { UniverThreadCommentPlugin } from '@univerjs/thread-comment' // [!code ++]
import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui' // [!code ++]
import ThreadCommentUIEnUS from '@univerjs/thread-comment-ui/locale/en-US' // [!code ++]

import '@univerjs/sheets-thread-comment-ui/lib/index.css'
import '@univerjs/thread-comment-ui/lib/index.css' // [!code ++]

import '@univerjs/sheets-thread-comment/facade' // [!code ++]

const univer = new Univer({
  locale: LocaleType.EN_US,
  locales: {
    [LocaleType.EN_US]: mergeLocales(
      ThreadCommentUIEnUS, // [!code ++]
      SheetsThreadCommentUIEnUS, // [!code ++]
    ),
  },
})

univer.registerPlugin(UniverThreadCommentPlugin) // [!code ++]
univer.registerPlugin(UniverThreadCommentUIPlugin) // [!code ++]
univer.registerPlugin(UniverSheetsThreadCommentPlugin) // [!code ++]
univer.registerPlugin(UniverSheetsThreadCommentUIPlugin) // [!code ++]
```

#### Использование с функцией совместной работы

Если вы используете функцию [совместной работы](https://docs.univer.ai/ru-RU/guides/sheets/features/collaboration.md), настройте её следующим образом:

#### npm

```bash
npm install @univerjs-pro/thread-comment-datasource
```

#### pnpm

```bash
pnpm add @univerjs-pro/thread-comment-datasource
```

#### yarn

```bash
yarn add @univerjs-pro/thread-comment-datasource
```

#### bun

```bash
bun add @univerjs-pro/thread-comment-datasource
```

```typescript
import { UniverThreadCommentDataSourcePlugin } from '@univerjs-pro/thread-comment-datasource' // [!code ++]

univer.registerPlugin(UniverThreadCommentDataSourcePlugin) // [!code ++]
```

## Поддержка мобильных устройств

Сначала настройте [мобильный редактор](https://docs.univer.ai/ru-RU/guides/sheets/getting-started/installation.md#mobile-support). В коде инициализации режима плагинов на этой странице замените указанные настольные регистрации мобильными экспортами тех же пакетов **до открытия документа**. Сохраните модели, стили, локализации и импорты Facade; не регистрируйте оба варианта.

| Пакет                                | Настольная регистрация              | Мобильная регистрация                     |
| ------------------------------------ | ----------------------------------- | ----------------------------------------- |
| `@univerjs/sheets-thread-comment-ui` | `UniverSheetsThreadCommentUIPlugin` | `UniverSheetsThreadCommentMobileUIPlugin` |
| `@univerjs/thread-comment-ui`        | `UniverThreadCommentUIPlugin`       | `UniverThreadCommentMobileUIPlugin`       |

## Режим предустановок

### Установка

#### npm

```bash
npm install @univerjs/preset-sheets-thread-comment
```

#### pnpm

```bash
pnpm add @univerjs/preset-sheets-thread-comment
```

#### yarn

```bash
yarn add @univerjs/preset-sheets-thread-comment
```

#### bun

```bash
bun add @univerjs/preset-sheets-thread-comment
```

### Использование

```typescript
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'
import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US'
import { UniverSheetsThreadCommentPreset } from '@univerjs/preset-sheets-thread-comment' // [!code ++]
import UniverPresetSheetsThreadCommentEnUS from '@univerjs/preset-sheets-thread-comment/locales/en-US' // [!code ++]
import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'

import '@univerjs/preset-sheets-core/lib/index.css'
import '@univerjs/preset-sheets-thread-comment/lib/index.css' // [!code ++]

const { univerAPI } = createUniver({
  locale: LocaleType.EN_US,
  locales: {
    [LocaleType.EN_US]: mergeLocales(
      UniverPresetSheetsCoreEnUS,
      UniverPresetSheetsThreadCommentEnUS, // [!code ++]
    ),
  },
  presets: [
    UniverSheetsCorePreset(),
    UniverSheetsThreadCommentPreset(), // [!code ++]
  ],
})
```

## Facade API

Полные определения типов Facade API доступны в разделе [FacadeAPI](https://docs.univer.ai/ru-RU/reference/facade/thread-comment.md).

### Импорт

> [!INFO: Примечание о режиме плагинов]
> Вручную импортировать пакет Facade требуется только в режиме плагинов. В режиме предустановок соответствующий пакет Facade уже включён, поэтому дополнительный импорт не нужен.

```typescript
import '@univerjs/sheets-thread-comment/facade'
```

### Создание комментария к ячейке

Создать новый конструктор комментария можно с помощью `univerAPI.newTheadComment()`, который возвращает экземпляр `FTheadCommentBuilder`. Методы можно вызывать цепочкой, задавая различные свойства комментария.

Ниже перечислены некоторые методы [`FTheadCommentBuilder`](https://docs.univer.ai/ru-RU/reference/facade/thead-comment-builder.md):

| Метод       | Описание                                |
| ----------- | --------------------------------------- |
| setContent  | Задаёт содержимое комментария           |
| setPersonId | Задаёт идентификатор автора комментария |
| setDateTime | Задаёт дату и время комментария         |
| setId       | Задаёт идентификатор комментария        |
| setThreadId | Задаёт идентификатор ветки комментариев |

```typescript
// Create a new comment
const richText = univerAPI.newRichText().insertText('hello univer')
const commentBuilder = univerAPI.newTheadComment()
  .setContent(richText)

console.log(commentBuilder.content.toPlainText())

// Add the comment to cell A1
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const cell = fWorksheet.getRange('A1')
const result = await cell.addCommentAsync(commentBuilder)
```

### Получение комментариев к ячейкам

Получить комментарии можно следующими методами, возвращающими экземпляр `FThreadComment`. Затем комментарий можно обновить, удалить или пометить как решённый.

* `FWorkbook.getComments()`: получить все комментарии в книге
* `FfWorksheet.getComments()`: получить все комментарии на листе
* `FRange.getComment()`: получить комментарий верхней левой ячейки диапазона
* `FRange.getComments()`: получить все комментарии в диапазоне

Ниже перечислены некоторые методы [`FThreadComment`](https://docs.univer.ai/ru-RU/reference/facade/thread-comment.md):

| Метод          | Описание                                          |
| -------------- | ------------------------------------------------- |
| getIsRoot      | Проверяет, является ли комментарий корневым       |
| getCommentData | Возвращает данные комментария                     |
| getReplies     | Возвращает список ответов на комментарий          |
| getRange       | Возвращает диапазон комментария                   |
| getRichText    | Возвращает форматированное содержимое комментария |
| deleteAsync    | Удаляет комментарий и ответы на него              |
| updateAsync    | Обновляет содержимое комментария                  |
| resolveAsync   | Помечает комментарий как решённый                 |
| replyAsync     | Отвечает на комментарий                           |

```typescript
// Get all comments in the workbook
const fWorkbook = univerAPI.getActiveWorkbook()
fWorkbook.getComments()

// Get all comments in the active worksheet
const fWorksheet = fWorkbook.getActiveSheet()
fWorksheet.getComments()

const fRange = fWorksheet.getRange('A1:B2')
// Get the comment of cell A1
fRange.getComment()

// Get all comments in the range A1:B2
fRange.getComments()
```

### Очистка комментариев к ячейкам

* `FWorkbook.clearComments()`: удалить все комментарии в книге
* `FWorksheet.clearComments()`: удалить все комментарии на листе
* `FRange.clearCommentAsync()`: удалить комментарий верхней левой ячейки диапазона
* `FRange.clearCommentsAsync()`: удалить все комментарии в диапазоне

```typescript
// Clear all comments in the workbook
const fWorkbook = univerAPI.getActiveWorkbook()
await fWorkbook.clearComments()

// Clear all comments in the active worksheet
const fWorksheet = fWorkbook.getActiveSheet()
await fWorksheet.clearComments()

const fRange = fWorksheet.getRange('A1:B2')

// Clear the comment of cell A1
await fRange.clearCommentAsync()

// Clear all comments in the range A1:B2
await fRange.clearCommentsAsync()
```

### Получение списка ответов на комментарий

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Get all comments in the worksheet
const comments = fWorksheet.getComments()
comments.forEach((comment) => {
  // If the comment is a root comment, get its replies
  if (comment.getIsRoot()) {
    const replies = comment.getReplies()
    replies.forEach((reply) => {
      console.log(reply.getCommentData())
    })
  }
})
```

### Обновление, удаление, завершение и ответы на комментарии

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Create a new comment and add it to cell A1
const richText = univerAPI.newRichText().insertText('hello univer')
const commentBuilder = univerAPI.newTheadComment()
  .setContent(richText)
  .setId('mock-comment-id')
const cell = fWorksheet.getRange('A1')
await cell.addCommentAsync(commentBuilder)

// Update the comment and reply after 3 seconds
setTimeout(async () => {
  // Get the comment by ID and update its content
  const comment = fWorksheet.getCommentById('mock-comment-id')
  const newRichText = univerAPI.newRichText().insertText('Hello Univer AI')
  await comment.updateAsync(newRichText)

  // Create a new reply comment and set its content
  const replyText = univerAPI.newRichText().insertText('Hello Univer AI! GO! GO! GO!')
  const reply = univerAPI.newTheadComment().setContent(replyText)
  await comment.replyAsync(reply)
}, 3000)

// Resolve the comment and delete it after 6 seconds
setTimeout(async () => {
  const comment = fWorksheet.getCommentById('mock-comment-id')
  await comment.resolveAsync()
  await comment.deleteAsync()
}, 6000)
```

### Обработчики событий

Полные определения типов событий доступны в разделе [Events](https://docs.univer.ai/ru-RU/reference/facade/events.md).

Модуль комментариев предоставляет события для отслеживания добавления, обновления и удаления комментариев, а также изменения их статуса. Подписаться на любое событие можно с помощью `univerAPI.addEvent()`.

#### События добавления комментариев

`univerAPI.Event.CommentAdded`: срабатывает после добавления комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentAdded, (params) => {
  const { comment, workbook, worksheet, row, col } = params
})

// Remove the event listener, use `disposable.dispose()`
```

`univerAPI.Event.BeforeCommentAdd`: срабатывает перед добавлением комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentAdd, (params) => {
  const { comment, workbook, worksheet, row, col } = params

  // Cancel the comment addition operation
  params.cancel = true
})

// Remove the event listener, use `disposable.dispose()`
```

#### События обновления комментариев

`univerAPI.Event.CommentUpdated`: срабатывает после обновления комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentUpdated, (params) => {
  const { comment, workbook, worksheet, row, col } = params
})

// Remove the event listener, use `disposable.dispose()`
```

`univerAPI.Event.BeforeCommentUpdate`: срабатывает перед обновлением комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentUpdate, (params) => {
  const { comment, workbook, worksheet, row, col, newContent } = params

  // Cancel the comment update operation
  params.cancel = true
})

// Remove the event listener, use `disposable.dispose()`
```

#### События удаления комментариев

`univerAPI.Event.CommentDeleted`: срабатывает после удаления комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentDeleted, (params) => {
  const { commentId, workbook, worksheet } = params
})

// Remove the event listener, use `disposable.dispose()`
```

`univerAPI.Event.BeforeCommentDelete`: срабатывает перед удалением комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentDelete, (params) => {
  const { comment, workbook, worksheet, row, col } = params

  // Cancel the comment deletion operation
  params.cancel = true
})

// Remove the event listener, use `disposable.dispose()`
```

#### События изменения статуса комментария

`univerAPI.Event.CommentResolved`: срабатывает после изменения статуса комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentResolved, (params) => {
  const { comment, row, col, resolved, workbook, worksheet } = params
})

// Remove the event listener, use `disposable.dispose()`
```

`univerAPI.Event.BeforeCommentResolve`: срабатывает перед изменением статуса комментария

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentResolve, (params) => {
  const { comment, row, col, resolved, workbook, worksheet } = params

  // Cancel the comment resolution operation
  params.cancel = true
})

// Remove the event listener, use `disposable.dispose()`
```

Все события содержат следующие общие параметры:

* `workbook`: текущий экземпляр книги
* `worksheet`: текущий экземпляр листа
* `row`: индекс строки комментария
* `col`: индекс столбца комментария
* `comment`: объект комментария (в событиях удаления передаётся только `commentId`)

Специальные параметры:

* событие `BeforeCommentUpdate` содержит `newContent`: новое содержимое комментария (тип RichTextValue)
* события `CommentResolved` и `BeforeCommentResolve` содержат `resolved`: статус комментария

Обработчики всех событий с префиксом `Before` могут вернуть `params.cancel = true`, чтобы отменить соответствующую операцию.

## Общие операции

Импортируйте общую Facade комментариев и Facade продукта. Методы продукта создают стабильные привязки, общая API управляет ответами, изменениями, разрешением и удалением. `getComments()` читает локальное состояние. `listCommentsAsync()` синхронизирует уже известные обсуждения через настроенный источник, но не обнаруживает все обсуждения на сервере.

```ts
import '@univerjs/thread-comment/facade'

const [thread] = univerAPI.getComments({ resolved: false })
if (thread) {
  await univerAPI.replyCommentAsync({
    unitId: thread.unitId,
    subUnitId: thread.subUnitId,
    threadId: thread.threadId,
    content: 'Reviewed.',
  })
}
```

## Общие обсуждения

Интегрируйте Comment Service и Endpoint через [Server SDK](https://docs.univer.ai/ru-RU/server/collaboration/extensions.md), затем после настройки совместного редактирования и лицензии зарегистрируйте `UniverThreadCommentDataSourcePlugin` из `@univerjs-pro/thread-comment-datasource`. Источник использует `/universer-api/comment/unit/{unitId}/...` и `/universer-api/user/list`: предоставьте эти маршруты в приложении. Сервер должен отдельно проверять права на чтение и запись комментариев, не полагаясь на право редактирования документа.
