univer实现excel协同

快速入门

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/@univerjs/umd/lib/univer.full.umd.js"></script>
    <script src="https://unpkg.com/@univerjs/umd/lib/locale/zh-CN.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs/umd/lib/univer.css">
    <style>
        #app{
            width: 100%;
            height: 100vh;
        }
    </style>
</head>
<body>
    <div id="app"></div>

    <script>
        var {
          UniverCore,
          UniverDesign,
          UniverEngineRender,
          UniverEngineFormula,
          UniverDocs,
          UniverDocsUi,
          UniverUi,
          UniverSheets,
          UniverSheetsUi,
          UniverSheetsNumfmt,
          UniverSheetsFormula,
          UniverFacade,
        } = window
     
        var univer = new UniverCore.Univer({
          theme: UniverDesign.defaultTheme,
          locale: UniverCore.LocaleType.ZH_CN,
          locales: {
            [UniverCore.LocaleType.ZH_CN]: UniverUMD['zh-CN'],
          },
        });
     
        univer.registerPlugin(UniverEngineRender.UniverRenderEnginePlugin);
        univer.registerPlugin(UniverEngineFormula.UniverFormulaEnginePlugin);
     
        univer.registerPlugin(UniverUi.UniverUIPlugin, {
          container: "app",
        });
     
        univer.registerPlugin(UniverDocs.UniverDocsPlugin);
        univer.registerPlugin(UniverDocsUi.UniverDocsUIPlugin);
     
        univer.registerPlugin(UniverSheets.UniverSheetsPlugin);
        univer.registerPlugin(UniverSheetsUi.UniverSheetsUIPlugin);
        univer.registerPlugin(UniverSheetsNumfmt.UniverSheetsNumfmtPlugin);
        univer.registerPlugin(UniverSheetsFormula.UniverSheetsFormulaPlugin);
     
        univer.createUnit(UniverCore.UniverInstanceType.UNIVER_SHEET, {})
     
        const univerAPI = UniverFacade.FUniver.newAPI(univer)
      </script>
</body>
</html>

在这里插入图片描述

使用univer后端服务协同

后端部署

bash -c "$(curl -fsSL https://get.univer.ai)"

在这里插入图片描述
打开链接获取token,后续的安装就开始了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
访问8000

curl http://127.0.0.1:8000

在这里插入图片描述

如果机器停止了,重启之后可以运行docker compose up启动

页面部署

说明服务启动起来了,引入js库尝试,发现报错

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/@univerjs/umd/lib/univer.full.umd.js"></script>
  <script src="https://unpkg.com/@univerjs/umd/lib/locale/zh-CN.js"></script>
  <script src="https://unpkg.com/@univerjs-pro/collaboration/lib/umd/index.js"></script>
  <script src="https://unpkg.com/@univerjs-pro/collaboration-client/lib/umd/index.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/@univerjs/umd/lib/univer.css">
  <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/collaboration-client/lib/index.css">
  <style>
    #app {
      width: 100%;
      height: 100vh;
    }
  </style>
</head>

<body>
  <div id="app"></div>

  <script>
    var {
      UniverCore,
      UniverDesign,
      UniverEngineRender,
      UniverEngineFormula,
      UniverDocs,
      UniverDocsUi,
      UniverUi,
      UniverSheets,
      UniverSheetsUi,
      UniverSheetsNumfmt,
      UniverSheetsFormula,
      UniverFacade,
      UniverCollaborationPlugin,
      UniverCollaborationClientPlugin
    } = window

    var univer = new UniverCore.Univer({
      theme: UniverDesign.defaultTheme,
      locale: UniverCore.LocaleType.ZH_CN,
      locales: {
        [UniverCore.LocaleType.ZH_CN]: UniverUMD['zh-CN'],
      },
    });

    univer.registerPlugin(UniverEngineRender.UniverRenderEnginePlugin);
    univer.registerPlugin(UniverEngineFormula.UniverFormulaEnginePlugin);

    univer.registerPlugin(UniverUi.UniverUIPlugin, {
      container: "app",
    });

    univer.registerPlugin(UniverDocs.UniverDocsPlugin);
    univer.registerPlugin(UniverDocsUi.UniverDocsUIPlugin);

    univer.registerPlugin(UniverSheets.UniverSheetsPlugin);
    univer.registerPlugin(UniverSheetsUi.UniverSheetsUIPlugin);
    univer.registerPlugin(UniverSheetsNumfmt.UniverSheetsNumfmtPlugin);
    univer.registerPlugin(UniverSheetsFormula.UniverSheetsFormulaPlugin);
    
    univer.registerPlugin(UniverCollaborationPlugin);
    univer.registerPlugin(UniverCollaborationClientPlugin, {
      authzUrl: 'http://192.168.56.10:8000/universer-api/authz',
      snapshotServerUrl: 'http://192.168.56.10:8000/universer-api/snapshot',
      collabSubmitChangesetUrl: 'http://192.168.56.10:8000/universer-api/comb',
      collabWebSocketUrl: 'ws://192.168.56.10:8000/universer-api/comb/connect',
    });

    univer.createUnit(UniverCore.UniverInstanceType.UNIVER_SHEET, {})
    const univerAPI = UniverFacade.FUniver.newAPI(univer)
  </script>
</body>

</html>

在这里插入图片描述

vue3部署

采用vue3方式开发

 pnpm init
 pnpm create vite --registry=http://registry.npm.taobao.org

在这里插入图片描述

pnpm install --registry=http://registry.npm.taobao.org
pnpm run dev

安装依赖包

