Files
super_video/src/views/interview/practice/my-notes/index.vue
T
zhongyidianandClaude Opus 4.7 3e258b87d9 feat: 完善课程学习与技能树体验
完善课程资源、学习进度与技能树解锁体验,统一视频播放与引导相关交互。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:30:18 +08:00

169 lines
4.6 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 { computed, onBeforeUnmount, ref } from 'vue'
import { useRouter } from 'vue-router'
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import { ImgButton } from '@/components/Button'
import PracticeRatingModal, {
type PracticeRatingItem,
} from '@/components/PracticeRatingModal'
import { useInterviewStore } from '@/stores/modules/interview'
const router = useRouter()
const store = useInterviewStore()
type PracticeRatingScores = Record<string, number>
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 noteContent = ref<string>(store.practiceNoteContent)
/** 保存弹窗 */
const showModal = ref<boolean>(false)
const showSuccess = ref<boolean>(false)
let successTimer: number | undefined
/** 返回上一页 */
const handleBack = (): void => {
router.back()
}
const disabled = computed<boolean>(() => noteContent.value.trim() === '')
/** 评估项目列表 */
const defaultEvaluationItems: PracticeRatingItem[] = [
{
title: '人物表达',
description: '能清晰介绍人物身份、特点或故事,让观众认识人物',
score: 0,
},
{
title: '素材拍摄',
description: '画面包含必要人物镜头、环境镜头与细节素材,内容较丰富',
score: 0,
},
{
title: '镜头语言',
description: '合理使用移动镜头、特写、跟拍等方式增强表现力',
score: 0,
},
{
title: '剪辑结构',
description: '结构完整清晰,段落顺畅,内容有起承转合',
score: 0,
},
{
title: '音画关系',
description: '画面与配音/环境音基本匹配,能辅助理解内容',
score: 0,
},
{
title: '综合观感',
description: '作品完整,有真实感与感染力,具备观看吸引力',
score: 0,
},
]
const evaluationItems = ref<PracticeRatingItem[]>(
applyScores(defaultEvaluationItems, store.practiceSelfEvaluationScores),
)
const handleSave = (): void => {
const content = noteContent.value.trim()
if (!content) return
store.setPracticeNoteContent(noteContent.value)
store.markViewed('InterviewPractice')
showSuccess.value = true
window.clearTimeout(successTimer)
successTimer = window.setTimeout(() => {
showSuccess.value = false
}, 1500)
}
const handleSaveEvaluation = (items: PracticeRatingItem[]): void => {
store.setPracticeSelfEvaluationScores(toScores(items))
}
onBeforeUnmount(() => {
window.clearTimeout(successTimer)
})
</script>
<template>
<div
class="w-full h-full bg-no-repeat bg-cover px-8 pt-[400px]"
:style="{
backgroundImage: getBackgroundImage('interview/practice/我的创作笔记'),
}"
>
<ImgButton
class="absolute top-0 right-0"
:image="IMAGE_PATHS.COMPONENTS.CLOSE"
@click="handleBack"
/>
<textarea
v-model="noteContent"
class="w-full h-[300px]"
name="myNotes"
placeholder="点击输入创作笔记"
></textarea>
<div
v-if="showSuccess"
class="absolute left-1/2 top-1/2 z-[100] -translate-x-1/2 -translate-y-1/2 rounded-2xl bg-black/70 px-16 py-8 text-5xl font-bold text-white"
>
提交成功
</div>
<div class="absolute bottom-24 left-1/2 -translate-x-1/2 flex gap-60">
<ImgButton
image="vlog/practice/保存"
:disabled="disabled"
@click="handleSave"
/>
<ImgButton
image="vlog/practice/自评"
:disabled="disabled"
@click="showModal = true"
/>
</div>
<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>
<style scoped>
textarea {
border: none;
outline: none;
resize: none;
font-size: 36px;
background-color: transparent;
}
textarea::placeholder {
color: #5d5b5b;
font-weight: 700;
}
</style>