npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@koi-br/office-sdk-wrapper

v1.0.4

Published

一个统一的办公服务SDK封装库,同时支持 **WPS Office** 和 **OnlyOffice**。

Downloads

18

Readme

office-sdk-wrapper

一个统一的办公服务SDK封装库,同时支持 WPS OfficeOnlyOffice

📦 Installation / 安装

npm install @koi-br/office-sdk-wrapper

Vue项目额外依赖

如果你的项目使用Vue,还需要安装OnlyOffice的Vue组件:

npm install @onlyoffice/document-editor-vue

🚀 Quick Start / 快速开始

Using WPS Office / 使用WPS Office

import { createWPSSDK, DocumentType } from '@koi-br/office-sdk-wrapper';

const sdk = await createWPSSDK({
  fileId: "your-file-id",
  appId: "your-app-id",
  containerSelector: ".office-container",
  token: "your-access-token",
  isReadOnly: false,
  documentType: DocumentType.WORD,
  onReady: (sdk) => {
    console.log('WPS SDK ready!', sdk);
  }
});

// Use unified API methods
await sdk.searchAndLocateText('Hello World', true);
await sdk.insertTextAtCursor('New text content');
await sdk.saveDocument();

Using OnlyOffice / 使用OnlyOffice

import { createOnlyOfficeSDK, DocumentType } from '@koi-br/office-sdk-wrapper';

const sdk = await createOnlyOfficeSDK({
  fileId: "your-file-id",
  appId: "your-app-id",
  containerSelector: ".office-container",
  isReadOnly: false,
  documentType: DocumentType.WORD,
  documentConfig: {
    title: 'My Document',
    url: 'https://your-server.com/documents/your-file-id'
  },
  editorConfig: {
    lang: 'zh-CN',
    mode: 'edit'
  },
  onReady: (sdk) => {
    console.log('OnlyOffice SDK ready!', sdk);
  }
});

// Same API as WPS!
await sdk.searchAndLocateText('Hello World', true);
await sdk.insertTextAtCursor('New text content');
await sdk.saveDocument();

Universal Approach / 通用方法

import { initOfficeSDK, OfficeProvider, DocumentType } from '@koi-br/office-sdk-wrapper';

// Let users choose their preferred office suite
const provider = OfficeProvider.WPS; // or OfficeProvider.ONLYOFFICE

const sdk = await initOfficeSDK({
  fileId: "your-file-id",
  appId: "your-app-id",
  containerSelector: ".office-container",
  provider: provider,
  isReadOnly: false,
  documentType: DocumentType.WORD,
  token: "your-access-token",
  onReady: (sdk) => {
    console.log(`${sdk.provider.toUpperCase()} SDK ready!`, sdk);
  }
});

🤖 Smart Configuration / 智能配置

使用智能配置管理器,让系统根据你的需求自动推荐最佳提供商:

import { createSmartConfig, initOfficeSDK } from '@koi-br/office-sdk-wrapper';

// 智能配置推荐
const { config, recommendation } = createSmartConfig(
  {
    fileId: "your-file-id",
    appId: "your-app-id",
    containerSelector: ".office-container"
  },
  {
    needsAdvancedRevision: true,  // 需要高级修订功能
    needsCollaboration: false,    // 不需要多人协作
    isVueProject: false,         // 不是Vue项目
    hasWPSLicense: true          // 有WPS许可证
  }
);

console.log(`推荐使用: ${recommendation.provider}`);
console.log(`推荐理由: ${recommendation.reason}`);
console.log(`提示: ${recommendation.tips.join(', ')}`);

// 使用推荐的配置
const sdk = await initOfficeSDK(config);

⚙️ Environment-based Auto Selection / 基于环境的自动选择

import { getConfigManager } from '@koi-br/office-sdk-wrapper';

// 设置环境变量或全局变量
process.env.OFFICE_PROVIDER = 'wps'; // or 'onlyoffice'
// 或者在浏览器中设置: window.__OFFICE_PROVIDER__ = 'wps';