pnpm add @univerjs/core @univerjs/design @univerjs/docs @univerjs/docs-ui @univerjs/engine-formula @univerjs/engine-render @univerjs/sheets @univerjs/sheets-formula @univerjs/sheets-ui @univerjs/ui --registry=http://registry.npm.taobao.org

pnpm add @univerjs/facade --registry=http://registry.npm.taobao.org

在这里插入图片描述
在这里插入图片描述
修改App.vue

<template>
  <div ref="excelContent" style="width: 100%;height: 900px;"></div>
</template>
<script setup lang="ts">

import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";

import { onMounted, ref } from 'vue'
import { LocaleType, Tools, Univer, UniverInstanceType } from "@univerjs/core";
import { defaultTheme } from "@univerjs/design";

import { UniverFormulaEnginePlugin } from "@univerjs/engine-formula";
import { UniverRenderEnginePlugin } from "@univerjs/engine-render";

import { UniverUIPlugin } from "@univerjs/ui";

import { UniverDocsPlugin } from "@univerjs/docs";
import { UniverDocsUIPlugin } from "@univerjs/docs-ui";

import { UniverSheetsPlugin } from "@univerjs/sheets";
import { UniverSheetsFormulaPlugin } from "@univerjs/sheets-formula";
import { UniverSheetsUIPlugin } from "@univerjs/sheets-ui";

import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import { FUniver } from '@univerjs/facade'

const excelContent = ref<HTMLElement | null>(null)

onMounted(() => {
  initSheet()
})

const initSheet = () => {
  const univer = new Univer({
    theme: defaultTheme,
    locale: LocaleType.ZH_CN,
    locales: {
      [LocaleType.ZH_CN]: Tools.deepMerge(
        SheetsZhCN,
        DocsUIZhCN,
        SheetsUIZhCN,
        SheetsFormulaZhCN,
        UIZhCN,
        DesignZhCN,
      ),
    },
  });

  univer.registerPlugin(UniverRenderEnginePlugin);
  univer.registerPlugin(UniverFormulaEnginePlugin);

  univer.registerPlugin(UniverUIPlugin, {
    container: excelContent.value!,
  });

  univer.registerPlugin(UniverDocsPlugin);
  univer.registerPlugin(UniverDocsUIPlugin);

  univer.registerPlugin(UniverSheetsPlugin);
  univer.registerPlugin(UniverSheetsUIPlugin);
  univer.registerPlugin(UniverSheetsFormulaPlugin);

  univer.createUnit(UniverInstanceType.UNIVER_SHEET, {});
  const univerAPI = FUniver.newAPI(univer)
}

</script>
<style scoped>
.excel-container {
  width: 100%;
  height: 100%;
  min-height: 90vh;
}
</style>

启动项目查看效果
在这里插入图片描述

协同编辑

pnpm add @univerjs-pro/collaboration @univerjs-pro/collaboration-client --registry=http://registry.npm.taobao.org

在这里插入图片描述
修改App.vue

<template>
  <div ref="excelContent" style="width: 100%;height: 900px;"></div>
</template>
<script setup lang="ts">

import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";
import '@univerjs-pro/collaboration-client/lib/index.css';

import { onMounted, ref } from 'vue'
import { LocaleType, Tools, Univer, UniverInstanceType,IAuthzIoService,IUndoRedoService } from "@univerjs/core";
import { defaultTheme } from "@univerjs/design";

import { UniverFormulaEnginePlugin } from "@univerjs/engine-formula";
import { UniverRenderEnginePlugin } from "@univerjs/engine-render";

import { UniverUIPlugin } from "@univerjs/ui";

import { UniverDocsPlugin } from "@univerjs/docs";
import { UniverDocsUIPlugin } from "@univerjs/docs-ui";

import { UniverSheetsPlugin } from "@univerjs/sheets";
import { UniverSheetsFormulaPlugin } from "@univerjs/sheets-formula";
import { UniverSheetsUIPlugin } from "@univerjs/sheets-ui";

import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import { FUniver } from '@univerjs/facade'

import { UniverCollaborationPlugin } from '@univerjs-pro/collaboration';
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client';
import CollaborationClientZhCN from '@univerjs-pro/collaboration-client/locale/zh-CN';

const excelContent = ref<HTMLElement | null>(null)

onMounted(() => {
  initSheet()
})

const initSheet = () => {
  const univer = new Univer({
    // 通过将 override 选项设置为 [[IAuthzIoService, null]],可以告诉 Univer 不要注册内置的 IAuthzIoService。
    // 通过将 override 选项设置为 [[IUndoRedoService, null]],可以告诉 Univer 不要注册内置的 IUndoRedoService
    // 这样,Univer 将使用 UniverCollaborationPlugin 中提供的服务作为权限、重做恢复服务的实现。
    override: [
      [IAuthzIoService,null],
      [IUndoRedoService,null],
    ],
    theme: defaultTheme,
    locale: LocaleType.ZH_CN,
    locales: {
      [LocaleType.ZH_CN]: Tools.deepMerge(
        SheetsZhCN,
        DocsUIZhCN,
        SheetsUIZhCN,
        SheetsFormulaZhCN,
        UIZhCN,
        DesignZhCN,
        CollaborationClientZhCN
      ),
    },
  });

  univer.registerPlugin(UniverRenderEnginePlugin);
  univer.registerPlugin(UniverFormulaEnginePlugin);

  univer.registerPlugin(UniverUIPlugin, {
    container: excelContent.value!,
  });

  univer.registerPlugin(UniverDocsPlugin);
  univer.registerPlugin(UniverDocsUIPlugin);

  univer.registerPlugin(UniverSheetsPlugin);
  univer.registerPlugin(UniverSheetsUIPlugin);
  univer.registerPlugin(UniverSheetsFormulaPlugin);

  univer.registerPlugin(UniverCollaborationPlugin);
  univer.registerPlugin(UniverCollaborationClientPlugin, {
    authzUrl: 'http://192.168.56.10:8000/universer-api/authz',
    snapshotServerUrl: 'http://192.168.56.10:8000/universer-api/snapshot',
    collabSubmitChangesetUrl: 'http://192.168.56.10:8000/universer-api/comb',
    collabWebSocketUrl: 'ws://192.168.56.10:8000/universer-api/comb/connect',
  });

  univer.createUnit(UniverInstanceType.UNIVER_SHEET, {});
  const univerAPI = FUniver.newAPI(univer)
  if(univerAPI){
    console.log("univerAPI")
  }
}

