# Spec: 第三步 - 模型生成和展示功能 ## ADDED Requirements ### 生成模型展示 - **Requirement**: 实现已生成模型的展示区域,支持点击放大预览功能 - **Scenario**: 用户可以看到通过第二步生成的3D模型,模型以缩略图形式展示,点击后可以使用ModelViewer组件进行全屏预览 ### 重新生成功能 - **Requirement**: 添加重新生成模型按钮,支持更新模型内容 - **Scenario**: 用户对当前生成的模型不满意时,点击重新生成按钮,系统重新执行模型生成算法 ### 导出功能 - **Requirement**: 实现导出功能,提供不同格式的模型文件导出选项 - **Scenario**: 用户可以选择不同的文件格式(如GLB、OBJ、FBX等)进行模型导出,下载到本地 ### 发货功能 - **Requirement**: 添加发货按钮,点击后进入第四步物流发货环节 - **Scenario**: 用户满意模型结果后,点击发货按钮,系统进入物流信息填写流程并进入第四步 ### 模型预览集成 - **Requirement**: 集成现有的ModelViewer组件进行全屏模型预览 - **Scenario**: 点击模型缩略图后弹出全屏预览对话框,用户可以旋转、缩放、查看模型详情 ## 技术实现细节 ### 布局结构 ```html

{{ t('disassembly.steps.model') }}

{{ t('disassembly.status.completed') }}
{{ t('disassembly.actions.previewModel') }}
{{ t('disassembly.actions.export') }} {{ t('disassembly.actions.regenerate') }} {{ t('disassembly.actions.ship') }}
``` ### 模型预览对话框 ```javascript const modelPreviewVisible = ref(false) const openModelPreview = () => { modelPreviewVisible.value = true } ``` ```html
``` ### 重新生成逻辑 ```javascript const regenerateModel = async () => { // 检查是否有第四步需要覆盖 if (workflowState.currentStep >= 4) { const confirmed = await ElMessageBox.confirm( t('disassembly.confirm.regenerateModelOverride'), t('common.confirm'), { confirmButtonText: t('common.confirm'), cancelButtonText: t('common.cancel'), type: 'warning' } ) if (!confirmed) return } try { regenerateLoading.value = true // 重新生成模型(用户后续实现) // const newModel = await regenerateModelAPI(contentId) // 模拟重新生成过程 await new Promise(resolve => setTimeout(resolve, 4000)) // 更新模型数据(使用不同的demo模型或随机生成) generatedModelUrl.value = generateMockModel() // 清空第四步 if (workflowState.currentStep >= 4) { workflowState.contentData.shippingInfo = {} workflowState.stepStatus[4] = 'pending' workflowState.currentStep = 3 } ElMessage.success(t('disassembly.success.modelRegenerateCompleted')) } catch (error) { ElMessage.error(t('disassembly.errors.modelRegenerateFailed')) } finally { regenerateLoading.value = false } } ``` ### 导出功能实现 ```javascript const handleExport = async (format) => { try { ElMessage.info(t('disassembly.info.exporting')) // 调用导出API(用户后续实现) // await exportModelAPI(contentId, format) // 模拟导出过程 await new Promise(resolve => setTimeout(resolve, 2000)) // 创建下载链接 const downloadUrl = generateDownloadUrl(format) const link = document.createElement('a') link.href = downloadUrl link.download = `model-${contentId}.${format}` document.body.appendChild(link) link.click() document.body.removeChild(link) ElMessage.success(t('disassembly.success.exportCompleted')) } catch (error) { ElMessage.error(t('disassembly.errors.exportFailed')) } } const generateDownloadUrl = (format) => { // 模拟不同格式的下载链接 const mockUrls = { glb: '/src/assets/demo/model.glb', obj: '/src/assets/demo/model.obj', // 假设存在 fbx: '/src/assets/demo/model.fbx', // 假设存在 gltf: '/src/assets/demo/model.gltf' // 假设存在 } return mockUrls[format] || mockUrls.glb } ``` ### 发货流程 ```javascript const proceedToShipping = async () => { try { shippingLoading.value = true // 更新步骤状态 updateStepStatus(3, 'completed') updateStepStatus(4, 'current') workflowState.currentStep = 4 ElMessage.success(t('disassembly.success.proceedToShipping')) } catch (error) { ElMessage.error(t('disassembly.errors.proceedToShippingFailed')) } finally { shippingLoading.value = false } } ``` ### 样式实现 ```css .model-display { background: #ffffff; border-radius: 12px; padding: 24px; margin-bottom: 32px; box-shadow: 0 2px 8px rgba(107, 70, 193, 0.1); } .model-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; } .model-header h3 { margin: 0; color: #1f2937; font-size: 18px; font-weight: 600; } .model-preview-container { display: flex; justify-content: center; align-items: center; background: #f8fafc; border-radius: 8px; padding: 16px; margin-bottom: 24px; } .model-thumbnail { position: relative; cursor: pointer; border-radius: 8px; overflow: hidden; transition: transform 200ms ease; } .model-thumbnail:hover { transform: scale(1.02); } .preview-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(107, 70, 193, 0.8); display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; transition: opacity 200ms ease; color: white; } .preview-overlay .el-icon { font-size: 32px; margin-bottom: 8px; } .model-thumbnail:hover .preview-overlay { opacity: 1; } .step-actions { display: flex; gap: 16px; justify-content: flex-end; padding-top: 24px; border-top: 1px solid #e5e7eb; } .step-actions .el-dropdown { margin-right: auto; } /* 响应式设计 */ @media (max-width: 768px) { .model-display { padding: 16px; } .model-preview-container { padding: 12px; } .step-actions { flex-direction: column; gap: 12px; } .step-actions .el-dropdown { margin-right: 0; width: 100%; } .step-actions .el-button { width: 100%; } } ``` ## 数据模拟 ```javascript // 模拟不同模型数据 const generateMockModel = () => { const models = [ '/src/assets/demo/model.glb', '/src/assets/demo/model2.glb', // 假设存在 '/src/assets/demo/model3.glb' // 假设存在 ] return models[Math.floor(Math.random() * models.length)] } ``` ## 验证标准 - 生成模型能够正确加载和显示 - 点击模型能够弹出全屏预览对话框 - ModelViewer组件在预览对话框中正常工作 - 重新生成按钮能够触发模型重新生成流程 - 导出功能能够正常下载不同格式的文件 - 发货按钮能够正常进入第四步 - 响应式布局在各种设备上表现良好