// 自动选择提供商
const manager = getConfigManager();
const config = manager.autoSelectProvider({
  fileId: "your-file-id",
  appId: "your-app-id",
  containerSelector: ".office-container"
}, {
  fallback: OfficeProvider.WPS,
  checkAvailability: true
});

const sdk = await initOfficeSDK(config);

🛠️ API Reference / API 参考

Unified Interface Methods / 统一接口方法

All SDK instances implement the same interface, regardless of the underlying office suite:

所有SDK实例都实现相同的接口,无论底层使用的是哪个办公套件:

interface IOfficeSDK {
  // Document Operations / 文档操作
  saveDocument(): Promise<void>;
  setDocumentReadOnly(isReadOnly: boolean): Promise<void>;
  getDocumentLength(): Promise<number>;
  
  // Text Operations / 文本操作
  searchAndLocateText(content: string, highlight?: boolean): Promise<SearchResult | null>;
  insertTextAtCursor(text: string): Promise<boolean>;
  clearHighlight(): Promise<void>;
  replaceText(original: string, replacement: string, pos: number, length: number): Promise<{success: boolean, modifyDate?: string}>;
  
  // Formatting / 格式化
  formatDocumentFont(fontFormat: FontFormat): Promise<void>;
  
  // Revision Management / 修订管理
  getLatestRevisionDate(): Promise<string>;
  getRevisionsByDate(date: string): Promise<RevisionInfo[]>;
  handleRevisions(date: string, action: 'accept' | 'reject' | 'highlight'): Promise<void>;
  
  // Lifecycle / 生命周期
  destroy(): Promise<void>;
  isReady(): boolean;
}

Configuration Interfaces / 配置接口

Base Configuration / 基础配置

interface BaseInitConfig {
  fileId: string;                    // 文件ID
  appId: string;                     // 应用ID
  containerSelector: string;         // 容器选择器
  isReadOnly?: boolean;              // 是否只读模式
  token?: string;                    // 访问令牌
  onReady?: (sdk: IOfficeSDK) => void;      // 初始化完成回调
  onError?: (error: any) => void;           // 错误回调
  provider: OfficeProvider;          // 办公软件提供商
  documentType?: DocumentType;       // 文档类型
}

WPS Specific Configuration / WPS特定配置

interface WPSInitConfig extends BaseInitConfig {
  provider: OfficeProvider.WPS;
  simple?: boolean;                  // 简单模式
  refreshToken?: (token: string, timeout?: number) => void;
}

OnlyOffice Specific Configuration / OnlyOffice特定配置

interface OnlyOfficeInitConfig extends BaseInitConfig {
  provider: OfficeProvider.ONLYOFFICE;
  editorConfig?: {
    mode?: 'edit' | 'view' | 'review';
    lang?: string;
    callbackUrl?: string;
  };
  documentConfig?: {
    fileType?: string;
    key?: string;
    title?: string;
    url?: string;
  };
}

🖼️ React Example / React示例

import React, { useEffect, useState } from 'react';
import { initOfficeSDK, OfficeProvider, DocumentType } from '@koi-br/office-sdk-wrapper';

function OfficeComponent() {
  const [sdk, setSdk] = useState(null);
  const [provider, setProvider] = useState(OfficeProvider.WPS);

  useEffect(() => {
    const initSDK = async () => {
      const sdkInstance = await initOfficeSDK({
        fileId: "your-file-id",
        appId: "your-app-id",
        containerSelector: ".office-container",
        provider: provider,
        documentType: DocumentType.WORD,
        onReady: setSdk,
        token: "your-token"
      });
    };

    initSDK();
    return () => sdk?.destroy();
  }, [provider]);

  const switchProvider = async (newProvider) => {
    if (sdk) {
      await sdk.destroy();
      setSdk(null);
    }
    setProvider(newProvider);
  };

  return (
    <div>
      <div className="controls">
        <button onClick={() => switchProvider(OfficeProvider.WPS)}>
          WPS Office
        </button>
        <button onClick={() => switchProvider(OfficeProvider.ONLYOFFICE)}>
          OnlyOffice
        </button>
        <button onClick={() => sdk?.insertTextAtCursor('Hello!')}>
          Insert Text
        </button>
        <button onClick={() => sdk?.saveDocument()}>
          Save
        </button>
      </div>
      <div className="office-container" style={{width: '100%', height: '600px'}} />
    </div>
  );
}

