6.8 KiB
6.8 KiB
Spec: 第二步 - 拆件结果展示功能
ADDED Requirements
拆件结果展示
- Requirement: 实现已拆件图片内容的展示布局,支持多张图片的展示
- Scenario: 用户可以看到拆件后的图片结果,图片以网格或列表形式展示,支持点击预览
重新生成功能
- Requirement: 添加重新生成按钮,实现重新执行拆件逻辑并更新图片内容
- Scenario: 用户对当前拆件结果不满意时,点击重新生成按钮,系统重新执行拆件算法并生成新的图片结果
生成模型功能
- Requirement: 添加生成模型按钮,点击后进入第三步模型生成环节
- Scenario: 用户满意拆件结果后,点击生成模型按钮,系统进入模型生成流程并进入第三步
步骤覆盖逻辑
- Requirement: 实现上游操作覆盖下游内容的逻辑处理
- Scenario: 用户在第二步点击重新生成时,如果已有第三步或第四步内容,系统会弹出确认对话框并清空下游步骤
技术实现细节
布局结构
<div class="disassembly-step-content">
<div class="disassembly-results">
<div class="results-header">
<h3>{{ t('disassembly.steps.disassembly') }}</h3>
<el-tag type="success">{{ t('disassembly.status.completed') }}</el-tag>
</div>
<div class="results-grid">
<div
v-for="(image, index) in disassemblyImages"
:key="index"
class="result-image-container"
@click="openResultImagePreview(image)"
>
<img :src="image.url" :alt="`拆件结果 ${index + 1}`" />
<div class="image-overlay">
<el-icon><ZoomIn /></el-icon>
</div>
</div>
</div>
</div>
<div class="step-actions">
<el-button
type="warning"
@click="regenerateDisassembly"
:loading="regenerateLoading"
>
{{ t('disassembly.actions.regenerate') }}
</el-button>
<el-button
type="primary"
@click="generateModel"
:loading="modelGenerationLoading"
>
{{ t('disassembly.actions.generateModel') }}
</el-button>
</div>
</div>
重新生成逻辑
const regenerateDisassembly = async () => {
// 检查是否有下游步骤需要覆盖
if (hasDownstreamContent()) {
const confirmed = await ElMessageBox.confirm(
t('disassembly.confirm.regenerateOverride'),
t('common.confirm'),
{
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning'
}
)
if (!confirmed) return
}
try {
regenerateLoading.value = true
// 重新执行拆件逻辑(用户后续实现)
// const newResults = await callDisassemblyAPI(contentId, true)
// 模拟重新生成过程
await new Promise(resolve => setTimeout(resolve, 3000))
// 更新拆件结果
disassemblyImages.value = generateMockDisassemblyResults()
// 清空下游步骤
clearDownstreamSteps(2)
ElMessage.success(t('disassembly.success.regenerateCompleted'))
} catch (error) {
ElMessage.error(t('disassembly.errors.regenerateFailed'))
} finally {
regenerateLoading.value = false
}
}
const generateModel = async () => {
try {
modelGenerationLoading.value = true
// 生成模型(用户后续实现)
// const modelData = await generateModelAPI(contentId)
// 模拟模型生成过程
await new Promise(resolve => setTimeout(resolve, 2000))
// 更新步骤状态
updateStepStatus(2, 'completed')
updateStepStatus(3, 'current')
workflowState.currentStep = 3
workflowState.contentData.generatedModel = '/src/assets/demo/model.glb'
ElMessage.success(t('disassembly.success.modelGenerationStarted'))
} catch (error) {
ElMessage.error(t('disassembly.errors.modelGenerationFailed'))
} finally {
modelGenerationLoading.value = false
}
}
下游步骤覆盖逻辑
const hasDownstreamContent = () => {
return workflowState.currentStep > 2
}
const clearDownstreamSteps = (fromStep) => {
Object.keys(workflowState.stepStatus).forEach(step => {
const stepNum = parseInt(step)
if (stepNum > fromStep) {
workflowState.stepStatus[step] = 'pending'
if (stepNum === 3) {
workflowState.contentData.generatedModel = null
}
if (stepNum === 4) {
workflowState.contentData.shippingInfo = {}
}
}
})
// 调整当前步骤
workflowState.currentStep = fromStep
}
样式实现
.disassembly-results {
background: #ffffff;
border-radius: 12px;
padding: 24px;
margin-bottom: 32px;
box-shadow: 0 2px 8px rgba(107, 70, 193, 0.1);
}
.results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.results-header h3 {
margin: 0;
color: #1f2937;
font-size: 18px;
font-weight: 600;
}
.results-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.result-image-container {
position: relative;
aspect-ratio: 1;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: transform 200ms ease;
}
.result-image-container:hover {
transform: scale(1.02);
}
.result-image-container img {
width: 100%;
height: 100%;
object-fit: cover;
}
.image-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(107, 70, 193, 0.8);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 200ms ease;
color: white;
font-size: 24px;
}
.result-image-container:hover .image-overlay {
opacity: 1;
}
.step-actions {
display: flex;
gap: 16px;
justify-content: flex-end;
padding-top: 24px;
border-top: 1px solid #e5e7eb;
}
/* 响应式设计 */
@media (max-width: 768px) {
.disassembly-results {
padding: 16px;
}
.results-grid {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.step-actions {
flex-direction: column;
}
}
数据模拟
// 模拟拆件结果数据
const generateMockDisassemblyResults = () => {
return [
{
url: '/src/assets/demo/suoluetu.png',
title: '拆件结果 1',
description: '主体部分'
},
{
url: '/src/assets/demo/suoluetu.png',
title: '拆件结果 2',
description: '细节部分'
},
{
url: '/src/assets/demo/suoluetu.png',
title: '拆件结果 3',
description: '组件部分'
}
]
}
验证标准
- 拆件结果图片能够正确加载和显示
- 点击图片能够弹出预览对话框
- 重新生成按钮能够触发重新拆件流程
- 生成模型按钮能够正常进入第三步
- 步骤覆盖逻辑在各种情况下正常工作
- 响应式布局在各种设备上表现良好