15 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 打卡视频生成与展示 | 实现打卡勾选生成视频后,在饮食记录页面定时查询视频任务状态并显示,在打卡详情支持视频播放,勾选生成视频的打卡帖子在社区最新tab显示 |
|
false |
打卡视频生成与展示功能实现计划
背景分析
根据代码探索,当前系统已具备:
- 打卡发布:
[checkin-publish.vue](msh_single_uniapp/pages/tool/checkin-publish.vue)支持勾选"生成打卡视频分享到社区",会调用KieAI创建视频任务并返回taskId - 数据存储:
eb_user_sign表存储task_id和enable_ai_video字段,eb_article表存储视频URL和任务状态 - 视频生成: 通过
[ToolSora2Service](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolSora2ServiceImpl.java)调用KieAI API - 状态查询接口:
GET /api/front/kieai/video/task/{taskId}已存在
缺失功能:
- 打卡时未创建
eb_article记录来存储视频 - 饮食记录页面不显示视频任务状态
- 打卡详情页不支持视频播放
- 社区帖子未关联视频信息
实现方案
数据库层面
1. 修改表结构
eb_user_sign表: 已有 task_id, enable_ai_video 字段,无需修改
v2_community_posts表: 已有 video_url 字段(从SQL看到),需确认Java实体类是否包含
eb_article表: 已有 video_url, task_id, status_task, check_in_record_id 字段
2. 数据流设计
flowchart TD
A[用户勾选生成视频并发布打卡] --> B[前端:调用KieAI创建视频任务]
B --> C[前端:获得taskId]
C --> D[前端:提交打卡 带taskId+enableAIVideo]
D --> E[后端:保存eb_user_sign记录]
E --> F[后端:创建eb_article记录]
F --> G[eb_article: taskId, statusTask=0, checkInRecordId]
H[饮食记录页面] --> I[加载打卡列表API]
I --> J[返回 taskId, enableAIVideo, videoUrl]
J --> K[前端:检测有taskId且无videoUrl]
K --> L[启动定时轮询 /kieai/video/task/taskId]
L --> M{任务状态?}
M -->|进行中| N[显示生成中状态]
M -->|完成| O[更新videoUrl到article]
M -->|失败| P[显示失败状态]
O --> Q[页面刷新后显示视频]
R[打卡详情页] --> S[查询详情API]
S --> T[返回taskId+videoUrl]
T --> U{有videoUrl?}
U -->|是| V[显示video标签播放]
U -->|否+有taskId| W[显示生成中状态]
X[社区最新tab] --> Y[查询v2_community_posts]
Y --> Z[关联eb_user_sign.enableAIVideo]
Z --> AA[显示有视频标记的帖子]
后端改动
1. 更新打卡提交逻辑
[ToolCheckinServiceImpl.submit()](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCheckinServiceImpl.java)
- 在打卡成功后,如果
enableAIVideo=1且有taskId,创建eb_article记录:type = 2(视频类型)task_id = taskIdstatus_task = 0(已创建)check_in_record_id = userSign.idtitle= 打卡备注或默认标题- 其他字段按现有逻辑填充
2. 更新打卡列表接口
[ToolCheckinServiceImpl.getList()](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCheckinServiceImpl.java)
- 查询时关联
eb_article表(通过eb_user_sign.task_id = eb_article.task_id) - 返回字段增加:
videoUrl: 从eb_article.video_url获取videoStatus: 从eb_article.status_task获取 (0=生成中, 1=完成, 2=失败)taskId: 已有enableAIVideo: 已有
3. 更新打卡详情接口
[ToolCheckinServiceImpl.getDetail()](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCheckinServiceImpl.java)
- 增加返回
videoUrl和videoStatus字段
4. 完善KieAI回调处理
[KieAIController.handleCallback()](msh_crmeb_22/crmeb-front/src/main/java/com/zbkj/front/controller/KieAIController.java)
- 当前只记录日志,需改为:
- 解析回调参数获取
taskId,state,result_urls - 根据
taskId更新eb_article表:status_task = 1(成功) 或2(失败)video_url = result_urls[0]
- 解析回调参数获取
参考 models-integration 项目的实现:
articleMapper.updateVideoUrlAndTaskStatusByTaskId(taskId, videoUrl, statusTask);
5. 更新社区列表接口
[ToolCommunityServiceImpl.getList()](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCommunityServiceImpl.java)
- 当前已关联
eb_user_sign获取mealType - 同样方式关联获取
enable_ai_video和task_id - 通过
task_id关联eb_article获取video_url - 返回字段增加:
hasVideo: boolean (是否有视频)videoUrl: 视频地址enableAIVideo: 是否启用了视频生成
6. 更新V2CommunityPost实体类
[V2CommunityPost.java](msh_crmeb_22/crmeb-common/src/main/java/com/zbkj/common/model/tool/V2CommunityPost.java)
- 确认是否已有
videoUrl字段,若无则添加:
@ApiModelProperty(value = "视频地址")
private String videoUrl;
前端改动
1. 饮食记录页面增加视频状态显示
[dietary-records.vue](msh_single_uniapp/pages/tool/dietary-records.vue)
显示逻辑:
- 列表项增加视频状态角标:
- 有
videoUrl: 显示"📹视频"标记 - 有
taskId但无videoUrl: 显示"⏳生成中"或进度条 videoStatus = 2: 显示"❌生成失败"
- 有
轮询逻辑:
data() {
return {
pollingTasks: [], // 需要轮询的任务列表
pollingTimer: null
}
},
methods: {
// 启动轮询
startPolling() {
if (this.pollingTimer) return;
this.pollingTimer = setInterval(() => {
this.pollVideoTasks();
}, 5000); // 每5秒查询一次
},
// 轮询视频任务状态
async pollVideoTasks() {
const tasksToCheck = this.recordList.filter(item =>
item.enableAIVideo && item.taskId && !item.videoUrl
);
if (tasksToCheck.length === 0) {
this.stopPolling();
return;
}
for (const task of tasksToCheck) {
try {
const res = await getVideoTaskStatus(task.taskId);
if (res.code === 200 && res.data) {
const status = res.data.state;
if (status === 'success') {
// 刷新列表以获取最新视频URL
this.loadRecordList();
break;
} else if (status === 'failed') {
// 标记失败
task.videoStatus = 2;
}
}
} catch (error) {
console.error('查询视频任务失败:', error);
}
}
},
// 停止轮询
stopPolling() {
if (this.pollingTimer) {
clearInterval(this.pollingTimer);
this.pollingTimer = null;
}
}
}
生命周期:
onLoad() {
this.loadRecordList();
this.startPolling();
},
onUnload() {
this.stopPolling();
},
onShow() {
// 从其他页面返回时重新检查
this.loadRecordList();
this.startPolling();
}
模板增加视频状态标记:
<view class="video-status-badge" v-if="item.enableAIVideo">
<text v-if="item.videoUrl" class="status-success">📹 有视频</text>
<text v-else-if="item.videoStatus === 2" class="status-failed">❌ 生成失败</text>
<text v-else class="status-pending">⏳ 生成中</text>
</view>
2. 打卡详情页增加视频播放
[checkin-detail.vue](msh_single_uniapp/pages/tool/checkin-detail.vue)
数据结构更新:
data() {
return {
checkinData: {
// ...现有字段
videoUrl: '',
taskId: '',
enableAIVideo: false,
videoStatus: 0
}
}
}
模板增加视频播放器:
<!-- 在图片轮播区域下方或上方增加 -->
<view class="video-section" v-if="checkinData.videoUrl">
<view class="video-header">
<text class="video-icon">🎬</text>
<text class="video-title">打卡视频</text>
</view>
<video
class="checkin-video"
:src="checkinData.videoUrl"
controls
:show-center-play-btn="true"
:enable-progress-gesture="true"
object-fit="contain"
></video>
</view>
<!-- 视频生成中状态 -->
<view class="video-generating" v-else-if="checkinData.enableAIVideo && checkinData.taskId">
<text class="generating-icon">⏳</text>
<text class="generating-text">视频生成中,请稍后...</text>
</view>
formatCheckinData更新:
formatCheckinData(item) {
// ...现有逻辑
this.checkinData = {
// ...现有字段
videoUrl: item.videoUrl || '',
taskId: item.taskId || '',
enableAIVideo: item.enableAIVideo || false,
videoStatus: item.videoStatus || 0
};
}
3. 社区页面显示视频标记
[community.vue](msh_single_uniapp/pages/tool_main/community.vue)
formatPostList更新:
formatPostList(list) {
return list.map(item => {
// ...现有逻辑
return {
// ...现有字段
hasVideo: item.hasVideo || false,
videoUrl: item.videoUrl || '',
enableAIVideo: item.enableAIVideo || false
};
});
}
卡片增加视频标记:
<view class="post-card">
<!-- 现有内容 -->
<!-- 视频标记 -->
<view class="video-badge" v-if="item.hasVideo || item.videoUrl">
<text class="badge-icon">🎬</text>
<text class="badge-text">视频</text>
</view>
</view>
样式:
.video-badge {
position: absolute;
top: 8px;
right: 8px;
background: rgba(0, 0, 0, 0.6);
border-radius: 12px;
padding: 4px 10px;
display: flex;
align-items: center;
gap: 4px;
.badge-icon {
font-size: 14px;
}
.badge-text {
font-size: 12px;
color: #fff;
}
}
4. 新增API方法
[tool.js](msh_single_uniapp/api/tool.js)
/**
* 查询视频任务状态
* @param {String} taskId - 任务ID
*/
export function getVideoTaskStatus(taskId) {
return request.get(`kieai/video/task/${taskId}`, {
apiKey: 'your-api-key' // 从配置获取
});
}
关键技术细节
1. 轮询策略
- 触发条件: 列表中存在
enableAIVideo=true且taskId不为空但videoUrl为空的记录 - 轮询间隔: 5秒
- 停止条件:
- 所有任务都有
videoUrl或videoStatus=2 - 页面销毁(onUnload)
- 超过最大轮询次数(如60次,即5分钟)
- 所有任务都有
- 优化: 只轮询当前可见列表中的任务,避免全量查询
2. 视频播放兼容性
- 使用uni-app的
<video>组件,支持小程序、H5、APP - 视频格式要求: mp4 (KieAI返回格式)
- 封面图: 可使用打卡的第一张照片作为视频封面
3. 错误处理
- 视频生成失败: 显示失败状态,允许用户重新生成或查看原因
- 网络错误: 轮询失败时静默处理,不影响用户浏览
- 回调失败: 前端轮询作为兜底方案
文件清单
后端Java文件
| 文件 | 改动类型 | 说明 |
|---|---|---|
[ToolCheckinServiceImpl.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCheckinServiceImpl.java) |
修改 | submit增加article创建,getList/getDetail增加video字段 |
[KieAIController.java](msh_crmeb_22/crmeb-front/src/main/java/com/zbkj/front/controller/KieAIController.java) |
修改 | 完善回调处理更新article表 |
[ToolKieAIServiceImpl.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolKieAIServiceImpl.java) |
修改 | handleTaskCallback增加更新article逻辑 |
[ToolCommunityServiceImpl.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCommunityServiceImpl.java) |
修改 | getList关联video信息 |
[V2CommunityPost.java](msh_crmeb_22/crmeb-common/src/main/java/com/zbkj/common/model/tool/V2CommunityPost.java) |
检查/修改 | 确认有videoUrl字段 |
[ArticleDao.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/dao/ArticleDao.java) |
新增方法 | 增加updateVideoUrlByTaskId方法 |
前端Vue文件
| 文件 | 改动类型 | 说明 |
|---|---|---|
[dietary-records.vue](msh_single_uniapp/pages/tool/dietary-records.vue) |
修改 | 增加视频状态显示和轮询逻辑 |
[checkin-detail.vue](msh_single_uniapp/pages/tool/checkin-detail.vue) |
修改 | 增加视频播放器 |
[community.vue](msh_single_uniapp/pages/tool_main/community.vue) |
修改 | 增加视频标记 |
[tool.js](msh_single_uniapp/api/tool.js) |
新增方法 | 增加getVideoTaskStatus API |
测试要点
- 打卡流程: 勾选生成视频 → 发布 → 验证taskId保存 → 验证article记录创建
- 状态轮询: 饮食记录页面显示"生成中" → 等待KieAI完成 → 自动更新显示"有视频"
- 视频播放: 打卡详情查看视频 → 播放正常 → 控制条功能正常
- 社区显示: 最新tab显示有视频标记的帖子 → 点击查看带视频
- 异常处理: 视频生成失败 → 显示失败状态 → 不影响打卡记录查看
- 回调机制: KieAI回调成功 → article表正确更新 → 前端轮询立即获取到结果