forked from zhongyidian/super_video
feat: 完善访谈与vlog模块页面,重组设备与图片公共资源,新增音频管理与一班对接工具
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c4c9be9d35
commit
fc9633f371
159 files changed
+4823
-2535
No files matched your search
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { Video } from '@/components'
|
||||
import { IMAGE_PATHS, getPublicPath } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const playing = ref(false)
|
||||
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden bg-black">
|
||||
<Video
|
||||
class="w-full h-full"
|
||||
:src="getPublicPath('video/editing/yingxiao_batch.mp4')"
|
||||
v-model="playing"
|
||||
:muted="false"
|
||||
:volume="1"
|
||||
:controls="true"
|
||||
:hideNativeControls="true"
|
||||
/>
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="handleBack"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script lang="ts" setup>
|
||||
import { IMAGE_PATHS, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden">
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="back"
|
||||
/>
|
||||
<img class="absolute inset-0" :src="getStaticImage('img/背景.png')" alt="" />
|
||||
|
||||
<img class="absolute top-5 z-10" :src="getStaticImage('img/调色-标题.png')" alt="" />
|
||||
|
||||
<div class="relative h-full pt-28 overflow-y-scroll">
|
||||
<img :src="getStaticImage('interview/img/调色实践.png')" alt="" />
|
||||
<ImgButton
|
||||
class="absolute top-[1180px] left-[51.5%] -translate-x-1/2"
|
||||
image="after-editing/color/调色实践"
|
||||
@click="router.push({ name: 'InterviewColor' })"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<GuideSteps :visible="true" position-offset-y="85%">
|
||||
<GuideStepsItem>这份长图文干货满满,滚动鼠标查看完整内容吧</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</template>
|
||||
@@ -5,7 +5,6 @@ import { ImgButton } from '@/components/Button'
|
||||
import { Overlay } from '@/components/Overlay'
|
||||
import { ref } from 'vue'
|
||||
import ImageFilter from '@/components/ImageFilter/ImageFilter.vue'
|
||||
import { useInterviewStore } from '@/stores'
|
||||
|
||||
const selected = ref<number | undefined>(1)
|
||||
const btnState = ref(false)
|
||||
@@ -25,11 +24,11 @@ const adjustmentList = ref([
|
||||
|
||||
const colorBarList = ref([
|
||||
{ id: 1, name: '原图', filter: 'none' },
|
||||
{ id: 2, name: '暖阳', filter: 'sepia(0.3) contrast(1.1) brightness(1.1)' },
|
||||
{ id: 2, name: '暖阳', filter: 'saturate(2.5) contrast(2.1)' },
|
||||
{ id: 3, name: '冷调', filter: 'hue-rotate(180deg) contrast(0.9)' },
|
||||
{ id: 4, name: '复古', filter: 'sepia(0.6) contrast(1.2) brightness(0.9)' },
|
||||
{ id: 5, name: '黑白', filter: 'grayscale(1)' },
|
||||
{ id: 6, name: '鲜艳', filter: 'saturate(1.5) contrast(1.1)' }
|
||||
{ id: 6, name: '鲜艳', filter: 'sepia(0.1) saturate(2.5) contrast(2.1) brightness(1)' }
|
||||
])
|
||||
|
||||
// 获取指定参数的值
|
||||
@@ -117,10 +116,8 @@ const handleTryOther = () => {
|
||||
}
|
||||
|
||||
const handleFinish = () => {
|
||||
useInterviewStore().setInterviewUnlockProgress(4)
|
||||
|
||||
router.push({
|
||||
name: 'Interview'
|
||||
name: 'Film'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -157,7 +154,7 @@ const changeColor = (item: { id: number; name: string }) => {
|
||||
class="relative w-[1273px] h-[732px] bg-no-repeat bg-cover mt-10 p-2 pb-[26px] pr-[26px]"
|
||||
:style="{ backgroundImage: getBackgroundImage('after-editing/color/图片框.png') }"
|
||||
>
|
||||
<ImageFilter ref="imageFilterRef" :src="getStaticImage('after-editing/color/图片')" />
|
||||
<ImageFilter ref="imageFilterRef" :src="getStaticImage('after-editing/color/film_img')" />
|
||||
|
||||
<!-- 开启对比 -->
|
||||
<ImgButton
|
||||
@@ -258,6 +255,14 @@ const changeColor = (item: { id: number; name: string }) => {
|
||||
<!-- title -->
|
||||
<img class="absolute top-0 left-0" :src="getStaticImage('after-editing/color/标题-调色实践')" />
|
||||
|
||||
<!-- 回到顶部按钮 - 最后一页显示 -->
|
||||
<p class="absolute left-40 bottom-10 flex items-center">
|
||||
<img class="rotate-0 w-28 mr-4" src="@/assets/svg/deng.svg" />
|
||||
<span class="text-white text-2xl font-bold">
|
||||
推荐参数:亮度 90、对比度 100、饱和度 100、曝光 - 90、色调 0、锐化 100、模糊 0
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<!-- 保存图片弹窗 -->
|
||||
<Overlay :visible="showModal" @close="handleModalClose">
|
||||
<div class="relative w-[1000px] h-[600px] flex items-center justify-center">
|
||||
|
||||
@@ -1,69 +1,63 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import ImgButton from '@/components/Button/ImgButton.vue'
|
||||
// import { GuideSteps } from '@/components/Guide'
|
||||
import { StepNavigation } from '@/components/Guide'
|
||||
import { IMAGE_PATHS } from '@/utils'
|
||||
import { Video } from '@/components'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 导入视频文件
|
||||
import videoBasic from '/video/vlog_zhizuobianjiaojing_jichujianji.mp4'
|
||||
import videoSoundeffect from '/video/vlog_renwuqujing_yingxiaochuli.mp4'
|
||||
import videoPackaging from '/video/vlog_renwuqujing_baozhuang.mp4'
|
||||
import videoCopyright from '/video/vlog_renwuqujing_banquanguifan.mp4'
|
||||
const videoList = [videoBasic, videoSoundeffect, videoPackaging, videoCopyright]
|
||||
|
||||
const videoRef = ref<HTMLVideoElement>()
|
||||
const navigationSteps = [
|
||||
{
|
||||
id: 'step1',
|
||||
label: '后期制作',
|
||||
content: '声画剪辑流程',
|
||||
type: 'post' as const
|
||||
},
|
||||
{
|
||||
id: 'step2',
|
||||
label: '后期制作',
|
||||
content: 'J-cut/L-cut运用',
|
||||
type: 'post' as const
|
||||
},
|
||||
{
|
||||
id: 'step3',
|
||||
label: '后期制作',
|
||||
content: '【Q3】节奏剪辑技巧',
|
||||
type: 'post' as const
|
||||
}
|
||||
]
|
||||
|
||||
const currentVideoIndex = ref(0)
|
||||
const playing = ref(false)
|
||||
const showStepNavigation = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
// 确保视频元素加载并自动播放
|
||||
if (videoRef.value) {
|
||||
videoRef.value.src = videoList[currentVideoIndex.value]
|
||||
videoRef.value.load()
|
||||
|
||||
// 尝试自动播放
|
||||
const playPromise = videoRef.value.play()
|
||||
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(error => {
|
||||
// 自动播放失败,可能是浏览器策略阻止,需要用户交互
|
||||
console.log('自动播放被阻止:', error)
|
||||
})
|
||||
}
|
||||
|
||||
// 监听视频结束事件
|
||||
videoRef.value.addEventListener('ended', playNextVideo)
|
||||
}
|
||||
})
|
||||
|
||||
// 播放下一个视频
|
||||
const playNextVideo = () => {
|
||||
if (currentVideoIndex.value < videoList.length - 1) {
|
||||
currentVideoIndex.value++
|
||||
if (videoRef.value) {
|
||||
videoRef.value.src = videoList[currentVideoIndex.value]
|
||||
videoRef.value.load()
|
||||
|
||||
// 自动播放下一个视频
|
||||
const playPromise = videoRef.value.play()
|
||||
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(error => {
|
||||
console.log('自动播放被阻止:', error)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (currentVideoIndex.value >= videoList.length - 1) {
|
||||
playing.value = false
|
||||
return
|
||||
}
|
||||
|
||||
currentVideoIndex.value++
|
||||
nextTick(() => {
|
||||
playing.value = true
|
||||
})
|
||||
}
|
||||
|
||||
// 监听当前视频索引变化
|
||||
watch(currentVideoIndex, newIndex => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.src = videoList[newIndex]
|
||||
videoRef.value.load()
|
||||
}
|
||||
})
|
||||
const handleStepClick = (index: number) => {
|
||||
currentVideoIndex.value = index
|
||||
// showStepNavigation.value = false
|
||||
nextTick(() => {
|
||||
playing.value = true
|
||||
})
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
router.back()
|
||||
@@ -71,29 +65,40 @@ const handleClose = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!--使用动态绑定和ref-->
|
||||
<video
|
||||
ref="videoRef"
|
||||
<div class="relative w-full h-full overflow-hidden bg-black">
|
||||
<Video
|
||||
:src="videoList[currentVideoIndex]"
|
||||
type="video/mp4"
|
||||
controls
|
||||
preload="auto"
|
||||
class="video-player"
|
||||
autoplay
|
||||
></video>
|
||||
v-model="playing"
|
||||
:muted="false"
|
||||
:volume="1"
|
||||
@ended="playNextVideo"
|
||||
/>
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-10"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="handleClose"
|
||||
/>
|
||||
<button
|
||||
class="absolute right-4 top-1/2 z-10 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full bg-blue-500/80 text-white transition-all duration-200 hover:bg-blue-500"
|
||||
title="步骤导航"
|
||||
@click="showStepNavigation = true"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M3 4H17M3 8H17M3 12H17M3 16H17"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<StepNavigation
|
||||
:visible="showStepNavigation"
|
||||
:background-image="''"
|
||||
:steps="navigationSteps"
|
||||
:current-step-index="currentVideoIndex"
|
||||
@step-click="handleStepClick"
|
||||
@close="showStepNavigation = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.video-player {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { Video } from '@/components'
|
||||
import { IMAGE_PATHS, getPublicPath } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const playing = ref(false)
|
||||
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden bg-black">
|
||||
<Video
|
||||
class="w-full h-full"
|
||||
:src="getPublicPath('video/on-site/dygmk_zlsxhbj.mp4')"
|
||||
v-model="playing"
|
||||
:muted="false"
|
||||
:volume="1"
|
||||
:controls="true"
|
||||
:hideNativeControls="true"
|
||||
/>
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="handleBack"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -3,7 +3,8 @@ import { getStaticImage } from '@/utils'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getBackgroundImage } from '@/utils'
|
||||
defineOptions({ name: 'VlogMenu' })
|
||||
import { useInterviewStore } from '@/stores'
|
||||
defineOptions({ name: 'InterviewMenu' })
|
||||
|
||||
/**
|
||||
* 菜单项 (前期准备、中期拍摄、后期剪辑)
|
||||
@@ -33,13 +34,13 @@ const menuItems = ref([
|
||||
label: '资源筹备',
|
||||
routeName: 'InterviewResource',
|
||||
parentValue: 1,
|
||||
disabled: true
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '创意构想',
|
||||
routeName: 'InterviewCreative',
|
||||
parentValue: 1,
|
||||
disabled: true
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '脚本撰写',
|
||||
@@ -51,32 +52,32 @@ const menuItems = ref([
|
||||
label: '分镜制作',
|
||||
routeName: 'InterviewStoryboard',
|
||||
parentValue: 1,
|
||||
disabled: true
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '设备准备',
|
||||
routeName: 'InterviewMidtermEquipment',
|
||||
routeName: 'InterviewEquipment',
|
||||
parentValue: 2,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '实地取景',
|
||||
routeName: 'InterviewMidtermShooting',
|
||||
routeName: 'InterviewShooting',
|
||||
parentValue: 2,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '现场拍摄',
|
||||
routeName: 'Interview现场拍摄',
|
||||
routeName: 'InterviewOnsiteShooting',
|
||||
parentValue: 2,
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
label: '素材管理',
|
||||
routeName: 'Interview素材管理',
|
||||
parentValue: 3,
|
||||
disabled: true
|
||||
disabled: false
|
||||
},
|
||||
// {
|
||||
// label: '素材管理',
|
||||
// routeName: 'Interview素材管理',
|
||||
// parentValue: 3,
|
||||
// disabled: true
|
||||
// },
|
||||
{
|
||||
label: '剪辑',
|
||||
routeName: 'InterviewEditing',
|
||||
@@ -85,15 +86,21 @@ const menuItems = ref([
|
||||
},
|
||||
{
|
||||
label: '调色',
|
||||
routeName: 'InterviewColor',
|
||||
routeName: 'InterviewColorPractice',
|
||||
parentValue: 3,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '音频',
|
||||
routeName: 'InterviewAudio',
|
||||
parentValue: 3,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: '导出发布',
|
||||
routeName: 'Interview导出发布',
|
||||
routeName: 'InterviewExportPublish',
|
||||
parentValue: 3,
|
||||
disabled: true
|
||||
disabled: false
|
||||
}
|
||||
])
|
||||
|
||||
@@ -102,12 +109,19 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
const interview = useInterviewStore()
|
||||
|
||||
const isViewed = (routeName: string) => {
|
||||
return interview.viewed?.[routeName] === true
|
||||
}
|
||||
|
||||
const currentParentValue = computed<number>(() => {
|
||||
return props.currentStep
|
||||
}) // 当前选中的父级菜单项
|
||||
|
||||
const currentItemValue = ref<string>('') // 当前选中的子级菜单项
|
||||
const currentItemValue = computed<string>(() => {
|
||||
return router.currentRoute.value.name?.toString() ?? ''
|
||||
})
|
||||
|
||||
const getMenuItems = computed(() => {
|
||||
return menuItems.value.filter(item => item.parentValue === currentParentValue.value)
|
||||
@@ -115,7 +129,6 @@ const getMenuItems = computed(() => {
|
||||
|
||||
const handleItemClick = (item: { routeName: string; disabled: boolean }) => {
|
||||
if (item.disabled) return
|
||||
currentItemValue.value = item.routeName
|
||||
router.push({ name: item.routeName })
|
||||
}
|
||||
</script>
|
||||
@@ -124,9 +137,9 @@ const handleItemClick = (item: { routeName: string; disabled: boolean }) => {
|
||||
<div class="absolute left-20 top-0 bottom-0 w-[520px] pt-28" v-if="currentStep">
|
||||
<!-- 分类名称 -->
|
||||
<div class="absolute top-3 left-24 flex items-center space-x-2">
|
||||
<span class="text-4xl text-[#fbbf24] font-black">{{
|
||||
category[currentParentValue - 1].label
|
||||
}}</span>
|
||||
<span class="text-4xl text-[#fbbf24] font-black">
|
||||
{{ category[currentParentValue - 1].label }}
|
||||
</span>
|
||||
<img class="filter-blue" :src="category[currentParentValue - 1].icon" alt="" />
|
||||
</div>
|
||||
<!-- 背景图片 -->
|
||||
@@ -150,7 +163,14 @@ const handleItemClick = (item: { routeName: string; disabled: boolean }) => {
|
||||
class="absolute inset-0 bg-cover bg-center bg-no-repeat opacity-0 group-hover:opacity-100 transition-opacity duration-300"
|
||||
:style="{ backgroundImage: getBackgroundImage('components/menu-hover.png') }"
|
||||
></div>
|
||||
<span :class="[!item.disabled ? 'menu-glow-text' : '']">{{ item.label }}</span>
|
||||
<span class="flex items-center gap-2" :class="[!item.disabled ? 'menu-glow-text' : '']">
|
||||
<span>{{ item.label }}</span>
|
||||
<img
|
||||
:class="['w-10', isViewed(item.routeName) ? 'brightness-90' : 'brightness-50']"
|
||||
src="@/assets/images/midterm/完成.png"
|
||||
alt=""
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<script lang="ts" setup>
|
||||
import { IMAGE_PATHS, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden">
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="back"
|
||||
/>
|
||||
<img class="absolute inset-0" :src="getStaticImage('img/背景.png')" alt="" />
|
||||
|
||||
<img class="absolute top-5 z-10" :src="getStaticImage('img/创意构想-标题.png')" alt="" />
|
||||
|
||||
<div class="relative h-full pt-28 overflow-y-scroll">
|
||||
<img :src="getStaticImage('interview/img/创意构想.png')" alt="" />
|
||||
</div>
|
||||
|
||||
<GuideSteps :visible="true" position-offset-y="85%">
|
||||
<GuideStepsItem>这份长图文干货满满,滚动鼠标查看完整内容吧</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="tsx" setup>
|
||||
<script lang="tsx" name="Interview" setup>
|
||||
defineOptions({ name: 'Interview' })
|
||||
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { ProgressBar, Overlay } from '@/components'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useInterviewStore } from '@/stores'
|
||||
@@ -12,7 +13,8 @@ const router = useRouter()
|
||||
const interview = useInterviewStore()
|
||||
const visible = ref(false)
|
||||
|
||||
const currentStep = ref(interview.InterviewUnlockProgress)
|
||||
const currentStep = computed(() => interview.InterviewUnlockProgress)
|
||||
const progress = computed(() => interview.progressPercent)
|
||||
|
||||
const handleComplete = () => {
|
||||
// console.log('完成前置条件')
|
||||
@@ -21,8 +23,7 @@ const handleComplete = () => {
|
||||
}
|
||||
|
||||
const handleStepChange = (step: number) => {
|
||||
// 处理步骤变化逻辑
|
||||
currentStep.value = step
|
||||
interview.setInterviewUnlockProgress(step)
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
@@ -48,9 +49,19 @@ onMounted(() => {
|
||||
<!-- 背景图片-center -->
|
||||
<div
|
||||
class="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.VLOG.BG_CENTER) }"
|
||||
:style="{ backgroundImage: getBackgroundImage('interview/访谈背景.png') }"
|
||||
></div>
|
||||
|
||||
<!-- 关闭 -->
|
||||
<div class="absolute top-[140px] left-[calc(50%)] -translate-x-1/2">
|
||||
<div
|
||||
class="flex items-center justify-center text-white font-[1000] [text-shadow:_6px_6px_4px_#2b80c1,_6px_6px_4px_#2b80c1,_6px_6px_4px_#2b80c1,_6px_6px_4px_#2b80c1]"
|
||||
>
|
||||
<span class="text-6xl">学习进度:</span>
|
||||
<span class="text-7xl">{{ progress }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 关闭 -->
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
@@ -66,7 +77,7 @@ onMounted(() => {
|
||||
|
||||
<!-- 标题 -->
|
||||
<div class="absolute top-2 left-1/2 -translate-x-1/2">
|
||||
<ImgButton :image="IMAGE_PATHS.VLOG.TITLE" />
|
||||
<ImgButton :image="'interview/访谈-聆听与对话.png'" />
|
||||
</div>
|
||||
|
||||
<!-- 任务取景按钮 -->
|
||||
@@ -96,13 +107,20 @@ onMounted(() => {
|
||||
|
||||
<!-- 进度条 -->
|
||||
<div class="absolute left-0 bottom-0 w-full">
|
||||
<ProgressBar :current-step="currentStep" @step-change="handleStepChange" />
|
||||
<ProgressBar
|
||||
module-name="interview"
|
||||
:current-step="currentStep"
|
||||
:completed-step="interview.completedStep"
|
||||
@step-change="handleStepChange"
|
||||
/>
|
||||
</div>
|
||||
</Overlay>
|
||||
|
||||
<div class="absolute bottom-0 w-full">
|
||||
<ProgressBar
|
||||
module-name="interview"
|
||||
:current-step="currentStep"
|
||||
:completed-step="interview.completedStep"
|
||||
@complete="handleComplete"
|
||||
@step-change="handleStepChange"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="tsx" setup>
|
||||
import { getBackgroundImage, getStaticImage, IMAGE_PATHS } from '@/utils'
|
||||
import { GuideSteps, GuideStepsItem, type GuideStep } from '@/components/Guide'
|
||||
import { ref, computed } from 'vue'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
|
||||
@@ -12,38 +12,59 @@ const back = () => {
|
||||
router.back()
|
||||
}
|
||||
const steps = [
|
||||
{ id: 'step1', content: '先认识 Vlog:点击右侧「1.vlog初识」继续' },
|
||||
{ id: 'step2', content: '这是主要内容区域的边框' }
|
||||
{
|
||||
id: 'step1',
|
||||
content: '先认识 Vlog:点击右侧「1.vlog初识」继续',
|
||||
highlightSelector: '.img-switch-item--vlog'
|
||||
},
|
||||
{
|
||||
id: 'step2',
|
||||
content: '这是主要内容区域的边框',
|
||||
highlightSelector: '.work-border'
|
||||
}
|
||||
]
|
||||
const stepIndex = ref(0)
|
||||
const hiddenbar = ref(false)
|
||||
const currentIndex = ref(0) // 当前显示的图片索引
|
||||
const selectedMenuIndex = ref(0) // 当前选中的菜单项索引
|
||||
const currentIndex = ref(0)
|
||||
const selectedMenuIndex = ref(0)
|
||||
|
||||
// 菜单项数据
|
||||
const menuItems = ref([
|
||||
{ id: 'phone', name: '手机', disabled: false },
|
||||
{ id: 'phone-stand', name: '手机支架', disabled: true },
|
||||
{ id: 'bluetooth-remote', name: '蓝牙遥控器', disabled: true },
|
||||
{ id: 'stabilizer', name: '稳定器', disabled: true },
|
||||
{ id: 'props', name: '常用道具', disabled: true },
|
||||
{ id: 'phone-lens', name: '手机辅助箱头', disabled: true }
|
||||
])
|
||||
const equipmentItems = [
|
||||
{
|
||||
id: 'camera',
|
||||
name: '相机 / 摄像机 / 微单',
|
||||
productImages: [
|
||||
getStaticImage('equipment/相机产品.png'),
|
||||
getStaticImage('equipment/摄像机产品.png'),
|
||||
getStaticImage('equipment/微单产品.png')
|
||||
],
|
||||
title: getStaticImage('equipment/相机标题.png'),
|
||||
text: getStaticImage('equipment/相机内容.png')
|
||||
},
|
||||
{
|
||||
id: 'tripod',
|
||||
name: '三脚架',
|
||||
productImages: [getStaticImage('equipment/三角架产品.png')],
|
||||
title: getStaticImage('equipment/三脚架标题.png'),
|
||||
text: getStaticImage('equipment/三脚架内容.png')
|
||||
},
|
||||
{
|
||||
id: 'light',
|
||||
name: '灯光',
|
||||
productImages: [
|
||||
getStaticImage('equipment/led补光灯.png'),
|
||||
getStaticImage('equipment/环形灯产品.png')
|
||||
],
|
||||
title: getStaticImage('equipment/灯标题.png'),
|
||||
text: getStaticImage('equipment/灯内容.png')
|
||||
}
|
||||
]
|
||||
|
||||
const phoneList = ref([
|
||||
{ phoneImg: getStaticImage('equipment/设备-手机1.png') },
|
||||
{ phoneImg: getStaticImage('equipment/设备-手机2.png') }
|
||||
])
|
||||
const menuItems = ref(
|
||||
equipmentItems.map(item => ({ id: item.id, name: item.name, disabled: false }))
|
||||
)
|
||||
|
||||
const platetitleList = ref([
|
||||
{ title: getStaticImage('equipment/标题-苹果.png') },
|
||||
{ title: getStaticImage('equipment/标题-安卓小米.png') }
|
||||
])
|
||||
const currentEquipment = computed(() => equipmentItems[selectedMenuIndex.value])
|
||||
const currentProductImages = computed(() => currentEquipment.value.productImages)
|
||||
|
||||
const platetextList = ref([
|
||||
{ text: getStaticImage('equipment/内容-苹果.png') },
|
||||
{ text: getStaticImage('equipment/内容-安卓小米.png') }
|
||||
])
|
||||
const hiddenbarclick = () => {
|
||||
hiddenbar.value = !hiddenbar.value
|
||||
}
|
||||
@@ -55,11 +76,12 @@ const selectMenuItem = (index: number, item: { id: string; name: string; disable
|
||||
return
|
||||
}
|
||||
selectedMenuIndex.value = index
|
||||
currentIndex.value = 0
|
||||
}
|
||||
|
||||
// 下一张图片
|
||||
const nextPhone = () => {
|
||||
if (currentIndex.value < phoneList.value.length - 1) {
|
||||
if (currentIndex.value < currentProductImages.value.length - 1) {
|
||||
currentIndex.value++
|
||||
}
|
||||
}
|
||||
@@ -70,14 +92,6 @@ const prevPhone = () => {
|
||||
currentIndex.value--
|
||||
}
|
||||
}
|
||||
|
||||
const handleStepChange = (_step: GuideStep | null, index: number) => {
|
||||
stepIndex.value = index
|
||||
}
|
||||
|
||||
const currentHighlight = computed(() =>
|
||||
stepIndex.value === 0 ? '.img-switch-item--vlog' : '.work-border'
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<div class="equipment-index">
|
||||
@@ -139,12 +153,14 @@ const currentHighlight = computed(() =>
|
||||
<img src="@/assets/images/equipment/按钮-左滑.png" alt="" />
|
||||
</div>
|
||||
<div class="equipment-phoneImg">
|
||||
<img :src="phoneList[currentIndex].phoneImg" alt="" />
|
||||
<img :src="currentProductImages[currentIndex]" alt="" />
|
||||
</div>
|
||||
<div
|
||||
class="equipment-rightbutton"
|
||||
@click="nextPhone"
|
||||
:style="{ visibility: currentIndex < phoneList.length - 1 ? 'visible' : 'hidden' }"
|
||||
:style="{
|
||||
visibility: currentIndex < currentProductImages.length - 1 ? 'visible' : 'hidden'
|
||||
}"
|
||||
>
|
||||
<img src="@/assets/images/equipment/按钮-右滑.png" alt="" />
|
||||
</div>
|
||||
@@ -155,11 +171,11 @@ const currentHighlight = computed(() =>
|
||||
</div>
|
||||
|
||||
<div class="title">
|
||||
<img :src="platetitleList[currentIndex].title" alt="" />
|
||||
<img :src="currentEquipment.title" alt="" />
|
||||
</div>
|
||||
<div class="plate-content">
|
||||
<div class="text">
|
||||
<img :src="platetextList[currentIndex].text" alt="" />
|
||||
<img :src="currentEquipment.text" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -176,10 +192,8 @@ const currentHighlight = computed(() =>
|
||||
<!-- 引导步骤 -->
|
||||
<GuideSteps
|
||||
:steps="steps"
|
||||
:highlight-selector="currentHighlight"
|
||||
:highlight-padding="12"
|
||||
:highlight-radius="20"
|
||||
@step-change="handleStepChange"
|
||||
position-offset-y="85%"
|
||||
>
|
||||
<GuideStepsItem>
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ImgButton, Video } from '@/components'
|
||||
import { StepNavigation } from '@/components/Guide'
|
||||
import { IMAGE_PATHS, getPublicPath, getStaticImage } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const playing = ref(false)
|
||||
const showStepNavigation = ref(false)
|
||||
const currentVideoIndex = ref(0)
|
||||
|
||||
const navigationSteps = [
|
||||
{
|
||||
id: 'q1-shoot-material',
|
||||
label: '中期拍摄',
|
||||
content: '素材怎么拍',
|
||||
type: 'shooting' as const
|
||||
},
|
||||
{
|
||||
id: 'q1-required-shots',
|
||||
label: '中期拍摄',
|
||||
content: '必拍镜头有哪些',
|
||||
type: 'shooting' as const
|
||||
},
|
||||
{
|
||||
id: 'q2-moving-shot',
|
||||
label: '中期拍摄',
|
||||
content: '移动镜头的作用',
|
||||
type: 'shooting' as const
|
||||
},
|
||||
{
|
||||
id: 'q2-close-up',
|
||||
label: '中期拍摄',
|
||||
content: '特写镜头的作用',
|
||||
type: 'shooting' as const
|
||||
}
|
||||
]
|
||||
|
||||
const videoList = [
|
||||
getPublicPath('video/on-site/dygmk_mmps_batch.mp4'),
|
||||
getPublicPath('video/on-site/dygmk_hgydjt_batch.mp4'),
|
||||
getPublicPath('video/on-site/dygmk_jzxjj_batch.mp4'),
|
||||
getPublicPath('video/on-site/dygmk_czsjx_batch.mp4')
|
||||
]
|
||||
|
||||
const currentVideo = computed(() => videoList[currentVideoIndex.value])
|
||||
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
const handleStepClick = (index: number) => {
|
||||
currentVideoIndex.value = index
|
||||
// showStepNavigation.value = false
|
||||
nextTick(() => {
|
||||
playing.value = true
|
||||
})
|
||||
}
|
||||
|
||||
const handleStepNavigationClose = () => {
|
||||
showStepNavigation.value = false
|
||||
}
|
||||
|
||||
const handleEnded = () => {
|
||||
if (currentVideoIndex.value >= videoList.length - 1) {
|
||||
playing.value = false
|
||||
return
|
||||
}
|
||||
|
||||
currentVideoIndex.value++
|
||||
nextTick(() => {
|
||||
playing.value = true
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden bg-black">
|
||||
<Video
|
||||
:src="currentVideo"
|
||||
v-model="playing"
|
||||
:muted="false"
|
||||
:volume="1"
|
||||
:controls="true"
|
||||
:hideNativeControls="true"
|
||||
@ended="handleEnded"
|
||||
>
|
||||
<template #overlay>
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20 pointer-events-auto"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="back"
|
||||
/>
|
||||
<button
|
||||
class="absolute right-4 top-1/2 z-20 -translate-y-1/2 w-12 h-12 rounded-full bg-blue-500/80 text-white transition-all duration-200 hover:bg-blue-500 pointer-events-auto flex items-center justify-center"
|
||||
title="资源列表"
|
||||
@click="showStepNavigation = true"
|
||||
>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M3 4H17M3 8H17M3 12H17M3 16H17"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
</Video>
|
||||
|
||||
<StepNavigation
|
||||
:visible="showStepNavigation"
|
||||
:background-image="getStaticImage('work/vlog背景全屏待定')"
|
||||
:steps="navigationSteps"
|
||||
:current-step-index="currentVideoIndex"
|
||||
@step-click="handleStepClick"
|
||||
@close="handleStepNavigationClose"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -9,7 +9,6 @@ import StartOverlay from '../components/StartOverlay.vue'
|
||||
import LoadingOverlay from '@/components/Loading/LoadingOverlay.vue'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useInterviewStore } from '@/stores'
|
||||
|
||||
const router = useRouter()
|
||||
const start = ref(false)
|
||||
@@ -90,7 +89,6 @@ const captureScene = async () => {
|
||||
*/
|
||||
const handleComplete = () => {
|
||||
showGuide.value = false
|
||||
useInterviewStore().setInterviewUnlockProgress(3)
|
||||
router.push({
|
||||
name: 'Interview'
|
||||
})
|
||||
@@ -252,7 +250,7 @@ const handleComplete = () => {
|
||||
|
||||
<!-- 引导步骤 -->
|
||||
<GuideSteps v-if="showGuide" positionOffsetY="80%" @complete="handleComplete">
|
||||
<GuideStepsItem> 实地取景已全部完成,现在跟着我走进现场开始正式的拍摄吧~ </GuideStepsItem>
|
||||
<GuideStepsItem>实地取景已全部完成,现在跟着我走进现场开始正式的拍摄吧~</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script lang="ts" setup>
|
||||
import { IMAGE_PATHS, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden">
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="back"
|
||||
/>
|
||||
<img class="absolute inset-0" :src="getStaticImage('img/背景.png')" alt="" />
|
||||
|
||||
<img class="absolute top-5 z-10" :src="getStaticImage('img/资源筹备-标题.png')" alt="" />
|
||||
|
||||
<div class="relative h-full pt-28 overflow-y-scroll">
|
||||
<img :src="getStaticImage('interview/img/资源筹备.png')" alt="" />
|
||||
</div>
|
||||
|
||||
<GuideSteps :visible="true" position-offset-y="85%">
|
||||
<GuideStepsItem>这份长图文干货满满,滚动鼠标查看完整内容吧</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</template>
|
||||
Whitespace-only changes.
@@ -1,88 +1,44 @@
|
||||
<script lang="ts" setup>
|
||||
import { IMAGE_PATHS } from '@/utils'
|
||||
import { IMAGE_PATHS, getPublicPath, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { ref } from 'vue'
|
||||
import sample from './sample.vue'
|
||||
import writing from './writing.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getStaticImage } from '@/utils'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
import { Video } from '@/components'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const writingtext = ref('撰写格式')
|
||||
const hiddenbar = ref(false)
|
||||
const formatClick = () => {
|
||||
writingtext.value = '撰写格式'
|
||||
}
|
||||
const sampleanClick = () => {
|
||||
writingtext.value = '样例展示'
|
||||
// router.push({ name: 'sample' })
|
||||
}
|
||||
|
||||
const hiddenbarclick = () => {
|
||||
hiddenbar.value = !hiddenbar.value
|
||||
}
|
||||
|
||||
const back = () => {
|
||||
// 跳转设备准备
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full">
|
||||
<!-- 返回按钮 -->
|
||||
<div class="relative w-full h-full overflow-hidden">
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-10"
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="back"
|
||||
/>
|
||||
<!-- 侧边栏 -->
|
||||
<div
|
||||
:class="[
|
||||
'absolute h-full left-0 top-0 transition-transform duration-300 z-10',
|
||||
hiddenbar ? 'translate-x-[-400px]' : 'translate-x-[0px]'
|
||||
]"
|
||||
>
|
||||
<img class="absolute inset-0 -z-10" src="@/assets/images/equipment/侧边导航栏.png" alt="" />
|
||||
<img class="absolute inset-0" :src="getStaticImage('img/背景.png')" alt="" />
|
||||
|
||||
<!-- 脚本撰写 -->
|
||||
<img class="" :src="getStaticImage(IMAGE_PATHS.VLOG.SCRIPTINGTITLE)" />
|
||||
<img class="absolute top-5 z-10" :src="getStaticImage('img/脚本编写-标题.png')" alt="" />
|
||||
|
||||
<img
|
||||
class="absolute bottom-4 left-6"
|
||||
src="@/assets/images/vlog/制作变焦镜/左边导航栏/ai分镜工具.png"
|
||||
alt=""
|
||||
/>
|
||||
<div class="relative h-full pt-28 overflow-y-scroll">
|
||||
<img :src="getStaticImage('interview/img/脚本编写.png')" alt="" />
|
||||
|
||||
<div class="absolute left-0 top-36">
|
||||
<ImgButton
|
||||
:image="
|
||||
writingtext == '撰写格式' ? IMAGE_PATHS.VLOG.FORMATLIANG : IMAGE_PATHS.VLOG.FORMATAN
|
||||
"
|
||||
@click="formatClick"
|
||||
/>
|
||||
<ImgButton
|
||||
:image="
|
||||
writingtext == '样例展示' ? IMAGE_PATHS.VLOG.SAMPLELANG : IMAGE_PATHS.VLOG.SAMPLEAN
|
||||
"
|
||||
@click="sampleanClick"
|
||||
<div class="absolute top-[250px] left-[8%] w-[960px]">
|
||||
<Video
|
||||
:src="getPublicPath('video/editing/color_jianji_batch.mp4')"
|
||||
playsinline
|
||||
controls
|
||||
:muted="false"
|
||||
:volume="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="[
|
||||
'absolute transition-transform duration-200 top-1/2 -translate-y-1/2 z-20',
|
||||
hiddenbar ? ' translate-x-[-38px]' : 'absolute translate-x-[270px]'
|
||||
]"
|
||||
@click="hiddenbarclick()"
|
||||
>
|
||||
<ImgButton :image="hiddenbar ? 'equipment/按钮-展开' : 'equipment/按钮-收缩'" />
|
||||
</div>
|
||||
|
||||
<div class="absolute w-full h-full left-0 top-0">
|
||||
<writing v-if="writingtext == '撰写格式'"></writing>
|
||||
<sample v-else-if="writingtext == '样例展示'"></sample>
|
||||
</div>
|
||||
<GuideSteps :visible="true" position-offset-y="85%">
|
||||
<GuideStepsItem>这份长图文干货满满,滚动鼠标查看完整内容吧</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,175 +0,0 @@
|
||||
<script lang="tsx" setup>
|
||||
import { getBackgroundImage, getStaticImage, IMAGE_PATHS } from '@/utils'
|
||||
import { GuideSteps, GuideStepsItem, type GuideStep } from '@/components/Guide'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ImagePreview } from '@/components'
|
||||
import { useScale } from '@/composables/useScale'
|
||||
import { useInterviewStore } from '@/stores'
|
||||
const router = useRouter()
|
||||
const showDoubao = ref(false)
|
||||
const interview = useInterviewStore()
|
||||
const steps = [
|
||||
{ id: 'step1', content: '先认识 Vlog:点击右侧「1.vlog初识」继续' },
|
||||
{ id: 'step2', content: '这是主要内容区域的边框' }
|
||||
]
|
||||
|
||||
const stepIndex = ref(1)
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
const handleStepChange = (_step: GuideStep | null, index: number) => {
|
||||
stepIndex.value = index
|
||||
}
|
||||
|
||||
const currentHighlight = computed(() =>
|
||||
stepIndex.value === 0 ? '.img-switch-item--vlog' : '.work-border'
|
||||
)
|
||||
|
||||
const clickdoubao = () => {
|
||||
interview.setInterviewUnlockProgress(2)
|
||||
router.push({
|
||||
name: 'Interview'
|
||||
})
|
||||
}
|
||||
|
||||
function openImages(urls: string[], startIndex = 0) {
|
||||
ImagePreview({
|
||||
images: urls,
|
||||
startIndex,
|
||||
maskClosable: true,
|
||||
getScaleMetrics: () => ({ scale: scale.value, offsetX: offsetX.value, offsetY: offsetY.value }),
|
||||
onClose: () => {
|
||||
showDoubao.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const { scale, offsetX, offsetY } = useScale()
|
||||
onMounted(() => {
|
||||
openImages([getStaticImage('vlog/脚本切图/我的志愿者手记拍摄脚本.png')])
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="writing-index">
|
||||
<!-- 背景图片 -->
|
||||
<div
|
||||
class="absolute inset-0 bg-cover bg-center bg-no-repeat writing-bg"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.VLOG.BIAOGEBG) }"
|
||||
>
|
||||
<div>
|
||||
<div class="writing-title">
|
||||
<img src="@/assets/images/vlog/标题栏-中间.png" alt="" class="titledibu" />
|
||||
<img
|
||||
src="@/assets/images/vlog/制作变焦镜/文字标题/《我的志愿者手记》分镜头脚本.png"
|
||||
alt=""
|
||||
class="titletext"
|
||||
/>
|
||||
</div>
|
||||
<div class="doubao" @click="clickdoubao">
|
||||
<img
|
||||
src="@/assets/images/vlog/制作变焦镜/ai脚本视频占位图.png"
|
||||
alt=""
|
||||
class="doubao-img"
|
||||
/>
|
||||
</div>
|
||||
<div class="shooting-return">
|
||||
<img src="@/assets/images/shooting/返回.png" alt="" @click="back" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div v-else>
|
||||
<div class="writing-title">
|
||||
<img src="@/assets/images/vlog/标题栏-中间.png" alt="" class="titledibu" />
|
||||
<img
|
||||
src="@/assets/images/vlog/制作变焦镜/文字标题/《我的志愿者手记》分镜头脚本.png"
|
||||
alt=""
|
||||
class="titletext"
|
||||
/>
|
||||
</div>
|
||||
<div class="biaogehome" @click="deletebiaoge()">
|
||||
<img
|
||||
src="@/assets/images/vlog/脚本切图/我的志愿者手记拍摄脚本.png"
|
||||
alt=""
|
||||
class="biaoge-img"
|
||||
/>
|
||||
<img src="@/assets/images/midterm/叉.png" alt="" class="biaoge-x" />
|
||||
</div>
|
||||
<div class="shooting-return">
|
||||
<img src="@/assets/images/shooting/返回.png" alt="" @click="back" />
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- 引导步骤 -->
|
||||
<GuideSteps
|
||||
v-if="showDoubao"
|
||||
:steps="steps"
|
||||
:highlight-selector="currentHighlight"
|
||||
:highlight-padding="12"
|
||||
:highlight-radius="20"
|
||||
@step-change="handleStepChange"
|
||||
position-offset-y="85%"
|
||||
>
|
||||
<GuideStepsItem>
|
||||
<img src="@/assets/images/components/引导/ai脚本工具引导.png" alt="" />
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="less" scoped>
|
||||
.writing-index {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.shooting-return {
|
||||
position: absolute;
|
||||
right: -90%;
|
||||
top: 0;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.doubao .doubao-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.biaoge-x {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
right: 0px;
|
||||
width: 70px;
|
||||
cursor: pointer;
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
.writing-title {
|
||||
.titledibu {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
left: 30%;
|
||||
}
|
||||
|
||||
.titletext {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
.biaogehome {
|
||||
position: absolute;
|
||||
top: 165px;
|
||||
left: 5%;
|
||||
width: 94%;
|
||||
}
|
||||
|
||||
.biaogehome .biaoge-img {
|
||||
height: 896px !important;
|
||||
width: 1800px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
@@ -1,61 +0,0 @@
|
||||
<template>
|
||||
<div class="writing-index">
|
||||
<!-- 背景图片 -->
|
||||
<div
|
||||
class="absolute inset-0 bg-cover bg-center bg-no-repeat writing-bg"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.VLOG.SCRIPTING) }"
|
||||
>
|
||||
<div class="geshi-title">
|
||||
<img src="@/assets/images/vlog/标题栏-中间.png" alt="" class="titledibu" />
|
||||
<img
|
||||
src="@/assets/images/vlog/制作变焦镜/文字标题/脚本的概念和基本要素.png"
|
||||
alt=""
|
||||
class="titletext"
|
||||
/>
|
||||
</div>
|
||||
<video :src="fourth" controls></video>
|
||||
<!-- <div class="shooting-return">
|
||||
<img src="@/assets/images/shooting/返回.png" alt="" @click="back" />
|
||||
</div> -->
|
||||
<!-- 引导步骤 -->
|
||||
<!-- <GuideSteps :steps="steps" :highlight-selector="currentHighlight" :highlight-padding="12"
|
||||
:highlight-radius="20" @step-change="handleStepChange" position-offset-y="85%" hidden:false>
|
||||
<GuideStepsItem>
|
||||
<img src="@/assets/images/equipment/设备准备引导1.png" alt="" />
|
||||
</GuideStepsItem>
|
||||
</GuideSteps> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
|
||||
import fourth from '/video/vlog_renwuqujing_jiaobencehua.mp4'
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.writing-index {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.geshi-title {
|
||||
.titledibu {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
left: 30%;
|
||||
}
|
||||
|
||||
.titletext {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 45%;
|
||||
}
|
||||
}
|
||||
|
||||
.shooting-return {
|
||||
position: absolute;
|
||||
right: -90%;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script lang="ts" setup>
|
||||
import { IMAGE_PATHS, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full h-full overflow-hidden">
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-20"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@click="back"
|
||||
/>
|
||||
<img class="absolute inset-0" :src="getStaticImage('img/背景.png')" alt="" />
|
||||
|
||||
<img class="absolute top-5 z-10" :src="getStaticImage('img/分镜制作-标题.png')" alt="" />
|
||||
|
||||
<div class="relative h-full pt-28 overflow-y-scroll">
|
||||
<img :src="getStaticImage('interview/img/分镜制作.png')" alt="" />
|
||||
</div>
|
||||
|
||||
<GuideSteps :visible="true" position-offset-y="85%">
|
||||
<GuideStepsItem>这份长图文干货满满,滚动鼠标查看完整内容吧</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
</template>
|
||||
@@ -99,6 +99,13 @@ const handleVideoChange = () => {
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
if (key.value === 'idea') {
|
||||
interview.setInterviewUnlockProgress(1)
|
||||
router.push({
|
||||
name: 'Interview'
|
||||
})
|
||||
return
|
||||
}
|
||||
router.back()
|
||||
}
|
||||
|
||||
@@ -119,11 +126,6 @@ const handleComplete = () => {
|
||||
router.push({
|
||||
name: 'InterviewWork'
|
||||
})
|
||||
} else {
|
||||
if (interview.InterviewUnlockProgress == 0) interview.setInterviewUnlockProgress(1)
|
||||
router.push({
|
||||
name: 'Interview'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +152,6 @@ onMounted(() => {
|
||||
<template>
|
||||
<div class="w-full h-full relative bg-white/10" @click="handleClick">
|
||||
<template v-if="key !== 'case' && key !== 'profession'">
|
||||
<ImgButton class="absolute left-4 top-4 z-10" :image="image"></ImgButton>
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-10"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@@ -189,10 +190,6 @@ onMounted(() => {
|
||||
@ended="onEnded"
|
||||
>
|
||||
<template v-slot:overlay>
|
||||
<ImgButton
|
||||
class="absolute left-4 top-4 z-10 pointer-events-auto"
|
||||
:image="image"
|
||||
></ImgButton>
|
||||
<ImgButton
|
||||
class="absolute right-0 top-0 z-10 pointer-events-auto"
|
||||
:image="IMAGE_PATHS.COMPONENTS.BACK"
|
||||
@@ -201,7 +198,7 @@ onMounted(() => {
|
||||
</template>
|
||||
</Video>
|
||||
<div v-else-if="key === 'idea'" :src="image">
|
||||
<img :src="getStaticImage('work/思路提点全屏')" alt="" />
|
||||
<img :src="getStaticImage('interview/work/思路提点全屏')" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ref, computed } from 'vue'
|
||||
import { getBackgroundImage, IMAGE_PATHS, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import WorkSideSwitcher from './components/WorkSideSwitcher.vue'
|
||||
import { GuideSteps, type GuideStep } from '@/components/Guide'
|
||||
import { GuideSteps } from '@/components/Guide'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useScale } from '@/composables/useScale'
|
||||
import { ImagePreview } from '@/components'
|
||||
@@ -17,7 +17,6 @@ const interview = useInterviewStore()
|
||||
type WorkTab = 'vlog' | 'case' | 'profession' | 'idea'
|
||||
|
||||
const selected = ref<WorkTab>('case')
|
||||
const stepIndex = ref(0)
|
||||
const workSideSwitcherRef = ref<InstanceType<typeof WorkSideSwitcher>>()
|
||||
|
||||
const isGuideInterviewTask = computed(() => interview.isGuideInterviewTask)
|
||||
@@ -28,32 +27,37 @@ const steps = [
|
||||
{
|
||||
id: 'step1',
|
||||
content:
|
||||
'现在我们要一起走进 Vlog 的世界。简单说,Vlog 就是用视频记录生活的一种方式 —— 它像一本会动的日记,能把我们身边的小事、瞬间的心情,通过镜头变得生动又具体。'
|
||||
'现在我们要一起走进 Vlog 的世界。简单说,Vlog 就是用视频记录生活的一种方式 —— 它像一本会动的日记,能把我们身边的小事、瞬间的心情,通过镜头变得生动又具体。',
|
||||
highlightSelector: '.img-switch-item--case'
|
||||
},
|
||||
{ id: 'step2', content: '接下来,我们就通过一个具体的案例,看看 Vlog 是怎么“捕捉美好” 的吧。' }
|
||||
{
|
||||
id: 'step2',
|
||||
content: '接下来,我们就通过一个具体的案例,看看 Vlog 是怎么“捕捉美好” 的吧。',
|
||||
highlightSelector: '.work-border'
|
||||
}
|
||||
]
|
||||
|
||||
//切换图片
|
||||
const sideSwitcherItems = ref([
|
||||
{
|
||||
key: 'vlog',
|
||||
description: '记录身边的美好',
|
||||
image: 'work/vlog背景全屏待定'
|
||||
description: '我的职业蓝图',
|
||||
image: 'interview/work/案件赏析小屏'
|
||||
},
|
||||
{
|
||||
key: 'case',
|
||||
description: '案例赏析-桂花酒酿小圆子',
|
||||
image: 'work/案例背景待定'
|
||||
description: '我的职业蓝图',
|
||||
image: 'interview/work/案件赏析小屏'
|
||||
},
|
||||
{
|
||||
key: 'profession',
|
||||
description: '专业剖析-桂花酒酿小圆子',
|
||||
image: 'work/专业剖析小屏'
|
||||
description: '我的职业蓝图',
|
||||
image: 'interview/work/案件赏析小屏'
|
||||
},
|
||||
{
|
||||
key: 'idea',
|
||||
description: '思路提点-桂花酒酿小圆子',
|
||||
image: 'work/思路提点小屏'
|
||||
description: '我的职业蓝图',
|
||||
image: 'interview/work/思路提点小屏'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -62,21 +66,13 @@ const currentItem = computed(() => {
|
||||
return sideSwitcherItems.value.find(item => item.key === selected.value)
|
||||
})
|
||||
|
||||
const currentHighlight = computed(() =>
|
||||
stepIndex.value === 0 ? '.img-switch-item--case' : '.work-border'
|
||||
)
|
||||
|
||||
const handleStepChange = (_step: GuideStep | null, index: number) => {
|
||||
stepIndex.value = index
|
||||
}
|
||||
|
||||
const handleSideSwitcherChange = (value: WorkTab) => {
|
||||
if (selected.value === value) return
|
||||
}
|
||||
|
||||
const handleImageClick = () => {
|
||||
router.push({
|
||||
name: 'FilmVideo',
|
||||
name: 'InterviewVideo',
|
||||
query: {
|
||||
image:
|
||||
workSideSwitcherRef.value?.items.find(item => item.key === selected.value)?.activeImage ||
|
||||
@@ -87,7 +83,7 @@ const handleImageClick = () => {
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
router.push({ name: 'Film' })
|
||||
router.push({ name: 'Interview' })
|
||||
}
|
||||
|
||||
const handleWorkClick = () => {
|
||||
@@ -99,7 +95,6 @@ const handleGuideComplete = () => {
|
||||
}
|
||||
|
||||
const handleOpenGuide = () => {
|
||||
stepIndex.value = 0
|
||||
interview.setIsGuideInterviewTask(true)
|
||||
}
|
||||
|
||||
@@ -120,7 +115,7 @@ function openImages(urls: string[], startIndex = 0) {
|
||||
<!-- 背景图片-center -->
|
||||
<div
|
||||
class="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.WORK.BG) }"
|
||||
:style="{ backgroundImage: getBackgroundImage('interview/work/任务取景框背景') }"
|
||||
></div>
|
||||
|
||||
<!-- 关闭 -->
|
||||
@@ -135,6 +130,13 @@ function openImages(urls: string[], startIndex = 0) {
|
||||
class="work-border absolute top-[140px] left-24 inset-0 bg-cover bg-center bg-no-repeat z-10 w-[1360px] h-[800px] p-10"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.WORK.BORDER) }"
|
||||
>
|
||||
<!-- 手 -->
|
||||
<div
|
||||
class="absolute left-[46%] top-[40%] -translate-x-1/2 -translate-y-1/2 z-10 animate-bounce pointer-events-none"
|
||||
>
|
||||
<img class="w-40" :src="getStaticImage('work/小手')" alt="" />
|
||||
<span class="text-white text-2xl font-bold ml-5">点击进入</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center pl-16 w-[1357px] h-[265px] absolute -bottom-16 left-0 bg-cover bg-center bg-no-repeat z-20"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.WORK.TITLE) }"
|
||||
@@ -142,8 +144,8 @@ function openImages(urls: string[], startIndex = 0) {
|
||||
<span
|
||||
class="mt-24 text-white font-bold text-6xl [text-shadow:0_2px_4px_rgba(0,0,0,0.2),0_0_6px_rgba(0,207,255,0.9),0_0_14px_rgba(0,207,255,0.7)]"
|
||||
>
|
||||
{{ currentItem?.description }}</span
|
||||
>
|
||||
{{ currentItem?.description }}
|
||||
</span>
|
||||
</div>
|
||||
<img
|
||||
@click="handleImageClick"
|
||||
@@ -174,10 +176,8 @@ function openImages(urls: string[], startIndex = 0) {
|
||||
<GuideSteps
|
||||
v-if="isGuideInterviewTask"
|
||||
:steps="steps"
|
||||
:highlight-selector="currentHighlight"
|
||||
:highlight-padding="12"
|
||||
:highlight-radius="20"
|
||||
@step-change="handleStepChange"
|
||||
@complete="handleGuideComplete"
|
||||
@skip="handleGuideComplete"
|
||||
position-offset-y="85%"
|
||||
|
||||
Reference in new issue
Block a user