完善新手导航和三大创作模块的视频完成缓存、未完成提示与学习进度计算,确保进度按实际学习资源完成情况更新。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
123 lines
3.4 KiB
Vue
123 lines
3.4 KiB
Vue
<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>
|