完善新手导航和三大创作模块的视频完成缓存、未完成提示与学习进度计算,确保进度按实际学习资源完成情况更新。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
import { moduleStepMap } from '@/config/moduleStepMap'
|
|
|
|
export type ProductionModuleKey = 'vlog' | 'interview' | 'film'
|
|
|
|
type StepKey = 1 | 2 | 3
|
|
|
|
const countViewedRoutes = (
|
|
routes: readonly string[],
|
|
viewed: Record<string, boolean>,
|
|
) => {
|
|
if (routes.length === 0) return 0
|
|
return routes.filter((routeName) => viewed[routeName]).length
|
|
}
|
|
|
|
const getStepProgress = (
|
|
routes: readonly string[],
|
|
viewed: Record<string, boolean>,
|
|
) => {
|
|
if (routes.length === 0) return 0
|
|
return countViewedRoutes(routes, viewed) / routes.length
|
|
}
|
|
|
|
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>,
|
|
workVideosWatched: Record<string, boolean> = {},
|
|
) => {
|
|
const stepRoutes = moduleStepMap[moduleKey]
|
|
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 (
|
|
progress >= 85 &&
|
|
step1Progress === 22 &&
|
|
step2Progress === 22 &&
|
|
step3Progress === 21
|
|
) {
|
|
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)
|
|
}
|