# Spec: 第三步 - 模型生成和展示功能
## ADDED Requirements
### 生成模型展示
- **Requirement**: 实现已生成模型的展示区域,支持点击放大预览功能
- **Scenario**: 用户可以看到通过第二步生成的3D模型,模型以缩略图形式展示,点击后可以使用ModelViewer组件进行全屏预览
### 重新生成功能
- **Requirement**: 添加重新生成模型按钮,支持更新模型内容
- **Scenario**: 用户对当前生成的模型不满意时,点击重新生成按钮,系统重新执行模型生成算法
### 导出功能
- **Requirement**: 实现导出功能,提供不同格式的模型文件导出选项
- **Scenario**: 用户可以选择不同的文件格式(如GLB、OBJ、FBX等)进行模型导出,下载到本地
### 发货功能
- **Requirement**: 添加发货按钮,点击后进入第四步物流发货环节
- **Scenario**: 用户满意模型结果后,点击发货按钮,系统进入物流信息填写流程并进入第四步
### 模型预览集成
- **Requirement**: 集成现有的ModelViewer组件进行全屏模型预览
- **Scenario**: 点击模型缩略图后弹出全屏预览对话框,用户可以旋转、缩放、查看模型详情
## 技术实现细节
### 布局结构
```html
{{ t('disassembly.actions.previewModel') }}
{{ t('disassembly.actions.export') }}
GLB格式
OBJ格式
FBX格式
GLTF格式
{{ 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组件在预览对话框中正常工作
- 重新生成按钮能够触发模型重新生成流程
- 导出功能能够正常下载不同格式的文件
- 发货按钮能够正常进入第四步
- 响应式布局在各种设备上表现良好