🖼️ Vue Example / Vue示例

重要说明:Vue组件的正确导入方式

由于 Vue 单文件组件的特殊性,请按照下表正确导入:

| 功能 | 导入来源 | 示例 | |------|------|------| | Vue组件 | 组件路径 | import OnlyOfficeVueEditor from '@koi-br/office-sdk-wrapper/src/components/OnlyOfficeVueEditor.vue' | | Vue适配器 | vue 模块 | import { createOnlyOfficeVueSDK } from '@koi-br/office-sdk-wrapper/vue' | | 类型定义 | vue 模块 | import type { OnlyOfficeVueAdapter } from '@koi-br/office-sdk-wrapper/vue' | | 通用功能 | 主模块 | import { OfficeProvider, DocumentType } from '@koi-br/office-sdk-wrapper' |

// ✅ 正确的导入方式

// 1. Vue组件从组件路径直接导入
import OnlyOfficeVueEditor from '@koi-br/office-sdk-wrapper/src/components/OnlyOfficeVueEditor.vue';

// 2. 适配器和类型从 vue 模块导入
import { 
  createOnlyOfficeVueSDK,
  type OnlyOfficeVueAdapter,
  DocumentType 
} from '@koi-br/office-sdk-wrapper/vue';

// 3. 通用功能从主模块导入
import { 
  OfficeProvider,
  createWPSSDK
} from '@koi-br/office-sdk-wrapper';
// ❌ 错误的导入方式(不要这样做)
import { 
  OnlyOfficeVueEditor  // 这个导入会失败!
} from '@koi-br/office-sdk-wrapper/vue';

方法一:使用封装的Vue组件(推荐)

<template>
  <div class="office-app">
    <div class="controls">
      <button @click="handleInsertText">插入文本</button>
      <button @click="handleSaveDocument">保存文档</button>
      <button @click="handleSearch">搜索文本</button>
    </div>
    
    <OnlyOfficeVueEditor
      :init-config="editorConfig"
      :editor-id="editorId"
      @ready="handleEditorReady"
      @error="handleEditorError"
      @document-ready="handleDocumentReady"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
// Vue组件从组件路径导入
import OnlyOfficeVueEditor from '@koi-br/office-sdk-wrapper/src/components/OnlyOfficeVueEditor.vue';
// 适配器和类型从vue模块导入
import { 
  createOnlyOfficeVueSDK,
  type OnlyOfficeVueAdapter,
  DocumentType 
} from '@koi-br/office-sdk-wrapper/vue';

const fileId = ref('your-file-id');
const appId = ref('your-app-id');
const editorId = ref(`onlyoffice-${Date.now()}`);
const sdkRef = ref<OnlyOfficeVueAdapter | null>(null);
const editorRef = ref<any>(null);

const editorConfig = computed(() => ({
  fileId: fileId.value,
  appId: appId.value,
  containerSelector: '.office-container',
  isReadOnly: false,
  documentType: DocumentType.WORD,
  documentConfig: {
    title: 'My Document',
    url: 'https://example.com/document.docx',
    key: fileId.value
  },
  editorConfig: {
    lang: 'zh-CN',
    mode: 'edit' as const
  },
  onReady: (sdk: OnlyOfficeVueAdapter) => {
    sdkRef.value = sdk;
    console.log('ONLYOFFICE SDK 准备就绪');
  },
  onError: (error: any) => {
    console.error('SDK 错误:', error);
  }
}));

// 创建适配器实例
onMounted(async () => {
  sdkRef.value = createOnlyOfficeVueSDK(editorConfig.value);
  await sdkRef.value.initialize();
});

const handleInsertText = async () => {
  if (sdkRef.value?.isReady()) {
    await sdkRef.value.insertTextAtCursor('Hello from Vue!');
  }
};

