This commit is contained in:
songjianyang committed 2025-09-18 01:10:43 +08:00
commit 29f91bb10b
27 files changed
+924 -24

No files matched your search

+10 -13
View File
@@ -16,8 +16,8 @@ const isImageLoading = ref(false)
// 预加载图片映射
const imageMap = {
vlog: IMAGE_PATHS.ACTION.VIDEO1,
film: IMAGE_PATHS.ACTION.VIDEO2,
interview: IMAGE_PATHS.ACTION.VIDEO3
film: IMAGE_PATHS.ACTION.VIDEO3,
interview: IMAGE_PATHS.ACTION.VIDEO2
}
// 预加载所有图片
@@ -63,6 +63,12 @@ const selectedImage = computed(() => {
return getBackgroundImage(imageMap[selectedModule.value])
})
const handleSkill = () => {
router.push({
name: 'Skill'
})
}
// 生命周期
onMounted(() => {
preloadImages()
@@ -90,8 +96,10 @@ onMounted(() => {
@click.stop="handleClick"
></div>
<!-- 技能树 按钮 -->
<ImgButton
v-if="status"
@click="handleSkill"
:image="IMAGE_PATHS.ACTION.SKILLS_BTN"
class="absolute bottom-0 right-0 z-30"
/>
@@ -127,16 +135,5 @@ onMounted(() => {
alt=""
/>
</div>
<!-- <GuideSteps @complete="handleComplete" @skip="handleSkip">
<GuideStepsItem>欢迎来到短视频达人应用!我是你的导学小龙</GuideStepsItem>
<GuideStepsItem>
现在让我们一起走进
<em class="text-red-500">Vlog</em>
的世界。简单说,
<em class="text-red-500">Vlog</em>
就是用视频记录生活的一种方式--它像一本会动的日记能把我们身边的小事、瞬间的心情,通过镜头变得生动又具体。
</GuideStepsItem>
</GuideSteps> -->
</div>
</template>
+15 -5
View File
@@ -23,7 +23,7 @@ const currentHighlight = computed(() =>
const router = useRouter()
const currentStep = ref(0)
const currentStep = ref(1)
const handleComplete = () => {
console.log('完成前置条件')
@@ -47,6 +47,7 @@ interface SimpleStep {
const handleStepChangeGui = (_step: SimpleStep | null, index: number) => {
stepIndex.value = index
}
const highlightShow = ref(true)
</script>
<template>
@@ -76,19 +77,19 @@ const handleStepChangeGui = (_step: SimpleStep | null, index: number) => {
<ImgButton :image="IMAGE_PATHS.VLOG.TASK_BTN" @click="handleWorkClick" />
</div>
<!-- 前期准备底板 -->
<div class="absolute right-90 ml-[135px]">
<div v-if="highlightShow" class="absolute right-90 ml-[135px]">
<ImgButton :image="IMAGE_PATHS.VLOG.PREPARE" />
</div>
<!-- 脚本撰写按钮 -->
<div class="absolute left-[13%] top-1/3">
<div v-if="highlightShow" class="absolute left-[13%] top-1/3">
<ImgButton :image="IMAGE_PATHS.VLOG.Scripting" />
</div>
<!-- 选中箭头 -->
<div class="absolute left-[13%] top-[37%] -translate-x-1/2">
<div v-if="highlightShow" class="absolute left-[13%] top-[37%] -translate-x-1/2">
<ImgButton :image="IMAGE_PATHS.VLOG.SelectArrow" />
</div>
<!-- 进度百分比 -->
<div 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">
<div class="flex">
<ImgButton :image="IMAGE_PATHS.VLOG.Progress" />
<ImgButton :image="IMAGE_PATHS.VLOG.Four" />
@@ -101,6 +102,7 @@ const handleStepChangeGui = (_step: SimpleStep | null, index: number) => {
<div class="absolute bottom-0 w-full">
<ProgressBar
v-if="highlightShow"
:current-step="currentStep"
@complete="handleComplete"
@step-change="handleStepChange"
@@ -118,6 +120,14 @@ const handleStepChangeGui = (_step: SimpleStep | null, index: number) => {
</GuideStepsItem>
</GuideSteps>
</div>
<div
v-if="highlightShow"
class="absolute right-0 top-0"
style="z-index: 998; cursor: pointer"
@click="highlightShow = false"
>
<img src="@/assets/images/midterm/叉.png" alt="" />
</div>
</template>
<style>
.guide-ui {
+49
View File
@@ -0,0 +1,49 @@
<template>
<div
class="absolute inset-0 bg-cover bg-center bg-no-repeat equipment-bg"
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.EQUIPMENT.BG) }"
>
<Sidebar
:menu-items="menuItems"
:default-active="defaultActive"
@item-selected="handleMenuItemSelected"
@toggle="handleSidebarToggle"
/>
</div>
</template>
<script setup lang="tsx">
import { ref, reactive, onMounted } from 'vue'
import Sidebar from '@/components/Sidebar/Sidebar.vue'
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import equipmentPhone from '@/assets/images/equipment/手机-亮.png'
import equipmentPhone2 from '@/assets/images/equipment/手机-暗.png'
const menuItems = ref([
{
activeIcon: equipmentPhone,
inactiveIcon: equipmentPhone2,
title: '手机'
},
{
activeIcon: equipmentPhone,
inactiveIcon: equipmentPhone2,
title: '手机2'
},
{
activeIcon: equipmentPhone,
inactiveIcon: equipmentPhone2,
title: '手机3'
}
])
const defaultActive = ref(0)
const handleMenuItemSelected = (index: number) => {
defaultActive.value = index
console.log('选中了菜单项:', index)
// 根据选中的菜单项更新页面内容
}
const handleSidebarToggle = (collapsed: boolean) => {
console.log('侧边栏状态:', collapsed ? '已折叠' : '已展开')
}
</script>
<style scoped lang="less"></style>
+273
View File
@@ -0,0 +1,273 @@
<script lang="tsx" setup>
defineOptions({ name: 'SkillPage' })
import { ref, computed } from 'vue'
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
import { ImgButton } from '@/components/Button'
import { GuideSteps } from '@/components/Guide'
import { useRouter } from 'vue-router'
const router = useRouter()
const stepIndex = ref(0)
const selected = ref(false)
const sideStatus = ref(true)
const status = ref(false)
const selectedButton = ref('拍摄基础')
//按钮 {key: '拍摄基础', value: '拍摄基础'}
const buttons = ref([
{ key: '拍摄基础', value: '拍摄基础' },
{ key: '内容策划', value: '内容策划' },
{ key: '拍摄执行', value: '拍摄执行' },
{ key: '后期制作', value: '后期制作' },
{ key: '版权伦理意识', value: '版权伦理意识' }
])
// 预留:按钮选中状态(如需启用再恢复逻辑)
//引导步骤
const steps = [
{
id: 'step1',
content: '可以点击左右箭头切换到对应模块的知识树哦'
}
]
// 预留:模块按钮(如需启用再补充实现)
const currentHighlight = computed(() =>
stepIndex.value === 0 ? '.img-switch-item--vlog' : '.work-border'
)
const selectedImage = computed(() => {
return selected.value ? 'skill/画面构图选中' : 'skill/画面构图未选中'
})
interface SimpleStep {
id: string
content: string
}
const handleStepChange = (_step: SimpleStep | null, index: number) => {
stepIndex.value = index
}
const handleClose = () => {
router.back()
}
const handleClick = () => {
selected.value = true
router.push({
name: 'SkillVdieo'
})
}
setTimeout(() => {
status.value = true
}, 1000)
</script>
<template>
<div class="w-full h-full relative font-semibold">
<!-- 背景图片-center -->
<div
class="absolute inset-0 bg-cover bg-center bg-no-repeat"
:style="{ backgroundImage: getBackgroundImage('skill/技能树背景') }"
></div>
<ImgButton class="absolute left-0 top-1/2 -translate-y-1/2" :image="'skill/左滑'"> </ImgButton>
<ImgButton
@click="sideStatus = false"
class="absolute right-0 top-1/2 -translate-y-1/2"
:image="'skill/右滑'"
>
</ImgButton>
<!-- 周围模块标签(静态绘制) -->
<div v-show="sideStatus" class="module module-left-bottom module-vertical">
<div
:class="['module-text blue-text', status ? 'text-white' : 'text-[#969696e6_!important]']"
>
拍摄基础
</div>
<div :class="['module-percent', status ? 'red-text' : 'blue-text']">0%</div>
</div>
<div v-show="sideStatus" class="module module-left-middle module-vertical">
<div
:class="['module-text blue-text', status ? 'text-white' : 'text-[#969696e6_!important]']"
>
内容策划
</div>
<div :class="['module-percent', status ? 'red-text' : 'blue-text']">0%</div>
</div>
<div v-show="!sideStatus" class="module module-right-middle module-vertical">
<div
:class="['module-text blue-text', status ? 'text-white' : 'text-[#969696e6_!important]']"
>
拍摄执行
</div>
<div :class="['module-percent', status ? 'red-text' : 'blue-text']">0%</div>
</div>
<div v-show="sideStatus" class="module module-right-upper module-vertical">
<div
:class="['module-text blue-text', status ? 'text-white' : 'text-[#969696e6_!important]']"
>
后期制作
</div>
<div :class="['module-percent', status ? 'red-text' : 'blue-text']">0%</div>
</div>
<div v-show="sideStatus" class="module module-right-far module-vertical">
<div
:class="['module-text blue-text', status ? 'text-white' : 'text-[#969696e6_!important]']"
>
版权伦理意识
</div>
<div :class="['module-percent', status ? 'red-text' : 'blue-text']">0%</div>
</div>
<!-- 画面构图 -->
<ImgButton
v-show="!sideStatus"
@click="handleClick"
class="absolute top-[38%] left-[23%] z-10"
:image="selectedImage"
/>
<!-- 景别 -->
<ImgButton v-show="!sideStatus" class="absolute top-[15%] left-[33%] z-10" image="skill/景别" />
<!-- 返回 -->
<ImgButton
class="absolute right-0 top-0"
:image="IMAGE_PATHS.COMPONENTS.BACK"
@click="handleClose"
/>
<!-- 树 -->
<div
class="absolute top-28 left-[calc(50%-30px)] -translate-x-1/2 w-[786px] h-[875px] bg-cover bg-center bg-no-repeat"
:style="{
backgroundImage: status
? getBackgroundImage('skill/技能树-亮')
: getBackgroundImage('skill/技能树-灰')
}"
></div>
<div class="absolute bottom-28 left-1/2 -translate-x-1/2">
<span class="blue-text tracking-[18px] text-5xl">
{{ !sideStatus ? '技能树-vlog' : '技能树-新手启航' }}
</span>
</div>
<div class="absolute bottom-10 left-1/2 -translate-x-1/2">
<span class="red-text text-4xl">{{
status ? '当前尚未收集任何知识点,快去学习收集知识点吧' : '当前已全部解锁'
}}</span>
</div>
<!-- 引导与高亮 -->
<GuideSteps
v-if="status"
:steps="steps"
:highlight-selector="currentHighlight"
:highlight-padding="12"
:highlight-radius="20"
@step-change="handleStepChange"
position-offset-y="85%"
/>
</div>
</template>
<style scoped>
/* 强发光蓝绿主标题(图2风格) */
.blue-text {
/* 文字本体采用蓝绿渐变并保持白色高亮视觉 */
background: linear-gradient(180deg, #cfffff 0%, #9ff3ff 40%, #6ee7ff 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
/* 多层发光,柔边外扩 */
text-shadow:
0 0 2px rgba(255, 255, 255, 0.9),
0 0 6px rgba(79, 241, 255, 0.9),
0 0 14px rgba(79, 241, 255, 0.8),
0 0 28px rgba(0, 199, 255, 0.6),
0 0 46px rgba(0, 199, 255, 0.45);
}
/* 强发光白粉副标题(图2风格) */
.red-text {
background: linear-gradient(180deg, #ffffff 0%, #ffe9e9 55%, #ffd1d1 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow:
0 0 2px rgba(255, 255, 255, 0.9),
0 0 8px rgba(255, 135, 135, 0.85),
0 0 18px rgba(255, 135, 135, 0.65),
0 0 32px rgba(255, 110, 110, 0.55);
}
/* 模块标签基础样式 */
.module {
position: absolute;
display: flex;
align-items: center;
gap: 8px;
}
/* 竖排布局 */
.module-vertical {
cursor: pointer;
align-items: flex-end;
}
.module-vertical .module-text {
writing-mode: vertical-rl;
text-orientation: upright;
}
.module-vertical .module-percent {
transform: translateY(6px);
}
.module-text {
/* color: rgba(150, 150, 150, 0.9); */
font-size: 36px;
letter-spacing: 8px;
}
.module-percent {
color: #ffffff;
font-size: 28px;
}
/* 位置近似图2布局 */
.module-left-bottom {
left: 10%;
bottom: 22%;
}
.module-left-middle {
left: 25%;
top: 48%;
}
.module-right-middle {
right: 26%;
top: 52%;
}
.module-right-upper {
right: 18%;
top: 42%;
}
.module-right-far {
right: 8%;
top: 50%;
}
</style>
+43
View File
@@ -0,0 +1,43 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import ImgButton from '@/components/Button/ImgButton.vue'
import { IMAGE_PATHS } from '@/utils'
import six from '/video/新手导航_九种构图法.mp4'
const router = useRouter()
const videoRef = ref()
const handleClose = () => {
router.back()
}
const handlePlay = () => {
if (!videoRef.value) return
videoRef.value.muted = false
videoRef.value.volume = 1
}
</script>
<template>
<div class="w-full h-full relative bg-white/10" @click="handlePlay">
<!-- 返回 -->
<ImgButton
class="absolute right-0 top-0 z-10"
:image="IMAGE_PATHS.COMPONENTS.BACK"
@click="handleClose"
/>
<video ref="videoRef" :src="six" controls></video>
</div>
</template>
<style scoped>
video {
width: 100%;
height: 100%;
/* 核心:保持视频比例,多余部分被裁剪 */
object-fit: cover;
}
</style>
+11
View File
@@ -27,6 +27,10 @@ const handleWorkClick = () => {
router.push({ name: 'Work' })
}
const handleClose = () => {
router.back()
}
onMounted(() => {
if (route.query.key === 'video') {
currentStep.value = 1
@@ -42,6 +46,13 @@ onMounted(() => {
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.VLOG.BG_CENTER) }"
></div>
<!-- 关闭 -->
<ImgButton
class="absolute right-0 top-0 z-20"
:image="IMAGE_PATHS.COMPONENTS.CLOSE"
@click="handleClose"
/>
<!-- 背景图片 -->
<div
class="absolute inset-0 bg-cover bg-center bg-no-repeat"
+1 -1
View File
@@ -38,7 +38,7 @@ const handleVideoChange = () => {
steps.value = [
{
id: 'step1',
content: '已完成专业剖析,即可查看脚本'
content: '恭喜你,已完成专业剖析的学习,点击【查看脚本】回顾视频脚本吧!'
}
]
return
+22 -3
View File
@@ -1,10 +1,13 @@
<script lang="tsx" setup>
import { ref, computed, onMounted } from 'vue'
<script lang="tsx" name="Work" setup>
defineOptions({ name: 'Work' })
import { ref, computed, onMounted, onActivated } 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'
import { useScale } from '@/composables/useScale'
import { ImagePreview } from '@/components'
const router = useRouter()
const route = useRoute()
@@ -91,7 +94,22 @@ const handleClose = () => {
//状态是否完成前置
const isComplete = ref(false)
onMounted(() => {
const handleWorkClick = () => {
if (!isComplete.value) return
openImages([getStaticImage('work/桂花酒酿小圆子')])
}
const { scale, offsetX, offsetY } = useScale()
function openImages(urls: string[], startIndex = 0) {
ImagePreview({
images: urls,
startIndex,
maskClosable: true,
getScaleMetrics: () => ({ scale: scale.value, offsetX: offsetX.value, offsetY: offsetY.value })
})
}
onActivated(() => {
if (route.query.key === 'work') {
selected.value = 'profession'
isComplete.value = true
@@ -153,6 +171,7 @@ onMounted(() => {
<ImgButton
class="absolute right-14 bottom-10"
:image="isComplete ? IMAGE_PATHS.WORK.TASK_BTN_OK : IMAGE_PATHS.WORK.TASK_BTN"
@click="handleWorkClick"
/>
<!-- 引导与高亮 -->