</script>
<style scoped>
.excel-container {
  width: 100%;
  height: 100%;
  min-height: 90vh;
}
</style>

在这里插入图片描述

一直离线状态,没搞清楚原因

把官方的例子跑起来了,说明后端是没有问题的
在这里插入图片描述

代码如下

<!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
      Univer UMD With Collaboration, Live Share, Print, Exchange
    </title>
    <script src="https://unpkg.com/@univerjs/umd/lib/univer.full.umd.js"></script>
    <script src="https://unpkg.com/@univerjs/umd/lib/locale/zh-CN.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs/umd/lib/univer.css">
  
    <script src="https://unpkg.com/@univerjs-pro/license/lib/umd/index.js"></script>
    
    <script src="https://unpkg.com/@univerjs-pro/collaboration/lib/umd/index.js"></script>
    <script src="https://unpkg.com/@univerjs-pro/collaboration-client/lib/umd/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/collaboration-client/lib/index.css">
  
    <script src="https://unpkg.com/@univerjs-pro/live-share/lib/umd/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/live-share/lib/index.css">
  
    <script src="https://unpkg.com/@univerjs-pro/print/lib/umd/index.js"></script>
    <script src="https://unpkg.com/@univerjs-pro/sheets-print/lib/umd/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/sheets-print/lib/index.css">
  
    <script src="https://unpkg.com/@univerjs-pro/exchange-client/lib/umd/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/exchange-client/lib/index.css">
  
    <script src="https://unpkg.com/@univerjs-pro/sheets-exchange-client/lib/umd/index.js"></script>
 
    <script src="https://unpkg.com/@univerjs-pro/engine-pivot/lib/umd/index.js"></script>
    <script src="https://unpkg.com/@univerjs-pro/sheets-pivot/lib/umd/index.js"></script>
    <script src="https://unpkg.com/@univerjs-pro/sheets-pivot-ui/lib/umd/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/sheets-pivot-ui/lib/index.css">
 
    <script src="https://unpkg.com/@univerjs-pro/edit-history-viewer/lib/umd/index.js"></script>
    <script src="https://unpkg.com/@univerjs-pro/edit-history-loader/lib/umd/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/edit-history-viewer/lib/index.css">
    <style>
      body {
        margin: 0;
        padding: 0;
        font-family: Arial, sans-serif;
      }
  
      #app {
        height: 100vh;
        width: 100vw;
      }
    </style>
  </head>
  
  <body>
    <div id="app"></div>
    <script>
      var {
        UniverCore,
        UniverDesign,
        UniverEngineRender,
        UniverEngineFormula,
        UniverDocs,
        UniverDocsUi,
        UniverUi,
        UniverSheets,
        UniverSheetsUi,
        UniverSheetsNumfmt,
        UniverCollaboration,
        UniverCollaborationClient,
        UniverSheetsThreadComment,
        UniverExchangeClient,
        UniverFacade
      } = window;
      var { UniverSheetsFormulaPlugin } = UniverSheetsFormula;
      var { UniverSheetsExchangeClientPlugin } = UniverSheetsExchangeClient;
      var { UniverSheetsNumfmtPlugin } = UniverSheetsNumfmt;
      var { UniverDocsPlugin } = UniverDocs;
      var { UniverRenderEnginePlugin } = UniverEngineRender;
      var { UniverFormulaEnginePlugin } = UniverEngineFormula;
      var { UniverUIPlugin } = UniverUi;
      var { UniverDocsUIPlugin } = UniverDocsUi;
      var { UniverSheetsPlugin } = UniverSheets;
      var { UniverSheetsUIPlugin } = UniverSheetsUi;
      var { UniverSheetsPivotTablePlugin } = UniverSheetsPivot;
      var { UniverSheetsPivotTableUIPlugin } = UniverSheetsPivotUi;
      var { UniverEditHistoryLoaderPlugin } = UniverEditHistoryLoader;
      var { UniverCollaborationPlugin } = UniverCollaboration;
      var { UniverCollaborationClientPlugin } = UniverCollaborationClient;
      var { UniverLiveSharePlugin } = UniverLiveShare;
      var { UniverSheetsPrintPlugin } = UniverSheetsPrint;
      var { UniverSheetsThreadCommentPlugin, IThreadCommentMentionDataService } = UniverSheetsThreadComment;
      var { defaultTheme, greenTheme } = UniverDesign;
      var { FUniver } = UniverFacade;
      var { UniverExchangeClientPlugin }= UniverExchangeClient;
      var {UniverLicensePlugin} = UniverLicense;
      var {
        UniverInstanceType,
        Tools,
        IUndoRedoService,
        IAuthzIoService,
        LocaleType,
        Univer,
        IConfigService
      } = window.UniverCore;
    </script>
    <script>
      // 你好,开发者,这是一个简单的示例,展示如何使用 Univer UMD 实现协作、实时共享、打印和导入导出功能
      // 如果你想使用协作、实时共享、打印和交换功能,你需要配置 `universerEndpoint`
      // `universerEndpoint` 是提供协作、实时共享、打印和交换服务的 Univer 后端服务器地址
      // 你可以在自己的服务器上部署 Univer 服务器,详见部署指南:https://univer.ai/zh-CN/guides/sheet/server/docker
  
      const universerEndpoint = '192.168.56.10:8000';
  
      // 协同插件从 URL 中获取 unit 参数,如果没有 unit 参数,则创建一个新的 unit
      const url = new URL(window.location.href)
      const unit = url.searchParams.get('unit')
      if (unit) {
  
        // 加载协作、打印、交换的国际化资源
        Promise.all([
          fetch('https://unpkg.com/@univerjs-pro/collaboration-client/lib/locale/zh-CN.json').then(res => res.json()),
          fetch('https://unpkg.com/@univerjs-pro/sheets-print/lib/locale/zh-CN.json').then(res => res.json()),
          fetch('https://unpkg.com/@univerjs-pro/exchange-client/lib/locale/zh-CN.json').then(res => res.json()),
          fetch('https://unpkg.com/@univerjs-pro/edit-history-viewer/lib/locale/zh-CN.json').then(res => res.json()),
          fetch('https://unpkg.com/@univerjs-pro/sheets-pivot/lib/locale/zh-CN.json').then(res => res.json()),
          fetch('https://unpkg.com/@univerjs-pro/sheets-pivot-ui/lib/locale/zh-CN.json').then(res => res.json()),
      ]).then((langs) => {
          setup(Tools.deepMerge(UniverUMD['zh-CN'],...langs));
        })
      } else {
        const { UniverInstanceType } = window.UniverCore;
        fetch(`http://${universerEndpoint}/universer-api/snapshot/${UniverInstanceType.UNIVER_SHEET}/unit/-/create`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            type: UniverInstanceType.UNIVER_SHEET,
            name: 'New Sheet By Univer',
            creator: 'user',
          }),
        }).then((response) => {
          if (!response.ok) {
            throw new Error('Failed to create new sheet')
          }
  
          return response.json()
        }).then((data) => {
          if (!data.unitID) {
            throw new Error('create unit failed')
          }
  
          url.searchParams.set('unit', data.unitID)
          url.searchParams.set('type', String(UniverInstanceType.UNIVER_SHEET))
          window.location.href = url.toString()
        }).catch((error) => {
          console.error(error)
        })
      }
  
      const setup = (locales) => {
        var univer = new Univer({
          theme: defaultTheme,
          locale: LocaleType.ZH_CN,
          locales:{
              [LocaleType.ZH_CN]: locales,
          },
          override: [
            [IAuthzIoService, null],
            [IUndoRedoService, null]
          ]
        });
        univer.registerPlugin(UniverRenderEnginePlugin);
        univer.registerPlugin(UniverDocsPlugin);
        univer.registerPlugin(UniverFormulaEnginePlugin);
        univer.registerPlugin(UniverSheetsFormulaPlugin);
  
        univer.registerPlugin(UniverUIPlugin, {
          container: "app",
        });
  
        univer.registerPlugin(UniverDocsUIPlugin);
  
        univer.registerPlugin(UniverSheetsPlugin);
        univer.registerPlugin(UniverSheetsUIPlugin);
  
        const mockUser = {
          userID: 'mockId',
          name: 'MockUser',
          avatar: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAInSURBVHgBtZU9TxtBEIbfWRzFSIdkikhBSqRQkJqkCKTCFkqVInSUSaT0wC8w/gXxD4gU2nRJkXQWhAZowDUUWKIwEgWWbEEB3mVmx3dn4DA2nB/ppNuPeWd29mMIPXDr+RxwtgRHeW6+guNPRxogqnL7Dwz9psJ27S4NShaeZTH3kwXy6I81dlRKcmRui88swdq9AcSFL7Buz1Vmlns64MiLsCjzwnIYHLH57tbfFbs7KRaXyEU8FVZofqccOfA5l7Q8LPIkGrwnb2RPNEXWFVMUF3L+kDCk0btDDAMzOm5YfAHDwp4tG74wnzAsiOYMnJ3GoDybA7IT98/jm5+JNnfiIzAS6LlqHQBN/i6b2t/cV1Hh6BfwYlHnHP4AXi5q/8kmMMpOs8+BixZw/Fd6xUEHEbnkgclvQP2fGp7uShRKnQ3G32rkjV1th8JhIGG7tR/JyjGteSOZELwGMmNqIIigRCLRh2OZIE6BjItdd7pCW6Uhm1zzkUtungSxwEUzNpQ+GQumtH1ej1MqgmNT6vwmhCq5yuwq56EYTbgeQUz3yvrpV1b4ok3nYJ+eYhgYmjRUqErx2EDq0Fr8FhG++iqVGqxlUJI/70Ar0UgJaWHj6hYVHJrfKssAHot1JfqwE9WVWzXZVd5z2Ws/4PnmtEjkXeKJDvxUecLbWOXH/DP6QQ4J72NS0adedp1aseBfXP8odlZFfPvBF7SN/8hky1TYuPOAXAEipMx15u5ToAAAAABJRU5ErkJggg==',
          anonymous: false,
          canBindAnonymous: false,
        };
        class CustomMentionDataService {
          trigger = '@';
  
          async getMentions (search) {
            return [
              {
                id: mockUser.userID,
                label: mockUser.name,
                type: 'user',
                icon: mockUser.avatar,
              },
              {
                id: '2',
                label: 'User2',
                type: 'user',
                icon: mockUser.avatar,
              },
            ];
          }
        }
  
        univer.registerPlugin(UniverSheetsThreadCommentPlugin, {
          overrides: [[IThreadCommentMentionDataService, { useClass: CustomMentionDataService }]],
        });
  
        // 注册协同插件
        univer.registerPlugin(UniverCollaborationPlugin);
        univer.registerPlugin(UniverCollaborationClientPlugin, {
          authzUrl: `http://${universerEndpoint}/universer-api/authz`,
          snapshotServerUrl: `http://${universerEndpoint}/universer-api/snapshot`,
          collabSubmitChangesetUrl: `http://${universerEndpoint}/universer-api/comb`,
          collabWebSocketUrl: `ws://${universerEndpoint}/universer-api/comb/connect`,
          // 如果你使用了导入导出插件,需要配置以下参数
          uploadFileServerUrl: `http://${universerEndpoint}/universer-api/stream/file/upload`,
          signUrlServerUrl: `http://${universerEndpoint}/universer-api/file/{fileID}/sign-url`,
        });
  
        // 注册实时共享插件
        univer.registerPlugin(UniverLiveSharePlugin)
  
        // 注册打印插件
        univer.registerPlugin(UniverSheetsPrintPlugin)
  
        // 注册导入导出插件
        univer.registerPlugin(UniverExchangeClientPlugin, {
          uploadFileServerUrl: `http://${universerEndpoint}/universer-api/stream/file/upload`,
          importServerUrl: `http://${universerEndpoint}/universer-api/exchange/{type}/import`,
          exportServerUrl: `http://${universerEndpoint}/universer-api/exchange/{type}/export`,
          getTaskServerUrl: `http://${universerEndpoint}/universer-api/exchange/task/{taskID}`,
          signUrlServerUrl: `http://${universerEndpoint}/universer-api/file/{fileID}/sign-url`,
        })
        univer.registerPlugin(UniverSheetsExchangeClientPlugin)
      }
    </script>
  </body>
  </html>