const handleSaveDocument = async () => {
  if (sdkRef.value?.isReady()) {
    await sdkRef.value.saveDocument();
  }
};

const handleSearch = async () => {
  if (sdkRef.value?.isReady()) {
    const result = await sdkRef.value.searchAndLocateText('搜索内容', true);
    console.log('搜索结果:', result);
  }
};

const handleEditorReady = (event: any) => {
  console.log('编辑器准备就绪:', event);
  // 设置Vue组件实例引用
  if (sdkRef.value) {
    sdkRef.value.setVueComponentInstance(editorRef.value);
  }
};

const handleEditorError = (error: any) => {
  console.error('编辑器错误:', error);
};

const handleDocumentReady = (event: any) => {
  console.log('文档准备就绪:', event);
};
</script>

<style scoped>
.office-app {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.controls {
  padding: 10px;
  background: #f5f5f5;
  display: flex;
  gap: 10px;
}

.controls button {
  padding: 8px 16px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.controls button:hover {
  background: #0056b3;
}
</style>

方法二:直接使用原生ONLYOFFICE Vue组件

<template>
  <div class="office-app">
    <DocumentEditor
      id="onlyoffice-editor"
      documentServerUrl="http://documentserver/"
      :config="onlyOfficeConfig"
      :events_onDocumentReady="onDocumentReady"
      :events_onAppReady="onAppReady"
      :events_onError="onError"
      :onLoadComponentError="onLoadComponentError"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';
import { DocumentEditor } from '@onlyoffice/document-editor-vue';

const fileId = ref('your-file-id');
const appId = ref('your-app-id');

const onlyOfficeConfig = computed(() => ({
  document: {
    fileType: "docx",
    key: fileId.value,
    title: "Example Document Title.docx",
    url: "https://example.com/url-to-example-document.docx"
  },
  documentType: "word",
  editorConfig: {
    mode: 'edit',
    lang: 'zh-CN',
    callbackUrl: "https://example.com/url-to-callback.ashx"
  }
}));

const onDocumentReady = (event: any) => {
  console.log("文档准备就绪:", event);
  
  // 获取编辑器实例
  const documentEditor = window.DocEditor.instances["onlyoffice-editor"];
  
  // 调用编辑器方法
  documentEditor.showMessage("欢迎使用 ONLYOFFICE 编辑器!");
};

const onAppReady = (event: any) => {
  console.log("应用程序准备就绪:", event);
};

const onError = (event: any) => {
  console.error("ONLYOFFICE 错误:", event);
};

const onLoadComponentError = (errorCode: number, errorDescription: string) => {
  switch(errorCode) {
    case -1: // 未知错误
      console.log(errorDescription);
      break;
    case -2: // 从文档服务器加载DocsAPI时出错
      console.log(errorDescription);
      break;
    case -3: // DocsAPI未定义
      console.log(errorDescription);
      break;
  }
};
</script>

Vue项目快速开始

  1. 安装依赖
npm install @koi-br/office-sdk-wrapper @onlyoffice/document-editor-vue vue
  1. 在Vue项目中配置
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  optimizeDeps: {
    include: ['@onlyoffice/document-editor-vue']
  },
  // 确保可以正确解析.vue文件
  resolve: {
    alias: {
      '@koi-br/office-sdk-wrapper': '@koi-br/office-sdk-wrapper'
    }
  }
})
  1. 在main.ts中注册组件
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.mount('#app')
  1. Vue组件使用示例

在你的Vue组件中:

<template>
  <div class="vue-office-demo">
    <!-- 正确使用Vue组件 -->
    <OnlyOfficeVueEditor
      :init-config="editorConfig"
      editor-id="demo-editor"
      @document-ready="handleDocumentReady"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
// 正确的导入方式
import OnlyOfficeVueEditor from '@koi-br/office-sdk-wrapper/src/components/OnlyOfficeVueEditor.vue';
import { DocumentType } from '@koi-br/office-sdk-wrapper/vue';

const editorConfig = ref({
  fileId: 'your-file-id',
  appId: 'your-app-id',
  containerSelector: '.office-container',
  isReadOnly: false,
  documentType: DocumentType.WORD,
  documentConfig: {
    title: 'My Document',
    url: 'https://example.com/document.docx'
  }
});

