feat: 完善课程学习与技能树体验
完善课程资源、学习进度与技能树解锁体验,统一视频播放与引导相关交互。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
6f289959be
commit
3e258b87d9
314 files changed
+7020
-3386
No files matched your search
@@ -69,7 +69,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, useSlots, onMounted, onUnmounted, reactive } from 'vue'
|
||||
import { ref, computed, useSlots, onMounted, onUnmounted } from 'vue'
|
||||
import { useScale } from '@/composables/useScale'
|
||||
import type { GuideStep } from './types'
|
||||
import SpotlightOverlay from './SpotlightOverlay.vue'
|
||||
import GuideDragon from './GuideDragon.vue'
|
||||
@@ -101,6 +102,7 @@ interface Props {
|
||||
interface Emits {
|
||||
(e: 'complete'): void
|
||||
(e: 'skip'): void
|
||||
(e: 'close'): void
|
||||
(e: 'step-change', step: GuideStep | null, index: number): void
|
||||
}
|
||||
|
||||
@@ -122,25 +124,13 @@ const emit = defineEmits<Emits>()
|
||||
const slots = useSlots()
|
||||
const internalShow = ref(true)
|
||||
const currentStepIndex = ref(0)
|
||||
const { scaleStyle: alignStyle } = useScale()
|
||||
|
||||
// 合并外部 visible 和内部 show 状态
|
||||
// 只有当外部 visible 为 true 且内部 internalShow 也为 true 时才显示
|
||||
const show = computed(() => {
|
||||
return props.visible && internalShow.value
|
||||
})
|
||||
const alignStyle = reactive<{
|
||||
left: string
|
||||
top: string
|
||||
transform: string
|
||||
width: string
|
||||
height: string
|
||||
}>({
|
||||
left: '0px',
|
||||
top: '0px',
|
||||
transform: 'scale(1)',
|
||||
width: '1920px',
|
||||
height: '1080px',
|
||||
})
|
||||
const normalizeSelector = (selector?: string | null) => {
|
||||
if (!selector) return null
|
||||
const trimmed = selector.trim()
|
||||
@@ -244,12 +234,14 @@ const handleNext = () => {
|
||||
}
|
||||
|
||||
const handleSkip = () => {
|
||||
emit('skip')
|
||||
handleComplete()
|
||||
}
|
||||
|
||||
const handleComplete = () => {
|
||||
internalShow.value = false
|
||||
emit('complete')
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const goToStep = (index: number) => {
|
||||
@@ -335,34 +327,11 @@ onMounted(() => {
|
||||
if (props.autoStart && props.autoPlayInterval > 0) {
|
||||
startAutoPlay()
|
||||
}
|
||||
// 同步到 .app-content 的缩放与偏移,使引导面板与页面对齐
|
||||
const syncAlign = () => {
|
||||
const el = document.querySelector('.app-content') as HTMLElement | null
|
||||
if (!el) return
|
||||
const style = window.getComputedStyle(el)
|
||||
const transform = style.transform
|
||||
let scale = 1
|
||||
if (transform && transform !== 'none') {
|
||||
const match = transform.match(/matrix\(([^)]+)\)/)
|
||||
if (match) {
|
||||
const parts = match[1].split(',').map((s) => parseFloat(s.trim()))
|
||||
if (!Number.isNaN(parts[0])) scale = parts[0]
|
||||
}
|
||||
}
|
||||
alignStyle.transform = `scale(${scale})`
|
||||
alignStyle.left = style.left || '0px'
|
||||
alignStyle.top = style.top || '0px'
|
||||
alignStyle.width = style.width || '1920px'
|
||||
alignStyle.height = style.height || '1080px'
|
||||
}
|
||||
syncAlign()
|
||||
window.addEventListener('resize', syncAlign)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('keydown', handleKeydown)
|
||||
stopAutoPlay()
|
||||
window.removeEventListener('resize', () => {})
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
|
||||
Reference in new issue
Block a user