Collaboration
Suivez l’Intégration collaborative pour exécuter l’exemple, connecter votre application et vérifier la persistance et les autorisations. Les détails et exemples Web/Server sont disponibles sur Démarrage rapide de la collaboration.
Créez le Unit via une API métier authentifiée appelant Collaboration Service, puis chargez son identifiant dans le navigateur. Configurez HTTP, Session Ticket et WebSocket selon le Quick Start, puis la persistance et les autorisations serveur pour la lecture, JOIN et les modifications.
Avant d’utiliser ces API, vérifiez que le backend cible prend en charge les Unit PDF. Le bon fonctionnement de l’exemple Sheets ne prouve pas la prise en charge PDF.
Charger un PDF collaboratif
Après avoir créé une unité PDF avec l'API du serveur ou importPdfToUnitIdAsync, chargez-la avec la façade de collaboration :
Définissez l’utilisateur courant avant de charger le document. Voir Intégration collaborative.
import { UserManagerService } from '@univerjs/core'import '@univerjs-pro/collaboration-client/facade'univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })const pdf = await univerAPI.getCollaboration().loadPdfAsync(unitId)if (!pdf) { throw new Error(`PDF unit not found: ${unitId}`)}console.log(pdf.getId(), pdf.getName())loadPdfAsync charge le snapshot du serveur, prépare la session de collaboration et renvoie un objet FPdf. Elle renvoie null lorsque l'unité ne peut pas être associée à un PDF.
Utilisez états, renvois et récupération des conflits pour afficher l’enregistrement et préserver les modifications non confirmées avant rechargement.
Suppression du chargement intégré par URL des documents collaboratifs
À noter
À partir de la version 1.2.0, Univer a supprimé le chargement intégré par URL des documents collaboratifs. Les paramètres unit et type de l’URL ne sont plus lus automatiquement pour charger un document collaboratif.
Si votre application dépend de ce comportement, vous pouvez le rétablir avec un plugin personnalisé.
Intégrer le plugin personnalisé
Copiez les quatre fichiers ci-dessous dans votre projet en respectant cette arborescence :
custom-url-load/├── plugin.ts├── controllers/│ └── data-loader.controller.ts└── services/ ├── url.service.ts └── web-url.service.tsAprès avoir initialisé l’éditeur et les plugins de collaboration, définissez l’utilisateur courant avant d’enregistrer CustomUrlLoadPlugin.
import { UserManagerService } from '@univerjs/core'import { CustomUrlLoadPlugin } from './custom-url-load/plugin'univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })univer.registerPlugin(CustomUrlLoadPlugin)Une fois enregistré, le plugin charge le document ; il n’est donc pas nécessaire d’appeler loadPdfAsync() pour le même document. Si votre application charge déjà les documents via la Facade, vous pouvez conserver l’approche de la section précédente et gérer les URL selon les besoins de votre application.
Code complet du plugin
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import { DependentOn, Inject, Injector, Plugin } from '@univerjs/core'import { CollaborationDataLoaderController } from './controllers/data-loader.controller'import { IURLService } from './services/url.service'import { WebURLService } from './services/web-url.service'@DependentOn(UniverCollaborationClientPlugin)export class CustomUrlLoadPlugin extends Plugin { static override pluginName = 'CUSTOM_URL_LOAD_PLUGIN' constructor( _config: undefined, @Inject(Injector) protected override readonly _injector: Injector ) { super() } override onStarting(): void { this._injector.add([IURLService, { useClass: WebURLService }]) this._injector.add([CollaborationDataLoaderController]) this.disposeWithMe(this._injector.get(IURLService)) this.disposeWithMe(this._injector.get(CollaborationDataLoaderController)) }}import { DataLoaderService } from '@univerjs-pro/collaboration-client'import { ILogService, Inject, RxDisposable } from '@univerjs/core'import { IURLService } from '../services/url.service'/** * Charge un document collaboratif à partir des paramètres de l’URL. */export class CollaborationDataLoaderController extends RxDisposable { constructor( @IURLService private readonly _urlService: IURLService, @ILogService private readonly _logService: ILogService, @Inject(DataLoaderService) private readonly _dataLoaderService: DataLoaderService ) { super() const unitId = this._urlService.getParam('unit') const type = this._urlService.getParam('type') if (!unitId || !type) { return } this._dataLoaderService.loadUnit(unitId, Number(type)) .catch((error: unknown) => { this._logService.error('[CollaborationDataLoaderController]', error) }) }}import type { IDisposable } from '@univerjs/core'import type { Observable } from 'rxjs'import { createIdentifier } from '@univerjs/core'export interface IURLService extends IDisposable { getParam: (key: string) => string | undefined setParam: (key: string, value: string, useReplace?: boolean) => void removeParam: (key: string, useReplace?: boolean) => void readonly urlChange$: Observable<void>}export const IURLService = createIdentifier<IURLService>('demo.custom-url-load.url-service')import type { IURLService } from './url.service'import { RxDisposable } from '@univerjs/core'import { fromEvent, map, shareReplay, takeUntil } from 'rxjs'export class WebURLService extends RxDisposable implements IURLService { readonly urlChange$ = fromEvent(window, 'popstate').pipe( map(() => undefined), takeUntil(this.dispose$), shareReplay({ bufferSize: 1, refCount: true }) ) getParam(key: string): string | undefined { return new URL(window.location.href).searchParams.get(key) ?? undefined } setParam(key: string, value: string, useReplace = false): void { const url = new URL(window.location.href) url.searchParams.set(key, value) this._updateUrl(url, useReplace) } removeParam(key: string, useReplace = false): void { const url = new URL(window.location.href) url.searchParams.delete(key) this._updateUrl(url, useReplace) } private _updateUrl(url: URL, useReplace: boolean): void { if (useReplace) { window.history.replaceState(window.history.state, '', url.toString()) } else { window.history.pushState(window.history.state, '', url.toString()) } }}Que pensez-vous de ce guide ?