Работа над интерактивным обучением
This commit is contained in:
118
resources/js/Components/Onboarding/Onboarding.vue
Normal file
118
resources/js/Components/Onboarding/Onboarding.vue
Normal 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>
|
||||
Reference in New Issue
Block a user