使用websocket协同

pnpm init
pnpm add ws --registry=http://registry.npm.taobao.org

修改package.json

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ws": "^8.18.0"
  }
}

新建index.js

//创建一个WebSocket服务器,在8080端口启动
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8089 });
console.log("websocket服务器启动于:localhost:8089");

// 监听前端连接websocket(ws.on的connection事件)
server.on('connection', function connection(ws, req) {
  const ip = req.socket.remoteAddress;
  const port = req.socket.remotePort;
  const clientName = ip + port;
 
  console.log('%s 连接了', clientName);

  ws.on('message', (msg = {}) => {
    console.log('客户端发送给服务器端', msg.toString('utf8'));
    // 由服务端往客户端发送数据
    server.clients.forEach((client) => {
      //console.log(client, 'client');
      client.send(msg);
    });
  });
});
//只要有WebSocket连接到该服务器,就会触发'connection'事件;req对象可以用来获取客户端的信息,如ip、端口号
//获取所有已连接的客户端信息,则可以使用server.clients数据集
 
// 服务器接收数据(ws.on的message事件)
// module.exports.listener = () => {
//   server.on('connection', (ws, req) => {
//     console.log('有客户端连接成功了', ws, req);
 
//     // 对客户端的连接对象进行message事件的监听
//     // 当客户端有消息发送给服务器时,服务器就能够触发该消息
//     // msg:由客户端发给服务端的数据
//     ws.on('message', (msg = {}) => {
//       console.log('客户端发送给服务器端', msg);
//       // 当接收到客户端传的参数之后服务器端可以执行某些操作(具体看需求)
//       // 小编这里是做了一个数据返回给客户端
//       // 是当客户端连接成功之后会发送一条信息告诉服务器,服务器监听到信息之后再返回数据给客户端
 