const handleDocumentReady = (event: any) => {
  console.log('文档准备就绪:', event);
};
</script>
  1. 运行Vue示例
# 克隆项目
git clone https://github.com/your-repo/@koi-br/office-sdk-wrapper.git
cd office-sdk-wrapper

# 安装依赖
npm install

# 运行Vue示例
cd examples/vue-example
npm install
npm run dev

🔄 Vue项目中的提供商切换

<template>
  <div class="office-app">
    <!-- 提供商选择 -->
    <div class="provider-selector">
      <button 
        @click="switchProvider(OfficeProvider.WPS)"
        :class="{ active: currentProvider === OfficeProvider.WPS }"
      >
        WPS Office
      </button>
      <button 
        @click="switchProvider(OfficeProvider.ONLYOFFICE)"
        :class="{ active: currentProvider === OfficeProvider.ONLYOFFICE }"
      >
        OnlyOffice
      </button>
    </div>
    
    <!-- WPS容器 -->
    <div 
      v-show="currentProvider === OfficeProvider.WPS"
      class="wps-container"
      style="width: 100%; height: 600px;"
    ></div>
    
    <!-- OnlyOffice Vue组件 -->
    <OnlyOfficeVueEditor
      v-show="currentProvider === OfficeProvider.ONLYOFFICE"
      :init-config="onlyOfficeConfig"
      :editor-id="`onlyoffice-${Date.now()}`"
      @document-ready="handleDocumentReady"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, watch } from 'vue';
// Vue组件从组件路径导入
import OnlyOfficeVueEditor from '@koi-br/office-sdk-wrapper/src/components/OnlyOfficeVueEditor.vue';
// 其他功能从主模块导入
import { 
  createWPSSDK,
  OfficeProvider,
  DocumentType,
  type IOfficeSDK
} from '@koi-br/office-sdk-wrapper';
// Vue适配器从vue模块导入
import { createOnlyOfficeVueSDK } from '@koi-br/office-sdk-wrapper/vue';

const currentProvider = ref(OfficeProvider.WPS);
const currentSDK = ref<IOfficeSDK | null>(null);

const baseConfig = {
  fileId: "your-file-id",
  appId: "your-app-id",
  isReadOnly: false,
  documentType: DocumentType.WORD
};

const onlyOfficeConfig = reactive({
  ...baseConfig,
  containerSelector: ".onlyoffice-container",
  documentConfig: {
    title: 'My Document',
    url: 'https://example.com/document.docx'
  },
  editorConfig: {
    lang: 'zh-CN',
    mode: 'edit' as const
  }
});

const switchProvider = async (provider: OfficeProvider) => {
  // 销毁当前SDK
  if (currentSDK.value) {
    await currentSDK.value.destroy();
    currentSDK.value = null;
  }
  
  currentProvider.value = provider;
  
  // 创建新的SDK
  if (provider === OfficeProvider.WPS) {
    currentSDK.value = await createWPSSDK({
      ...baseConfig,
      containerSelector: ".wps-container",
      token: "your-wps-token"
    });
  }
  // OnlyOffice由Vue组件管理,无需手动创建
};

const handleDocumentReady = (event: any) => {
  console.log('OnlyOffice文档准备就绪:', event);
};
</script>

🔧 Configuration Management / 配置管理

配置验证 / Configuration Validation

import { getConfigManager } from 'office-sdk-wrapper';

const manager = getConfigManager();

// 验证配置
const validation = manager.validateConfig({
  fileId: "your-file-id",
  appId: "your-app-id", 
  containerSelector: ".office-container",
  provider: OfficeProvider.WPS
});

if (!validation.isValid) {
  console.error('配置错误:', validation.errors);
  console.warn('配置警告:', validation.warnings);
  console.log('建议:', validation.suggestions);
}

推荐配置生成 / Recommended Configuration

import { getConfigManager, OfficeProvider } from 'office-sdk-wrapper';

const manager = getConfigManager();

