[]
本教程基于《协同编辑 快速开始》教程,介绍如何配置权限(Permissions)功能。为便于理解核心逻辑,本教程在前端和后端使用相同的mockUsers模拟用户。在实际应用中,请根据具体业务需求进行修改。
将基础教程中的代码替换为以下内容:
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 sqlite3 from 'sqlite3';
import { SqliteDb } from '@grapecity-software/js-collaboration-ot-sqlite';
import { presenceFeature } from '@grapecity-software/js-collaboration-presence';
const mockUsers = [
// 允许编辑
{id: '0', name: "editUser", color: "#0000ff", mode: 'edit'},
// 查看者
{id: '1', name: "viewerUser", color: '#008000', mode: 'viewer'},
// 查看者
{id: '2', name: "viewerUser", color: '#9900cc', mode: 'viewer'},
];
// 注册类型
OT.TypesManager.register(type);
const app = express();
const httpServer = http.createServer(app);
const server = new Server({ httpServer });
const port = 8080;
// 初始化数据库
const db = new sqlite3.Database("./docs.db");
const sqliteDbAdapter = new SqliteDb(db);
// 初始化OT文档服务
const documentServices = new OT.DocumentServices({ db: sqliteDbAdapter });
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`);
});将基础教程中的代码替换为以下内容:
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: "editUser", color: "#0000ff", mode: 'edit'},
// 查看者
{id: '1', name: "viewerUser", color: '#008000', mode: 'viewer'},
// 查看者
{id: '2', name: "viewerUser", color: '#9900cc', mode: 'viewer'},
];
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(){
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 } });
const doc = new OT.SharedDoc(conn);
// 创建presence
const presence = new Presence(conn);
// 绑定presence
await bindPresence(workbook, presence, user);
// 绑定用户
workbook.collaboration.setUser(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);
}
}构建客户端代码
npm run build启动服务器
npm run start