//       // 由服务端往客户端发送数据
//       server.clients.forEach((client) => {
//         console.log(client, 'client');
//         // client.send(JSON.stringify(info));
//         client.send(msg);
//       });
//     });
//   });
// };

把websocket启动起来

pnpm run dev

前端参考vue3搭建起来,然后修改App.vue

<template>
  <div id="excelContent" style="width: 100%;height: 900px;"></div>
</template>

<script setup lang="ts">
import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";

import { onMounted, ref } from 'vue'
import { LocaleType, Tools, Univer, UniverInstanceType } from "@univerjs/core";
import { defaultTheme } from "@univerjs/design";

import { UniverFormulaEnginePlugin } from "@univerjs/engine-formula";
import { UniverRenderEnginePlugin } from "@univerjs/engine-render";

import { UniverUIPlugin } from "@univerjs/ui";

import { UniverDocsPlugin } from "@univerjs/docs";
import { UniverDocsUIPlugin } from "@univerjs/docs-ui";

import { UniverSheetsPlugin } from "@univerjs/sheets";
import { UniverSheetsFormulaPlugin } from "@univerjs/sheets-formula";
import { UniverSheetsUIPlugin } from "@univerjs/sheets-ui";

import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import { FUniver } from '@univerjs/facade'

onMounted(() => {
  initSheet()
})

