Интеграция совместного редактирования

Подключение редактора Univer к совместному сервису для работы пользователей над одним документом.

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

Подготовьте сервер по руководству Интеграция сервера, затем настройте редактор и загрузку ниже. Рассматривайте Server и Web из Быстрого старта Office вместе.

100%

Подключение существующего редактора

Сохраните ваш редактор Web SDK. По настройке браузера в быстром старте добавьте плагины совместного редактирования и адреса загрузки документов, отправки изменений и WebSocket. Поддерживайте совместимые версии браузерных и серверных пакетов.

Фиксированные пользователи и права примера предназначены для демонстрации. В приложении передавайте учётные данные в запросах, чтобы сервер проверял личность и доступ к документу. Лицензирование описано в настройке лицензии.

Создание и открытие одного документа

Создание и открытие — разные действия:

  1. При создании документа сервер сохраняет его и возвращает ID.
  2. Браузер загружает этот ID. Используйте его повторно при открытии или передаче другому пользователю.

Поле API unitId — это ID документа. Не создавайте новый пустой локальный документ при каждом посещении.

Задайте текущего пользователя до загрузки документа. Он определяет личность участника и владельца локального офлайн-кэша; см. Идентификация и авторизация.

Например, после регистрации Sheets и совместных плагинов загрузите серверную таблицу:

TypeScript
import { UserManagerService } from '@univerjs/core'import '@univerjs-pro/collaboration-client/facade'univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })const workbook = await univerAPI.getCollaboration().loadSheetAsync('your-document-id')if (!workbook) throw new Error('Document could not be loaded')

Способы загрузки для продуктов описаны в Sheets, Docs, Slides, Boards, Bases и PDFs. Проверьте поддержку в продукте и целевом серверном выпуске.

Проверка синхронизации, сохранения и прав

Откройте один документ в двух независимых сеансах, например обычном и приватном окне. Измените его в одном и проверьте второй. Затем проверьте содержимое после обновления, переподключения и перезапуска сервера.

Тестируйте редактора, читателя и пользователя без доступа. Режим только для чтения в UI управляет взаимодействиями страницы, но сервер всё равно должен отклонять неавторизованные чтения и изменения.

Если загрузка работает, а синхронизация нет, проверьте WebSocket. Если после перезапуска содержимое исчезает, проверьте серверное хранилище. Настройки описаны в интеграции сервера.

Добавление обмена файлами, комментариев или истории

Для совместного редактирования импортированного файла создайте документ из преобразованных данных; см. Интеграция обмена файлами. Комментарии и история требуют собственных плагинов, сервисов и прав. Следуйте разделу Модули расширений Office.

Настройка панелей истории описана в Sheets, Docs, Slides, Boards и Bases. Текущие возможности PDFs см. в Истории PDFs.

Состояние синхронизации и повторные отправки

После импорта Facade событие CollaborationStatusChanged сообщает текущее состояние уже совместно редактируемых документов при регистрации, затем изменения без последовательных повторов состояния. hasWritePending(unitId) учитывает ожидающие отправки, подтверждения и офлайн-изменения. Без ID проверяется документ в фокусе. Наличие соединения не означает сохранение изменений.

TypeScript
import '@univerjs-pro/collaboration-client/facade'const collaboration = univerAPI.getCollaboration()const statusSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationStatusChanged, (event) => {  console.info(event.unitId, event.status, collaboration.hasWritePending(event.unitId))})const resendSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationChangesetResend, (event) => {  console.info(event.unitId, event.reason, event.attempt, event.unsyncedMutationCount, event.nextDelayMs)})

CollaborationChangesetResend вызывается при повторной отправке, не первой. Причины: ack_timeout, request_failed, license_editing_connections_exceeded, should_retry, reconnect. Поля attempt, elapsedMs, unsyncedMutationCount, nextDelayMs подходят для индикатора сохранения и повторов. При удалении редактора освобождайте подписки.

