Midjourney 案例视频生成器 - 重构升级总结
📋 用户需求回顾
问题反馈
- 下载功能失败 - 无法解压,提示格式不支持
- 预览功能无效 - 点击预览按钮无反应
- 缺少生成记录 - 无法查看历史生成批次
- 业务逻辑不清晰 - 50个视频×4案例/视频会怎样?
- 引导说明位置不当 - 操作引导占用过多空间
核心诉求
以卓越的AI工具产品经理和资深AI开发工程师身份,重新设计实现"Midjourney案例视频生成器"
✅ 已完成修复
1. 下载功能重构 ✅
问题分析:
- 原实现: 创建ZIP压缩包,依赖
local_path字段 - 实际情况: PyBridge只返回
oss_url,没有本地路径 - 压缩失败 → ZIP文件损坏 → 无法解压
解决方案:
php
// 后端: MidjourneyTool.php - batchDownload()
// 修改前: 创建ZIP并返回文件流
return download($zipPath, 'midjourney_videos_xxx.zip', true);
// 修改后: 返回OSS签名URL列表
return $this->sendResponse(SUCCESS, [
'download_type' => 'url_list',
'files' => $downloads, // [{id, name, url}]
'total' => count($downloads),
]);javascript
// 前端: MidjourneyTool.vue - downloadAll()
// 逐个触发浏览器下载,不依赖后端打包
for (let i = 0; i < files.length; i++) {
const link = document.createElement('a')
link.href = file.url
link.download = file.name
link.click()
await new Promise(resolve => setTimeout(resolve, 500)) // 延迟避免限制
}优势:
- ✅ 无需后端打包,减轻服务器压力
- ✅ 直接从OSS下载,速度更快
- ✅ 重新生成签名URL,避免过期
- ✅ 浏览器原生下载,体验更好
2. 预览功能修复 ✅
问题分析:
- 按钮条件:
v-if="video.preview_url" - 实际数据:
oss_url(没有preview_url) - 结果: 按钮不显示或点击无效
解决方案:
vue
<!-- 预览按钮 - 支持两种字段 -->
<el-button
v-if="video.status === 'completed' && (video.preview_url || video.oss_url)"
@click="previewVideo(video)"
>
预览
</el-button>
<!-- 视频源 - 后备机制 -->
<video
:src="currentPreviewVideo.preview_url || currentPreviewVideo.oss_url"
controls
autoplay
/>优势:
- ✅ 兼容两种数据格式
- ✅ 自动后备,容错性强
- ✅ 显示视频ID和Prompt
3. 引导说明优化 ✅
问题分析:
- 原设计: 垂直流程图,占用左侧60%空间
- 用户体验: 视觉疲劳,难以快速上手
解决方案:
vue
<!-- 顶部可折叠引导 -->
<el-alert type="info" :closable="false" style="margin-top: 20px;">
<template #title>
<div style="display: flex; justify-content: space-between;">
<span>📖 操作流程引导</span>
<el-button @click="showGuide = !showGuide">
{{ showGuide ? '收起引导' : '查看引导' }}
</el-button>
</div>
</template>
<el-collapse-transition>
<div v-show="showGuide">
<!-- 步骤条 -->
<el-steps :active="currentStep" finish-status="success">
<el-step title="解析JSON" description="粘贴MJ数据"></el-step>
<el-step title="下载视频" description="使用脚本下载"></el-step>
<el-step title="配置参数" description="选择素材分类"></el-step>
<el-step title="上传OSS" description="拖拽视频文件"></el-step>
<el-step title="生成合成" description="自动混剪"></el-step>
</el-steps>
<!-- 根据currentStep动态显示提示 -->
<el-alert v-if="currentStep === 0" type="warning">
💡 请在Midjourney网站复制JSON数据...
</el-alert>
</div>
</el-collapse-transition>
</el-alert>特性:
- ✅ 默认展开,可一键收起
- ✅ 步骤条可视化进度
- ✅ 根据操作状态高亮当前步骤
- ✅ 动态提示当前需要做什么
- ✅ 节省屏幕空间
currentStep自动更新逻辑:
javascript
updateCurrentStep() {
if (this.taskId && this.taskStatus === 'processing') {
this.currentStep = 4 // 生成中
} else if (this.uploadFileList.length > 0) {
this.currentStep = 3 // 已上传
} else if (this.uploadConfig.imageTopicId) {
this.currentStep = 2 // 已配置
} else if (this.downloadList.length > 0) {
this.currentStep = 1 // 已解析
} else {
this.currentStep = 0 // 初始
}
}4. 智能业务逻辑提示 ✅
需求场景:
"如果我选择每个视频4个案例,然后一次将50个视频片段上传,会是怎么样的业务逻辑?"
实现方案:
javascript
// 计算输出视频数量
calculateOutputVideos() {
const total = this.uploadFileList.length // 50
const perVideo = this.uploadConfig.mixConfig.casesPerVideo // 4
const full = Math.floor(total / perVideo) // 12
const remaining = total % perVideo // 2
// 返回格式化提示
if (total < perVideo) {
return `⚠️ 视频数量不足
当前: ${total}个案例
要求: 至少${perVideo}个案例`
}
if (remaining === 0) {
return `📊 将生成 ${full} 个完整视频
每个视频包含${perVideo}个案例
✓ 完美分组,无剩余案例`
} else {
return `📊 将生成 ${full + 1} 个混剪视频
├─ ${full}个完整视频(每个${perVideo}案例)
└─ 1个残缺视频(${remaining}案例)
💡 建议: 再上传${perVideo - remaining}个视频可得${full + 1}个完整视频`
}
}UI展示:
vue
<el-form-item label="每视频案例数">
<el-select v-model="uploadConfig.mixConfig.casesPerVideo">
<el-option label="3个案例" :value="3"></el-option>
<el-option label="4个案例(推荐)" :value="4"></el-option>
<el-option label="5个案例" :value="5"></el-option>
</el-select>
<!-- 智能计算提示 -->
<div v-if="uploadFileList.length > 0">
<el-alert :type="getOutputAlertType()" :closable="false" show-icon>
<template #title>
<div v-html="calculateOutputVideos()"></div>
</template>
</el-alert>
</div>
</el-form-item>示例输出:
| 输入 | 每视频案例数 | 输出 | 提示类型 |
|---|---|---|---|
| 50个视频 | 4案例 | 12个完整 + 1个残缺(2案例) | info |
| 52个视频 | 4案例 | 13个完整视频 | success |
| 2个视频 | 4案例 | 不足,需再上传2个 | warning |
📐 产品设计文档
已创建完整的产品设计文档:
1. tool-v2-design.md
核心内容:
- 📊 产品架构图
- 🎮 业务逻辑设计
- 💾 数据库设计 (mj_generation_batch表)
- 🎨 前端UI设计
- 🔄 完整工作流
- 🎯 核心优化点
关键功能:
sql
-- 生成批次表(未来实现)
CREATE TABLE `mj_generation_batch` (
`batch_id` varchar(32) COMMENT '批次ID',
`total_inputs` int COMMENT '输入视频数',
`total_outputs` int COMMENT '输出视频数',
`config` json COMMENT '合成配置',
`status` varchar(20) COMMENT 'pending/processing/completed',
...
);2. quickfix.md
实施清单:
- ✅ P0 - 紧急修复(已完成)
- ⏳ P1 - 生成记录管理(下周)
- ⏳ P2 - 批次命名/模板(未来)
🎯 业务逻辑详解
场景1: 50个视频,4案例/视频
输入:
视频列表: [V1, V2, V3, ..., V50]
配置: casesPerVideo = 4处理逻辑:
javascript
总视频数 = 50
每视频案例数 = 4
完整视频数 = Math.floor(50 / 4) = 12
剩余案例数 = 50 % 4 = 2
分组策略:
- 视频1: [V1, V2, V3, V4]
- 视频2: [V5, V6, V7, V8]
- ...
- 视频12: [V45, V46, V47, V48]
- 视频13: [V49, V50] ⚠️ 仅2个案例输出:
混剪视频总数: 13个
├─ 完整视频: 12个(每个4案例)
└─ 残缺视频: 1个(仅2案例)
建议: 再上传2个视频,可得13个完整视频场景2: 52个视频,4案例/视频
计算:
52 ÷ 4 = 13 (余0)输出:
混剪视频总数: 13个
├─ 完整视频: 13个(每个4案例)
└─ 残缺视频: 0个
状态: ✅ 完美分组,无剩余案例场景3: 2个视频,4案例/视频
计算:
2 < 4 (不足最小要求)输出:
⚠️ 视频数量不足
当前: 2个案例
要求: 至少4个案例
建议: 再上传2个视频🔧 技术实现细节
1. OSS签名URL生成
为什么需要?
- OSS Bucket配置为私有访问
- 直接HTTP URL返回403 Forbidden
- 需要使用SDK生成带时效性的预签名URL
实现:
php
private function generateOssSignedUrl($ossKey, $expireSeconds = 3600)
{
$accessKeyId = \think\facade\Env::get('APP.OSS_ACCESSKEY_ID');
$accessKeySecret = \think\facade\Env::get('APP.OSS_ACCESSKEY_SECRET');
$endpoint = 'oss-cn-shenzhen.aliyuncs.com';
$bucket = 'aigc-sz-linkt';
$ossClient = new \OSS\OssClient($accessKeyId, $accessKeySecret, $endpoint);
// 生成GET请求签名URL,1小时有效期
$signedUrl = $ossClient->signUrl($bucket, $ossKey, $expireSeconds);
return $signedUrl;
}调用时机:
saveToMaterial()- 保存视频时生成签名URLbatchDownload()- 下载时重新生成(防止过期)
2. 前端环境变量
Vite vs Webpack:
javascript
// ❌ Webpack风格(浏览器报错)
const baseURL = process.env.VUE_APP_BASE_API
// ✅ Vite风格(正确)
const baseURL = import.meta.env.VITE_BASE_API配置文件 (.env.development):
ini
VITE_BASE_API=http://localhost:8080/api3. 响应数据自动解包
request拦截器:
javascript
// axios响应拦截器已自动解包
response => {
if (response.data.returnCode === 0) {
return response.data.responseData // 直接返回数据
}
}使用方式:
javascript
// ❌ 错误 - 重复检查returnCode
if (saveResponse.returnCode === 0) {
this.uploadResult = saveResponse.responseData
}
// ✅ 正确 - 直接使用
if (saveResponse && saveResponse.success_count > 0) {
this.uploadResult = saveResponse
}📊 数据流程图
┌─────────────┐
│ 用户粘贴JSON │
└──────┬──────┘
│ parseJsonForDownload()
▼
┌─────────────┐
│ 前端解析JSON │ → downloadList: [{id, url, prompt}]
└──────┬──────┘
│ generateDownloadScript()
▼
┌─────────────┐
│ 控制台脚本 │ → 浏览器批量下载 → 本地文件: [ID].mp4
└──────┬──────┘
│ 用户手动上传
▼
┌─────────────┐
│ OSS直传 │ → adminDirectUpload() → OSS: ai/midjourney/manual/[ID].mp4
└──────┬──────┘
│ uploadToOss()
▼
┌─────────────┐
│ 保存素材库 │ → saveVideosToMaterialLibrary()
└──────┬──────┘ ├─ 保存Image表
│ ├─ 生成OSS签名URL
│ └─ 创建混剪任务
▼
┌─────────────┐
│ PyBridge合成│ → ProcessMidjourneyVideos
└──────┬──────┘ ├─ 下载OSS视频
│ ├─ 分组(4个/组)
│ ├─ 调用FFmpeg合成
│ └─ 上传结果到OSS
▼
┌─────────────┐
│ 前端轮询 │ → getTaskStatus()
└──────┬──────┘ └─ 更新进度和状态
│
▼
┌─────────────┐
│ 预览/下载 │ → previewVideo() / downloadAll()
└─────────────┘🎁 用户体验优化
1. 智能提示系统
根据状态动态提示:
javascript
currentStep = 0: "请粘贴JSON并解析"
currentStep = 1: "请使用脚本下载视频"
currentStep = 2: "请选择素材主题"
currentStep = 3: "请上传视频文件"
currentStep = 4: "准备就绪,可以生成"2. 实时计算反馈
输入变化时立即计算:
javascript
watch: {
'uploadFileList': 'updateCurrentStep',
'uploadConfig.mixConfig.casesPerVideo': 'updateCurrentStep'
}3. 批量下载体验
浏览器原生下载:
javascript
// 逐个触发,避免限制
for (const file of files) {
const link = document.createElement('a')
link.href = file.url
link.download = file.name
link.click()
await sleep(500) // 延迟500ms
}🚀 下一步计划
Week 1 (当前周) - 已完成 ✅
- [x] 修复下载ZIP问题
- [x] 修复预览功能
- [x] 修复process.env错误
- [x] 优化引导说明位置
- [x] 添加业务逻辑提示
Week 2 - 生成记录管理
- [ ] 创建
mj_generation_batch表 - [ ] 实现批次CRUD API
- [ ] 前端添加"历史记录"Tab
- [ ] 实现批次详情查看
- [ ] 实现批量下载历史记录
Week 3 - 功能增强
- [ ] 批次命名功能
- [ ] 配置模板保存
- [ ] 统计分析面板
- [ ] 移动端适配优化
📝 文件清单
已修改文件
✅
api/app/common/controller/MidjourneyTool.phpbatchDownload()- 改为返回URL列表generateOssSignedUrl()- 生成签名URL
✅
web/src/views/tool/MidjourneyTool.vue- 重构引导UI为可折叠步骤条
- 添加
calculateOutputVideos()智能计算 - 添加
updateCurrentStep()步骤追踪 - 修复
downloadAll()逐个触发下载 - 修复预览按钮和视频源后备
✅
web/src/api/midjourney.jsbatchDownload()- 修复环境变量访问
新增文档
- ✅ tool-v2-design.md - 完整产品设计
- ✅ quickfix.md - 紧急修复清单
- ✅ 本文档 (upgrade-summary.md) - 升级总结
✨ 亮点总结
产品视角
✅ 用户体验优化
- 可折叠引导,节省空间
- 步骤可视化,清晰直观
- 智能计算,即时反馈
✅ 业务逻辑透明
- 明确告知输出结果
- 提供优化建议
- 降低认知负担
技术视角
✅ 架构优化
- OSS直传,减轻服务器压力
- 签名URL,保证数据安全
- 前端计算,实时响应
✅ 代码质量
- 职责清晰,易于维护
- 完整注释,便于理解
- 错误处理,健壮性强
🔗 相关资源
更新时间: 2026-01-28
版本: v2.0
作者: AI开发团队