feat: 完善视频学习进度缓存

完善新手导航和三大创作模块的视频完成缓存、未完成提示与学习进度计算,确保进度按实际学习资源完成情况更新。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhongyidianandClaude Opus 4.7 committed 2026-05-11 09:05:29 +08:00
1 parent 1f8723aabd
commit 6f289959be
63 files changed
+3139 -1126

No files matched your search

+82 -21
View File
@@ -1,41 +1,102 @@
import { moduleStepMap } from '@/config/moduleStepMap'
type ProductionModuleKey = 'vlog' | 'interview' | 'film'
export type ProductionModuleKey = 'vlog' | 'interview' | 'film'
type StepKey = 1 | 2 | 3
const countViewedRoutes = (routes: readonly string[], viewed: Record<string, boolean>) => {
const countViewedRoutes = (
routes: readonly string[],
viewed: Record<string, boolean>,
) => {
if (routes.length === 0) return 0
return routes.filter(routeName => viewed[routeName]).length
return routes.filter((routeName) => viewed[routeName]).length
}
const getStepProgress = (routes: readonly string[], viewed: Record<string, boolean>) => {
const getStepProgress = (
routes: readonly string[],
viewed: Record<string, boolean>,
) => {
if (routes.length === 0) return 0
return countViewedRoutes(routes, viewed) / routes.length
}
const interpolate = (start: number, end: number, progress: number) =>
start + (end - start) * progress
const WORK_COMPLETION_KEYS = ['case', 'profession', 'idea'] as const
const getWorkProgress = (workVideosWatched: Record<string, boolean>) =>
countViewedRoutes(WORK_COMPLETION_KEYS, workVideosWatched) /
WORK_COMPLETION_KEYS.length
export const getProductionModuleProgress = (
moduleKey: ProductionModuleKey,
viewed: Record<string, boolean>
viewed: Record<string, boolean>,
workVideosWatched: Record<string, boolean> = {},
) => {
const stepRoutes = moduleStepMap[moduleKey]
const hasAnyViewed = Object.values(stepRoutes).some(routes =>
routes.some(routeName => viewed[routeName])
)
const taskProgress = getWorkProgress(workVideosWatched) * 20
const stepProgress = (step: StepKey) =>
getStepProgress(stepRoutes[step], viewed)
const step1Progress = stepProgress(1) * 22
const step2Progress = stepProgress(2) * 22
const step3Progress = stepProgress(3) * 21
const progress = taskProgress + step1Progress + step2Progress + step3Progress
if (!hasAnyViewed) return 0
if (
progress >= 85 &&
step1Progress === 22 &&
step2Progress === 22 &&
step3Progress === 21
) {
return 100
}
const stepProgress = (step: StepKey) => getStepProgress(stepRoutes[step], viewed)
const step1Progress = stepProgress(1)
const step2Progress = stepProgress(2)
const step3Progress = stepProgress(3)
if (step1Progress < 1) return Math.round(interpolate(20, 42, step1Progress))
if (step2Progress < 1) return Math.round(interpolate(42, 64, step2Progress))
if (step3Progress < 1) return Math.round(interpolate(64, 85, step3Progress))
return 100
return Math.round(progress)
}
const BASIC_ELEMENTS_VIDEO_KEYS = [
'basic-composition:step1',
'basic-composition:step2',
'basic-light:step2',
'basic-light:step3',
'basic-light:step4',
'basic-camera-movement:step2',
'basic-camera-movement:step3',
'basic-shooting-skills:step2',
'basic-shooting-skills:step3',
'basic-shooting-skills:step4',
'basic-shooting-skills:step5',
'basic-shooting-skills:step6',
'basic-shooting-skills:step7',
'basic-short-video-editing-skills:step2',
'basic-short-video-editing-skills:step3',
'basic-short-video-editing-skills:step4',
'basic-short-video-editing-skills:step5',
'basic-short-video-editing-skills:step6',
'basic-short-video-editing-skills:step7',
'basic-short-video-editing-skills:step8',
'basic-short-video-editing-skills:step9',
'basic-short-video-editing-skills:step10',
'basic-short-video-editing-skills:step11',
] as const
export const getBasicElementsProgress = (
unlockProgress: number,
isUnlocked: boolean,
learningVideosWatched: Record<string, boolean> = {},
) => {
if (isUnlocked) return 100
const watchedProgress =
(countViewedRoutes(BASIC_ELEMENTS_VIDEO_KEYS, learningVideosWatched) /
BASIC_ELEMENTS_VIDEO_KEYS.length) *
100
return Math.round(
Math.max(0, Math.min(100, Math.max(unlockProgress, watchedProgress))),
)
}
export const getOverallStudyProgress = (progresses: readonly number[]) => {
if (progresses.length === 0) return 0
const total = progresses.reduce((sum, progress) => sum + progress, 0)
return Math.round(total / progresses.length)
}