Работа над интерактивным обучением

This commit is contained in:
brusnitsyn
2026-07-14 17:30:33 +09:00
parent 7ec32eb097
commit 082f2b8b01
15 changed files with 609 additions and 19 deletions

View File

@@ -0,0 +1,118 @@
<script setup>
import {ref, onMounted, nextTick, inject, computed, watch} from 'vue'
import { VOnboardingWrapper, VOnboardingStep } from 'v-onboarding'
import { useOnboardingStore } from '../../Stores/onboarding'
import { router } from '@inertiajs/vue3'
import { route } from 'ziggy-js'
import {NCard, NSpace, NButton, NTag} from 'naive-ui'
const wrapper = ref(null)
const store = useOnboardingStore()
const currentRoute = ref(route().current())
const currentSteps = computed(() => store.currentTourSteps)
onMounted(async () => {
if (store.isActive && store.activeStepIndex !== null) {
await nextTick()
wrapper.value?.goToStep(store.activeStepIndex)
}
})
// Следим за изменением индекса шага
watch(() => store.activeStepIndex, async (newIndex, oldIndex) => {
if (newIndex === null || !store.isActive) return
const steps = store.currentTourSteps
const step = steps[newIndex]
if (!step) return
const stepRoute = step.route
// Если шаг на другой странице — переходим
if (stepRoute && stepRoute !== currentRoute.value) {
// Переход на нужную страницу (индекс уже сохранён в сторе)
router.visit(route(stepRoute))
// Не возвращаем false, просто делаем переход
// После перехода onMounted восстановит шаг
} else {
wrapper.value?.goToStep(store.activeStepIndex)
}
}, { immediate: true }) // immediate, чтобы сработало при первом запуске
// Обработчик кнопки "Далее" в обычных шагах
const handleNext = (next, exit, isLast) => {
if (isLast) {
exit()
store.finish()
} else {
// Вызываем next() это переключит шаг внутри библиотеки,
// но нам также нужно обновить store.activeStepIndex, чтобы watch сработал
const nextIndex = store.activeStepIndex + 1
store.setStep(nextIndex) // обновляем стор
next() // говорим библиотеке переключиться
}
}
// Обработчик кнопки "Назад" в обычных шагах
const handlePrevious = (previous, exit, isFirst) => {
if (isFirst) {
} else {
// Вызываем next() это переключит шаг внутри библиотеки,
// но нам также нужно обновить store.activeStepIndex, чтобы watch сработал
const nextIndex = store.activeStepIndex - 1
store.setStep(nextIndex) // обновляем стор
previous() // говорим библиотеке переключиться
}
}
const onFinish = () => {
store.finish()
}
</script>
<template>
<VOnboardingWrapper
ref="wrapper"
:steps="currentSteps"
@finish="onFinish"
>
<template #default="{ step, next, previous, exit, isFirst, isLast }">
<VOnboardingStep>
<NCard
style="max-width: 320px;"
:title="step.content.title"
class="rounded-lg! mt-1"
size="small"
>
<p>{{ step.content.description }}</p>
<template #footer>
<NSpace justify="end">
<NButton
v-if="!isFirst"
size="small"
@click="handlePrevious(previous, exit, isFirst)"
>
Назад
</NButton>
<NButton
type="primary"
size="small"
:disabled="step.manual"
@click="handleNext(next, exit, isLast)"
>
{{ isLast ? 'Завершить' : 'Далее' }}
</NButton>
</NSpace>
</template>
</NCard>
</VOnboardingStep>
</template>
</VOnboardingWrapper>
</template>
<style>
:root {
--v-onboarding-overlay-z: 9999;
--v-onboarding-step-z: 9999;
}
</style>