const initSheet = () => {
  const univer = new Univer({
    theme: defaultTheme,
    locale: LocaleType.ZH_CN,
    locales: {
      [LocaleType.ZH_CN]: Tools.deepMerge(
        SheetsZhCN,
        DocsUIZhCN,
        SheetsUIZhCN,
        SheetsFormulaZhCN,
        UIZhCN,
        DesignZhCN,
      ),
    },
  });

  univer.registerPlugin(UniverRenderEnginePlugin);
  univer.registerPlugin(UniverFormulaEnginePlugin);

  univer.registerPlugin(UniverUIPlugin, {
    container: 'excelContent',
  });

  univer.registerPlugin(UniverDocsPlugin);
  univer.registerPlugin(UniverDocsUIPlugin);

  univer.registerPlugin(UniverSheetsPlugin);
  univer.registerPlugin(UniverSheetsUIPlugin);
  univer.registerPlugin(UniverSheetsFormulaPlugin);

  //必须指定id
  univer.createUnit(UniverInstanceType.UNIVER_SHEET, {
    id: 'univer-1',
    sheets: {
      'sheet-01': {
        id: 'sheet-01',
        name: 'sheet1',
        cellData: {},
      },
    },
  });
  const univerAPI = FUniver.newAPI(univer)


  const ws = univerAPI.createSocket('ws://localhost:8089');

  ws.open$.subscribe(() => {
    console.log('websocket opened');
    // ws.send('hello')
  });

  ws.message$.subscribe((message) => {
    const data = message.data;
    let result = '';
    if (data instanceof Blob) {
      // Create a FileReader to read the Blob data  
      const reader = new FileReader();

      // Define the onload event handler  
      reader.onload = (e) => {
        // The result property contains the data as a typed array or string  
        // Here we assume the data is a UTF-8 encoded string  
        const resultData = e.target?.result
        if (typeof resultData == 'string') {
          result = resultData;
          console.log(result);
          console.log('websocket message', result);
          const content = JSON.parse(result);//JSON.parse(message.data);
          console.log('content', content);

          const { command, options } = content;

          const { id, params } = command;

          console.log(params, 'params--------');

          // 接受到协同数据,本地落盘
          univerAPI.executeCommand(id, params, options);
        }
      };

      // Read the Blob data as a text string  
      reader.readAsText(data, 'utf-8');
    } else if (typeof data === 'string') {
      result = data;
      //console.log('websocket message', JSON.parse(message.data));
      console.log('websocket message', result);
      const content = JSON.parse(result);//JSON.parse(message.data);
      console.log('content', content);

      const { command, options } = content;

      const { id, params } = command;

      console.log(params, 'params--------');

      // 接受到协同数据,本地落盘
      univerAPI.executeCommand(id, params, options);
    }

  });

  ws.close$.subscribe(() => {
    console.log('websocket closed');
  });

  ws.error$.subscribe((error) => {
    console.log('websocket error', error);
  });

  univerAPI.onCommandExecuted((command, options) => {
    // 仅同步本地 mutation
    if (
      command.type !== 2 ||
      options?.fromCollab ||
      options?.onlyLocal ||
      command.id === 'doc.mutation.rich-text-editing'
    ) {
      return;
    }

    const commandInfo = JSON.stringify({
      command,
      options: { fromCollab: true },
    });
    console.log(commandInfo, 'commandInfo');
    ws.send(commandInfo);
  });
}
</script>

<style scoped></style>

在这里插入图片描述

导入导出禁止编辑

在这里插入图片描述
IWorksheetData
IWorkBookData
ICellData
导入导出
导入导出
导入的例子
导入导出

创建vue+univer项目

pnpm create vite --registry=http://registry.npm.taobao.org
pnpm add @univerjs/core @univerjs/design @univerjs/docs @univerjs/docs-ui @univerjs/engine-formula @univerjs/engine-render @univerjs/sheets @univerjs/sheets-formula @univerjs/sheets-ui @univerjs/ui --registry=http://registry.npm.taobao.org
pnpm add @univerjs/facade --registry=http://registry.npm.taobao.org
pnpm add @univerjs-pro/facade --registry=http://registry.npm.taobao.org

App.vue

<template>
  <div>
    <button @click="importExcel">加载数据</button>
    <button @click="updateData">更新数据</button>
    <button @click="closeOrOpenEditor">禁止或者开启编辑</button>
    <button @click="saveData">保存数据</button>
  </div>
  <div ref="excelContent" style="width: 100%;height: 900px;"></div>
</template>

<script setup lang="ts">


import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";

import {onMounted, ref} from 'vue'
import {LocaleType, Tools, Univer, UniverInstanceType, IWorkbookData, BooleanNumber} from "@univerjs/core";
import {defaultTheme} from "@univerjs/design";

import {UniverFormulaEnginePlugin} from "@univerjs/engine-formula";
import {UniverRenderEnginePlugin} from "@univerjs/engine-render";

import {UniverUIPlugin} from "@univerjs/ui";

import {UniverDocsPlugin} from "@univerjs/docs";
import {UniverDocsUIPlugin} from "@univerjs/docs-ui";

import {UniverSheetsPlugin} from "@univerjs/sheets";
import {UniverSheetsFormulaPlugin} from "@univerjs/sheets-formula";
import {UniverSheetsUIPlugin} from "@univerjs/sheets-ui";

import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import {FUniver} from "@univerjs-pro/facade";

const excelContent = ref<HTMLElement | null>(null)

onMounted(() => {
  initSheet()
})

