This commit is contained in:
gaofeihang committed 2025-09-17 21:59:51 +08:00
commit f22333f6f5
29 files changed
+696 -59

No files matched your search

+6 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import { getBackgroundImage, getStaticImage, IMAGE_PATHS } from '@/utils'
import { ImgButton } from '@/components/Button'
import { ModuleSwitcher } from './components/ModuleSwitcher'
import { computed, ref, onMounted } from 'vue'
@@ -121,6 +121,11 @@ onMounted(() => {
class="absolute top-60 right-1/2 translate-x-1/2"
@click="handleCloseGuide"
/>
<img
class="absolute bottom-0 left-1/2 -translate-x-1/2"
:src="getStaticImage('home/新手导航')"
alt=""
/>
</div>
<!-- <GuideSteps @complete="handleComplete" @skip="handleSkip">
+187 -21
View File
@@ -12,6 +12,7 @@
<img src="@/assets/images/equipment/选中按钮.png" alt="" />
<img src="@/assets/images/equipment/手机-亮.png" alt="" />
</span>
<span>手机支架</span>
</div>
<!-- 设备准备按钮 -->
<div class="equipment-bt">
@@ -21,14 +22,58 @@
:class="hiddenbar ? 'equipment-unfold1' : 'equipment-unfold2'"
@click="hiddenbarclick()"
>
<img src="@/assets/images/equipment/按钮-展开.png" alt="" />
<img
:src="
hiddenbar
? '/src/assets/images/equipment/按钮-展开.png'
: '/src/assets/images/equipment/按钮-收缩.png'
"
alt=""
/>
</div>
</div>
<div class="equipment-layout">
<div class="equipment-home">
<div
class="equipment-leftbutton"
@click="prevPhone"
:style="{ visibility: currentIndex > 0 ? 'visible' : 'hidden' }"
>
<img src="@/assets/images/equipment/按钮-左滑.png" alt="" />
</div>
<div class="equipment-phoneImg">
<img :src="phoneList[currentIndex].phoneImg" alt="" />
</div>
<div
class="equipment-rightbutton"
@click="nextPhone"
:style="{ visibility: currentIndex < phoneList.length - 1 ? 'visible' : 'hidden' }"
>
<img src="@/assets/images/equipment/按钮-右滑.png" alt="" />
</div>
</div>
<div class="equipment-purpose">
<div class="plate">
<img src="@/assets/images/equipment/浮空屏.png" alt="" />
</div>
<div class="title">
<img src="@/assets/images/equipment/标题-安卓小米.png" alt="" />
<!-- <img src="@/assets/images/equipment/标题-苹果.png" alt=""> -->
</div>
<div class="text">
<img src="@/assets/images/equipment/内容-安卓小米.png" alt="" />
<!-- <img src="@/assets/images/equipment/内容-苹果.png" alt=""> -->
</div>
</div>
</div>
<!-- 引导步骤 -->
<GuideSteps
@complete="handleComplete"
@skip="handleSkip"
:keyboard-navigation="true"
position-offset-y="85%"
:steps="steps"
:highlight-selector="currentHighlight"
:highlight-padding="12"
:highlight-radius="20"
@step-change="handleStepChange"
>
<GuideStepsItem>
<img src="@/assets/images/equipment/设备准备引导1.png" alt="" />
@@ -41,33 +86,73 @@
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
import { ref } from 'vue'
const hiddenbar = ref()
import { ref, computed } from 'vue'
const steps = [
{ id: 'step1', content: '先认识 Vlog:点击右侧「1.vlog初识」继续' },
{ id: 'step2', content: '这是主要内容区域的边框' }
]
const stepIndex = ref(0)
const hiddenbar = ref(false)
const currentIndex = ref(0) // 当前显示的图片索引
const phoneList = ref([
{ phoneImg: '/src/assets/images/equipment/设备-手机1.png' },
{ phoneImg: '/src/assets/images/equipment/设备-手机2.png' }
])
const hiddenbarclick = () => {
hiddenbar.value = !hiddenbar.value
}
const handleComplete = () => {
console.log('引导完成')
// 下一张图片
const nextPhone = () => {
if (currentIndex.value < phoneList.value.length - 1) {
currentIndex.value++
}
}
const handleSkip = () => {
console.log('跳过引导')
// 上一张图片
const prevPhone = () => {
if (currentIndex.value > 0) {
currentIndex.value--
}
}
interface SimpleStep {
id: string
content: string
}
const handleStepChange = (_step: SimpleStep | null, index: number) => {
stepIndex.value = index
}
const currentHighlight = computed(() =>
stepIndex.value === 0 ? '.img-switch-item--vlog' : '.work-border'
)
</script>
<style lang="less" scoped>
<style lang="less">
.equipment-index {
// display: flex;
width: 100%;
height: 100%;
}
.equipment-bg {
display: flex;
// display: flex;
}
.equipment-layout {
position: relative;
width: 100%;
height: 100%;
}
.equipment-bar {
position: relative;
position: absolute;
top: 0;
left: 0;
z-index: 10;
.equipment-bt {
position: absolute;
@@ -83,29 +168,27 @@ const handleSkip = () => {
.equipment-unfold1 {
position: absolute;
top: 45%;
right: -110px;
top: 490px;
left: -41px;
width: 150px;
img {
width: 100%;
height: 100%;
object-fit: contain;
/* 确保图片按比例缩放 */
}
}
.equipment-unfold2 {
position: absolute;
top: 45%;
right: -69px;
top: 490px;
left: 268px;
width: 150px;
img {
width: 100%;
height: 100%;
object-fit: contain;
/* 确保图片按比例缩放 */
}
}
@@ -119,5 +202,88 @@ const handleSkip = () => {
display: flex;
}
}
.guide-ui {
top: 80% !important;
}
.dragon-character {
top: 80% !important;
}
}
.equipment-home {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.equipment-leftbutton {
position: absolute;
top: 511px;
left: 350px;
width: 200px;
height: 200px;
cursor: pointer;
z-index: 10;
}
.equipment-phoneImg {
position: absolute;
top: 313px;
left: 500px;
width: 446px;
height: 484px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.equipment-rightbutton {
position: absolute;
top: 511px;
right: 770px;
width: 200px;
height: 200px;
cursor: pointer;
z-index: 10;
}
}
.equipment-purpose {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.title {
position: absolute;
top: 0;
left: 1200px;
}
.text {
position: absolute;
top: 74px;
left: 1292px;
width: 364px;
}
.plate {
position: absolute;
top: 0;
left: 1200px;
}
}
</style>
+14 -2
View File
@@ -25,6 +25,11 @@ const handleWorkClick = () => {
// 处理任务取景按钮点击逻辑
router.push({ name: 'Work' })
}
const handleClick = () => {
// 处理任务取景按钮点击逻辑
router.push({ name: 'equipment' })
}
const highlightShow = ref(true)
</script>
@@ -59,7 +64,10 @@ const highlightShow = ref(true)
<ImgButton :image="IMAGE_PATHS.VLOG.Midterm" />
</div>
<!-- 进度百分比 -->
<div v-if="highlightShow" class="absolute left-1/2 top-[12%] -translate-x-1/2">
<div
v-if="highlightShow"
class="absolute left-1/2 top-[12%] -translate-x-1/2 pointer-events-none"
>
<div class="flex">
<ImgButton :image="IMAGE_PATHS.VLOG.Progress" />
<ImgButton :image="IMAGE_PATHS.VLOG.Four" />
@@ -73,7 +81,11 @@ const highlightShow = ref(true)
class="absolute left-[21%] top-[9%] -translate-x-1/2"
style="z-index: 998"
>
<ImgButton :image="IMAGE_PATHS.VLOG.MidtermEquipment" class="ml-[60px]" />
<ImgButton
:image="IMAGE_PATHS.VLOG.MidtermEquipment"
@click="handleClick"
class="ml-[60px]"
/>
<ImgButton :image="IMAGE_PATHS.VLOG.MidtermFraming" class="ml-[40px]" />
<ImgButton :image="IMAGE_PATHS.VLOG.MidtermShoot" class="ml-[20px]" />
</div>
+6 -2
View File
@@ -7,7 +7,6 @@ import { ProgressBar } from '@/components'
import { useRouter } from 'vue-router'
import { GuideSteps } from '@/components/Guide'
type WorkTab = 'vlog' | 'case' | 'profession' | 'idea'
const steps = [
{
id: 'step1',
@@ -115,7 +114,11 @@ const highlightShow = ref(true)
:highlight-padding="12"
:highlight-radius="20"
@step-change="handleStepChangeGui"
/>
>
<GuideStepsItem>
<img src="@/assets/images/midterm/前期准备引导1.png" alt="" />
</GuideStepsItem>
</GuideSteps>
</div>
<div
v-if="highlightShow"
@@ -130,6 +133,7 @@ const highlightShow = ref(true)
.guide-ui {
top: 80% !important;
}
.dragon-character {
top: 80% !important;
}
+13 -3
View File
@@ -2,11 +2,12 @@
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import { ImgButton } from '@/components/Button'
import { ref } from 'vue'
import { onMounted, ref } from 'vue'
import { ProgressBar } from '@/components'
import { useRouter } from 'vue-router'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const currentStep = ref(0)
@@ -25,6 +26,12 @@ const handleWorkClick = () => {
// 处理任务取景按钮点击逻辑
router.push({ name: 'Work' })
}
onMounted(() => {
if (route.query.key === 'video') {
currentStep.value = 1
}
})
</script>
<template>
@@ -51,7 +58,10 @@ const handleWorkClick = () => {
class="absolute left-24 top-24"
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.VLOG.TASK_CAMERA) }"
>
<ImgButton :image="IMAGE_PATHS.VLOG.TASK_BTN" @click="handleWorkClick" />
<ImgButton
:image="currentStep === 1 ? IMAGE_PATHS.VLOG.TASK_BTN_OK : IMAGE_PATHS.VLOG.TASK_BTN"
@click="handleWorkClick"
/>
</div>
<!-- 引导任务 -->
+141
View File
@@ -0,0 +1,141 @@
<script lang="ts" setup>
import { computed, nextTick, onMounted, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import ImgButton from '@/components/Button/ImgButton.vue'
import { GuideSteps } from '@/components/Guide'
import { getStaticImage, IMAGE_PATHS } from '@/utils'
import second from '/video/Vlog模块_任务取景框_专业剖析_基础景别运用.mp4'
import third from '/video/Vlog模块_任务取景框_专业剖析_画面构图.mp4'
import fourth from '/video/Vlog模块_任务取景框_专业剖析_脚本策划.mp4'
import five from '/video/Vlog模块_任务取景框_专业剖析_动态事件跟拍与抓拍.mp4'
import six from '/video/Vlog模块_任务取景框_专业剖析_素材导入、剪辑拼接.mp4'
const router = useRouter()
const route = useRoute()
const videoRef = ref()
const status = ref(false)
//引导步骤
const steps = ref([
{
id: 'step1',
content: '试着用这些方法记录身边的小事,你会发现,原来平凡的日子里有这么多值得捕捉的瞬间。'
}
])
// 视频列表
const videoList = [second, third, fourth, five, six]
const currentVideoIndex = ref(0)
//按顺序播放
const currentVideo = computed(() => videoList[currentVideoIndex.value])
const handleVideoChange = () => {
if (currentVideoIndex.value < videoList.length - 1) {
currentVideoIndex.value++
} else {
status.value = true
steps.value = [
{
id: 'step1',
content: '已完成专业剖析,即可查看脚本'
}
]
return
}
nextTick(() => {
if (!videoRef.value) return
videoRef.value.muted = false
videoRef.value.volume = 1
videoRef.value.play()
})
}
const handleClose = () => {
router.back()
}
const image = computed(() => route.query.image as string)
const key = computed(() => route.query.key as string)
const handleClick = () => {
if (!videoRef.value) return
videoRef.value.muted = false
videoRef.value.volume = 1
}
const handlePlay = () => {
if (!videoRef.value) return
videoRef.value.muted = false
videoRef.value.volume = 1
}
const handleComplete = () => {
if (key.value === 'profession') {
router.push({
name: 'Work',
query: {
key: 'work'
}
})
} else {
router.push({
name: 'midterm',
query: {
key: 'midterm'
}
})
}
}
onMounted(() => {
if (key.value === 'idea') {
status.value = true
}
})
</script>
<template>
<div class="w-full h-full relative bg-white/10" @click="handleClick">
<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"
@click="handleClose"
/>
<div v-if="key === 'vlog'" :src="image">
<img :src="getStaticImage('work/vlog背景全屏待定')" alt="" />
</div>
<video
ref="videoRef"
v-else-if="key === 'case'"
src="/video/案例赏析-美食小确幸:桂花酒酿小圆子.mp4"
controls
@play="handlePlay"
></video>
<!-- 专业剖析 -->
<video
ref="videoRef"
v-else-if="key === 'profession'"
:src="currentVideo"
controls
@play="handlePlay"
@ended="handleVideoChange"
></video>
<div v-else-if="key === 'idea'" :src="image">
<img :src="getStaticImage('work/思路提点全屏')" alt="" />
</div>
</div>
<!-- 引导与高亮 -->
<GuideSteps v-if="status" :steps="steps" position-offset-y="85%" @complete="handleComplete" />
</template>
<style scoped>
video {
width: 100%;
height: 100%;
/* 核心:保持视频比例,多余部分被裁剪 */
object-fit: cover;
}
</style>
@@ -44,4 +44,8 @@ const items = [
]
const onChange = (val: string) => emit('change', val as WorkTab)
defineExpose({
items
})
</script>
+99 -8
View File
@@ -1,20 +1,61 @@
<script lang="tsx" setup>
import { ref, computed } from 'vue'
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import { ref, computed, onMounted } from 'vue'
import { getBackgroundImage, IMAGE_PATHS, getStaticImage } from '@/utils'
import { ImgButton } from '@/components/Button'
import WorkSideSwitcher from './components/WorkSideSwitcher.vue'
import { GuideSteps } from '@/components/Guide'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
type WorkTab = 'vlog' | 'case' | 'profession' | 'idea'
const selected = ref<WorkTab>('vlog')
const stepIndex = ref(0)
const workSideSwitcherRef = ref<InstanceType<typeof WorkSideSwitcher>>()
const status = ref(false)
//引导步骤
const steps = [
{ id: 'step1', content: '先认识 Vlog:点击右侧「1.vlog初识」继续' },
{ id: 'step2', content: '这是主要内容区域的边框' }
{
id: 'step1',
content:
'现在我们要一起走进 Vlog 的世界。简单说,Vlog 就是用视频记录生活的一种方式 —— 它像一本会动的日记,能把我们身边的小事、瞬间的心情,通过镜头变得生动又具体。'
},
{ id: 'step2', content: '接下来,我们就通过一个具体的案例,看看 Vlog 是怎么“捕捉美好” 的吧。' }
]
//切换图片
const sideSwitcherItems = ref([
{
key: 'vlog',
description: '记录身边的美好',
image: 'work/vlog初识框'
},
{
key: 'case',
description: '美食小确幸:桂花酒酿小圆子',
image: 'work/案例背景待定'
},
{
key: 'profession',
description: '美食小确幸:桂花酒酿小圆子',
image: 'work/案例背景待定'
},
{
key: 'idea',
description: '美食小确幸:桂花酒酿小圆子',
image: 'work/思路提点小屏'
}
])
//当前选中的item
const currentItem = computed(() => {
return sideSwitcherItems.value.find(item => item.key === selected.value)
})
const currentHighlight = computed(() =>
stepIndex.value === 0 ? '.img-switch-item--vlog' : '.work-border'
)
@@ -26,6 +67,38 @@ interface SimpleStep {
const handleStepChange = (_step: SimpleStep | null, index: number) => {
stepIndex.value = index
}
const handleSideSwitcherChange = (value: WorkTab) => {
if (selected.value === value) return
}
const handleImageClick = () => {
router.push({
name: 'Video',
query: {
image:
workSideSwitcherRef.value?.items.find(item => item.key === selected.value)?.activeImage ||
'',
key: selected.value
}
})
}
const handleClose = () => {
router.back()
}
//状态是否完成前置
const isComplete = ref(false)
onMounted(() => {
if (route.query.key === 'work') {
selected.value = 'profession'
isComplete.value = true
} else {
status.value = true
}
})
</script>
<template>
@@ -36,6 +109,13 @@ const handleStepChange = (_step: SimpleStep | null, index: number) => {
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.WORK.BG) }"
></div>
<!-- 关闭 -->
<ImgButton
class="absolute right-0 top-0"
:image="IMAGE_PATHS.COMPONENTS.CLOSE"
@click="handleClose"
/>
<!-- border图片 -->
<div
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"
@@ -48,31 +128,42 @@ const handleStepChange = (_step: SimpleStep | null, index: number) => {
<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)]"
>
记录身边的美好</span
{{ currentItem?.description }}</span
>
</div>
<img class="rounded-[62px]" src="@/assets/images/work/image1.png" alt="" />
<img
@click="handleImageClick"
class="rounded-[62px] cursor-pointer"
:src="getStaticImage(currentItem?.image || '')"
alt=""
/>
</div>
<!-- 左侧选项切换 -->
<div class="absolute right-4 top-32 z-20">
<WorkSideSwitcher
ref="workSideSwitcherRef"
v-model="selected"
@change="() => {}"
@change="handleSideSwitcherChange"
:item-class="'w-[462px] h-[142px] '"
/>
</div>
<!-- 任务取景按钮 -->
<ImgButton class="absolute right-14 bottom-10" :image="IMAGE_PATHS.WORK.TASK_BTN" />
<ImgButton
class="absolute right-14 bottom-10"
:image="isComplete ? IMAGE_PATHS.WORK.TASK_BTN_OK : IMAGE_PATHS.WORK.TASK_BTN"
/>
<!-- 引导与高亮 -->
<GuideSteps
v-if="status"
:steps="steps"
:highlight-selector="currentHighlight"
:highlight-padding="12"
:highlight-radius="20"
@step-change="handleStepChange"
position-offset-y="85%"
/>
</div>
</template>