Работа над интерактивным обучением для дежурного и мед. сестры
This commit is contained in:
22
package-lock.json
generated
22
package-lock.json
generated
@@ -1122,7 +1122,8 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@tailwindcss/language-server": {
|
||||
"version": "0.14.29",
|
||||
@@ -1937,8 +1938,7 @@
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.13.0.tgz",
|
||||
"integrity": "sha512-PJuXT6zdiCbv0IkX5cqkKFVIIh+9v3kqP9zsOHEGpIWi7DfTgzvfOKc8icw6G3/ulR3V1alDDUtOVH0zWCWGEQ==",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"peer": true
|
||||
"license": "SEE LICENSE IN LICENSE"
|
||||
},
|
||||
"node_modules/async-validator": {
|
||||
"version": "4.2.5",
|
||||
@@ -2169,7 +2169,6 @@
|
||||
"integrity": "sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@emotion/hash": "~0.8.0",
|
||||
"csstype": "~3.0.5"
|
||||
@@ -2245,7 +2244,6 @@
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -2299,7 +2297,6 @@
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
@@ -2320,6 +2317,7 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
@@ -2394,6 +2392,7 @@
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.5.tgz",
|
||||
"integrity": "sha512-QCwxUDULPlXv8F6tqMMKx5dNkTe6OaBYRMPYeXKBlyOoKvAmE0ac6pW7fFhSscJ/5SI7666/U/B+MElbsrJlIg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.4.1",
|
||||
@@ -2407,6 +2406,7 @@
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
@@ -3183,7 +3183,8 @@
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.4.1",
|
||||
@@ -3301,7 +3302,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
|
||||
"integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^7.7.7"
|
||||
},
|
||||
@@ -3387,7 +3387,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.5.0.tgz",
|
||||
"integrity": "sha512-V7uzGi9bqOOOyM/6IkJdpFyjGZj7llz1v0oWnYkZKcYLvbz6VcHVLmzKqkvegjuMumpfIEKGLmWHwFb39XFCpw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tweetnacl": "^1.0.3"
|
||||
}
|
||||
@@ -3628,6 +3627,7 @@
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz",
|
||||
"integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.4.1"
|
||||
@@ -3840,7 +3840,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
|
||||
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -4198,7 +4197,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz",
|
||||
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.26",
|
||||
"@vue/compiler-sfc": "3.5.26",
|
||||
@@ -4311,6 +4309,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -4331,6 +4330,7 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 v-if="rect && overlayStyle">
|
||||
<div
|
||||
class="tour-overlay"
|
||||
:style="style"
|
||||
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,
|
||||
|
||||
@@ -23,6 +23,10 @@ const props = defineProps({
|
||||
type: [HTMLElement, String, Object],
|
||||
default: null
|
||||
},
|
||||
disabledControllers: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
|
||||
@@ -19,8 +19,8 @@ const onboarding = useOnboardingStore()
|
||||
const userStore = useAuthStore()
|
||||
const modalStore = useModalStore()
|
||||
|
||||
if (userStore.user.role.slug === 'dej')
|
||||
onboarding.start("welcomeDuty")
|
||||
// if (userStore.user.role.slug === 'nurse')
|
||||
// onboarding.start("welcomeNurse")
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const themeVars = useThemeVars()
|
||||
@@ -67,11 +67,12 @@ const isLockReportButton = computed(() => {
|
||||
return getHours(serverTime.value) < 6 || getHours(serverTime.value) >= 7
|
||||
})
|
||||
|
||||
const showSelectUserModal = ref(false)
|
||||
const showSelectDutyUserModal = ref(false)
|
||||
const showSelectNurseUserModal = ref(false)
|
||||
|
||||
const openReport = (path) => {
|
||||
modalStore.showSelectDutyUserModal = true
|
||||
showSelectDutyUserModal.value = true
|
||||
onboarding.emit('selectUser:opened')
|
||||
}
|
||||
|
||||
const openNurseReport = () => {
|
||||
@@ -80,7 +81,8 @@ const openNurseReport = () => {
|
||||
// } else {
|
||||
// router.visit('/nurse/report')
|
||||
// }
|
||||
modalStore.showSelectNurseUserModal = true
|
||||
showSelectNurseUserModal.value = true
|
||||
onboarding.emit('selectUser:opened')
|
||||
}
|
||||
|
||||
const cardColor = computed(() => themeVars.value.cardColor)
|
||||
@@ -90,7 +92,7 @@ const dividerColor = computed(() => themeVars.value.dividerColor)
|
||||
<template>
|
||||
<AppLayout>
|
||||
<div class="flex flex-col justify-center items-center" style="min-height: calc(100vh - 48px);">
|
||||
<NFlex vertical :size="10" class="max-w-2xl w-full" style="padding: 0 16px 24px;">
|
||||
<NFlex id="launcher" vertical :size="10" class="max-w-2xl w-full" style="padding: 0 16px 0 16px;">
|
||||
|
||||
<!-- Профиль -->
|
||||
<NEl id="user-panel" class="profile-card rounded-2xl" style="padding: 18px 22px;">
|
||||
@@ -192,9 +194,9 @@ const dividerColor = computed(() => themeVars.value.dividerColor)
|
||||
</NFlex>
|
||||
</div>
|
||||
|
||||
<SelectUserModal v-model:show="modalStore.showSelectDutyUserModal" :only-user-department="false" />
|
||||
<SelectUserModal v-model:show="showSelectDutyUserModal" :only-user-department="false" />
|
||||
<SelectUserModal
|
||||
v-model:show="modalStore.showSelectNurseUserModal"
|
||||
v-model:show="showSelectNurseUserModal"
|
||||
target-path="/nurse/report"
|
||||
submit-label="Перейти к журналу пациентов"
|
||||
:with-exists-check="false"
|
||||
|
||||
@@ -7,8 +7,11 @@ import {format} from "date-fns";
|
||||
import {router, usePage} from "@inertiajs/vue3";
|
||||
import AppPanel from "../../../Components/AppPanel.vue"
|
||||
import AppSearchAddress from '../../../Components/AppSearchAddress.vue';
|
||||
import {useOnboardingStore} from "../../../Stores/onboarding.js";
|
||||
|
||||
const show = defineModel('show', { default: false })
|
||||
|
||||
const onboarding = useOnboardingStore()
|
||||
const currentStep = ref(1)
|
||||
const currentStatus = ref('process')
|
||||
const isFinallyStep = computed(() => currentStep.value === 2)
|
||||
@@ -224,10 +227,16 @@ const onAfterLeave = () => {
|
||||
currentStep.value = 1
|
||||
searchOptions.value = []
|
||||
}
|
||||
|
||||
const onUpdatePatientSource = (v) => {
|
||||
if (v === 'mis') onboarding.emit('newPatientModal:patientTypeSelected')
|
||||
if (v === 'special') onboarding.emit('newPatientModal:patientTypeSelected')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="show"
|
||||
id="create-new-patient-modal"
|
||||
segmented
|
||||
preset="card"
|
||||
title="Добавление пациента"
|
||||
@@ -243,7 +252,7 @@ const onAfterLeave = () => {
|
||||
</NSteps>
|
||||
<NTabs tab-class="hidden!" :value="currentStep">
|
||||
<NTabPane :name="1" class="mt-4">
|
||||
<NRadioGroup class="w-full space-y-2!" v-model:value="form.patient_source">
|
||||
<NRadioGroup class="w-full space-y-2!" v-model:value="form.patient_source" @update:value="v => onUpdatePatientSource(v)">
|
||||
<AppRadio title="МИС" value="mis" description="Выберите, если пациента можно найти в системе МИС" />
|
||||
<AppRadio title="Спец. контингент" value="special" description="Выберите, если пациента нет в системе МИС" />
|
||||
</NRadioGroup>
|
||||
|
||||
@@ -17,6 +17,7 @@ import ActionsColumnDataTable from "../Components/ActionsColumnDataTable.vue";
|
||||
import {useAppDialog} from "../../../Composables/useAppDialog.js";
|
||||
import {format} from "date-fns";
|
||||
import DatePickerQuery from "../../../Components/DatePickerQuery.vue";
|
||||
import {useOnboardingStore} from "../../../Stores/onboarding.js";
|
||||
|
||||
const props = defineProps({
|
||||
patients: {
|
||||
@@ -53,6 +54,7 @@ const props = defineProps({
|
||||
|
||||
const canEdit = computed(() => props.canSaveReport || props.canEditPastReport)
|
||||
|
||||
const onboarding = useOnboardingStore()
|
||||
const showAddMedicalHistoryModal = shallowRef(false)
|
||||
const showEditMedicalHistoryModal = shallowRef(false)
|
||||
const editHistoryId = ref(null)
|
||||
@@ -210,18 +212,23 @@ const submit = () => {
|
||||
|
||||
const reportCreator = computed(() => {
|
||||
if (props.latestReport === null) return ''
|
||||
if (props.latestReport.doctor.LPUDoctorID === 0) return 'Отчет создан системой'
|
||||
if (props.latestReport.doctor?.LPUDoctorID === 0) return 'Отчет создан системой'
|
||||
else return `Отчет создан: ${props.latestReport.doctor.FAM_V} ${props.latestReport.doctor.IM_V} ${props.latestReport.doctor.OT_V}`
|
||||
})
|
||||
const reportCreatorType = computed(() => {
|
||||
if (props.latestReport === null) return 'warning'
|
||||
if (props.latestReport.doctor.LPUDoctorID === 0) return 'error'
|
||||
if (props.latestReport.doctor?.LPUDoctorID === 0) return 'error'
|
||||
else return 'warning'
|
||||
})
|
||||
|
||||
const formattedLabel = (word, count) => {
|
||||
return `${word} (${count})`
|
||||
}
|
||||
|
||||
const onShowCreatePatientModal = () => {
|
||||
showAddMedicalHistoryModal.value = true
|
||||
onboarding.emit('createNewPatientModal:opened')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -237,19 +244,19 @@ const formattedLabel = (word, count) => {
|
||||
{{ reportCreator }}
|
||||
</NTag>
|
||||
</NSpace>
|
||||
<DatePickerQuery :date="dates" :is-head-or-admin="true" class="text-lg!" hint />
|
||||
<DatePickerQuery id="date-selector" :date="dates" :is-head-or-admin="true" class="text-lg!" hint />
|
||||
</NFlex>
|
||||
</AppPanel>
|
||||
<AppPanel header="Журнал пациентов" header-include-body>
|
||||
<template v-if="canEdit" #header-extra>
|
||||
<NButton secondary :loading="loading" @click="showAddMedicalHistoryModal = true">
|
||||
<NButton id="add-new-patient" secondary :loading="loading" @click="onShowCreatePatientModal">
|
||||
<template #icon>
|
||||
<TbCirclePlus />
|
||||
</template>
|
||||
Добавить пациента
|
||||
</NButton>
|
||||
</template>
|
||||
<NTabs type="line">
|
||||
<NTabs id="view-tabs" type="line">
|
||||
<NTabPane name="all"
|
||||
:tab="formattedLabel('В отделении', patientsByGroup.in_department.length)"
|
||||
>
|
||||
|
||||
@@ -27,6 +27,8 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const reportStore = useReportStore()
|
||||
const onboarding = useOnboardingStore()
|
||||
|
||||
const formRef = ref()
|
||||
|
||||
const rawUsers = ref([])
|
||||
@@ -153,10 +155,15 @@ const onSubmit = (e) => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
if (reportExists.value) return
|
||||
|
||||
router.visit(props.targetPath, {
|
||||
data: {
|
||||
userId: reportStore.reportInfo.userId,
|
||||
departmentId: reportStore.reportInfo.departmentId
|
||||
},
|
||||
onSuccess: () => {
|
||||
onboarding.emit('navigate:report')
|
||||
show.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -177,22 +184,11 @@ const onChangeDepartment = (departmentId) => {
|
||||
usersLoaded.value = false
|
||||
fetchUsers(departmentId)
|
||||
}
|
||||
|
||||
const onboarding = useOnboardingStore()
|
||||
const onAfterEnter = async () => {
|
||||
// Если онбординг активен и текущий шаг имеет opensModal, переходим к следующему
|
||||
if (!onboarding.isActive) return
|
||||
|
||||
await nextTick()
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
onboarding.setStep(onboarding.activeStepIndex + 1)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="show"
|
||||
id="modal-select-user"
|
||||
preset="card"
|
||||
class="max-w-[420px]"
|
||||
:mask-closable="false"
|
||||
|
||||
@@ -271,10 +271,10 @@ watch(() => props, (newProps) => {
|
||||
{{ reportCreator }}
|
||||
</NTag>
|
||||
</NSpace>
|
||||
<DatePickerQuery :date="dates" :is-head-or-admin="true" class="text-lg!" />
|
||||
<DatePickerQuery id="date-selector" :date="dates" :is-head-or-admin="true" class="text-lg!" />
|
||||
</NFlex>
|
||||
<NDivider dashed class="my-4! mt-3!" />
|
||||
<NRow class="grow space-x-2 h-[82.78px]">
|
||||
<NRow id="statistic-widgets" class="grow space-x-2 h-[82.78px]">
|
||||
<NCol :span="3">
|
||||
<HeaderWidget label="Коек"
|
||||
:counter="stats.duty.beds" />
|
||||
@@ -305,7 +305,7 @@ watch(() => props, (newProps) => {
|
||||
</NRow>
|
||||
</AppPanel>
|
||||
<div class="grid grid-cols-[1fr_auto] gap-x-2">
|
||||
<AppPanel>
|
||||
<AppPanel id="input-widgets">
|
||||
<NFlex align="center" :wrap="false">
|
||||
<NFormItem label="Поступило" :show-feedback="false">
|
||||
<NInputNumber :disabled="!canSaveReport" :min="0" v-model:value="reportForm.recipient" />
|
||||
@@ -335,7 +335,7 @@ watch(() => props, (newProps) => {
|
||||
</NFlex>
|
||||
</div>
|
||||
<AppPanel>
|
||||
<NTabs type="segment">
|
||||
<NTabs id="view-tabs" type="segment">
|
||||
<NTabPane name="mis" tab="МИС" display-directive="show">
|
||||
<DutyPatientsPane :patients="patientCollection" :nurse-patients="nursePatientCollection" @create-observable="addObservablePatient" @remove-observable="removeObservablePatient" />
|
||||
</NTabPane>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import welcomeDuty from "./welcomeDuty"
|
||||
import welcomeNurse from "./welcomeNurse"
|
||||
|
||||
export default {
|
||||
welcomeDuty
|
||||
welcomeDuty,
|
||||
welcomeNurse,
|
||||
}
|
||||
@@ -3,83 +3,78 @@ export default {
|
||||
name: 'Знакомство с Метрикой',
|
||||
steps: [
|
||||
{
|
||||
id: 'wellcome',
|
||||
target: '#user-panel',
|
||||
route: 'start', // главная страница
|
||||
id: 'step-0',
|
||||
target: '#launcher',
|
||||
route: 'start',
|
||||
title: '👋 Добро пожаловать!',
|
||||
description: 'Это ваша панель управления. Сейчас мы покажем вам основные возможности.',
|
||||
popper: { placement: 'bottom-start' }, // опционально: позиция тултипа
|
||||
on: {
|
||||
afterStep: () => {
|
||||
const modalStore = useModalStore()
|
||||
modalStore.showSelectDutyUserModal = false
|
||||
},
|
||||
beforeStep: () => {
|
||||
const modalStore = useModalStore()
|
||||
modalStore.showSelectDutyUserModal = false
|
||||
},
|
||||
}
|
||||
description: 'Это ваша рабочая область. Сейчас мы покажем вам основные возможности.',
|
||||
highlight: true,
|
||||
scroll: false,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
attachTo: { element: '#new-report-duty' },
|
||||
route: 'start', // переходим на страницу отчётов
|
||||
content: {
|
||||
id: 'step-1',
|
||||
target: '#new-report-duty',
|
||||
route: 'start',
|
||||
title: '✏️ Создать отчёт',
|
||||
description: 'Нажмите эту кнопку, чтобы начать создание нового отчёта.'
|
||||
},
|
||||
on: {
|
||||
afterStep: () => {
|
||||
const modalStore = useModalStore()
|
||||
const onboarding = useOnboardingStore()
|
||||
|
||||
if (onboarding.activeStepIndex === 2) modalStore.showSelectDutyUserModal = true
|
||||
if (onboarding.activeStepIndex < 2) modalStore.showSelectDutyUserModal = false
|
||||
},
|
||||
beforeStep: () => {
|
||||
const modalStore = useModalStore()
|
||||
const onboarding = useOnboardingStore()
|
||||
|
||||
if (onboarding.activeStepIndex < 2) modalStore.showSelectDutyUserModal = false
|
||||
},
|
||||
},
|
||||
description: 'Нажмите эту кнопку, чтобы начать создание нового отчёта.',
|
||||
manual: true,
|
||||
highlight: true,
|
||||
scroll: false,
|
||||
allowInteraction: true,
|
||||
nextEvent: 'selectUser:opened'
|
||||
},
|
||||
{
|
||||
attachTo: { element: '#modal-select-user-department' },
|
||||
id: 'step-2',
|
||||
target: '#modal-select-user',
|
||||
route: 'start',
|
||||
content: { title: 'Выберите отделение', description: 'Можете использовать список, либо ввести ФИО для поиска' },
|
||||
insideModal: true, // флаг, что этот шаг внутри модалки
|
||||
options: {
|
||||
disableInteraction: false
|
||||
}
|
||||
title: 'Выберите отделение и ответственного',
|
||||
description: 'Можете использовать список, либо ввести для поиска',
|
||||
manual: true,
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: true,
|
||||
nextEvent: 'navigate:report'
|
||||
},
|
||||
{
|
||||
attachTo: { element: '#modal-select-user-doctor' },
|
||||
route: 'start',
|
||||
content: { title: 'Введите ответственного', description: 'Можете использовать список, либо ввести ФИО для поиска' },
|
||||
insideModal: true, // флаг, что этот шаг внутри модалки
|
||||
id: 'step-3',
|
||||
target: '#date-selector',
|
||||
route: 'report',
|
||||
title: 'Календарь',
|
||||
description: 'Здесь Вы можете просмотреть предыдущие отчеты, путем выбора даты в календаре.',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
attachTo: { element: '#modal-select-user-submit' },
|
||||
route: 'start',
|
||||
content: { title: 'Подтвердите ввод' },
|
||||
insideModal: true, // флаг, что этот шаг внутри модалки
|
||||
manual: true
|
||||
id: 'step-4',
|
||||
target: '#statistic-widgets',
|
||||
route: 'report',
|
||||
title: 'Основная статистика',
|
||||
description: 'Здесь отображается информация из МИС и журнала пациентов',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
attachTo: { element: '#report-name-input' },
|
||||
route: 'report', // страница создания отчёта
|
||||
content: {
|
||||
title: '📝 Название отчёта',
|
||||
description: 'Введите название, чтобы легко находить отчёт позже.'
|
||||
}
|
||||
id: 'step-5',
|
||||
target: '#input-widgets',
|
||||
route: 'report',
|
||||
title: 'Поля ввода',
|
||||
description: 'Поля заполняются данными из МИС автоматически. Но вы можете их изменить.',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
attachTo: { element: '#save-report-btn' },
|
||||
route: 'reports.create',
|
||||
content: {
|
||||
title: '💾 Сохранить',
|
||||
description: 'После заполнения всех полей нажмите "Сохранить", чтобы завершить.'
|
||||
}
|
||||
}
|
||||
id: 'step-6',
|
||||
target: '#view-tabs',
|
||||
route: 'report',
|
||||
title: 'Представления',
|
||||
description: 'Вы можете переключать представления. Вам доступны МИС и Журнал пациентов (заполняет старшая медицинская сестра отделения)',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
94
resources/js/Tours/welcomeNurse.js
Normal file
94
resources/js/Tours/welcomeNurse.js
Normal file
@@ -0,0 +1,94 @@
|
||||
export default {
|
||||
id: 'welcome-nurse',
|
||||
name: 'Знакомство с Метрикой',
|
||||
steps: [
|
||||
{
|
||||
id: 'step-0',
|
||||
target: '#launcher',
|
||||
route: 'start',
|
||||
title: '👋 Добро пожаловать!',
|
||||
description: 'Это ваша рабочая область. Сейчас мы покажем вам основные возможности.',
|
||||
highlight: true,
|
||||
scroll: false,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
id: 'step-1',
|
||||
target: '#new-report-nurse',
|
||||
route: 'start',
|
||||
title: '✏️ Создать отчёт',
|
||||
description: 'Нажмите эту кнопку, чтобы начать создание нового отчёта.',
|
||||
manual: true,
|
||||
highlight: true,
|
||||
scroll: false,
|
||||
allowInteraction: true,
|
||||
nextEvent: 'selectUser:opened'
|
||||
},
|
||||
{
|
||||
id: 'step-2',
|
||||
target: '#modal-select-user',
|
||||
route: 'start',
|
||||
title: 'Выберите отделение и ответственного',
|
||||
description: 'Можете использовать список, либо ввести для поиска',
|
||||
manual: true,
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: true,
|
||||
nextEvent: 'navigate:report'
|
||||
},
|
||||
{
|
||||
id: 'step-3',
|
||||
target: '#date-selector',
|
||||
route: 'nurse.report',
|
||||
title: 'Календарь',
|
||||
description: 'Здесь Вы можете просмотреть предыдущие отчеты, путем выбора даты в календаре.',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
id: 'step-4',
|
||||
target: '#view-tabs',
|
||||
route: 'nurse.report',
|
||||
title: 'Представления',
|
||||
description: 'Вы можете переключать представления. Для удобства пациенты разделены на категории.',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
{
|
||||
id: 'step-5',
|
||||
target: '#add-new-patient',
|
||||
route: 'nurse.report',
|
||||
title: 'Добавление пациента',
|
||||
description: 'Нажмите эту кнопку, чтобы добавить пациента.',
|
||||
manual: true,
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: true,
|
||||
nextEvent: 'createNewPatientModal:opened'
|
||||
},
|
||||
{
|
||||
id: 'step-6',
|
||||
target: '#create-new-patient-modal',
|
||||
route: 'nurse.report',
|
||||
title: 'Форма создания',
|
||||
description: 'Для начала вам нужно выбрать тип пациента. Если пациент есть в МИС, то выберите МИС. Иначе Спец. контингент',
|
||||
manual: true,
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: true,
|
||||
nextEvent: 'newPatientModal:patientTypeSelected'
|
||||
},
|
||||
{
|
||||
id: 'step-7',
|
||||
target: '#create-new-patient-modal',
|
||||
route: 'nurse.report',
|
||||
title: 'Форма создания',
|
||||
description: 'Заполните все необходимые поля, и нажмите кнопку Добавить',
|
||||
highlight: true,
|
||||
scroll: true,
|
||||
allowInteraction: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user