# 前端实现方案 - 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. ❌ **不需要**实现三阶段保存 所有复杂的逻辑都由后端处理!