Files
super_video/src/views/interview/practice/video/index.vue
T
zhongyidianandClaude Opus 4.7 6f289959be feat: 完善视频学习进度缓存
完善新手导航和三大创作模块的视频完成缓存、未完成提示与学习进度计算,确保进度按实际学习资源完成情况更新。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:05:29 +08:00

123 lines
3.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts" setup>
import { useRouter } from 'vue-router'
import { Video } from '@/components'
import { ImgButton } from '@/components/Button'
import PracticeRatingModal, {
type PracticeRatingItem,
} from '@/components/PracticeRatingModal'
import { IMAGE_PATHS, getPublicPath } from '@/utils'
import { useInterviewStore } from '@/stores/modules/interview'
import { computed, ref } from 'vue'
const router = useRouter()
const store = useInterviewStore()
const props = defineProps({
path: {
type: String,
required: true,
},
})
type PracticeRatingScores = Record<string, number>
const workKey = computed<string>(() => decodeURIComponent(props.path))
const applyScores = (
items: PracticeRatingItem[],
scores: PracticeRatingScores,
): PracticeRatingItem[] =>
items.map((item) => ({
...item,
score: scores[item.title] ?? item.score,
}))
const toScores = (items: PracticeRatingItem[]): PracticeRatingScores =>
Object.fromEntries(items.map((item) => [item.title, item.score]))
/** 评估项目列表 */
const defaultEvaluationItems: PracticeRatingItem[] = [
{
title: '人物表达',
description: '能清晰介绍人物身份、特点或故事,让观众认识人物',
score: 4,
},
{
title: '素材拍摄',
description: '画面包含必要人物镜头、环境镜头与细节素材,内容较丰富',
score: 2,
},
{
title: '镜头语言',
description: '合理使用移动镜头、特写、跟拍等方式增强表现力',
score: 5,
},
{
title: '剪辑结构',
description: '结构完整清晰,段落顺畅,内容有起承转合',
score: 0,
},
{
title: '音画关系',
description: '画面与配音/环境音基本匹配,能辅助理解内容',
score: 5,
},
{
title: '综合观感',
description: '作品完整,有真实感与感染力,具备观看吸引力',
score: 5,
},
]
const evaluationItems = ref<PracticeRatingItem[]>(
applyScores(
defaultEvaluationItems,
store.getPracticeWorkRating(workKey.value),
),
)
const handleSaveEvaluation = (items: PracticeRatingItem[]): void => {
store.setPracticeWorkRating(workKey.value, toScores(items))
}
/** 保存弹窗 */
const showModal = ref<boolean>(false)
/** 返回上一页 */
const handleBack = (): void => {
router.back()
}
</script>
<template>
<div class="relative h-full">
<ImgButton
class="absolute right-0 top-0 z-50"
:image="IMAGE_PATHS.COMPONENTS.BACK"
@click="handleBack"
/>
<ImgButton
class="absolute right-0 bottom-10 z-50"
image="vlog/practice/评分"
@click="showModal = true"
/>
<Video
:src="getPublicPath(decodeURIComponent(props.path))"
:volume="1"
:muted="false"
:controls="true"
:loop="false"
/>
<PracticeRatingModal
:visible="showModal"
v-model:items="evaluationItems"
background-image="interview/practice/人物访谈短片创作-作品评分表"
top-tip="评分时要关注6个维度哦~分别是人物表达、素材拍摄、镜头语言、剪辑结构、音画关系、综合观感每个维度满分5分,能打1-5分,记得对照作品表现来打分呀~"
bottom-tip="己评价的实战作品,从封面入口就能直接看到具体评分!打了多少分一目了然,不用再点进详情页翻找啦~"
@save="handleSaveEvaluation"
@close="showModal = false"
/>
</div>
</template>