request_failed означает сбой запроса, допускающий повторную попытку, например сетевую ошибку или HTTP 408, 429, 5xx. license_editing_connections_exceeded означает, что все разрешённые лицензией подключения для редактирования заняты и сервер запросил повторную отправку.

Задержка объединения и тайм-аут подтверждения различаются. По умолчанию в миллисекундах: sendChangesetTimeout: 2000, changesetAckTimeout: 20000, maxChangesetAckTimeout: 120000. Запрос отправки использует тот же тайм-аут подтверждения. Неподтверждённые изменения отправляются повторно с экспоненциальным увеличением интервала до максимума. Равные два тайм-аута дают постоянный интервал.

TypeScript
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import { BrowserCollaborationSocketService } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientPlugin, {  socketService: BrowserCollaborationSocketService,  sendChangesetTimeout: 200,  changesetAckTimeout: 20_000,  maxChangesetAckTimeout: 120_000,})

Добавьте параметры в существующую регистрацию клиента, сохранив socket и endpoints. Пресеты совместной работы Sheets и Docs используют задержку объединения 200 мс и не предоставляют настройки тайм-аута подтверждения; для них используйте режим плагинов.

Обработка конфликтов приложением

CollaborationConflict вызывается один раз при входе в конфликт после попытки очистить офлайн-кеш. Подпишитесь до загрузки документов. reason: transform_failed, apply_failed, changeset_rejected, license_unit_type_rejected, permission_rejected или remote_revert; при наличии message и revert дают подробности.

license_unit_type_rejected означает, что лицензия сервера не поддерживает совместное редактирование документов этого типа.

TypeScript
import type { IEventParamConfig } from '@univerjs/core/facade'import '@univerjs-pro/collaboration-client/facade'const conflicts = new Map<string, IEventParamConfig['CollaborationConflict']>()const conflictSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationConflict, (event) => {  conflicts.set(event.unitId, event)})

Пример сохраняет событие для экрана восстановления. Map существует только в памяти: до перезагрузки сохраните или экспортируйте localChanges. Удержать данные нужно в этом событии: очищенный кеш затем не восстановить. awaitingChangeset мог уже примениться на сервере, поэтому не воспроизводите его без проверки.

При cacheCleared: false перезагрузка повторно применит старый кеш. Сначала решите проблему очистки. Очистка не означает сохранение несинхронизированных изменений. При permission_rejected также нужно восстановить доступ: перезагрузка не выдаёт права.

По умолчанию UI показывает уведомление с причиной и предлагает перезагрузку после успешной очистки либо повтор при ошибке очистки. Чтобы управлять восстановлением самостоятельно, задайте enableDefaultConflictUI: false в существующей инициализации и обработайте событие:

TypeScript
import { UniverCollaborationClientUIPlugin } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientUIPlugin, { enableDefaultConflictUI: false })

Добавьте пресет совместной работы к пресету редактора в существующем createUniver({ presets: [...] }), сохранив endpoints и историю. См. параметры событий и конфигурацию клиента.

Причины сервера и уведомления о лицензии

При отказе CollaborationConflict.message содержит причину, переданную сервером. Выбирайте восстановление по reason, не разбирая переведённый текст. Для license_unit_type_rejected нужна серверная лицензия на данный тип документа. license_editing_connections_exceeded означает повторную отправку: изменения ещё не подтверждены и будут отправлены снова. Не закрывайте редактор, пока hasWritePending(unitId) не станет false или приложение не сохранит изменения отдельно.

UI сообщает об исчерпании редакторских подключений и, при повторной отправке спустя не менее 20 секунд после первой, о задержке сохранения. Уведомления убираются при выходе документа из состояния ожидания подтверждения или его уничтожении. Отказ домена имеет отдельное уведомление. enableDefaultConflictUI: false отключает только восстановление конфликтов, но не уведомления ожидания или домена.

Насколько полезно это руководство?

© 2026 DreamNum Co., Ltd.