feat: 完善视频学习进度缓存

完善新手导航和三大创作模块的视频完成缓存、未完成提示与学习进度计算,确保进度按实际学习资源完成情况更新。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhongyidianandClaude Opus 4.7 committed 2026-05-11 09:05:29 +08:00
1 parent 1f8723aabd
commit 6f289959be
63 files changed
+3139 -1126

No files matched your search

+64 -17
View File
@@ -1,7 +1,13 @@
<template>
<Transition name="step-navigation" appear>
<Transition
name="step-navigation"
appear
>
<!-- 抽屉遮罩层 -->
<div v-if="visible" class="fixed inset-0 z-50 bg-black/30 backdrop-blur-md">
<div
v-if="visible"
class="fixed inset-0 z-50 bg-black/30 backdrop-blur-md"
>
<ImgButton
class="absolute right-0 top-0 z-[10]"
image="components/close"
@@ -20,14 +26,24 @@
@click.stop
>
<!-- 顶部分页箭头(上一页) -->
<div class="relative z-10 flex items-center justify-center pointer-events-none">
<div
class="relative z-10 flex items-center justify-center pointer-events-none"
>
<button
class="pointer-events-auto flex h-20 w-20 items-center justify-center border-none bg-transparent transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-40 hover:enabled:scale-110"
@click="goPrevPage"
:disabled="!canPrevPage"
>
<svg width="64" height="64" viewBox="0 0 40 40" fill="none">
<path d="M5 30L35 30L20 6Z" fill="white" />
<svg
width="64"
height="64"
viewBox="0 0 40 40"
fill="none"
>
<path
d="M5 30L35 30L20 6Z"
fill="white"
/>
</svg>
</button>
</div>
@@ -41,20 +57,31 @@
class="step-item-bg relative flex h-[122px] w-[831px] cursor-pointer items-center px-8 py-4 transition-all duration-300 hover:-translate-x-[23%]"
:class="{
'step-item-active-bg h-[230px] w-[1034px] pl-[180px] -translate-x-[23%]':
currentPageStartIndex + index === currentStepIndex
currentPageStartIndex + index === currentStepIndex,
}"
@click="handleStepClick(index)"
>
<!-- 步骤标签 -->
<div
class="mr-4 min-w-[5rem] rounded-full px-16 py-4 text-center text-2xl font-semibold shadow-md"
class="mr-0 min-w-[5rem] rounded-full px-16 py-4 text-center text-2xl font-semibold shadow-md"
:class="getTagColor(step.label)"
>
{{ step.label }}
</div>
<!-- 步骤内容 -->
<div class="mr-4 flex-1 text-3xl font-bold leading-[1.5]">
<div
class="mr-4 flex-1 text-3xl font-bold leading-[1.5] flex items-center"
>
<img
class="pointer-events-none h-12 w-12 object-contain transition-all duration-300"
:src="
completedSteps?.[currentPageStartIndex + index]
? completedIcon
: incompleteIcon
"
alt=""
/>
{{ step.content }}
</div>
@@ -63,7 +90,7 @@
class="absolute right-[15%] z-[1] flex items-center justify-center text-6xl font-semibold text-white/30 transition-all duration-300"
:class="{
'mb-20 text-[150px] text-white drop-shadow-[5px_10px_5px_rgba(0,0,0,0.1)]':
currentPageStartIndex + index === currentStepIndex
currentPageStartIndex + index === currentStepIndex,
}"
>
{{ currentPageStartIndex + index + 1 }}
@@ -79,8 +106,16 @@
@click="goNextPage"
:disabled="!canNextPage"
>
<svg width="64" height="64" viewBox="0 0 40 40" fill="none">
<path d="M5 10L35 10L20 34Z" fill="white" />
<svg
width="64"
height="64"
viewBox="0 0 40 40"
fill="none"
>
<path
d="M5 10L35 10L20 34Z"
fill="white"
/>
</svg>
</button>
</div>
@@ -94,6 +129,8 @@
import { ImgButton } from '@/components'
import { ref, computed, watch } from 'vue'
import { getTagColor } from '@/utils'
import completedIcon from '@/assets/images/midterm/完成.png'
import incompleteIcon from '@/assets/images/midterm/未完成.png'
export interface StepItem {
id: string
@@ -111,6 +148,8 @@ interface Props {
steps: StepItem[]
/** 当前步骤索引 */
currentStepIndex?: number
/** 步骤完成状态 */
completedSteps?: boolean[]
/** 是否显示关闭按钮 */
showClose?: boolean
}
@@ -122,7 +161,7 @@ interface Emits {
const props = withDefaults(defineProps<Props>(), {
currentStepIndex: 0,
showClose: true
showClose: true,
})
const emit = defineEmits<Emits>()
@@ -131,10 +170,15 @@ const emit = defineEmits<Emits>()
const pageSize = 5
const currentPage = ref(0)
const totalPages = computed(() => Math.max(1, Math.ceil((props.steps?.length ?? 0) / pageSize)))
const totalPages = computed(() =>
Math.max(1, Math.ceil((props.steps?.length ?? 0) / pageSize)),
)
const currentPageStartIndex = computed(() => currentPage.value * pageSize)
const pagedSteps = computed(() =>
props.steps.slice(currentPageStartIndex.value, currentPageStartIndex.value + pageSize)
props.steps.slice(
currentPageStartIndex.value,
currentPageStartIndex.value + pageSize,
),
)
const canPrevPage = computed(() => currentPage.value > 0)
@@ -164,14 +208,17 @@ const handleClose = () => {
// 当外部当前步骤改变时,自动定位到对应页
watch(
() => props.currentStepIndex,
newVal => {
(newVal) => {
const idx = newVal ?? 0
const targetPage = Math.floor(idx / pageSize)
if (targetPage !== currentPage.value) {
currentPage.value = Math.min(Math.max(targetPage, 0), totalPages.value - 1)
currentPage.value = Math.min(
Math.max(targetPage, 0),
totalPages.value - 1,
)
}
},
{ immediate: true }
{ immediate: true },
)
</script>