// 获取基于场景的推荐
const recommendation = manager.recommendProvider({
  needsAdvancedRevision: true,    // 需要高级修订功能
  needsCollaboration: false,      // 不需要协作功能
  isVueProject: true,            // Vue项目
  hasWPSLicense: false,          // 没有WPS许可证
  documentType: DocumentType.WORD,
  expectedFileSize: 'large'       // 大文件处理
});

console.log(`推荐使用: ${recommendation.provider}`);
console.log(`推荐理由: ${recommendation.reason}`);
recommendation.tips.forEach(tip => console.log(`💡 ${tip}`));

快速配置生成器 / Quick Config Generator

import { createQuickConfig, getConfigManager } from 'office-sdk-wrapper';

// 快速创建WPS配置
const wpsConfig = createQuickConfig(
  {
    fileId: "doc-001",
    appId: "app-001", 
    containerSelector: ".office-container"
  },
  OfficeProvider.WPS,
  {
    isReadOnly: false,
    documentType: DocumentType.WORD
  }
);

// 快速创建OnlyOffice配置
const onlyOfficeConfig = createQuickConfig(
  {
    fileId: "doc-001",
    appId: "app-001",
    containerSelector: ".office-container" 
  },
  OfficeProvider.ONLYOFFICE,
  {
    isReadOnly: false,
    documentType: DocumentType.WORD,
    documentUrl: 'https://example.com/document.docx'
  }
);

🚨 Error Handling / 错误处理

统一错误处理

import { createWPSSDK, createOnlyOfficeSDK } from 'office-sdk-wrapper';

try {
  const sdk = await createWPSSDK({
    fileId: "your-file-id",
    appId: "your-app-id",
    containerSelector: ".office-container",
    token: "your-token",
    onError: (error) => {
      // 统一错误处理
      console.error('SDK错误:', error);
      
      // 根据错误类型处理
      if (error.code === 'NETWORK_ERROR') {
        // 网络错误处理
        showNetworkErrorMessage();
      } else if (error.code === 'AUTH_ERROR') {
        // 认证错误处理
        redirectToLogin();
      }
    }
  });
  
  // 使用SDK方法时的错误处理
  try {
    await sdk.insertTextAtCursor('Hello World');
  } catch (methodError) {
    console.error('方法调用失败:', methodError);
    // 具体方法的错误处理
  }
  
} catch (initError) {
  console.error('SDK初始化失败:', initError);
  // 初始化失败的处理
}

错误重试机制

import { createWPSSDK } from 'office-sdk-wrapper';

async function createSDKWithRetry(config, maxRetries = 3) {
  let lastError;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      const sdk = await createWPSSDK(config);
      console.log(`SDK初始化成功,第${i + 1}次尝试`);
      return sdk;
    } catch (error) {
      lastError = error;
      console.warn(`第${i + 1}次初始化失败:`, error);
      
      // 如果不是最后一次重试,等待后重试
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
      }
    }
  }
  
  throw new Error(`SDK初始化失败,已重试${maxRetries}次: ${lastError.message}`);
}

// 使用重试机制
const sdk = await createSDKWithRetry({
  fileId: "your-file-id",
  appId: "your-app-id",
  containerSelector: ".office-container"
});

📱 响应式设计

// 响应式容器大小调整
const setupResponsiveContainer = (sdk) => {
  const resizeObserver = new ResizeObserver(entries => {
    for (let entry of entries) {
      const { width, height } = entry.contentRect;
      
      // 调整编辑器尺寸
      if (sdk.nativeInstance && sdk.nativeInstance.resize) {
        sdk.nativeInstance.resize(width, height);
      }
    }
  });
  
  const container = document.querySelector('.office-container');
  if (container) {
    resizeObserver.observe(container);
  }
  
  return () => resizeObserver.disconnect();
};

// 移动设备优化
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

const config = {
  ...baseConfig,
  editorConfig: {
    ...baseConfig.editorConfig,
    // 移动设备优化
    customization: {
      toolbarNoTabs: isMobile,
      toolbarHideFileName: isMobile,
      compactToolbar: isMobile
    }
  }
};