[]
        
首页
开发者学堂
文档
论坛
市场
生态机会
活动
在线咨询 立即试用
(Showing Draft Content)

用户活动状态

本教程基于《协同编辑 快速开始》教程,介绍如何配置 Presence(用户状态)功能。

前置条件

效果展示

image

具体步骤

步骤1:安装依赖

npm install @grapecity-software/js-collaboration-presence-client @grapecity-software/js-collaboration-presence

步骤2:修改server.js

将基础教程中的代码替换为以下内容:

import express from 'express';
import http from 'http';
import { Server } from '@grapecity-software/js-collaboration';
import * as OT from '@grapecity-software/js-collaboration-ot';
import { type } from '@grapecity-software/spread-sheets-collaboration';
import { presenceFeature } from '@grapecity-software/js-collaboration-presence';

const mockUsers = [
    {id: '0', name: "用户1", color: "#0000ff", mode: 'edit'},
    {id: '1', name: "用户2", color: '#008000', mode: 'edit'},
    {id: '2', name: "用户3", color: '#cc005f', mode: 'edit'},
];

// 注册类型
OT.TypesManager.register(type);

const app = express();
const httpServer = http.createServer(app);
const server = new Server({ httpServer });
const port = 8080;

// 初始化 OT(操作转换)文档服务
const documentServices = new OT.DocumentServices();
server.useFeature(OT.documentFeature(documentServices));
server.useFeature(presenceFeature());

// 初始化 OT 文档服务
app.use(express.static('public'));

// 身份验证中间件
server.use("connect", async (context, next) => {
    const token = context.connection.auth?.token;
    // 未提供令牌
    if (!token) return await next("未提供令牌");
    try {
        const user = mockUsers.find(u => u.id === token);
        // 用户不存在
        if (!user) return await next("用户不存在");
        // 将用户信息存入连接标签
        context.connection.tags.set("user", { id: user.id, username: user.name, mode: user.mode });
        await next();
    } catch {
        // 令牌无效
        await next("令牌无效");
    }
});

// 校验操作提交权限
documentServices.use('submit', async (context, next) => {
    console.log('已接收消息,用户ID:', context.connection.auth?.token);
    const userInfo = context.connection.tags.get('user');
    if (!userInfo) {
        console.error('用户信息不存在');
        await next('用户信息不存在');
    }
    // 只读用户禁止编辑
    if (userInfo.mode === 'viewer') {
        console.error('只读用户无法执行编辑操作');
        await next('只读用户无法编辑');
    }
    await next();
});

// 启动服务
httpServer.listen(port, () => {
    console.log(`服务正在监听端口 ${port}`);
    console.log(`<http://127.0.0.1:${port}/index.html`);
});

步骤3:修改client.js

将基础教程中的代码替换为以下内容:

import * as GC from '@grapecity-software/spread-sheets'
import '@grapecity-software/spread-sheets-collaboration-addon';
import {Client} from "@grapecity-software/js-collaboration-client";
import * as OT from "@grapecity-software/js-collaboration-ot-client";
import { type, bind, bindPresence } from '@grapecity-software/spread-sheets-collaboration-client';
import "@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css";
import {Presence} from "@grapecity-software/js-collaboration-presence-client";

// 定义浏览模式
const BrowsingMode = GC.Spread.Sheets.Collaboration.BrowsingMode;
// 模拟用户列表
const mockUsers = [
    {id: '0', name: "用户1", color: "#0000ff", mode: 'edit'},
    {id: '1', name: "用户2", color: '#008000', mode: 'edit'},
    {id: '2', name: "用户3", color: '#cc005f', mode: 'edit'},
];

/**
 * 根据用户ID获取用户信息(包含协作权限)
 * @param {string} id - 用户ID
 * @returns 包含权限的用户对象
 */
function getUser (id) {
    const user = mockUsers.find(u => u.id === id);
    return {
        ...user,
        permission: {
            // 编辑权限 / 只读权限
            mode: user.mode === 'edit' ? BrowsingMode.edit : BrowsingMode.view,
        }
    }
}

// 注册文档类型
OT.TypesManager.register(type);
// 页面加载完成后执行
window.onload = async function(){
    // 初始化 SpreadJS 工作簿
    const workbook = new GC.Spread.Sheets.Workbook('ss');
    // 随机选择一个模拟用户
    const randomUserId = Math.floor(Math.random() * mockUsers.length);
    const user = getUser(`${randomUserId }`);
    // 连接服务器,加入房间,并使用用户ID进行身份验证
    const conn = new Client().connect('room1', { auth: { token: user.id } });
    // 创建 OT 共享文档
    const doc = new OT.SharedDoc(conn);
    // 创建在线状态实例
    const presence = new Presence(conn);
    // 绑定在线状态到工作簿
    await bindPresence(workbook, presence, user);

    // 监听文档错误
    doc.on('error', (err) => {
        // 处理错误:可刷新页面或提示用户
        console.error('错误:', err);
    });

    // 获取文档数据
    await doc.fetch();
    // 如果文档不存在,初始化默认内容
    if (!doc.type) {
        workbook.getActiveSheet().getCell(0, 0).value("默认内容");
        // 创建共享文档快照
        await doc.create(workbook.collaboration.toSnapshot(), type.uri, {});
        // 绑定工作簿与共享文档
        await bind(workbook, doc);
    } else {
        // 已存在文档,直接绑定
        await bind(workbook, doc);
    }
}

步骤4:构建并运行

  1. 构建客户端代码

npm run build
  1. 启动服务器

npm run start