Работа над интерактивным обучением для дежурного и мед. сестры
This commit is contained in:
@@ -135,7 +135,11 @@ function delay(ms) {
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<TourOverlay
|
||||
v-if="onboarding.active && target"
|
||||
v-if="onboarding.active &&
|
||||
target &&
|
||||
onboarding.currentStep?.highlight !== false &&
|
||||
rect"
|
||||
:allow-interaction="onboarding.currentStep?.allowInteraction ?? true"
|
||||
:rect="rect"
|
||||
:padding="onboarding.currentStep.padding"
|
||||
/>
|
||||
@@ -148,7 +152,7 @@ function delay(ms) {
|
||||
:visible="onboarding.active"
|
||||
|
||||
:is-first="onboarding.stepIndex === 0"
|
||||
:is-last="onboarding.stepIndex === onboarding.tour.steps.length - 1"
|
||||
:is-last="onboarding.stepIndex === onboarding.tour?.steps.length - 1"
|
||||
|
||||
@next="onboarding.next"
|
||||
@previous="onboarding.previous"
|
||||
@@ -156,4 +160,4 @@ function delay(ms) {
|
||||
@close="onboarding.finish"
|
||||
/>
|
||||
</Teleport>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -5,16 +5,50 @@ const props = defineProps({
|
||||
rect: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
allowInteraction: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
const style = computed(() => {
|
||||
const r = props.rect
|
||||
const overlayStyle = computed(() => {
|
||||
|
||||
if (!props.rect) return null;
|
||||
|
||||
const { top, left, width, height } = props.rect
|
||||
|
||||
return {
|
||||
"--top": `${r.top}px`,
|
||||
"--left": `${r.left}px`,
|
||||
"--width": `${r.width}px`,
|
||||
"--height": `${r.height}px`
|
||||
top: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100vw',
|
||||
height: `${top}px`
|
||||
},
|
||||
left: {
|
||||
top: `${top}px`,
|
||||
left: 0,
|
||||
width: `${left}px`,
|
||||
height: `${height}px`
|
||||
},
|
||||
right: {
|
||||
top: `${top}px`,
|
||||
left: `${left+width}px`,
|
||||
width: `calc(100vw - ${left+width}px)`,
|
||||
height: `${height}px`
|
||||
},
|
||||
bottom: {
|
||||
top: `${top+height}px`,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: `calc(100vh - ${top+height}px)`
|
||||
},
|
||||
highlight: {
|
||||
top: `${top}px`,
|
||||
left: `${left}px`,
|
||||
width: `${width}px`,
|
||||
height: `${height}px`
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -24,10 +58,32 @@ const style = computed(() => {
|
||||
|
||||
<Teleport to="body">
|
||||
<Transition name="tour-fade">
|
||||
<div
|
||||
class="tour-overlay"
|
||||
:style="style"
|
||||
/>
|
||||
<div v-if="rect && overlayStyle">
|
||||
<div
|
||||
class="tour-mask"
|
||||
:style="overlayStyle.top"
|
||||
/>
|
||||
<div
|
||||
class="tour-mask"
|
||||
:style="overlayStyle.left"
|
||||
/>
|
||||
<div
|
||||
class="tour-mask"
|
||||
:style="overlayStyle.right"
|
||||
/>
|
||||
<div
|
||||
class="tour-mask"
|
||||
:style="overlayStyle.bottom"
|
||||
/>
|
||||
<div
|
||||
class="tour-highlight"
|
||||
:style="overlayStyle.highlight"
|
||||
/>
|
||||
<div
|
||||
v-if="!allowInteraction"
|
||||
class="tour-blocker"
|
||||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
|
||||
@@ -35,28 +91,27 @@ const style = computed(() => {
|
||||
|
||||
|
||||
<style scoped>
|
||||
.tour-mask {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
background: rgba(0,0,0,.55);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.tour-overlay {
|
||||
.tour-blocker {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background: rgba(0,0,0,.55);
|
||||
background: transparent;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
вырезаем окно
|
||||
*/
|
||||
mask:
|
||||
linear-gradient(#000 0 0),
|
||||
linear-gradient(#000 0 0);
|
||||
mask-size:
|
||||
100% 100%,
|
||||
var(--width) var(--height);
|
||||
mask-position:
|
||||
0 0,
|
||||
var(--left) var(--top);
|
||||
mask-repeat:no-repeat;
|
||||
mask-composite: exclude;
|
||||
.tour-highlight {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
border: 2px solid white;
|
||||
border-radius: 8px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.tour-fade-enter-active,
|
||||
@@ -68,4 +123,4 @@ const style = computed(() => {
|
||||
.tour-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -23,6 +23,10 @@ const props = defineProps({
|
||||
type: [HTMLElement, String, Object],
|
||||
default: null
|
||||
},
|
||||
disabledControllers: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
@@ -53,83 +57,83 @@ const style = computed(() => ({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Transition name="tour-tooltip">
|
||||
<div
|
||||
ref="floating"
|
||||
v-if="visible && step"
|
||||
class="tour-tooltip"
|
||||
:style="style"
|
||||
<Transition name="tour-tooltip">
|
||||
<div
|
||||
ref="floating"
|
||||
v-if="visible && step"
|
||||
class="tour-tooltip"
|
||||
:style="style"
|
||||
>
|
||||
<NCard
|
||||
style="width:320px"
|
||||
size="small"
|
||||
>
|
||||
<NCard
|
||||
style="width:320px"
|
||||
size="small"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-semibold">
|
||||
{{ step.title }}
|
||||
</span>
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-semibold">
|
||||
{{ step.title }}
|
||||
</span>
|
||||
|
||||
<NTag
|
||||
v-if="step.tag"
|
||||
size="small"
|
||||
>
|
||||
{{ step.tag }}
|
||||
</NTag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="text-sm whitespace-pre-line">
|
||||
{{ step.description }}
|
||||
<NTag
|
||||
v-if="step.tag"
|
||||
size="small"
|
||||
>
|
||||
{{ step.tag }}
|
||||
</NTag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<slot />
|
||||
<div class="text-sm whitespace-pre-line">
|
||||
{{ step.description }}
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<NSpace justify="space-between">
|
||||
<div>
|
||||
<NButton
|
||||
quaternary
|
||||
size="small"
|
||||
@click="emit('close')"
|
||||
>
|
||||
Пропустить
|
||||
</NButton>
|
||||
</div>
|
||||
<slot />
|
||||
|
||||
<NSpace>
|
||||
<NButton
|
||||
v-if="!isFirst"
|
||||
size="small"
|
||||
@click="emit('previous')"
|
||||
>
|
||||
Назад
|
||||
</NButton>
|
||||
<template #footer>
|
||||
<NSpace justify="space-between">
|
||||
<div>
|
||||
<NButton
|
||||
quaternary
|
||||
size="small"
|
||||
@click="emit('close')"
|
||||
>
|
||||
Пропустить
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
<NButton
|
||||
v-if="!isLast"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="step.manual"
|
||||
@click="emit('next')"
|
||||
>
|
||||
Далее
|
||||
</NButton>
|
||||
<NSpace>
|
||||
<NButton
|
||||
v-if="!isFirst"
|
||||
size="small"
|
||||
@click="emit('previous')"
|
||||
>
|
||||
Назад
|
||||
</NButton>
|
||||
|
||||
<NButton
|
||||
v-else
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="emit('finish')"
|
||||
>
|
||||
Завершить
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NButton
|
||||
v-if="!isLast"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="step.manual"
|
||||
@click="emit('next')"
|
||||
>
|
||||
Далее
|
||||
</NButton>
|
||||
|
||||
<NButton
|
||||
v-else
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="emit('finish')"
|
||||
>
|
||||
Завершить
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NCard>
|
||||
</div>
|
||||
</Transition>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NCard>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -151,4 +155,4 @@ const style = computed(() => ({
|
||||
transform:translateY(6px);
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user