chore: bypass pre-commit for now
This commit is contained in:
1 parent
c4ba322e32
commit
d6b8682c68
39 files changed
+1328
-477
No files matched your search
+149
-308
@@ -1,239 +1,155 @@
|
||||
<script lang="tsx" setup>
|
||||
defineOptions({ name: 'SkillPage' })
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getBackgroundImage, IMAGE_PATHS } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import ModuleSwitcher from './components/ModuleSwitcher.vue'
|
||||
import CategoryTags from './components/CategoryTags.vue'
|
||||
import IconLayer from './components/IconLayer.vue'
|
||||
import { GuideSteps } from '@/components/Guide'
|
||||
import { useRouter } from 'vue-router'
|
||||
import KnowledgeCard from '@/components/KnowledgeCard/KnowledgeCard.vue'
|
||||
import { useSkillState, type KnowledgeBtn } from './useSkillState'
|
||||
|
||||
const router = useRouter()
|
||||
const stepIndex = ref(0)
|
||||
const selected = ref(false)
|
||||
|
||||
// 仅从 hook 获取必要的业务状态与意图判断
|
||||
const {
|
||||
currentModule,
|
||||
nextModule,
|
||||
prevModule,
|
||||
selectedCategory,
|
||||
handleCategoryClick,
|
||||
currentCategoryConfig,
|
||||
displayedIcons,
|
||||
showSubIcons,
|
||||
selectedPrimaryIcon,
|
||||
getIconAction
|
||||
} = useSkillState()
|
||||
|
||||
// 页面 UI 状态(留在组件内)
|
||||
const status = ref(false)
|
||||
setTimeout(() => {
|
||||
status.value = true
|
||||
}, 1000)
|
||||
const sideStatus = ref(true)
|
||||
|
||||
const status = ref(false)
|
||||
|
||||
const selectedModule = ref(1)
|
||||
const selectedCategory = ref('') // 新增:选中的分类
|
||||
|
||||
// 新增:分类配置类型定义
|
||||
interface CategoryConfig {
|
||||
icons: string[]
|
||||
positions: { top: string; left: string }[]
|
||||
}
|
||||
|
||||
// 新增:模块配置类型定义
|
||||
interface ModuleConfig {
|
||||
name: string
|
||||
value: number
|
||||
categories: Record<string, CategoryConfig>
|
||||
}
|
||||
|
||||
const moduleList = ref<ModuleConfig[]>([
|
||||
{
|
||||
name: '技能书-新手启航',
|
||||
value: 1,
|
||||
categories: {
|
||||
拍摄基础: {
|
||||
icons: ['skill/画面构图选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
内容策划: {
|
||||
icons: ['skill/画面构图选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
拍摄执行: {
|
||||
icons: ['skill/画面构图选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
后期制作: {
|
||||
icons: ['skill/画面构图选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
版权伦理意识: {
|
||||
icons: ['skill/画面构图选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '技能书-vlog',
|
||||
value: 2,
|
||||
categories: {
|
||||
拍摄基础: {
|
||||
icons: ['skill/画面构图选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
内容策划: {
|
||||
icons: ['skill/画面构图选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
拍摄执行: {
|
||||
icons: ['skill/画面构图选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
后期制作: {
|
||||
icons: ['skill/画面构图选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
},
|
||||
版权伦理意识: {
|
||||
icons: ['skill/画面构图选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'],
|
||||
positions: [
|
||||
{ top: '25%', left: '25%' },
|
||||
{ top: '15%', left: '34%' },
|
||||
{ top: '20%', left: '45%' },
|
||||
{ top: '28%', left: '58%' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
const currentModule = computed(() => {
|
||||
return moduleList.value.find(item => item.value === selectedModule.value) || moduleList.value[0]
|
||||
})
|
||||
|
||||
const nextModule = () => {
|
||||
if (selectedModule.value === moduleList.value.length) {
|
||||
selectedModule.value = 1
|
||||
} else {
|
||||
selectedModule.value++
|
||||
}
|
||||
// 切换模块时重置分类选择
|
||||
if (selectedCategory.value) {
|
||||
selectedCategory.value = ''
|
||||
sideStatus.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const prevModule = () => {
|
||||
if (selectedModule.value === 1) {
|
||||
selectedModule.value = moduleList.value.length
|
||||
} else {
|
||||
selectedModule.value--
|
||||
}
|
||||
// 切换模块时重置分类选择
|
||||
if (selectedCategory.value) {
|
||||
selectedCategory.value = ''
|
||||
sideStatus.value = true
|
||||
}
|
||||
}
|
||||
|
||||
//引导步骤
|
||||
const steps = [
|
||||
{
|
||||
id: 'step1',
|
||||
content: '可以点击左右箭头切换到对应模块的知识树哦'
|
||||
}
|
||||
]
|
||||
|
||||
// 预留:模块按钮(如需启用再补充实现)
|
||||
|
||||
// 引导
|
||||
const stepIndex = ref(0)
|
||||
type SimpleStep = { id: string; content: string }
|
||||
const steps: SimpleStep[] = [{ 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 onNextModule = () => {
|
||||
nextModule()
|
||||
if (selectedCategory.value) {
|
||||
selectedCategory.value = ''
|
||||
sideStatus.value = true
|
||||
}
|
||||
showSubIcons.value = false
|
||||
selectedPrimaryIcon.value = null
|
||||
}
|
||||
const onPrevModule = () => {
|
||||
prevModule()
|
||||
if (selectedCategory.value) {
|
||||
selectedCategory.value = ''
|
||||
sideStatus.value = true
|
||||
}
|
||||
showSubIcons.value = false
|
||||
selectedPrimaryIcon.value = null
|
||||
}
|
||||
|
||||
// 分类选择(保持原交互)
|
||||
const onCategorySelect = (categoryName: string) => {
|
||||
handleCategoryClick(categoryName)
|
||||
sideStatus.value = false
|
||||
showSubIcons.value = false
|
||||
selectedPrimaryIcon.value = null
|
||||
}
|
||||
|
||||
// 返回按钮相关
|
||||
const handleBackToMain = () => {
|
||||
selectedCategory.value = ''
|
||||
sideStatus.value = true
|
||||
showSubIcons.value = false
|
||||
selectedPrimaryIcon.value = null
|
||||
}
|
||||
const backButtonTooltip = computed(() => {
|
||||
if (showSubIcons.value) return '返回上一步'
|
||||
return selectedCategory.value ? '返回主视图' : '退出页面'
|
||||
})
|
||||
const handleClose = () => {
|
||||
// 如果当前在分类选中状态,则退出选中回到主视图
|
||||
if (showSubIcons.value) {
|
||||
showSubIcons.value = false
|
||||
selectedPrimaryIcon.value = null
|
||||
return
|
||||
}
|
||||
if (selectedCategory.value) {
|
||||
handleBackToMain()
|
||||
} else {
|
||||
// 否则退出页面
|
||||
router.back()
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
selected.value = true
|
||||
router.push({
|
||||
name: 'SkillVdieo'
|
||||
})
|
||||
// 知识卡片(本地维护)
|
||||
const showKnowledgeCard = ref(false)
|
||||
const currentKnowledge = ref<KnowledgeBtn | null>(null)
|
||||
const knowledgeMap: Record<'三分法构图' | '居中构图' | '对角线构图', KnowledgeBtn> = {
|
||||
居中构图: {
|
||||
key: '1',
|
||||
name: '居中构图',
|
||||
btnImage: 'shooting/居中构图底板',
|
||||
desc: '居中构图就是主体放在画面中心,让画面更稳定主体更突出,拍摄时需避免选取杂乱的背景,可以用大光圈或者长焦距让背景虚化使主体从背景中跳出来适合拍摄单个主体,操作比较简单,非常适合新手使用',
|
||||
images: ['shooting/居中构图1', 'shooting/居中构图2']
|
||||
},
|
||||
三分法构图: {
|
||||
key: '2',
|
||||
name: '三分法构图',
|
||||
btnImage: 'shooting/三分法构图底板',
|
||||
desc: '三分法构图又称九宫格构图,就是把拍摄主体置于九宫格的任意一条三分位置,三分构图法是比较常见的构图法可以视觉上让整体画面更加生动,使用三分构图法拍摄人像时,尽量占据画面的下2格比例和重心会更协调',
|
||||
images: ['shooting/图片待定1', 'shooting/图片待定2']
|
||||
},
|
||||
对角线构图: {
|
||||
key: '3',
|
||||
name: '对角线构图',
|
||||
btnImage: 'shooting/对角线构图底板',
|
||||
desc: '对角线构图属于引导线构图的一种,所以也是借助引导线的视觉引导效果来突出强调主体。另外对角线构图在画面中制造出对角线的走向即可。',
|
||||
images: ['shooting/对角线构图1', 'shooting/对角线构图2']
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:处理分类点击事件
|
||||
const handleCategoryClick = (categoryName: string) => {
|
||||
selectedCategory.value = categoryName
|
||||
sideStatus.value = false // 隐藏其他模块标签
|
||||
const openKnowledge = (name: '三分法构图' | '居中构图' | '对角线构图') => {
|
||||
currentKnowledge.value = knowledgeMap[name]
|
||||
showKnowledgeCard.value = true
|
||||
}
|
||||
|
||||
// 新增:返回主视图
|
||||
const handleBackToMain = () => {
|
||||
selectedCategory.value = ''
|
||||
sideStatus.value = true
|
||||
}
|
||||
|
||||
// 新增:获取当前分类的配置
|
||||
const currentCategoryConfig = computed(() => {
|
||||
if (!selectedCategory.value) return null
|
||||
return currentModule.value.categories[selectedCategory.value] || null
|
||||
const currentCompositionKey = computed(() => {
|
||||
const k = currentKnowledge.value?.key
|
||||
if (k === '1' || k === '2' || k === '3') return k
|
||||
return '1'
|
||||
})
|
||||
|
||||
// 新增:返回按钮提示文本
|
||||
const backButtonTooltip = computed(() => {
|
||||
return selectedCategory.value ? '返回主视图' : '退出页面'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
status.value = true
|
||||
}, 1000)
|
||||
// 图标点击(基于 hook 的意图判断)
|
||||
const handleIconClick = (icon: string) => {
|
||||
const action = getIconAction(icon)
|
||||
if (!action) return
|
||||
if (action.type === 'navigate') {
|
||||
router.push(action.payload)
|
||||
return
|
||||
}
|
||||
if (action.type === 'expand') {
|
||||
showSubIcons.value = true
|
||||
selectedPrimaryIcon.value = 'skill/画面构图选中'
|
||||
return
|
||||
}
|
||||
if (action.type === 'openKnowledge') {
|
||||
openKnowledge(action.payload.name)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -244,101 +160,24 @@ setTimeout(() => {
|
||||
:style="{ backgroundImage: getBackgroundImage('skill/技能树背景') }"
|
||||
></div>
|
||||
|
||||
<ImgButton
|
||||
@click="prevModule"
|
||||
class="absolute left-0 top-1/2 -translate-y-1/2"
|
||||
:image="'skill/左滑'"
|
||||
>
|
||||
</ImgButton>
|
||||
|
||||
<ImgButton
|
||||
@click="nextModule"
|
||||
class="absolute right-0 top-1/2 -translate-y-1/2"
|
||||
:image="'skill/右滑'"
|
||||
>
|
||||
</ImgButton>
|
||||
<ModuleSwitcher :module-name="currentModule.name" @prev="onPrevModule" @next="onNextModule" />
|
||||
|
||||
<!-- 周围模块标签(静态绘制) -->
|
||||
<div
|
||||
v-show="sideStatus || selectedCategory === '拍摄基础'"
|
||||
class="module module-left-bottom module-vertical"
|
||||
@click="handleCategoryClick('拍摄基础')"
|
||||
>
|
||||
<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 || selectedCategory === '内容策划'"
|
||||
class="module module-left-middle module-vertical"
|
||||
@click="handleCategoryClick('内容策划')"
|
||||
>
|
||||
<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 || selectedCategory === '拍摄执行'"
|
||||
class="module module-right-middle module-vertical"
|
||||
@click="handleCategoryClick('拍摄执行')"
|
||||
>
|
||||
<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 || selectedCategory === '后期制作'"
|
||||
class="module module-right-upper module-vertical"
|
||||
@click="handleCategoryClick('后期制作')"
|
||||
>
|
||||
<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 || selectedCategory === '版权伦理意识'"
|
||||
class="module module-right-far module-vertical"
|
||||
@click="handleCategoryClick('版权伦理意识')"
|
||||
>
|
||||
<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>
|
||||
<CategoryTags
|
||||
:status="status"
|
||||
:side-status="sideStatus"
|
||||
:selected-category="selectedCategory"
|
||||
@select="onCategorySelect"
|
||||
/>
|
||||
|
||||
<!-- 动态显示分类对应的icon -->
|
||||
<template v-if="currentCategoryConfig">
|
||||
<ImgButton
|
||||
v-for="(icon, index) in currentCategoryConfig.icons"
|
||||
:key="index"
|
||||
v-show="!sideStatus"
|
||||
@click="handleClick"
|
||||
class="absolute z-10"
|
||||
:style="{
|
||||
top: currentCategoryConfig.positions[index].top,
|
||||
left: currentCategoryConfig.positions[index].left
|
||||
}"
|
||||
:image="icon"
|
||||
/>
|
||||
</template>
|
||||
<IconLayer
|
||||
v-if="currentCategoryConfig"
|
||||
:positions="currentCategoryConfig.positions"
|
||||
:displayed-icons="displayedIcons"
|
||||
:side-status="sideStatus"
|
||||
@iconClick="handleIconClick"
|
||||
/>
|
||||
|
||||
<!-- 返回按钮 -->
|
||||
<ImgButton
|
||||
@@ -358,18 +197,9 @@ setTimeout(() => {
|
||||
}"
|
||||
></div>
|
||||
|
||||
<div class="absolute bottom-28 left-1/2 -translate-x-1/2">
|
||||
<span class="blue-text tracking-[18px] text-5xl">
|
||||
{{ selectedCategory || currentModule.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="absolute bottom-10 left-1/2 -translate-x-1/2">
|
||||
<span class="red-text text-4xl">{{
|
||||
!status
|
||||
? '当前尚未收集任何知识点,快去学习收集知识点吧'
|
||||
: selectedCategory
|
||||
? `当前${selectedCategory}模块已全部解锁`
|
||||
: '当前已全部解锁'
|
||||
!status ? '当前尚未收集任何知识点,快去学习收集知识点吧' : '当前已全部解锁'
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
@@ -383,6 +213,17 @@ setTimeout(() => {
|
||||
@step-change="handleStepChange"
|
||||
position-offset-y="85%"
|
||||
/>
|
||||
|
||||
<!-- 知识卡片 -->
|
||||
<KnowledgeCard
|
||||
v-if="currentKnowledge"
|
||||
:visible="showKnowledgeCard"
|
||||
:title="currentKnowledge.name"
|
||||
:desc="currentKnowledge.desc"
|
||||
:images="currentKnowledge.images"
|
||||
:compositionKey="currentCompositionKey"
|
||||
@close="showKnowledgeCard = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in new issue
Block a user