let canEditor = true;
let univerAPI: FUniver | null = null;
let univer: Univer | null = null;
const initSheet = () => {
  univer = new Univer({
    theme: defaultTheme,
    locale: LocaleType.ZH_CN,
    locales: {
      [LocaleType.ZH_CN]: Tools.deepMerge(
          SheetsZhCN,
          DocsUIZhCN,
          SheetsUIZhCN,
          SheetsFormulaZhCN,
          UIZhCN,
          DesignZhCN,
      ),
    },
  });

  univer.registerPlugin(UniverRenderEnginePlugin);
  univer.registerPlugin(UniverFormulaEnginePlugin);

  univer.registerPlugin(UniverUIPlugin, {
    container: excelContent.value!,
  });

  univer.registerPlugin(UniverDocsPlugin);
  univer.registerPlugin(UniverDocsUIPlugin);

  univer.registerPlugin(UniverSheetsPlugin);
  univer.registerPlugin(UniverSheetsUIPlugin);
  univer.registerPlugin(UniverSheetsFormulaPlugin);
}
const importExcel = () => {
  const workbook: IWorkbookData = {
    id: '007',//唯一id
    name: '部门人数统计',
    appVersion: '1.0.0',
    locale: LocaleType.ZH_CN,
    styles: {},
    sheetOrder: ['sheet1', 'sheet2'],
    sheets: {
      sheet1: {
        id: 'sheet1',
        name: '工作表 1',
        tabColor: '#FF0000',
        hidden: BooleanNumber.FALSE,
        freeze: {xSplit: 1, ySplit: 1, startRow: 1, startColumn: 1},
        rowCount: 1000,
        columnCount: 26,
        defaultColumnWidth: 100,
        defaultRowHeight: 25,
        mergeData: [],
        cellData: {
          // 第一行
          0: {
            //t表示类型 布尔、字符串和数字 https://univer.ai/typedoc/@univerjs/core/enumerations/CellValueType
            // 第一列
            0: {v: 'A1'},
            // 第二列
            1: {v: 'B1'},
          },
          // 第二行
          1: {
            // 第一列
            0: {v: 'A2'},
            // 第二列
            1: {v: 'B2'},
          },
        },
        rowData: [],
        columnData: [],
        rowHeader: {width: 40},
        columnHeader: {height: 20},
        showGridlines: BooleanNumber.TRUE,
        rightToLeft: BooleanNumber.FALSE
      },
      sheet2: {}
    }
  };
  if (univer != null) {
    console.log('univer!=null')
    if (univerAPI == null) {
      //模拟服务端获取数据
      univer.createUnit(UniverInstanceType.UNIVER_SHEET, workbook);
      univerAPI = FUniver.newAPI(univer);
    }
  } else {
    console.log('univer==null')
  }
}

const updateData = () => {
  if (univerAPI != null) {
    const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet();
    // A1 设置数字 100
    const range = sheet?.getRange(0, 0, 1, 1);
    range?.setValue(100);
  }
}

const closeOrOpenEditor = () => {
  canEditor = !canEditor;
  if (univerAPI != null) {
    const workBook = univerAPI.getActiveWorkbook();
    workBook?.setEditable(canEditor);
  }
}

const saveData = () => {
  if (univerAPI != null) {
    const savedExcel = univerAPI.getActiveWorkbook()?.save();
    if (savedExcel != null) {
      console.log(savedExcel)
    }
  }else{
    console.log('数据为空')
  }
}
</script>

<style scoped>
</style>

在这里插入图片描述
配置单元格边框颜色

cellData: {
  // 第一行
  0: {
    //t表示类型 布尔、字符串和数字 https://univer.ai/typedoc/@univerjs/core/enumerations/CellValueType
    // 第一列
    0: {
      v: 'A1',
    },
    // 第二列
    1: {v: 'B1'},
  },
  // 第二行
  1: {
    // 第一列
    0: {v: 'A2'},
    // 第二列
    1: {
      v: 'B2',
      //边框
      s: {
        bd: {
          // 上边框
          t: {
            s: 7, // 边框样式
            cl: {  // 边框颜色
              rgb: '#ff0000'
            }
          },
          // 下边框
          b: {
            s: 7, // 边框样式
            cl: {  // 边框颜色
              rgb: '#ff0000'
            }
          },
          // 左边框
          l: {
            s: 7, // 边框样式
            cl: {  // 边框颜色
              rgb: '#ff0000'
            }
          },
          // 右边框
          r: {
            s: 7, // 边框样式
            cl: {  // 边框颜色
              rgb: '#ff0000'
            }
          },
        }
      }
    },
  },
},

在这里插入图片描述

高亮显示

pnpm add @univerjs/sheets-crosshair-highlight --registry=http://registry.npm.taobao.org

参考

https://univer.ai/zh-CN/guides/sheet/introduction
https://blog.csdn.net/m0_73884922/article/details/139971295
https://github.com/dream-num/usip-example/tree/main
https://github.com/dream-num/univer-pro-sheet-start-kit
https://github.com/dream-num/univer-sheet-start-kit

