# 前端实现方案 - WPS SDK 集成(无回调处理)
## 核心原则
**前端职责**:
- ✅ 初始化 WPS SDK
- ✅ 配置编辑器参数
- ✅ 处理用户交互
- ✅ 显示加载和错误状态
**后端职责**:
- ✅ 实现所有 WPS 回调接口
- ✅ 处理文件上传和存储
- ✅ 管理文件版本
- ✅ 处理三阶段保存
## 前端实现清单
### 1. 移除前端回调处理器
**删除文件**:
- `src/utils/wpsCallback.ts` - 不需要前端拦截请求
**原因**:
- WPS SDK 会直接调用后端接口
- 前端不应该拦截和模拟这些请求
- 所有回调逻辑由后端处理
### 2. 简化 WPS 初始化配置
**标准初始化方式**:
```typescript
// src/components/DocumentWpsAuditDialog/index.vue
const initWpsEditor = async () => {
if (!wpsContainerRef.value || !props.document?.ossId) {
return;
}
try {
wpsLoading.value = true;
wpsError.value = '';
// 检查 SDK
if (!(window as any).WebOfficeSDK) {
wpsError.value = 'WPS SDK 未加载';
wpsLoading.value = false;
return;
}
const WebOfficeSDK = (window as any).WebOfficeSDK;
// 获取文件类型
const officeType = getFileType(props.document.fileName || '');
// 生成文件 ID
const fileId = `${props.document.id}`;
// 标准初始化配置(按官方文档)
const config = {
// 必需参数
appId: 'SX20251229FLIAPDAPP',
officeType: officeType,
fileId: fileId,
// 可选参数
mount: wpsContainerRef.value,
// 自定义参数(会传递到后端回调接口)
customArgs: {
documentId: props.document.id,
fileName: props.document.fileName,
fileUrl: props.document.url,
userId: userStore.userId,
userName: userStore.userName
}
};
console.log('[WPS] 初始化配置:', config);
// 初始化编辑器
wpsInstance = WebOfficeSDK.init(config);
wpsLoading.value = false;
console.log('[WPS] 编辑器初始化成功');
} catch (err: any) {
console.error('[WPS] 初始化失败:', err);
wpsError.value = err.message || '初始化失败';
wpsLoading.value = false;
}
};
```
### 3. 文件类型映射
```typescript
// 获取 WPS 文件类型
const getFileType = (fileName: string): string => {
const name = fileName.toLowerCase();
// Word 文档
if (name.endsWith('.docx') || name.endsWith('.doc')) {
return 'w';
}
// Excel 表格
if (name.endsWith('.xlsx') || name.endsWith('.xls')) {
return 's';
}
// PowerPoint 演示
if (name.endsWith('.pptx') || name.endsWith('.ppt')) {
return 'p';
}
// PDF 文档
if (name.endsWith('.pdf')) {
return 'f';
}
// 默认为 Word
return 'w';
};
```
### 4. 保存文档(可选)
```typescript
// 手动保存文档
const saveWpsDocument = async () => {
if (!wpsInstance) {
ElMessage.warning('编辑器未初始化');
return null;
}
try {
console.log('[WPS] 开始保存文档');
// 调用 SDK 的 save 方法
// WPS SDK 会自动调用后端的三阶段保存接口
const result = await wpsInstance.save();
console.log('[WPS] 保存成功:', result);
ElMessage.success('文档已保存');
return result;
} catch (err: any) {
console.error('[WPS] 保存失败:', err);
ElMessage.error('保存失败: ' + err.message);
throw err;
}
};
```
### 5. 销毁编辑器
```typescript
// 销毁 WPS 编辑器
const destroyWpsEditor = () => {
if (wpsInstance) {
try {
if (wpsInstance.destroy) {
wpsInstance.destroy();
}
wpsInstance = null;
console.log('[WPS] 编辑器已销毁');
} catch (err) {
console.error('[WPS] 销毁编辑器失败:', err);
}
}
};
// 组件卸载时清理
onBeforeUnmount(() => {
destroyWpsEditor();
});
```
### 6. 错误处理和降级
```typescript
// 降级到 iframe 预览
const fallbackToIframe = () => {
wpsError.value = 'WPS 编辑器加载失败,已切换到预览模式';
// 模板中已有 iframe 降级方案
};
// 初始化时的错误处理
const initWpsEditor = async () => {
try {
// ... 初始化代码
} catch (err: any) {
console.error('[WPS] 初始化失败:', err);
wpsError.value = err.message || '初始化失败';
wpsLoading.value = false;
// 如果有 URL,降级到 iframe
if (props.document?.url) {
fallbackToIframe();
}
}
};
```
## 完整的组件代码结构
```vue
取消
提交审核
```
## 需要删除的代码
### 1. 删除回调处理器文件
```bash
# 删除这个文件
src/utils/wpsCallback.ts
```
### 2. 删除组件中的回调相关代码
```typescript
// 删除这些导入
import { setWpsFileInfo, clearWpsFileInfo } from '@/utils/wpsCallback';
// 删除这些调用
setWpsFileInfo(fileId, { ... });
clearWpsFileInfo(fileId);
```
## 后端需要实现的接口
### 1. 文件信息接口
```
GET /v1/3rd/file/info?_w_appid={appId}&_w_fileid={fileId}
```
### 2. 三阶段保存接口
```
GET /v3/3rd/files/:file_id/upload/prepare
POST /v3/3rd/files/:file_id/upload/address
POST /v3/3rd/files/:file_id/upload/complete
```
### 3. 其他可能需要的接口
```
GET /v1/3rd/file/version # 文件版本列表
POST /v1/3rd/file/rename # 文件重命名
POST /v1/3rd/file/copy # 文件复制
```
## 前端配置要点
### 1. customArgs 参数说明
```typescript
customArgs: {
// 这些参数会通过 X-User-Query 请求头传递到后端
documentId: props.document.id, // 文档ID
fileName: props.document.fileName, // 文件名
fileUrl: props.document.url, // 文件URL
userId: userStore.userId, // 用户ID
userName: userStore.userName // 用户名
}
```
**注意**:
- 不要使用保留字段:`type`, `version`, `mode`, `history_id`, `share_id`
- 建议使用业务前缀,如:`doc_id`, `doc_name`
### 2. fileId 生成规则
```typescript
// 简单方式:使用文档ID
const fileId = `${props.document.id}`;
// 或者:使用文档ID + 时间戳(确保唯一性)
const fileId = `${props.document.id}_${Date.now()}`;
// 或者:使用 UUID
import { v4 as uuidv4 } from 'uuid';
const fileId = uuidv4();
```
**建议**:使用文档ID,便于后端关联
### 3. officeType 映射
```typescript
const FILE_TYPE_MAP: Record = {
'doc': 'w', 'docx': 'w', // Word
'xls': 's', 'xlsx': 's', // Excel
'ppt': 'p', 'pptx': 'p', // PowerPoint
'pdf': 'f' // PDF
};
```
## 测试清单
### 前端测试
- [ ] SDK 加载成功
- [ ] 编辑器初始化成功
- [ ] 文档正确显示
- [ ] 可以编辑文档
- [ ] 保存按钮可用
- [ ] 错误提示正确
- [ ] 降级方案生效
### 集成测试(需要后端配合)
- [ ] 文件信息接口返回正确
- [ ] 保存功能正常
- [ ] 版本号正确递增
- [ ] 文件上传成功
- [ ] 审核流程完整
## 常见问题
### Q1: AppInfoNotExists 错误
**原因**:后端接口未实现或配置错误
**解决**:等待后端实现回调接口
### Q2: 编辑器加载失败
**原因**:SDK 文件未加载或网络问题
**解决**:检查 `public/web-office-sdk.js` 是否存在
### Q3: 保存失败
**原因**:后端三阶段保存接口未实现
**解决**:等待后端实现保存接口
### Q4: 文档不显示
**原因**:fileId 或 officeType 不正确
**解决**:检查参数配置和文件类型映射
## 总结
前端实现非常简单:
1. ✅ 引入 WPS SDK
2. ✅ 调用 `WebOfficeSDK.init()` 初始化
3. ✅ 传递正确的参数
4. ✅ 处理加载和错误状态
5. ❌ **不需要**处理任何回调接口
6. ❌ **不需要**拦截请求
7. ❌ **不需要**实现三阶段保存
所有复杂的逻辑都由后端处理!