<think>好的,用户现在问的是如何在UniverJS中监听复制粘贴操作并将数据写入表格。首先,我需要回顾之前提供的教程,特别是关于事件监听的部分。之前提到过监听单元格修改事件,用的是`onCellContentChanged`方法。但复制粘贴可能涉及更复杂的操作,比如处理剪贴板数据或者监听特定的事件。 用户可能是在使用UniverJS开发电子表格功能,需要处理用户的复制粘贴行为,可能是为了数据验证、格式处理或者自定义的粘贴逻辑。这时候,我需要确认UniverJS是否提供了直接监听复制粘贴事件的API,或者是否有其他方法可以间接实现。 查阅UniverJS的官方文档,可能需要查找关于剪贴板事件的部分。假设官方提供了`onCopy`和`onPaste`这样的事件监听器,用户就可以在这些事件的回调中处理数据。如果没有直接的事件,可能需要通过监听键盘事件(如Ctrl+C/Ctrl+V)来模拟,但这种方法可能存在兼容性问题。 接下来,我需要考虑如何将剪贴板中的数据解析并写入表格。例如,当用户粘贴时,获取剪贴板的内容,可能是文本或HTML格式,然后解析成单元格数据,再通过UniverJS的API写入指定区域。这里要注意的是,处理多行多列的数据,可能需要拆分文本中的换行符和制表符,以确定每个单元格的值。 此外,用户可能希望覆盖默认的粘贴行为,执行自定义操作,比如数据清洗或格式转换。这时候,可能需要阻止默认的粘贴事件,然后手动插入处理后的数据。例如,在粘贴时,将剪贴板中的逗号分隔值转换为表格的行列结构。 还需要考虑权限问题,比如浏览器中访问剪贴板内容可能需要用户授权,特别是在HTTPS环境下。可能需要使用`navigator.clipboard.readText()`来异步获取剪贴板内容,并在回调中处理数据。 在代码示例中,可能需要展示如何注册复制和粘贴事件,如何读取剪贴板内容,以及如何将处理后的数据通过UniverJS的API写入工作表。同时,要提醒用户注意异步操作的处理,比如使用`async/await`或Promise。 另外,用户可能需要处理粘贴时的选区范围,确定从哪个单元格开始粘贴,以及如何处理超出范围的数据。例如,如果用户复制了3行数据,但当前选区只有2行,是否需要截断或扩展选区,这些逻辑都需要在代码中处理。 最后,测试和调试也是很重要的部分。可能需要指导用户如何使用UniverJS的调试工具,比如`univer.debug()`,或者浏览器的开发者工具来检查事件触发和数据流是否正确。同时,处理剪贴板时的错误处理,比如用户拒绝权限时的回退方案,也需要考虑在内。</think>以下是关于在 UniverJS 中实现复制粘贴监听与数据写入的完整指南: --- ### **一、核心实现原理** 1. **事件机制**:通过监听 `onCopy` 和 `onPaste` 事件捕获操作 2. **剪贴板交互**:使用 `navigator.clipboard` API 读写系统剪贴板 3. **选区处理**:通过 `getSelection` 获取当前操作范围 --- ### **二、基础事件监听实现** ```typescript // 监听复制事件 workbook.getActiveSheet().onCopy((event) => { const selection = workbook.getActiveSheet().getSelection(); console.log('复制范围:', selection.getRange()); return true; // 返回true允许默认复制行为 }); // 监听粘贴事件 workbook.getActiveSheet().onPaste(async (event) => { const clipboardData = await navigator.clipboard.readText(); this.handlePasteData(clipboardData); return false; // 阻止默认粘贴行为 }); ``` --- ### **三、完整粘贴处理函数** ```typescript private async handlePasteData(data: string) { // 获取当前选区 const selection = workbook.getActiveSheet().getSelection(); const startCell = selection.getPrimary().start; // 解析剪贴板数据(支持TSV/CSV格式) const rows = data.split('\n').map(row => row.split('\t')); // 写入单元格 rows.forEach((row, rowIndex) => { row.forEach((cellValue, colIndex) => { const targetRow = startCell.row + rowIndex; const targetCol = startCell.col + colIndex; workbook.getActiveSheet() .getRange(targetRow, targetCol) .setValue(this.sanitizeValue(cellValue)); }); }); // 触发重计算 await workbook.getCommandManager().executeCommand('formula.calculate'); } // 数据清洗方法 private sanitizeValue(raw: string): string | number { const numericValue = parseFloat(raw.replace(/[^0-9.]/g, '')); return isNaN(numericValue) ? raw : numericValue; } ``` --- ### **四、高级功能扩展** #### 1. 格式保留粘贴 ```typescript // 获取带样式的复制数据 workbook.getActiveSheet().onCopy((event) => { const range = event.range; const dataWithStyle = range.getValues().map(row => row.map(cell => ({ value: cell.v, style: cell.s // 包含样式对象 })) ); event.clipboardData.setData('application/json', JSON.stringify(dataWithStyle)); return false; // 禁用默认复制 }); // 粘贴带样式数据 async function handleStyledPaste(jsonData: string) { const styledData = JSON.parse(jsonData); styledData.forEach((row: any[], rowIdx: number) => { row.forEach((cell, colIdx) => { const target = workbook.getActiveSheet().getRange(startRow + rowIdx, startCol + colIdx); target.setValue(cell.value); target.setStyle(cell.style); // 应用样式 }); }); } ``` #### 2. 跨工作表粘贴 ```typescript // 存储临时数据 let clipboardCache: any; workbook.onCopy((event) => { clipboardCache = event.range.getValues(); }); workbook.onPaste((event) => { if (clipboardCache) { const targetSheet = workbook.getSheet(event.sheetId); targetSheet.getRange(event.range).setValues(clipboardCache); } }); ``` --- ### **五、注意事项** 1. **浏览器权限**:需处理 HTTPS 环境和用户授权 ```typescript // 检查剪贴板权限 const permission = await navigator.permissions.query({name: 'clipboard-read'}); if (permission.state !== 'granted') { alert('请允许剪贴板访问权限'); } ``` 2. **性能优化**:批量写入时使用事务 ```typescript workbook.suspendCalc(); // 执行批量粘贴操作... workbook.resumeCalc(); ``` 3. **数据验证**:添加类型检查 ```typescript if (!Array.isArray(rows)) { throw new Error('无效的粘贴数据格式'); } ``` --- ### **六、调试技巧** 1. 启用调试模式: ```typescript univer.debug({ logClipboard: true, // 显示剪贴板操作日志 logSelection: true // 显示选区变化 }); ``` 2. 控制台快速测试: ```javascript // 模拟粘贴操作 univer.getActiveWorkbook().trigger('paste', { text: '测试\t数据\n第二行\t456' }); ``` --- 以上方案已处理以下关键问题: - 多格式数据解析(TSV/CSV/JSON) - 大数据量粘贴的性能优化 - 跨工作表/工作簿的粘贴兼容 - 样式保留与数据清洗 实际开发时建议参考官方文档的 [Clipboard Module](https://univer.ai/zh/docs/api/clipboard) 获取最新API细节。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

假装我不帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值