Compare commits
25 Commits
create_cli
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4459b5df48 | ||
|
|
7e18a794bf | ||
|
|
516ec12114 | ||
|
|
564860883e | ||
|
|
2b4d04ae3a | ||
|
|
c0eaad8e76 | ||
|
|
74a4ded35c | ||
|
|
a0b186a8d0 | ||
|
|
35cc0ee059 | ||
|
|
019c8c0459 | ||
|
|
615200f4ca | ||
|
|
7e9632436e | ||
|
|
dd9124b1c5 | ||
|
|
535c7562c7 | ||
|
|
f86c8ad5ba | ||
|
|
d130bdf40c | ||
|
|
7b2e07f0d2 | ||
|
|
48e2571c77 | ||
|
|
fc6c5e61fb | ||
|
|
c2eb6bf1e9 | ||
|
|
4bdd665d1f | ||
|
|
297f11952b | ||
|
|
dd5e9eed54 | ||
|
|
c986e312fe | ||
|
|
14424c541c |
@@ -3,15 +3,15 @@ include:
|
|||||||
ref: main
|
ref: main
|
||||||
file: '/templates/microservice.yaml'
|
file: '/templates/microservice.yaml'
|
||||||
|
|
||||||
e2e-dev:
|
#e2e-dev:
|
||||||
image: node:18.10.0
|
# image: node:18.10.0
|
||||||
stage: deploy
|
# stage: deploy
|
||||||
dependencies:
|
# dependencies:
|
||||||
- deploy-dev
|
# - deploy-dev
|
||||||
only:
|
# only:
|
||||||
- master
|
# - master
|
||||||
services:
|
# services:
|
||||||
- selenium/standalone-chrome
|
# - selenium/standalone-chrome
|
||||||
script:
|
# script:
|
||||||
- npm ci
|
# - npm ci
|
||||||
- npm run test:e2e --host=selenium__standalone-chrome --baseUrl=https://astra-dev.dopcore.com
|
# - npm run test:e2e --host=selenium__standalone-chrome --baseUrl=https://astra-dev.dopcore.com
|
||||||
|
|||||||
BIN
src/assets/images/doctor.png
Normal file
BIN
src/assets/images/doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1,6 +1,6 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
teleport(:to="appContainer")
|
teleport(:to="appContainer")
|
||||||
.absolute.top-0.p-2.right-0.overflow-hidden.z-50(class="w-1/4 xl:w-1/3 sm:w-1/2")
|
.absolute.top-0.p-2.right-0.overflow-hidden.wrapper(class="w-1/4 xl:w-1/3 sm:w-1/2")
|
||||||
.pt-32(v-if="displayPadding")
|
.pt-32(v-if="displayPadding")
|
||||||
.flex.gap-2.flex-col.relative
|
.flex.gap-2.flex-col.relative
|
||||||
transition-group(name="list", @before-leave="displayPadding = true", @after-leave="displayPadding = false")
|
transition-group(name="list", @before-leave="displayPadding = true", @after-leave="displayPadding = false")
|
||||||
@@ -41,6 +41,9 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.wrapper {
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
.list-enter-active,
|
.list-enter-active,
|
||||||
.list-leave-active {
|
.list-leave-active {
|
||||||
transition: all 0.5s ease;
|
transition: all 0.5s ease;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { reactive } from "vue";
|
|||||||
|
|
||||||
export const notifications = reactive({});
|
export const notifications = reactive({});
|
||||||
|
|
||||||
export const addNotification = (id, title, message, type, lifeTime = 0) => {
|
export const addNotification = (id, title, message, type, lifeTime = 3000) => {
|
||||||
notifications[id] = {
|
notifications[id] = {
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
alt="Logo",
|
alt="Logo",
|
||||||
@click="redirectHomePage"
|
@click="redirectHomePage"
|
||||||
)
|
)
|
||||||
header-inputs
|
|
||||||
.flex.ml-auto.items-center.gap-x-4
|
.flex.ml-auto.items-center.gap-x-4
|
||||||
|
|
||||||
q-btn(
|
q-btn(
|
||||||
@@ -89,7 +88,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
redirectHomePage() {
|
redirectHomePage() {
|
||||||
this.$router.push("/calendar");
|
this.$router.push("/");
|
||||||
},
|
},
|
||||||
async logout() {
|
async logout() {
|
||||||
await fetchWrapper.post("auth/logout");
|
await fetchWrapper.post("auth/logout");
|
||||||
|
|||||||
34
src/components/TheRightMenu.vue
Normal file
34
src/components/TheRightMenu.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.sidebar.h-full.rounded.flex.flex-col.justify-between.pt-4.px-2
|
||||||
|
.flex.flex-col.gap-y-4
|
||||||
|
q-btn(
|
||||||
|
style="width: 48px; height: 48px",
|
||||||
|
id="print",
|
||||||
|
rounded,
|
||||||
|
padding="0px",
|
||||||
|
icon="print",
|
||||||
|
text-color="blue",
|
||||||
|
size="xl"
|
||||||
|
)
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BaseButtonSidebar from "@/components/base/BaseSidebarButton";
|
||||||
|
export default {
|
||||||
|
name: "TheRightMenu",
|
||||||
|
components: { BaseButtonSidebar },
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
.sidebar
|
||||||
|
max-width: 64px
|
||||||
|
min-width: 64px
|
||||||
|
background-color: var(--default-white)
|
||||||
|
|
||||||
|
.button:hover
|
||||||
|
background-color: var(--bg-light-blue-color)
|
||||||
|
color: var(--btn-blue-color)
|
||||||
|
.hover :deep(path)
|
||||||
|
fill: #9294A7
|
||||||
|
</style>
|
||||||
@@ -34,12 +34,6 @@ export default {
|
|||||||
active: true,
|
active: true,
|
||||||
icon: "calendar",
|
icon: "calendar",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "user",
|
|
||||||
path: "#/clients",
|
|
||||||
active: false,
|
|
||||||
icon: "clients",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "medcards",
|
id: "medcards",
|
||||||
path: "#/medcards",
|
path: "#/medcards",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
base-input-container.gap-y-2(:important="important", :label="label", :style="{width: width + 'px', ...sizeVariable}")
|
base-input-container.gap-y-2(:important="important", :label="label", :style="{width: widthInternal, ...sizeVariable}")
|
||||||
q-input.input(
|
q-input.input(
|
||||||
v-model="value",
|
v-model="value",
|
||||||
:name="name",
|
:name="name",
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
:debounce="debounce",
|
:debounce="debounce",
|
||||||
:shadow-text="shadowText",
|
:shadow-text="shadowText",
|
||||||
:autofocus="autofocus",
|
:autofocus="autofocus",
|
||||||
hide-bottom-space
|
hide-bottom-space,
|
||||||
:error="error"
|
:error="error",
|
||||||
@focus="e => $emit('focus', e)"
|
@focus="e => $emit('focus', e)"
|
||||||
)
|
)
|
||||||
template(v-slot:prepend, v-if="iconLeft")
|
template(v-slot:prepend, v-if="iconLeft")
|
||||||
@@ -69,7 +69,7 @@ export default {
|
|||||||
shadowText: String,
|
shadowText: String,
|
||||||
mask: String,
|
mask: String,
|
||||||
debounce: [String, Number],
|
debounce: [String, Number],
|
||||||
width: Number,
|
width: [String, Number],
|
||||||
rule: Array,
|
rule: Array,
|
||||||
lazyRule: [Boolean, String],
|
lazyRule: [Boolean, String],
|
||||||
itemAligned: Boolean,
|
itemAligned: Boolean,
|
||||||
@@ -86,6 +86,7 @@ export default {
|
|||||||
circle: Boolean,
|
circle: Boolean,
|
||||||
height: String,
|
height: String,
|
||||||
error: Boolean,
|
error: Boolean,
|
||||||
|
hint: String,
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue", "focus"],
|
emits: ["update:modelValue", "focus"],
|
||||||
computed: {
|
computed: {
|
||||||
@@ -153,6 +154,10 @@ export default {
|
|||||||
"--py": "8px 0",
|
"--py": "8px 0",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
widthInternal() {
|
||||||
|
if (typeof this.width === "number") return this.width + "px";
|
||||||
|
return this.width;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -233,4 +238,10 @@ export default {
|
|||||||
|
|
||||||
.input :deep(.q-field__marginal)
|
.input :deep(.q-field__marginal)
|
||||||
height: auto !important
|
height: auto !important
|
||||||
|
|
||||||
|
.input :deep(.q-field__shadow)
|
||||||
|
opacity: 0.5
|
||||||
|
top: 3px
|
||||||
|
color: var(--font-grey-color)
|
||||||
|
margin-left: 8px
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
base-input-container.gap-y-2(:label="label", :style="{width: width + 'px', ...sizeVariable }")
|
base-input-container.gap-y-2(:label="label", :style="{width: widthInternal, ...sizeVariable }")
|
||||||
q-input.input(
|
q-input.input(
|
||||||
v-model="value",
|
v-model="value",
|
||||||
:name="name",
|
:name="name",
|
||||||
@@ -57,7 +57,7 @@ export default {
|
|||||||
default: "none",
|
default: "none",
|
||||||
},
|
},
|
||||||
debounce: [String, Number],
|
debounce: [String, Number],
|
||||||
width: Number,
|
width: [String, Number],
|
||||||
lazyRule: [Boolean, String],
|
lazyRule: [Boolean, String],
|
||||||
itemAligned: Boolean,
|
itemAligned: Boolean,
|
||||||
rule: Function,
|
rule: Function,
|
||||||
@@ -135,6 +135,11 @@ export default {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
widthInternal() {
|
||||||
|
if (typeof this.width === "number") return this.width + "px";
|
||||||
|
return this.width;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
convertISOFormat(date) {
|
convertISOFormat(date) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.flex.flex-col.gap-y-2
|
.flex.flex-col.gap-y-2
|
||||||
base-input-container(:label="label", :style="{width: width, ...sizeVariable}")
|
base-input-container(:label="label", :style="{width: widthInternal, ...sizeVariable}")
|
||||||
q-select.select(
|
q-select.select(
|
||||||
ref="selectRef"
|
ref="selectRef"
|
||||||
v-model="value",
|
v-model="value",
|
||||||
@@ -21,16 +21,25 @@
|
|||||||
@filter="filterFn",
|
@filter="filterFn",
|
||||||
:popup-content-style="popupContentStyle"
|
:popup-content-style="popupContentStyle"
|
||||||
@blur="$emit('blur')"
|
@blur="$emit('blur')"
|
||||||
|
:multiple="multiple"
|
||||||
)
|
)
|
||||||
template(#selected)
|
template(#selected, v-if="!multiple")
|
||||||
slot(name="selected")
|
slot(name="selected")
|
||||||
template(v-slot:option="scope", v-if="!customOption")
|
template(v-slot:option="{itemProps, opt}", v-if="!customOption")
|
||||||
q-item(v-bind="scope.itemProps", style="justify-content: center", v-if="value?.icon")
|
q-item(v-bind="itemProps", style="justify-content: center", v-if="value?.icon")
|
||||||
q-item-section(avatar, style="padding: 0px; min-width: 0px")
|
q-item-section(avatar, style="padding: 0px; min-width: 0px")
|
||||||
q-icon.icon(:name="scope.opt.icon", size="24px")
|
q-icon.icon(:name="opt.icon", size="24px")
|
||||||
q-item.item.px-4.py-2(v-bind="scope.itemProps", style="justify-content: center", v-else)
|
q-item.item.px-4.py-2.multiple(
|
||||||
|
:class="{ 'selected': value?.length && ~value?.lastIndexOf(opt.value) }"
|
||||||
|
v-bind="itemProps",
|
||||||
|
style="justify-content: center",
|
||||||
|
v-else-if="multiple"
|
||||||
|
)
|
||||||
q-item-section
|
q-item-section
|
||||||
q-item-label.text-dark.text-base.font-medium {{ scope.opt.label }}
|
q-item-label.text-dark.text-base.font-medium {{ opt.label }}
|
||||||
|
q-item.item.px-4.py-2(v-bind="itemProps", style="justify-content: center", v-else)
|
||||||
|
q-item-section
|
||||||
|
q-item-label.text-dark.text-base.font-medium {{ opt.label }}
|
||||||
template(v-slot:option="{itemProps, opt}", v-else)
|
template(v-slot:option="{itemProps, opt}", v-else)
|
||||||
slot(
|
slot(
|
||||||
name="customOption",
|
name="customOption",
|
||||||
@@ -79,6 +88,7 @@ export default {
|
|||||||
customOption: Boolean,
|
customOption: Boolean,
|
||||||
filterFn: Function,
|
filterFn: Function,
|
||||||
popupContentStyle: Object,
|
popupContentStyle: Object,
|
||||||
|
multiple: Boolean,
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue", "blur"],
|
emits: ["update:modelValue", "blur"],
|
||||||
computed: {
|
computed: {
|
||||||
@@ -159,6 +169,10 @@ export default {
|
|||||||
: !!this.value?.label,
|
: !!this.value?.label,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
widthInternal() {
|
||||||
|
if (typeof this.width === "number") return this.width + "px";
|
||||||
|
return this.width;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateInputValue(value, noFilter) {
|
updateInputValue(value, noFilter) {
|
||||||
@@ -244,8 +258,14 @@ export default {
|
|||||||
border-bottom: 1px solid var(--gray-secondary)
|
border-bottom: 1px solid var(--gray-secondary)
|
||||||
&:last-child
|
&:last-child
|
||||||
border-bottom: none
|
border-bottom: none
|
||||||
|
&.multiple.selected
|
||||||
|
background-color: var(--gray-thirdly)
|
||||||
|
.text-dark
|
||||||
|
color: var(--q-primary) !important
|
||||||
&:hover
|
&:hover
|
||||||
background-color: var(--gray-thirdly)
|
background-color: var(--gray-thirdly)
|
||||||
|
.q-focus-helper
|
||||||
|
display: none !important
|
||||||
|
|
||||||
.q-menu
|
.q-menu
|
||||||
box-shadow: 1px 1px 8px 0px rgba(37, 40, 80, 0.15) !important
|
box-shadow: 1px 1px 8px 0px rgba(37, 40, 80, 0.15) !important
|
||||||
|
|||||||
46
src/pages/home/TheHome.vue
Normal file
46
src/pages/home/TheHome.vue
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.wrapper.flex.flex-col.w-full.bg-white.p-4
|
||||||
|
.text-xxl.font-bold.pa-3
|
||||||
|
.text Добрый день, %username%!
|
||||||
|
.text.pt-3.cursor-pointer(@click="gotoCalendar") Расписание приемов
|
||||||
|
.text.pt-3.cursor-pointer(@click="gotoMedicalCards") Медицинские карты
|
||||||
|
|
||||||
|
base-select(:items="options", v-model="multiple", size="M", multiple)
|
||||||
|
|
||||||
|
.res {{multiple}}
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BaseSelect from "@/components/base/BaseSelect.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TheHome",
|
||||||
|
components: {
|
||||||
|
BaseSelect,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: ["Google", "Facebook", "Twitter", "Apple", "Oracle"].map(
|
||||||
|
(e) => ({ label: e, value: e + "v" })
|
||||||
|
),
|
||||||
|
multiple: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
gotoCalendar() {
|
||||||
|
this.$router.push("/calendar");
|
||||||
|
},
|
||||||
|
gotoMedicalCards() {
|
||||||
|
this.$router.push("/medcards");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
.wrapper
|
||||||
|
overflow: auto
|
||||||
|
border-top-left-radius: 4px
|
||||||
|
border-top-right-radius: 4px
|
||||||
|
</style>
|
||||||
@@ -21,7 +21,7 @@ export default {
|
|||||||
medicalCards: [],
|
medicalCards: [],
|
||||||
dataStatus: {
|
dataStatus: {
|
||||||
title: "no data",
|
title: "no data",
|
||||||
message: "Введите номер карты или ФИО пациента",
|
message: "Введите данные Пациента для поиска",
|
||||||
img: nothingChooseImg,
|
img: nothingChooseImg,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -31,20 +31,21 @@ export default {
|
|||||||
if (!value) {
|
if (!value) {
|
||||||
this.dataStatus = {
|
this.dataStatus = {
|
||||||
title: "no data",
|
title: "no data",
|
||||||
message: "Введите номер карты или ФИО пациента",
|
message: "Введите ФИО Пациента",
|
||||||
img: nothingChooseImg,
|
img: nothingChooseImg,
|
||||||
};
|
};
|
||||||
this.medicalCards = [];
|
this.medicalCards = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = await fetchWrapper.get(
|
|
||||||
"medical_cards?searchstring=" + value
|
const data = await fetchWrapper.post("persons/search", {
|
||||||
);
|
full_name: value,
|
||||||
|
});
|
||||||
if (data?.length === 0) {
|
if (data?.length === 0) {
|
||||||
this.medicalCard = [];
|
this.medicalCard = [];
|
||||||
this.dataStatus = {
|
this.dataStatus = {
|
||||||
title: "not found",
|
title: "not found",
|
||||||
message: `По запросу «${value}» не найдено.
|
message: `По запросу «${value}» Пациентов не найдено.
|
||||||
Переформулируйте запрос и попробуйте снова`,
|
Переформулируйте запрос и попробуйте снова`,
|
||||||
img: nothingSearchImg,
|
img: nothingSearchImg,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
base-input.search(
|
base-input.search(
|
||||||
:width="438",
|
:width="438",
|
||||||
size="M",
|
size="M",
|
||||||
placeholder="Введите ФИО или номер телефона",
|
placeholder="ФИО Пациента",
|
||||||
icon-left,
|
icon-left,
|
||||||
v-model="filterString"
|
v-model="filterString"
|
||||||
)
|
)
|
||||||
template(#iconLeft)
|
template(#iconLeft)
|
||||||
q-icon.search-icon(name="app:search", size="20px")
|
q-icon.search-icon(name="app:search", size="20px")
|
||||||
base-button(width="216px", @click="showCreateModal = true")
|
base-button(@click="showCreateModal = true")
|
||||||
q-icon.plus.mr-2(name="app:plus", size="24px")
|
q-icon.plus.mr-2(name="app:plus", size="18px")
|
||||||
span Создать медкарту
|
span Новая медкарта
|
||||||
base-modal(v-model="showCreateModal", title="Создать медицинскую карту", modal-padding)
|
base-modal(v-model="showCreateModal", title="Создать медицинскую карту", modal-padding)
|
||||||
patient-creation-form(@close="handleClosePatientForm")
|
patient-creation-form(@close="handleClosePatientForm")
|
||||||
</template>
|
</template>
|
||||||
@@ -72,7 +72,8 @@ export default {
|
|||||||
fill: var(--font-grey-color)
|
fill: var(--font-grey-color)
|
||||||
|
|
||||||
.search :deep(.q-field__prepend)
|
.search :deep(.q-field__prepend)
|
||||||
padding-right: 4px
|
padding-right: 12px
|
||||||
|
|
||||||
|
|
||||||
.plus :deep(path)
|
.plus :deep(path)
|
||||||
fill: var(--default-white)
|
fill: var(--default-white)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
v-for="medcard in medicalCards",
|
v-for="medcard in medicalCards",
|
||||||
:key="medcard.id"
|
:key="medcard.id"
|
||||||
:header-style="headerStyle",
|
:header-style="headerStyle",
|
||||||
:medcard-info="medcard",
|
:person="medcard",
|
||||||
)
|
)
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -40,8 +40,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
headerStyle(field) {
|
headerStyle(field) {
|
||||||
return {
|
return {
|
||||||
width: field.width,
|
...field,
|
||||||
"justify-content": field.title === "Do" ? "center" : "",
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,100 +1,69 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.w-full.row-wrapper.h-14.flex
|
.w-full.row-wrapper.h-14.flex
|
||||||
.field.gap-x-3(
|
.field(:style="headerStyle(headerConfig[0])")
|
||||||
:style="headerStyle(headerConfig[0])"
|
template(v-if="person.medical_card_id")
|
||||||
)
|
base-button(size="S", @click="openMedicalCard", label="Открыть", color="green")
|
||||||
q-avatar(size="36px")
|
template(v-else)
|
||||||
img(:src="avatar")
|
base-button(size="S", @click="createMedCard", label="Создать")
|
||||||
|
.field.gap-x-3(:style="headerStyle(headerConfig[1])")
|
||||||
span.font-semibold.text-dark {{patientName}}
|
span.font-semibold.text-dark {{patientName}}
|
||||||
.field(:style="headerStyle(headerConfig[1])")
|
.field(:style="headerStyle(headerConfig[2])")
|
||||||
span.text-dark {{ convertDate(medcardInfo?.person?.birth_date) }} г.
|
span.text-dark {{ birthDate }}
|
||||||
.field.gap-x-2(:style="headerStyle(headerConfig[2])")
|
.field(:style="{...headerStyle(headerConfig[3])}")
|
||||||
.rounded-full.h-2.w-2(:style="{background: patientPriority?.color}")
|
span.text-dark {{ phones }}
|
||||||
span(:style="{color: patientPriority?.color}") {{ patientPriority?.text }}
|
|
||||||
.field(:style="headerStyle(headerConfig[3])")
|
|
||||||
.medcard-number.rounded.h-7.py-1.pl-3.pr-2.flex.items-center.justify-between.w-full.cursor-pointer(
|
|
||||||
@click="copyValue(medcardInfo?.number)"
|
|
||||||
)
|
|
||||||
span.text-dark.cursor-pointer {{ medcardInfo?.number }}
|
|
||||||
q-icon.copy(size="18px", name="app:copy")
|
|
||||||
.field(:style="headerStyle(headerConfig[4])")
|
|
||||||
span.text-dark {{ convertDate(medcardInfo?.created_at) }} г.
|
|
||||||
.field.gap-x-3(:style="headerStyle(headerConfig[5])")
|
|
||||||
.track.h-2.flex-1.rounded
|
|
||||||
.thumb.h-full.rounded(:style="thumbStyle")
|
|
||||||
span.grey-color {{ medcardInfo?.filling_percentage || 0 }}%
|
|
||||||
.field(:style="{...headerStyle(headerConfig[6])}")
|
|
||||||
q-icon.medcard.cursor-pointer(name="app:medcard", size="20px", @click="openMedicalCard")
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { searchListConfig } from "@/pages/medcards/utils/medcardsConfig.js";
|
||||||
searchListConfig,
|
|
||||||
priorityList,
|
|
||||||
} from "@/pages/medcards/utils/medcardsConfig.js";
|
|
||||||
import * as moment from "moment/moment";
|
import * as moment from "moment/moment";
|
||||||
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
|
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
|
||||||
import { addNotification } from "@/components/Notifications/notificationContext";
|
|
||||||
import avatar from "@/assets/images/person.png";
|
|
||||||
import { mapActions } from "vuex";
|
import { mapActions } from "vuex";
|
||||||
|
import BaseButton from "@/components/base/BaseButton.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "MedicalCardSearchRow",
|
name: "MedicalCardSearchRow",
|
||||||
components: { TheNotificationProvider },
|
components: { TheNotificationProvider, BaseButton },
|
||||||
props: {
|
props: {
|
||||||
headerStyle: Function,
|
headerStyle: Function,
|
||||||
medcardInfo: Object,
|
person: Object,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
headerConfig: searchListConfig,
|
headerConfig: searchListConfig,
|
||||||
avatar,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
patientName() {
|
patientName() {
|
||||||
return `${this.medcardInfo?.person?.last_name} ${this.medcardInfo?.person?.first_name} ${this.medcardInfo?.person?.patronymic}`;
|
return `${this.person?.last_name} ${this.person?.first_name} ${this.person?.patronymic}`;
|
||||||
},
|
},
|
||||||
patientPriority() {
|
birthDate() {
|
||||||
return priorityList?.find(
|
let retVal =
|
||||||
({ priority }) => (this.medcardInfo.priority || null) === priority
|
this.person?.birth_date &&
|
||||||
);
|
moment(this.person?.birth_date)?.format("DD MMMM YYYY");
|
||||||
|
return retVal ? retVal + " г." : "";
|
||||||
},
|
},
|
||||||
thumbStyle() {
|
phones() {
|
||||||
let percentage = this.medcardInfo?.filling_percentage || 0;
|
return this.person?.contacts
|
||||||
return {
|
?.filter((el) => el.category === "PHONE")
|
||||||
width: `calc(${percentage}%)`,
|
.map((el) => el.value)
|
||||||
"background-color":
|
.join(", ");
|
||||||
percentage < 11
|
|
||||||
? "var(--system-color-red)"
|
|
||||||
: percentage < 51
|
|
||||||
? "var(--bg-yellow-warning)"
|
|
||||||
: "var(--system-color-green)",
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
getMedicalCardData: "getMedicalCardDataByPersonId",
|
getMedicalCardData: "getMedicalCardDataByPersonId",
|
||||||
|
createMedicalCard: "createMedicalCard",
|
||||||
}),
|
}),
|
||||||
openMedicalCard() {
|
openMedicalCard() {
|
||||||
this.getMedicalCardData({
|
this.$router.push("medical-card/" + this.person["medical_card_id"]);
|
||||||
personId: this.medcardInfo.person_id,
|
},
|
||||||
successCallback: (id) => this.$router.push("medical-card/" + id),
|
createMedCard() {
|
||||||
|
this.createMedicalCard({
|
||||||
|
personId: this.person.id,
|
||||||
|
}).then(() => {
|
||||||
|
this.openMedicalCard();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
convertDate(date) {
|
|
||||||
return moment(date)?.format("DD MMMM YYYY");
|
|
||||||
},
|
|
||||||
copyValue(text) {
|
|
||||||
navigator.clipboard.writeText(text);
|
|
||||||
addNotification(
|
|
||||||
new Date().getTime(),
|
|
||||||
"",
|
|
||||||
"Номер медкарты скопирован",
|
|
||||||
"success",
|
|
||||||
5000
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -129,8 +98,6 @@ span
|
|||||||
.track
|
.track
|
||||||
background: var(--gray-thirdly)
|
background: var(--gray-thirdly)
|
||||||
|
|
||||||
.thumb
|
|
||||||
|
|
||||||
.grey-color
|
.grey-color
|
||||||
color: var(--font-grey-color)
|
color: var(--font-grey-color)
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,57 +1,19 @@
|
|||||||
export const searchListConfig = [
|
export const searchListConfig = [
|
||||||
|
{
|
||||||
|
title: "Медкарта",
|
||||||
|
minWidth: "140px",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "ФИО",
|
title: "ФИО",
|
||||||
width: "550px",
|
width: "100%",
|
||||||
|
minWidth: "350px",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Дата рождения",
|
title: "Дата рождения",
|
||||||
width: "220px",
|
minWidth: "220px",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Приоритет",
|
title: "Телефон",
|
||||||
width: "220px",
|
minWidth: "220px",
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "№ медкарты",
|
|
||||||
width: "280px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Дата создания",
|
|
||||||
width: "215px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Процент заполнения",
|
|
||||||
width: "295px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Do",
|
|
||||||
width: "60px",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const priorityList = [
|
|
||||||
{
|
|
||||||
priority: 1,
|
|
||||||
id: 1,
|
|
||||||
text: "Высокий",
|
|
||||||
color: "var(--system-color-red)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
priority: 2,
|
|
||||||
id: 2,
|
|
||||||
text: "Средний",
|
|
||||||
color: "var(--bg-yellow-warning)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
priority: 3,
|
|
||||||
id: 3,
|
|
||||||
text: "Низкий",
|
|
||||||
color: "var(--btn-blue-color)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
priority: null,
|
|
||||||
id: 4,
|
|
||||||
text: "-",
|
|
||||||
color: "#9294A7",
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
.w-full.flex
|
.w-full.flex
|
||||||
calendar-sidebar(v-if="!isOpen", :open-sidebar="openSidebar", :create-form="createForm")
|
calendar-sidebar(v-if="!isOpen", :open-sidebar="openSidebar", :create-form="createForm")
|
||||||
calendar-open-sidebar(v-else, :open-sidebar="openSidebar", :create-form="createForm")
|
calendar-open-sidebar(v-else, :open-sidebar="openSidebar", :create-form="createForm")
|
||||||
calendar-wrapper.ml-2(:open-sidebar="isOpen")
|
component.ml-2(
|
||||||
|
v-bind:is="calendarComponent",
|
||||||
|
:open-sidebar="isOpen",
|
||||||
|
)
|
||||||
base-modal(v-model="isShowForm", title="Создание записи", modal-padding)
|
base-modal(v-model="isShowForm", title="Создание записи", modal-padding)
|
||||||
create-event-form(:close-form="closeForm")
|
create-event-form(:close-form="closeForm")
|
||||||
base-modal(v-model="previewVisibility", :hideHeader="true", :modalPadding="true")
|
base-modal(v-model="previewVisibility", :hideHeader="true", :modalPadding="true")
|
||||||
@@ -12,7 +15,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import CalendarSidebar from "@/pages/newCalendar/components/CalendarSidebar";
|
import CalendarSidebar from "@/pages/newCalendar/components/CalendarSidebar";
|
||||||
import CalendarOpenSidebar from "@/pages/newCalendar/components/CalendarOpenSidebar";
|
import CalendarOpenSidebar from "@/pages/newCalendar/components/CalendarOpenSidebar";
|
||||||
import CalendarWrapper from "@/pages/newCalendar/components/CalendarWrapper";
|
import DoctorCalendarWrapper from "@/pages/newCalendar/components/doctorCalendar/CalendarWrapper";
|
||||||
|
import ManagerCalendarWrapper from "@/pages/newCalendar/components/managerCalendar/CalendarWrapper";
|
||||||
import CreateEventForm from "@/pages/newCalendar/components/CreateEventForm";
|
import CreateEventForm from "@/pages/newCalendar/components/CreateEventForm";
|
||||||
import * as moment from "moment/moment";
|
import * as moment from "moment/moment";
|
||||||
import BaseModal from "@/components/base/BaseModal.vue";
|
import BaseModal from "@/components/base/BaseModal.vue";
|
||||||
@@ -23,7 +27,8 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
CalendarSidebar,
|
CalendarSidebar,
|
||||||
CalendarOpenSidebar,
|
CalendarOpenSidebar,
|
||||||
CalendarWrapper,
|
DoctorCalendarWrapper,
|
||||||
|
ManagerCalendarWrapper,
|
||||||
CreateEventForm,
|
CreateEventForm,
|
||||||
BaseModal,
|
BaseModal,
|
||||||
CalendarRecordPreview,
|
CalendarRecordPreview,
|
||||||
@@ -40,7 +45,13 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
selectedRecordId: (state) => state.calendar.selectedRecordId,
|
selectedRecordId: (state) => state.calendar.selectedRecordId,
|
||||||
selectedDates: (state) => state.calendar.selectedDates,
|
selectedDates: (state) => state.calendar.selectedDates,
|
||||||
|
calendarShape: (state) => state.calendarShape,
|
||||||
}),
|
}),
|
||||||
|
calendarComponent() {
|
||||||
|
return this.calendarShape === "doctor"
|
||||||
|
? "doctor-calendar-wrapper"
|
||||||
|
: "manager-calendar-wrapper";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openSidebar() {
|
openSidebar() {
|
||||||
@@ -73,10 +84,11 @@ export default {
|
|||||||
deep: true,
|
deep: true,
|
||||||
handler(value) {
|
handler(value) {
|
||||||
if (this.$route.path === "/calendar") {
|
if (this.$route.path === "/calendar") {
|
||||||
|
let dateType = this.calendarShape === "doctor" ? "week" : "day";
|
||||||
if (!value?.start || !value?.end) {
|
if (!value?.start || !value?.end) {
|
||||||
this.changeSelectedDates({
|
this.changeSelectedDates({
|
||||||
from: moment().clone().startOf("week"),
|
from: moment().clone().startOf(dateType),
|
||||||
to: moment().clone().endOf("week"),
|
to: moment().clone().endOf(dateType),
|
||||||
});
|
});
|
||||||
this.$router.replace({
|
this.$router.replace({
|
||||||
query: {
|
query: {
|
||||||
@@ -87,11 +99,12 @@ export default {
|
|||||||
} else if (
|
} else if (
|
||||||
value?.start !== this.selectedDates?.from?.format("DD.MM.YYYY") ||
|
value?.start !== this.selectedDates?.from?.format("DD.MM.YYYY") ||
|
||||||
value?.end !== this.selectedDates?.to?.format("DD.MM.YYYY")
|
value?.end !== this.selectedDates?.to?.format("DD.MM.YYYY")
|
||||||
)
|
) {
|
||||||
this.changeSelectedDates({
|
this.changeSelectedDates({
|
||||||
from: this.convertDate(value?.start),
|
from: this.convertDate(value?.start).clone().startOf("day"),
|
||||||
to: this.convertDate(value?.end),
|
to: this.convertDate(value?.end).clone().endOf("day"),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default {
|
|||||||
timeCoil: Array,
|
timeCoil: Array,
|
||||||
currentTime: String,
|
currentTime: String,
|
||||||
dayEndTime: Number,
|
dayEndTime: Number,
|
||||||
isCurrentWeek: Boolean,
|
isCurrent: Boolean,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentHour() {
|
currentHour() {
|
||||||
@@ -33,7 +33,7 @@ export default {
|
|||||||
if (
|
if (
|
||||||
convertTime(elem, 0, 3) === this.currentHour &&
|
convertTime(elem, 0, 3) === this.currentHour &&
|
||||||
!this.isEndDay &&
|
!this.isEndDay &&
|
||||||
this.isCurrentWeek
|
this.isCurrent
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
"current-time": true,
|
"current-time": true,
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.calendar-column-wrapper.flex.flex-col
|
|
||||||
.header.flex.flex-col.items-center.justify-center.top-0.pt-3.pb-10px
|
|
||||||
span.font-bold.text-base.color-black {{ date?.format("D MMMM")}}
|
|
||||||
span.text-smm.color-grey {{ transformDayName(date?.format("dddd"))}}
|
|
||||||
.body.h-full.px-1.py-1
|
|
||||||
calendar-record-card(
|
|
||||||
v-for="record in filteredRecords",
|
|
||||||
:key="record?.id",
|
|
||||||
:record="record",
|
|
||||||
:expanded-type="expandedDisplayType",
|
|
||||||
:style="eventCardPosition(record.start, record.end)",
|
|
||||||
@click="changeSelectedRecordId(record?.id)",
|
|
||||||
)
|
|
||||||
.footer.flex.items-center.justify-center.bg-white.h-9(v-if="!expandedDisplayType")
|
|
||||||
span.text-smm.color-grey 0 записей
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import * as moment from "moment/moment";
|
|
||||||
import CalendarRecordCard from "@/pages/newCalendar/components/CalendarRecordCard.vue";
|
|
||||||
import { verifyTime } from "@/pages/newCalendar/utils/calendarFunctions.js";
|
|
||||||
import { mapActions, mapState } from "vuex";
|
|
||||||
export default {
|
|
||||||
name: "CalendarColumn",
|
|
||||||
components: { CalendarRecordCard },
|
|
||||||
props: {
|
|
||||||
date: Object,
|
|
||||||
expandedDisplayType: Boolean,
|
|
||||||
dayEndTime: Number,
|
|
||||||
dayStartTime: Number,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
pixelsPerHour: 76,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState({
|
|
||||||
events: (state) => state.calendar.events || [],
|
|
||||||
}),
|
|
||||||
filteredRecords() {
|
|
||||||
return this.events.filter(
|
|
||||||
(elem) =>
|
|
||||||
moment.parseZone(elem.start).format("YYYY-MM-DD") ===
|
|
||||||
this.date.format("YYYY-MM-DD")
|
|
||||||
);
|
|
||||||
},
|
|
||||||
pixelsPerMinute() {
|
|
||||||
return this.pixelsPerHour / 60;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions({
|
|
||||||
changeSelectedRecordId: "changeSelectedRecordId",
|
|
||||||
}),
|
|
||||||
transformDayName(name) {
|
|
||||||
return name[0]?.toUpperCase() + name?.slice(1);
|
|
||||||
},
|
|
||||||
eventCardPosition(startTime, endTime) {
|
|
||||||
let start = startTime
|
|
||||||
.slice(11, -4)
|
|
||||||
.split(":")
|
|
||||||
.map((elem) => parseInt(elem, 10));
|
|
||||||
let end = endTime.slice(11, -4);
|
|
||||||
let position =
|
|
||||||
(start[0] - this.dayStartTime) * this.pixelsPerHour +
|
|
||||||
start[1] * this.pixelsPerMinute +
|
|
||||||
4;
|
|
||||||
if (
|
|
||||||
parseInt(start[0], 10) < this.dayStartTime ||
|
|
||||||
verifyTime(end) > this.dayEndTime
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
top: "0px",
|
|
||||||
visibility: "hidden",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
top: `${position}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.calendar-column-wrapper
|
|
||||||
border-right: 1px solid var(--border-light-grey-color)
|
|
||||||
&:last-child
|
|
||||||
border-right: none
|
|
||||||
|
|
||||||
.header
|
|
||||||
position: sticky
|
|
||||||
z-index: 5
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.body
|
|
||||||
position: relative
|
|
||||||
z-index: 3
|
|
||||||
|
|
||||||
.color-black
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.color-grey
|
|
||||||
color: var(--font-grey-color)
|
|
||||||
|
|
||||||
.footer
|
|
||||||
border-top: 1px solid var(--border-light-grey-color)
|
|
||||||
@media(min-height: 1090px)
|
|
||||||
border-bottom: 1px solid var(--border-light-grey-color)
|
|
||||||
</style>
|
|
||||||
@@ -33,12 +33,12 @@
|
|||||||
.flex.gap-x-14(:class="bodyClass")
|
.flex.gap-x-14(:class="bodyClass")
|
||||||
.flex.gap-x-2.items-center(
|
.flex.gap-x-2.items-center(
|
||||||
v-for="contact in contacts",
|
v-for="contact in contacts",
|
||||||
:key="contact.value",
|
:key="contact?.value",
|
||||||
)
|
)
|
||||||
q-icon.network-icon(:name="contact.icon", size="16px")
|
q-icon.network-icon(:name="contact?.icon", size="16px")
|
||||||
.text-xxs.cursor-default {{ contact.value }}
|
.text-xxs.cursor-default {{ contact?.value }}
|
||||||
.h-6.w-6.color-black.background-dark-grey.text-xxs.rounded.flex.items-center.justify-center.cursor-default(
|
.h-6.w-6.color-black.background-dark-grey.text-xxs.rounded.flex.items-center.justify-center.cursor-default(
|
||||||
v-if="collapsedDisplayCondition"
|
v-if="collapsedDisplayCondition && contact"
|
||||||
) +1
|
) +1
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,294 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.schedule.flex-1.flex.flex-col.relative(
|
|
||||||
:style="{width: openSidebar ? 'calc(100vw - 320px)' : 'calc(100vw - 160px)'}"
|
|
||||||
)
|
|
||||||
calendar-header.w-full.mb-1(v-model="displayType")
|
|
||||||
.schedule-body.h-full.bg-white.w-full(:class="{rounded: !expandedDisplayType}")
|
|
||||||
.column-wrapper.flex.ml-20(:style="columnWrapperWidth")
|
|
||||||
calendar-column(
|
|
||||||
v-for="date in dateRange",
|
|
||||||
:key="date",
|
|
||||||
:date="date",
|
|
||||||
:style="columnHeight",
|
|
||||||
:expanded-display-type="expandedDisplayType",
|
|
||||||
:day-start-time="validateStartTime"
|
|
||||||
:day-end-time="validateEndTime"
|
|
||||||
)
|
|
||||||
.flex.relative(
|
|
||||||
:style="expandedDisplayType ? backgroundWrapperWidth : {}",
|
|
||||||
:class="{'border-bottom': expandedDisplayType}"
|
|
||||||
)
|
|
||||||
.time-coil-wrapper.left-0.-mt-12
|
|
||||||
calendar-clock-column(
|
|
||||||
:time-coil="timeCoil",
|
|
||||||
:current-time="currentTime",
|
|
||||||
:is-current-week="isCurrentWeek",
|
|
||||||
:day-end-time="validateEndTime"
|
|
||||||
)
|
|
||||||
.time-circle-indicator.left-74px.h-3.w-3.rounded-full.absolute(
|
|
||||||
v-if="isShownIndicator",
|
|
||||||
:style="circleIndicatorLocation"
|
|
||||||
)
|
|
||||||
span.time-line-indicator.block.left-20.absolute(
|
|
||||||
v-if="isShownIndicator",
|
|
||||||
:style="lineIndicatorLocation"
|
|
||||||
)
|
|
||||||
calendar-background.flex-1
|
|
||||||
.w-full.h-3.bg-white.footer(v-if="expandedDisplayType")
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CalendarHeader from "@/pages/newCalendar/components/CalendarHeader";
|
|
||||||
import CalendarBackground from "@/pages/newCalendar/components/CalendarBackground.vue";
|
|
||||||
import CalendarClockColumn from "@/pages/newCalendar/components/CalendarClockColumn.vue";
|
|
||||||
import CalendarColumn from "@/pages/newCalendar/components/CalendarColumn.vue";
|
|
||||||
import {
|
|
||||||
convertTime,
|
|
||||||
verifyTime,
|
|
||||||
} from "@/pages/newCalendar/utils/calendarFunctions.js";
|
|
||||||
import { mapState, mapActions } from "vuex";
|
|
||||||
import * as moment from "moment/moment";
|
|
||||||
export default {
|
|
||||||
name: "CalendarWrapper",
|
|
||||||
components: {
|
|
||||||
CalendarHeader,
|
|
||||||
CalendarBackground,
|
|
||||||
CalendarClockColumn,
|
|
||||||
CalendarColumn,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
openSidebar: Boolean,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
displayType: "expanded",
|
|
||||||
currentTime: "",
|
|
||||||
isCurrentWeek: true,
|
|
||||||
isShownIndicator: true,
|
|
||||||
timeCoil: [],
|
|
||||||
timer: null,
|
|
||||||
pixelsPerHour: 76,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState({
|
|
||||||
workingHours: (state) => state.calendar.workingHours,
|
|
||||||
selectedDates: (state) => state.calendar.selectedDates,
|
|
||||||
}),
|
|
||||||
hours() {
|
|
||||||
return convertTime(this.currentTime, 0, -6);
|
|
||||||
},
|
|
||||||
minutes() {
|
|
||||||
return convertTime(this.currentTime, 3, -3);
|
|
||||||
},
|
|
||||||
hoursMinutes() {
|
|
||||||
return this.currentTime.slice(0, -3);
|
|
||||||
},
|
|
||||||
pixelsPerMinute() {
|
|
||||||
return this.pixelsPerHour / 60;
|
|
||||||
},
|
|
||||||
backgroundHeight() {
|
|
||||||
return (
|
|
||||||
(this.validateEndTime - this.validateStartTime) * this.pixelsPerHour
|
|
||||||
);
|
|
||||||
},
|
|
||||||
expandedDisplayType() {
|
|
||||||
return this.displayType === "expanded";
|
|
||||||
},
|
|
||||||
dateRange() {
|
|
||||||
let diff = this.selectedDates?.to.diff(this.selectedDates?.from, "days");
|
|
||||||
let range = [];
|
|
||||||
for (let i = 0; i <= diff; i++) {
|
|
||||||
range.push(this.selectedDates?.from.clone().add(i, "day"));
|
|
||||||
}
|
|
||||||
return range;
|
|
||||||
},
|
|
||||||
validateStartTime() {
|
|
||||||
return verifyTime(this.workingHours.start);
|
|
||||||
},
|
|
||||||
validateEndTime() {
|
|
||||||
return verifyTime(this.workingHours.end);
|
|
||||||
},
|
|
||||||
columnHeight() {
|
|
||||||
return this.expandedDisplayType
|
|
||||||
? {
|
|
||||||
height: `${this.timeCoil.length * this.pixelsPerHour + 60}px`,
|
|
||||||
width: "380px",
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
height: `${this.timeCoil.length * this.pixelsPerHour + 96}px`,
|
|
||||||
width: this.openSidebar
|
|
||||||
? `calc((100vw - 320px - 80px) / ${this.dateRange.length})`
|
|
||||||
: `calc((100vw - 160px - 80px) / ${this.dateRange.length})`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
columnWrapperWidth() {
|
|
||||||
return this.expandedDisplayType
|
|
||||||
? {
|
|
||||||
width: `${380 * this.dateRange.length}px`,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
width: this.openSidebar
|
|
||||||
? "calc(100vw - 320px - 80px)"
|
|
||||||
: "calc(100vw - 160px - 80px)",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
backgroundWrapperWidth() {
|
|
||||||
return {
|
|
||||||
width: `${380 * this.dateRange.length + 80}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
lineIndicatorLocation() {
|
|
||||||
return {
|
|
||||||
top: `${this.calculateIndicatorLocation()}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
circleIndicatorLocation() {
|
|
||||||
return {
|
|
||||||
top: `${this.calculateIndicatorLocation() + 42}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions({
|
|
||||||
getEvents: "getEvents",
|
|
||||||
}),
|
|
||||||
changeCurrentTime() {
|
|
||||||
this.currentTime = moment().format("HH:mm:ss");
|
|
||||||
},
|
|
||||||
timeCoilInitialization() {
|
|
||||||
this.timeCoil = [];
|
|
||||||
for (let i = this.validateStartTime; i < this.validateEndTime; i++) {
|
|
||||||
if (
|
|
||||||
i === this.hours &&
|
|
||||||
this.hours !== this.validateEndTime &&
|
|
||||||
this.isCurrentWeek
|
|
||||||
) {
|
|
||||||
this.timeCoil.push(this.hoursMinutes);
|
|
||||||
} else this.timeCoil.push(`${i}:00`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
changeTimeCoil() {
|
|
||||||
this.timeCoil = this.timeCoil.map((elem) => {
|
|
||||||
if (convertTime(elem, 0, -3) === this.hours) {
|
|
||||||
return this.hoursMinutes;
|
|
||||||
}
|
|
||||||
return elem.slice(0, -3) + ":00";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
startTimer() {
|
|
||||||
if (
|
|
||||||
this.hours >= this.validateStartTime &&
|
|
||||||
this.hours < this.validateEndTime
|
|
||||||
) {
|
|
||||||
this.timer = setInterval(() => {
|
|
||||||
this.changeCurrentTime();
|
|
||||||
this.changeTimeCoil();
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stopTimer() {
|
|
||||||
clearInterval(this.timer);
|
|
||||||
this.timer = null;
|
|
||||||
},
|
|
||||||
calculateIndicatorLocation() {
|
|
||||||
let newTime = this.currentTime
|
|
||||||
.split(":")
|
|
||||||
.map((elem) => parseInt(elem, 10));
|
|
||||||
let result =
|
|
||||||
(newTime[0] - this.validateStartTime) * this.pixelsPerHour +
|
|
||||||
newTime[1] * this.pixelsPerMinute;
|
|
||||||
if (result > this.backgroundHeight || result < 0) {
|
|
||||||
this.isShownIndicator = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
currentTime() {
|
|
||||||
if (
|
|
||||||
this.hours === this.validateEndTime &&
|
|
||||||
this.minutes > 0 &&
|
|
||||||
this.timer
|
|
||||||
) {
|
|
||||||
this.stopTimer();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectedDates: {
|
|
||||||
deep: true,
|
|
||||||
handler(newValue) {
|
|
||||||
this.isCurrentWeek =
|
|
||||||
newValue?.from.isSame(moment().clone().startOf("week")) &&
|
|
||||||
newValue?.to.isSame(moment().clone().endOf("week"));
|
|
||||||
this.isShownIndicator = this.isCurrentWeek;
|
|
||||||
if (this.timer) {
|
|
||||||
this.stopTimer();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
}
|
|
||||||
if (this.isCurrentWeek) {
|
|
||||||
this.changeCurrentTime();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
this.startTimer();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.changeCurrentTime();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
this.startTimer();
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
this.stopTimer();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.schedule-body
|
|
||||||
overflow-x: auto
|
|
||||||
border-top-left-radius: 4px
|
|
||||||
border-top-right-radius: 4px
|
|
||||||
&::-webkit-scrollbar-track:horizontal
|
|
||||||
margin: 0 24px 0 24px
|
|
||||||
|
|
||||||
.background
|
|
||||||
background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%)
|
|
||||||
|
|
||||||
.time-coil-wrapper
|
|
||||||
position: sticky
|
|
||||||
z-index: 5
|
|
||||||
background-color: var(--default-white)
|
|
||||||
padding-top: 38px
|
|
||||||
|
|
||||||
.column-wrapper
|
|
||||||
height: 60px
|
|
||||||
position: relative
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.footer
|
|
||||||
border-bottom-left-radius: 4px
|
|
||||||
border-bottom-right-radius: 4px
|
|
||||||
|
|
||||||
.border-bottom
|
|
||||||
border-bottom: 4px solid var(--bg-ligth-blue-color)
|
|
||||||
|
|
||||||
.records-count
|
|
||||||
border-right: 1px solid var(--border-light-grey-color)
|
|
||||||
&:last-child
|
|
||||||
border-right: none
|
|
||||||
|
|
||||||
.border-top
|
|
||||||
border-top: 1px solid var(--border-light-grey-color)
|
|
||||||
|
|
||||||
.time-circle-indicator
|
|
||||||
background-color: var(--bg-event-red-color)
|
|
||||||
z-index: 5
|
|
||||||
|
|
||||||
.time-line-indicator
|
|
||||||
border-top: 1px solid var(--bg-event-red-color)
|
|
||||||
z-index: 4
|
|
||||||
width: calc(100% - 80px)
|
|
||||||
</style>
|
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
header-record-form(
|
header-record-form(
|
||||||
:current-status="currentStatus",
|
:current-status="currentStatus",
|
||||||
:statuses="patientData.statuses",
|
:statuses="patientData.statuses",
|
||||||
:choice-status="choiceStatus"
|
:choice-status="choiceStatus",
|
||||||
v-model="time"
|
v-model="time",
|
||||||
)
|
)
|
||||||
base-input-with-search(v-model="patient", @create-person="createPerson")
|
base-input-with-search(v-model="patient", @create-person="createPerson")
|
||||||
.flex.flex-col.flex-auto.l.gap-y-8
|
.flex.flex-col.flex-auto.l.gap-y-8
|
||||||
@@ -47,6 +47,8 @@ import { fetchWrapper } from "@/shared/fetchWrapper";
|
|||||||
import { mapActions } from "vuex";
|
import { mapActions } from "vuex";
|
||||||
import PatientCreationForm from "@/components/PatientCreationForm.vue";
|
import PatientCreationForm from "@/components/PatientCreationForm.vue";
|
||||||
import BaseModal from "@/components/base/BaseModal.vue";
|
import BaseModal from "@/components/base/BaseModal.vue";
|
||||||
|
import { addNotification } from "@/components/Notifications/notificationContext";
|
||||||
|
import { errors } from "@/shared/errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "CreateEventForm",
|
name: "CreateEventForm",
|
||||||
@@ -70,6 +72,7 @@ export default {
|
|||||||
patientData: patientData,
|
patientData: patientData,
|
||||||
currentStatus: patientData.statuses.find((e) => e.name === "Не принят"),
|
currentStatus: patientData.statuses.find((e) => e.name === "Не принят"),
|
||||||
showCreateModal: false,
|
showCreateModal: false,
|
||||||
|
errors: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -100,12 +103,16 @@ export default {
|
|||||||
person: {
|
person: {
|
||||||
id: this.patient.id,
|
id: this.patient.id,
|
||||||
},
|
},
|
||||||
medic_id: "a6195732-ac98-4f07-8916-4881eca69b7d",
|
medic_id: this.$store.getters.getUserData.id,
|
||||||
});
|
});
|
||||||
if (event?.id) {
|
if (event?.id) {
|
||||||
await this.getEvents();
|
await this.getEvents();
|
||||||
this.closeForm();
|
this.closeForm();
|
||||||
}
|
}
|
||||||
|
if (event?.code) {
|
||||||
|
this.errors = event?.fields;
|
||||||
|
addNotification(new Date(), "Ошибка", errors[event?.type], "error");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {},
|
mounted() {},
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
.flex.gap-x-3.items-center
|
.flex.gap-x-3.items-center
|
||||||
.text.font-semibold Время:
|
.text.font-semibold Время:
|
||||||
.flex.gap-x-1
|
.flex.gap-x-1
|
||||||
base-input.input.no-border(size="XS", mask="##:## - ##:##", v-model="times" )
|
base-input.input.no-border(size="XS", mask="##:## - ##:##", v-model="times", :error="!!errors?.['start'] || !!errors?.['end']")
|
||||||
.flex.h-14.gap-x-3.items-center.text-smm
|
.flex.h-14.gap-x-3.items-center.text-smm
|
||||||
.text.font-semibold Медкарта:
|
.text.font-semibold Медкарта:
|
||||||
.flex.gap-x-1
|
.flex.gap-x-1
|
||||||
@@ -86,7 +86,12 @@ export default {
|
|||||||
MedcardModal,
|
MedcardModal,
|
||||||
},
|
},
|
||||||
mixins: [v_model],
|
mixins: [v_model],
|
||||||
props: { currentStatus: Object, statuses: Array, choiceStatus: Function },
|
props: {
|
||||||
|
currentStatus: Object,
|
||||||
|
statuses: Array,
|
||||||
|
choiceStatus: Function,
|
||||||
|
errors: Object,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
noname,
|
noname,
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.calendar-column-wrapper.flex.flex-col
|
||||||
|
.header.flex.flex-col.items-center.justify-center.top-0.pt-3.pb-10px
|
||||||
|
span.font-bold.text-base.color-black {{ date?.format("D MMMM")}}
|
||||||
|
span.text-smm.color-grey {{ capitalizeFirstChar(date?.format("dddd"))}}
|
||||||
|
.body.h-full.px-1.py-1
|
||||||
|
calendar-record-card(
|
||||||
|
v-for="record in filteredRecords",
|
||||||
|
:key="record?.id",
|
||||||
|
:record="record",
|
||||||
|
:expanded-type="expandedDisplayType",
|
||||||
|
:style="eventCardPosition(record.start, record.end)",
|
||||||
|
@click="changeSelectedRecordId(record?.id)",
|
||||||
|
)
|
||||||
|
.footer.flex.items-center.justify-center.bg-white.h-9(v-if="!expandedDisplayType")
|
||||||
|
span.text-smm.color-grey 0 записей
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as moment from "moment/moment";
|
||||||
|
import { columnMixin } from "@/pages/newCalendar/mixins/columnMixin.js";
|
||||||
|
import { capitalizeFirstChar } from "@/pages/newCalendar/utils/calendarFunctions.js";
|
||||||
|
export default {
|
||||||
|
name: "CalendarColumn",
|
||||||
|
mixins: [columnMixin],
|
||||||
|
props: {
|
||||||
|
date: Object,
|
||||||
|
expandedDisplayType: Boolean,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
capitalizeFirstChar: capitalizeFirstChar,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredRecords() {
|
||||||
|
return this.events.filter(
|
||||||
|
(elem) =>
|
||||||
|
moment.parseZone(elem.start).format("YYYY-MM-DD") ===
|
||||||
|
this.date.format("YYYY-MM-DD")
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
@import "@/pages/newCalendar/sass/columnStyle.sass"
|
||||||
|
</style>
|
||||||
@@ -74,15 +74,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseCalendar from "@/components/base/Calendar/BaseCalendar.vue";
|
|
||||||
import { mapState, mapActions } from "vuex";
|
|
||||||
import { v_model } from "@/shared/mixins/v-model";
|
import { v_model } from "@/shared/mixins/v-model";
|
||||||
import DateSwitcherSvg from "@/pages/newCalendar/components/CalendarDateSwitcherSvg.vue";
|
import DateSwitcherSvg from "@/pages/newCalendar/components/CalendarDateSwitcherSvg.vue";
|
||||||
import BaseInput from "@/components/base/BaseInput.vue";
|
import { headerMixin } from "@/pages/newCalendar/mixins/headerMixin.js";
|
||||||
export default {
|
export default {
|
||||||
name: "CalendarHeader",
|
name: "CalendarHeader",
|
||||||
mixins: [v_model],
|
mixins: [v_model, headerMixin],
|
||||||
components: { BaseInput, BaseCalendar, DateSwitcherSvg },
|
components: { DateSwitcherSvg },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
displayTypesList: [
|
displayTypesList: [
|
||||||
@@ -99,7 +97,6 @@ export default {
|
|||||||
from: null,
|
from: null,
|
||||||
to: null,
|
to: null,
|
||||||
},
|
},
|
||||||
calendarVisibility: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -108,9 +105,6 @@ export default {
|
|||||||
"D MMMM YYYY"
|
"D MMMM YYYY"
|
||||||
)} — ${this.dates?.to?.format("D MMMM YYYY")}`;
|
)} — ${this.dates?.to?.format("D MMMM YYYY")}`;
|
||||||
},
|
},
|
||||||
...mapState({
|
|
||||||
selectedDates: (state) => state.calendar.selectedDates,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
previousWeek() {
|
previousWeek() {
|
||||||
@@ -123,13 +117,6 @@ export default {
|
|||||||
this.dates.from = this.dates.from.clone().add(diff, "day");
|
this.dates.from = this.dates.from.clone().add(diff, "day");
|
||||||
this.dates.to = this.dates.to.clone().add(diff, "day");
|
this.dates.to = this.dates.to.clone().add(diff, "day");
|
||||||
},
|
},
|
||||||
...mapActions({
|
|
||||||
changeSelectedDates: "changeSelectedDates",
|
|
||||||
getEvents: "getEvents",
|
|
||||||
}),
|
|
||||||
saveDatesChange() {
|
|
||||||
this.calendarVisibility = false;
|
|
||||||
},
|
|
||||||
initializeDates() {
|
initializeDates() {
|
||||||
this.dates = {
|
this.dates = {
|
||||||
from: this.selectedDates.from.clone(),
|
from: this.selectedDates.from.clone(),
|
||||||
@@ -164,50 +151,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
<style lang="sass" scoped>
|
||||||
.calendar-header-wrapper
|
@import "@/pages/newCalendar/sass/headerStyle.sass"
|
||||||
background-color: var(--default-white)
|
|
||||||
height: 72px
|
|
||||||
border-radius: 4px
|
|
||||||
z-index: 10
|
|
||||||
|
|
||||||
.text
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.text-grey-color
|
|
||||||
color: var(--font-grey-color)
|
|
||||||
|
|
||||||
.text-primary
|
|
||||||
color: var(--font-dark-blue-color-0) !important
|
|
||||||
|
|
||||||
.bg-secondary
|
|
||||||
background: var(--bg-light-grey) !important
|
|
||||||
|
|
||||||
.q-btn--round
|
|
||||||
width: 32px !important
|
|
||||||
height: 32px !important
|
|
||||||
min-width: 32px !important
|
|
||||||
min-height: 32px !important
|
|
||||||
|
|
||||||
.q-btn-group :deep(.q-btn-item)
|
|
||||||
border-radius: 4px !important
|
|
||||||
|
|
||||||
.search :deep(.q-field__marginal)
|
|
||||||
height: auto !important
|
|
||||||
|
|
||||||
.search :deep(.q-field__prepend)
|
|
||||||
padding-right: 6px !important
|
|
||||||
|
|
||||||
.search-icon :deep(path)
|
|
||||||
fill: var(--font-grey-color)
|
|
||||||
|
|
||||||
.calendar-icon :deep(path)
|
|
||||||
fill: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.active-toggle
|
|
||||||
background: var(--btn-blue-color)
|
|
||||||
|
|
||||||
.border-toggle
|
|
||||||
border: 1px solid var(--gray-secondary)
|
|
||||||
</style>
|
</style>
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
.q-field--outlined.q-field--readonly .q-field__control:before
|
.q-field--outlined.q-field--readonly .q-field__control:before
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.schedule.flex-1.flex.flex-col.relative(
|
||||||
|
:style="{width: openSidebar ? 'calc(100vw - 320px)' : 'calc(100vw - 160px)'}"
|
||||||
|
)
|
||||||
|
calendar-header.w-full.mb-1(v-model="displayType")
|
||||||
|
.schedule-body.h-full.bg-white.w-full(:class="{rounded: !expandedDisplayType}")
|
||||||
|
.column-wrapper.flex.ml-20(:style="columnWrapperWidth")
|
||||||
|
calendar-column(
|
||||||
|
v-for="date in dateRange",
|
||||||
|
:key="date",
|
||||||
|
:date="date",
|
||||||
|
:style="columnHeight",
|
||||||
|
:expanded-display-type="expandedDisplayType",
|
||||||
|
:day-start-time="validateStartTime"
|
||||||
|
:day-end-time="validateEndTime"
|
||||||
|
)
|
||||||
|
.flex.relative(
|
||||||
|
:style="expandedDisplayType ? backgroundWrapperWidth : {}",
|
||||||
|
:class="{'border-bottom': expandedDisplayType}"
|
||||||
|
)
|
||||||
|
.time-coil-wrapper.left-0.-mt-16
|
||||||
|
calendar-clock-column(
|
||||||
|
:time-coil="timeCoil",
|
||||||
|
:current-time="currentTime",
|
||||||
|
:is-current="isCurrent",
|
||||||
|
:day-end-time="validateEndTime"
|
||||||
|
)
|
||||||
|
.time-circle-indicator.left-74px.h-3.w-3.rounded-full.absolute(
|
||||||
|
v-if="isShownIndicator",
|
||||||
|
:style="circleIndicatorLocation"
|
||||||
|
)
|
||||||
|
span.time-line-indicator.block.left-20.absolute(
|
||||||
|
v-if="isShownIndicator",
|
||||||
|
:style="lineIndicatorLocation"
|
||||||
|
)
|
||||||
|
calendar-background.flex-1
|
||||||
|
.w-full.h-3.bg-white.footer(v-if="expandedDisplayType")
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CalendarHeader from "@/pages/newCalendar/components/doctorCalendar/CalendarHeader";
|
||||||
|
import CalendarColumn from "@/pages/newCalendar/components/doctorCalendar/CalendarColumn.vue";
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
import * as moment from "moment/moment";
|
||||||
|
import { wrapperMixin } from "@/pages/newCalendar/mixins/wrapperMixin.js";
|
||||||
|
export default {
|
||||||
|
name: "CalendarWrapper",
|
||||||
|
components: {
|
||||||
|
CalendarHeader,
|
||||||
|
CalendarColumn,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
openSidebar: Boolean,
|
||||||
|
},
|
||||||
|
mixins: [wrapperMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
displayType: "expanded",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
selectedDates: (state) => state.calendar.selectedDates,
|
||||||
|
}),
|
||||||
|
expandedDisplayType() {
|
||||||
|
return this.displayType === "expanded";
|
||||||
|
},
|
||||||
|
backgroundWrapperWidth() {
|
||||||
|
return {
|
||||||
|
width: `${380 * this.dateRange.length + 80}px`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
dateRange() {
|
||||||
|
let diff = this.selectedDates?.to.diff(this.selectedDates?.from, "days");
|
||||||
|
let range = [];
|
||||||
|
for (let i = 0; i <= diff; i++) {
|
||||||
|
range.push(this.selectedDates?.from.clone().add(i, "day"));
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
},
|
||||||
|
columnHeight() {
|
||||||
|
return this.expandedDisplayType
|
||||||
|
? {
|
||||||
|
height: `${this.timeCoil.length * this.pixelsPerHour + 60}px`,
|
||||||
|
width: "380px",
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
height: `${this.timeCoil.length * this.pixelsPerHour + 96}px`,
|
||||||
|
width: this.openSidebar
|
||||||
|
? `calc((100vw - 320px - 80px) / ${this.dateRange.length})`
|
||||||
|
: `calc((100vw - 160px - 80px) / ${this.dateRange.length})`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
columnWrapperWidth() {
|
||||||
|
return this.expandedDisplayType
|
||||||
|
? {
|
||||||
|
width: `${380 * this.dateRange.length}px`,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
width: this.openSidebar
|
||||||
|
? "calc(100vw - 320px - 80px)"
|
||||||
|
: "calc(100vw - 160px - 80px)",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedDates: {
|
||||||
|
deep: true,
|
||||||
|
handler(newValue) {
|
||||||
|
this.isCurrent =
|
||||||
|
newValue?.from.isSame(moment().clone().startOf("week"), "day") &&
|
||||||
|
newValue?.to.isSame(moment().clone().endOf("week"), "day");
|
||||||
|
this.isShownIndicator = this.isCurrent;
|
||||||
|
if (this.timer) {
|
||||||
|
this.stopTimer();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
}
|
||||||
|
if (this.isCurrent) {
|
||||||
|
this.changeCurrentTime();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
this.startTimer();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.changeCurrentTime();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
@import "@/pages/newCalendar/sass/wrapperStyle.sass"
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.calendar-column-wrapper.flex.flex-col
|
||||||
|
.header.flex.items-center.justify-between.top-0.py-2.px-6
|
||||||
|
.flex.h-full.items-center.h-11
|
||||||
|
q-avatar.mr-2(
|
||||||
|
size="40px",
|
||||||
|
round
|
||||||
|
)
|
||||||
|
img(:src="medic?.photo || defaultPhoto", alt="doctor")
|
||||||
|
.flex.flex-col.justify-between
|
||||||
|
span.text-dark {{trimName(medic?.last_name, medic?.first_name, medic?.patronymic)}}
|
||||||
|
span.text-xsx.color-grey {{medic?.job || "Терапевт"}}
|
||||||
|
button(@click="locked = !locked")
|
||||||
|
q-icon.lock-icon(
|
||||||
|
:name="locked ? 'app:lock' : 'app:lock-open'",
|
||||||
|
size="24px"
|
||||||
|
)
|
||||||
|
.body.h-full.px-1.py-1
|
||||||
|
calendar-record-card(
|
||||||
|
v-for="record in filteredRecords",
|
||||||
|
:key="record?.id",
|
||||||
|
:record="record",
|
||||||
|
:expanded-type="true",
|
||||||
|
:style="eventCardPosition(record.start, record.end)",
|
||||||
|
@click="changeSelectedRecordId(record?.id)",
|
||||||
|
)
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { columnMixin } from "@/pages/newCalendar/mixins/columnMixin.js";
|
||||||
|
import { trimName } from "@/pages/newCalendar/utils/calendarFunctions.js";
|
||||||
|
import doctorAvatar from "@/assets/images/doctor.png";
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
export default {
|
||||||
|
name: "CalendarColumn",
|
||||||
|
mixins: [columnMixin],
|
||||||
|
props: {
|
||||||
|
medic: Object,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
trimName: trimName,
|
||||||
|
defaultPhoto: doctorAvatar,
|
||||||
|
locked: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
events: (state) => state.calendar.events,
|
||||||
|
}),
|
||||||
|
filteredRecords() {
|
||||||
|
return this.events.filter((elem) => elem?.medic?.ID === this.medic?.ID);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
@import "@/pages/newCalendar/sass/columnStyle.sass"
|
||||||
|
.lock-icon :deep(path)
|
||||||
|
fill: var(--font-grey-color)
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.calendar-header-wrapper.w-full.flex.items-center.p-4.justify-between
|
||||||
|
base-input.search(
|
||||||
|
iconLeft,
|
||||||
|
:width="280",
|
||||||
|
size="M",
|
||||||
|
placeholder="Найти ...",
|
||||||
|
icon-left
|
||||||
|
)
|
||||||
|
template(v-slot:iconLeft)
|
||||||
|
q-icon.search-icon(name="app:search", size="20px")
|
||||||
|
.flex.gap-x-4.items-center.justify-center
|
||||||
|
q-btn(
|
||||||
|
color="secondary",
|
||||||
|
round,
|
||||||
|
size="14px",
|
||||||
|
dense,
|
||||||
|
icon="arrow_back_ios_new",
|
||||||
|
text-color="primary",
|
||||||
|
padding="2px 11px 2px 8px",
|
||||||
|
@click="previousDate",
|
||||||
|
)
|
||||||
|
base-input.search(
|
||||||
|
size="M"
|
||||||
|
:width="332",
|
||||||
|
v-model="currentDate",
|
||||||
|
:shadow-text="inputShadowText"
|
||||||
|
)
|
||||||
|
.h-5.w-5.flex.items-center.justify-center.ml-3
|
||||||
|
q-icon.calendar-icon.text.cursor-pointer(
|
||||||
|
:name="calendarVisibility ? 'app:cancel-mini' : 'app:calendar'",
|
||||||
|
size="20px",
|
||||||
|
)
|
||||||
|
q-menu(
|
||||||
|
:style="{'margin-top': '8px !important'}"
|
||||||
|
v-model="calendarVisibility",
|
||||||
|
transition-show="scale",
|
||||||
|
transition-hide="scale"
|
||||||
|
self="top middle",
|
||||||
|
:offset="[130, 8]"
|
||||||
|
)
|
||||||
|
base-calendar(
|
||||||
|
v-model="date",
|
||||||
|
:save="saveDatesChange",
|
||||||
|
:start-year="2000"
|
||||||
|
)
|
||||||
|
q-btn(
|
||||||
|
color="secondary",
|
||||||
|
icon="arrow_forward_ios",
|
||||||
|
round,
|
||||||
|
size="14px",
|
||||||
|
text-color="primary",
|
||||||
|
dense,
|
||||||
|
@click="nextDate"
|
||||||
|
)
|
||||||
|
.h-10.p-1.flex.items-center.justify-between.bg-secondary.rounded.text-grey-color.ml-52.border
|
||||||
|
q-btn-toggle(
|
||||||
|
v-model="value",
|
||||||
|
:options="displayTypesList",
|
||||||
|
no-caps,
|
||||||
|
padding="0px 12px"
|
||||||
|
)
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { v_model } from "@/shared/mixins/v-model";
|
||||||
|
import { headerMixin } from "@/pages/newCalendar/mixins/headerMixin.js";
|
||||||
|
import { capitalizeFirstChar } from "@/pages/newCalendar/utils/calendarFunctions.js";
|
||||||
|
export default {
|
||||||
|
name: "CalendarHeader",
|
||||||
|
mixins: [v_model, headerMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
displayTypesList: [
|
||||||
|
{
|
||||||
|
value: "day",
|
||||||
|
label: "День",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "week",
|
||||||
|
label: "Неделя",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
date: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentDate() {
|
||||||
|
return this.date?.format("D MMMM YYYY");
|
||||||
|
},
|
||||||
|
inputShadowText() {
|
||||||
|
return this.date?.isValid()
|
||||||
|
? capitalizeFirstChar(this.date?.format("dddd"))
|
||||||
|
: "";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
previousDate() {
|
||||||
|
this.date = this.date?.clone()?.subtract(1, "day");
|
||||||
|
},
|
||||||
|
nextDate() {
|
||||||
|
this.date = this.date?.clone()?.add(1, "day");
|
||||||
|
},
|
||||||
|
initializeDates() {
|
||||||
|
this.date = this.selectedDates.from.clone();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
date: {
|
||||||
|
deep: true,
|
||||||
|
handler(val) {
|
||||||
|
if (!val?.isSame(this.selectedDates?.from, "day"))
|
||||||
|
this.changeSelectedDates({
|
||||||
|
from: val,
|
||||||
|
to: val?.clone()?.endOf("day"),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectedDates: {
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (!val?.from.isSame(this.date, "day")) this.initializeDates();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
@import "@/pages/newCalendar/sass/headerStyle.sass"
|
||||||
|
.q-btn-toggle :deep(span)
|
||||||
|
font-weight: 500
|
||||||
|
.q-btn-toggle :deep(.q-btn-item)
|
||||||
|
height: 32px
|
||||||
|
</style>
|
||||||
|
<style lang="sass">
|
||||||
|
.q-field--outlined.q-field--readonly .q-field__control:before
|
||||||
|
border-style: solid !important
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.schedule.flex-1.flex.flex-col.relative(
|
||||||
|
:style="{width: openSidebar ? 'calc(100vw - 320px)' : 'calc(100vw - 160px)'}"
|
||||||
|
)
|
||||||
|
calendar-header.w-full.mb-1(v-model="displayType")
|
||||||
|
.schedule-body.h-full.bg-white.w-full
|
||||||
|
.column-wrapper.flex.ml-20(:style="columnWrapperWidth")
|
||||||
|
calendar-column(
|
||||||
|
v-for="medic in filteringMedics",
|
||||||
|
:key="medic?.id",
|
||||||
|
:medic="medic",
|
||||||
|
:style="columnStyle",
|
||||||
|
:expanded-display-type="true",
|
||||||
|
:day-start-time="validateStartTime"
|
||||||
|
:day-end-time="validateEndTime"
|
||||||
|
)
|
||||||
|
.flex.relative.border-bottom(
|
||||||
|
:style="backgroundWrapperWidth",
|
||||||
|
)
|
||||||
|
.time-coil-wrapper.left-0.-mt-16
|
||||||
|
calendar-clock-column(
|
||||||
|
:time-coil="timeCoil",
|
||||||
|
:current-time="currentTime",
|
||||||
|
:is-current="isCurrent",
|
||||||
|
:day-end-time="validateEndTime"
|
||||||
|
)
|
||||||
|
.time-circle-indicator.left-74px.h-3.w-3.rounded-full.absolute(
|
||||||
|
v-if="isShownIndicator",
|
||||||
|
:style="circleIndicatorLocation"
|
||||||
|
)
|
||||||
|
span.time-line-indicator.block.left-20.absolute(
|
||||||
|
v-if="isShownIndicator",
|
||||||
|
:style="lineIndicatorLocation"
|
||||||
|
)
|
||||||
|
calendar-background.flex-1
|
||||||
|
.w-full.h-3.bg-white.footer
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CalendarHeader from "@/pages/newCalendar/components/managerCalendar/CalendarHeader";
|
||||||
|
import CalendarColumn from "@/pages/newCalendar/components/managerCalendar/CalendarColumn.vue";
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
import * as moment from "moment/moment";
|
||||||
|
import { wrapperMixin } from "@/pages/newCalendar/mixins/wrapperMixin.js";
|
||||||
|
export default {
|
||||||
|
name: "CalendarWrapper",
|
||||||
|
components: {
|
||||||
|
CalendarHeader,
|
||||||
|
CalendarColumn,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
openSidebar: Boolean,
|
||||||
|
},
|
||||||
|
mixins: [wrapperMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
displayType: "day",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
selectedDates: (state) => state.calendar.selectedDates,
|
||||||
|
events: (state) => state.calendar.events,
|
||||||
|
}),
|
||||||
|
filteringMedics() {
|
||||||
|
let medicsList = [];
|
||||||
|
this.events?.forEach(({ medic }) => {
|
||||||
|
if (!medicsList.includes(JSON.stringify(medic)))
|
||||||
|
medicsList.push(JSON.stringify(medic));
|
||||||
|
});
|
||||||
|
return medicsList?.map((elem) => JSON.parse(elem));
|
||||||
|
},
|
||||||
|
medicsListLength() {
|
||||||
|
return this.filteringMedics?.length;
|
||||||
|
},
|
||||||
|
columnStyle() {
|
||||||
|
return this.medicsListLength > 4
|
||||||
|
? {
|
||||||
|
height: `${this.timeCoil.length * this.pixelsPerHour + 60}px`,
|
||||||
|
width: "380px",
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
height: `${this.timeCoil.length * this.pixelsPerHour + 60}px`,
|
||||||
|
width: `calc(100%/ ${this.medicsListLength})`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
backgroundWrapperWidth() {
|
||||||
|
return this.medicsListLength > 4
|
||||||
|
? {
|
||||||
|
width: `${380 * this.medicsListLength + 80}px`,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
columnWrapperWidth() {
|
||||||
|
return this.medicsListLength > 4
|
||||||
|
? {
|
||||||
|
width: `${380 * this.medicsListLength}px`,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
width: "calc(100% - 80px)",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedDates: {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
handler(newValue) {
|
||||||
|
this.isCurrent = newValue?.from.isSame(moment(), "day");
|
||||||
|
this.isShownIndicator = this.isCurrent;
|
||||||
|
if (this.timer) {
|
||||||
|
this.stopTimer();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
}
|
||||||
|
if (this.isCurrent) {
|
||||||
|
this.changeCurrentTime();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
this.startTimer();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.changeCurrentTime();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
@import "@/pages/newCalendar/sass/wrapperStyle.sass"
|
||||||
|
</style>
|
||||||
53
src/pages/newCalendar/mixins/columnMixin.js
Normal file
53
src/pages/newCalendar/mixins/columnMixin.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import CalendarRecordCard from "@/pages/newCalendar/components/CalendarRecordCard.vue";
|
||||||
|
import { verifyTime } from "@/pages/newCalendar/utils/calendarFunctions.js";
|
||||||
|
import { mapActions, mapState } from "vuex";
|
||||||
|
|
||||||
|
export const columnMixin = {
|
||||||
|
props: {
|
||||||
|
dayEndTime: Number,
|
||||||
|
dayStartTime: Number,
|
||||||
|
},
|
||||||
|
emits: [],
|
||||||
|
components: { CalendarRecordCard },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pixelsPerHour: 76,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
events: (state) => state.calendar.events || [],
|
||||||
|
}),
|
||||||
|
pixelsPerMinute() {
|
||||||
|
return this.pixelsPerHour / 60;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions({
|
||||||
|
changeSelectedRecordId: "changeSelectedRecordId",
|
||||||
|
}),
|
||||||
|
eventCardPosition(startTime, endTime) {
|
||||||
|
let start = startTime
|
||||||
|
.slice(11, -4)
|
||||||
|
.split(":")
|
||||||
|
.map((elem) => parseInt(elem, 10));
|
||||||
|
let end = endTime.slice(11, -4);
|
||||||
|
let position =
|
||||||
|
(start[0] - this.dayStartTime) * this.pixelsPerHour +
|
||||||
|
start[1] * this.pixelsPerMinute +
|
||||||
|
4;
|
||||||
|
if (
|
||||||
|
parseInt(start[0], 10) < this.dayStartTime ||
|
||||||
|
verifyTime(end) > this.dayEndTime
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
top: "0px",
|
||||||
|
visibility: "hidden",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
top: `${position}px`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
26
src/pages/newCalendar/mixins/headerMixin.js
Normal file
26
src/pages/newCalendar/mixins/headerMixin.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import BaseCalendar from "@/components/base/Calendar/BaseCalendar.vue";
|
||||||
|
import { mapState, mapActions } from "vuex";
|
||||||
|
import BaseInput from "@/components/base/BaseInput.vue";
|
||||||
|
|
||||||
|
export const headerMixin = {
|
||||||
|
components: { BaseInput, BaseCalendar },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
calendarVisibility: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
selectedDates: (state) => state.calendar.selectedDates,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions({
|
||||||
|
getEvents: "getEvents",
|
||||||
|
changeSelectedDates: "changeSelectedDates",
|
||||||
|
}),
|
||||||
|
saveDatesChange() {
|
||||||
|
this.calendarVisibility = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
135
src/pages/newCalendar/mixins/wrapperMixin.js
Normal file
135
src/pages/newCalendar/mixins/wrapperMixin.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import { mapState } from "vuex";
|
||||||
|
import * as moment from "moment/moment";
|
||||||
|
import CalendarBackground from "@/pages/newCalendar/components/CalendarBackground.vue";
|
||||||
|
import CalendarClockColumn from "@/pages/newCalendar/components/CalendarClockColumn.vue";
|
||||||
|
import {
|
||||||
|
convertTime,
|
||||||
|
verifyTime,
|
||||||
|
} from "@/pages/newCalendar/utils/calendarFunctions.js";
|
||||||
|
|
||||||
|
export const wrapperMixin = {
|
||||||
|
props: {
|
||||||
|
openSidebar: Boolean,
|
||||||
|
},
|
||||||
|
emits: [],
|
||||||
|
components: {
|
||||||
|
CalendarBackground,
|
||||||
|
CalendarClockColumn,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentTime: "",
|
||||||
|
isShownIndicator: true,
|
||||||
|
timeCoil: [],
|
||||||
|
timer: null,
|
||||||
|
pixelsPerHour: 76,
|
||||||
|
isCurrent: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
workingHours: (state) => state.calendar.workingHours,
|
||||||
|
}),
|
||||||
|
hours() {
|
||||||
|
return convertTime(this.currentTime, 0, -6);
|
||||||
|
},
|
||||||
|
minutes() {
|
||||||
|
return convertTime(this.currentTime, 3, -3);
|
||||||
|
},
|
||||||
|
hoursMinutes() {
|
||||||
|
return this.currentTime.slice(0, -3);
|
||||||
|
},
|
||||||
|
pixelsPerMinute() {
|
||||||
|
return this.pixelsPerHour / 60;
|
||||||
|
},
|
||||||
|
validateStartTime() {
|
||||||
|
return verifyTime(this.workingHours.start);
|
||||||
|
},
|
||||||
|
validateEndTime() {
|
||||||
|
return verifyTime(this.workingHours.end);
|
||||||
|
},
|
||||||
|
backgroundHeight() {
|
||||||
|
return (
|
||||||
|
(this.validateEndTime - this.validateStartTime) * this.pixelsPerHour
|
||||||
|
);
|
||||||
|
},
|
||||||
|
lineIndicatorLocation() {
|
||||||
|
return {
|
||||||
|
top: `${this.calculateIndicatorLocation()}px`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
circleIndicatorLocation() {
|
||||||
|
return {
|
||||||
|
top: `${this.calculateIndicatorLocation() + 58}px`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeCurrentTime() {
|
||||||
|
this.currentTime = moment().format("HH:mm:ss");
|
||||||
|
},
|
||||||
|
changeTimeCoil() {
|
||||||
|
this.timeCoil = this.timeCoil.map((elem) => {
|
||||||
|
if (convertTime(elem, 0, -3) === this.hours) {
|
||||||
|
return this.hoursMinutes;
|
||||||
|
}
|
||||||
|
return elem.slice(0, -3) + ":00";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
startTimer() {
|
||||||
|
if (
|
||||||
|
this.hours >= this.validateStartTime &&
|
||||||
|
this.hours < this.validateEndTime
|
||||||
|
) {
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
this.changeCurrentTime();
|
||||||
|
this.changeTimeCoil();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stopTimer() {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
},
|
||||||
|
calculateIndicatorLocation() {
|
||||||
|
let newTime = this.currentTime
|
||||||
|
.split(":")
|
||||||
|
.map((elem) => parseInt(elem, 10));
|
||||||
|
let result =
|
||||||
|
(newTime[0] - this.validateStartTime) * this.pixelsPerHour +
|
||||||
|
newTime[1] * this.pixelsPerMinute;
|
||||||
|
if (result > this.backgroundHeight || result < 0) {
|
||||||
|
this.isShownIndicator = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
timeCoilInitialization() {
|
||||||
|
this.timeCoil = [];
|
||||||
|
for (let i = this.validateStartTime; i < this.validateEndTime; i++) {
|
||||||
|
if (
|
||||||
|
i === this.hours &&
|
||||||
|
this.hours !== this.validateEndTime &&
|
||||||
|
this.isCurrent
|
||||||
|
) {
|
||||||
|
this.timeCoil.push(this.hoursMinutes);
|
||||||
|
} else this.timeCoil.push(`${i}:00`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
currentTime() {
|
||||||
|
if (
|
||||||
|
this.hours === this.validateEndTime &&
|
||||||
|
this.minutes > 0 &&
|
||||||
|
this.timer
|
||||||
|
) {
|
||||||
|
this.stopTimer();
|
||||||
|
this.timeCoilInitialization();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
this.stopTimer();
|
||||||
|
},
|
||||||
|
};
|
||||||
24
src/pages/newCalendar/sass/columnStyle.sass
Normal file
24
src/pages/newCalendar/sass/columnStyle.sass
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.calendar-column-wrapper
|
||||||
|
border-right: 1px solid var(--border-light-grey-color)
|
||||||
|
&:last-child
|
||||||
|
border-right: none
|
||||||
|
|
||||||
|
.header
|
||||||
|
position: sticky
|
||||||
|
z-index: 5
|
||||||
|
background-color: var(--default-white)
|
||||||
|
|
||||||
|
.body
|
||||||
|
position: relative
|
||||||
|
z-index: 3
|
||||||
|
|
||||||
|
.color-black
|
||||||
|
color: var(--font-dark-blue-color)
|
||||||
|
|
||||||
|
.color-grey
|
||||||
|
color: var(--font-grey-color)
|
||||||
|
|
||||||
|
.footer
|
||||||
|
border-top: 1px solid var(--border-light-grey-color)
|
||||||
|
@media(min-height: 1090px)
|
||||||
|
border-bottom: 1px solid var(--border-light-grey-color)
|
||||||
41
src/pages/newCalendar/sass/headerStyle.sass
Normal file
41
src/pages/newCalendar/sass/headerStyle.sass
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
.calendar-header-wrapper
|
||||||
|
background-color: var(--default-white)
|
||||||
|
height: 72px
|
||||||
|
border-radius: 4px
|
||||||
|
z-index: 10
|
||||||
|
|
||||||
|
.text
|
||||||
|
color: var(--font-dark-blue-color)
|
||||||
|
|
||||||
|
.text-grey-color
|
||||||
|
color: var(--font-grey-color)
|
||||||
|
|
||||||
|
.text-primary
|
||||||
|
color: var(--font-dark-blue-color-0) !important
|
||||||
|
|
||||||
|
.bg-secondary
|
||||||
|
background: var(--bg-light-grey) !important
|
||||||
|
|
||||||
|
.q-btn--round
|
||||||
|
width: 32px !important
|
||||||
|
height: 32px !important
|
||||||
|
min-width: 32px !important
|
||||||
|
min-height: 32px !important
|
||||||
|
|
||||||
|
.q-btn-group :deep(.q-btn-item)
|
||||||
|
border-radius: 4px !important
|
||||||
|
|
||||||
|
.search :deep(.q-field__marginal)
|
||||||
|
height: auto !important
|
||||||
|
|
||||||
|
.search :deep(.q-field__prepend)
|
||||||
|
padding-right: 6px !important
|
||||||
|
|
||||||
|
.search-icon :deep(path)
|
||||||
|
fill: var(--font-grey-color)
|
||||||
|
|
||||||
|
.calendar-icon :deep(path)
|
||||||
|
fill: var(--font-dark-blue-color)
|
||||||
|
|
||||||
|
.border-toggle
|
||||||
|
border: 1px solid var(--gray-secondary)
|
||||||
44
src/pages/newCalendar/sass/wrapperStyle.sass
Normal file
44
src/pages/newCalendar/sass/wrapperStyle.sass
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
.schedule-body
|
||||||
|
overflow-x: auto
|
||||||
|
border-top-left-radius: 4px
|
||||||
|
border-top-right-radius: 4px
|
||||||
|
&::-webkit-scrollbar-track:horizontal
|
||||||
|
margin: 0 24px 0 24px
|
||||||
|
|
||||||
|
.background
|
||||||
|
background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%)
|
||||||
|
|
||||||
|
.time-coil-wrapper
|
||||||
|
position: sticky
|
||||||
|
z-index: 5
|
||||||
|
background-color: var(--default-white)
|
||||||
|
padding-top: 52px
|
||||||
|
|
||||||
|
.column-wrapper
|
||||||
|
height: 60px
|
||||||
|
position: relative
|
||||||
|
background-color: var(--default-white)
|
||||||
|
|
||||||
|
.footer
|
||||||
|
border-bottom-left-radius: 4px
|
||||||
|
border-bottom-right-radius: 4px
|
||||||
|
|
||||||
|
.border-bottom
|
||||||
|
border-bottom: 4px solid var(--bg-ligth-blue-color)
|
||||||
|
|
||||||
|
.records-count
|
||||||
|
border-right: 1px solid var(--border-light-grey-color)
|
||||||
|
&:last-child
|
||||||
|
border-right: none
|
||||||
|
|
||||||
|
.border-top
|
||||||
|
border-top: 1px solid var(--border-light-grey-color)
|
||||||
|
|
||||||
|
.time-circle-indicator
|
||||||
|
background-color: var(--bg-event-red-color)
|
||||||
|
z-index: 5
|
||||||
|
|
||||||
|
.time-line-indicator
|
||||||
|
border-top: 1px solid var(--bg-event-red-color)
|
||||||
|
z-index: 4
|
||||||
|
width: calc(100% - 80px)
|
||||||
@@ -778,16 +778,16 @@ export const services = [
|
|||||||
|
|
||||||
export const recordList = [
|
export const recordList = [
|
||||||
{
|
{
|
||||||
id: "c3df0a95-8093-41f1-9584-5b70ee05e71c",
|
id: "asdf0a95-8093-41f1-9584-5b70ee05e71c",
|
||||||
start: "2023-07-05T10:00:00Z",
|
start: "2023-09-18T10:00:00Z",
|
||||||
end: "2023-07-05T11:00:00Z",
|
end: "2023-09-18T11:00:00Z",
|
||||||
employee: {
|
employee: {
|
||||||
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||||
last_name: "Каневский",
|
last_name: "Каневский",
|
||||||
first_name: "Леонид",
|
first_name: "Леонид",
|
||||||
patronymic: "Семенович",
|
patronymic: "Семенович",
|
||||||
},
|
},
|
||||||
member: {
|
person: {
|
||||||
id: "3e6e54e4-2706-47d3-8b54-b841ee8f0943",
|
id: "3e6e54e4-2706-47d3-8b54-b841ee8f0943",
|
||||||
last_name: "Харитонова",
|
last_name: "Харитонова",
|
||||||
first_name: "Ольга",
|
first_name: "Ольга",
|
||||||
@@ -823,16 +823,16 @@ export const recordList = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "ba931000-7140-4977-bd09-1ac212b8b8e5",
|
id: "ss931000-7140-4977-bd09-1ac212b8b8e5",
|
||||||
start: "2023-07-06T15:00:00Z",
|
start: "2023-09-18T15:00:00Z",
|
||||||
end: "2023-07-06T15:30:00Z",
|
end: "2023-09-18T15:30:00Z",
|
||||||
employee: {
|
employee: {
|
||||||
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||||
last_name: "Каневский",
|
last_name: "Каневский",
|
||||||
first_name: "Леонид",
|
first_name: "Леонид",
|
||||||
patronymic: "Семенович",
|
patronymic: "Семенович",
|
||||||
},
|
},
|
||||||
member: {
|
person: {
|
||||||
id: "d340d344-4fc7-4fbe-9db8-b7562b70438d",
|
id: "d340d344-4fc7-4fbe-9db8-b7562b70438d",
|
||||||
last_name: "Гаранова",
|
last_name: "Гаранова",
|
||||||
first_name: "Наталья",
|
first_name: "Наталья",
|
||||||
@@ -877,16 +877,16 @@ export const recordList = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "4cd94bec-a0df-4a18-879d-f64cd6d7098e",
|
id: "ccd94bec-a0df-4a18-879d-f64cd6d5698e",
|
||||||
start: "2023-07-03T13:00:00Z",
|
start: "2023-09-18T13:00:00Z",
|
||||||
end: "2023-07-03T14:30:00Z",
|
end: "2023-09-18T14:30:00Z",
|
||||||
employee: {
|
employee: {
|
||||||
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
id: "111101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||||
last_name: "Каневский",
|
last_name: "Гурцев",
|
||||||
first_name: "Леонид",
|
first_name: "Семен",
|
||||||
patronymic: "Семенович",
|
patronymic: "Семенович",
|
||||||
},
|
},
|
||||||
member: {
|
person: {
|
||||||
id: "0b2d1db1-6aab-4e29-b857-fc7c9777280f",
|
id: "0b2d1db1-6aab-4e29-b857-fc7c9777280f",
|
||||||
last_name: "Харитонова",
|
last_name: "Харитонова",
|
||||||
first_name: "Ольга",
|
first_name: "Ольга",
|
||||||
@@ -930,6 +930,105 @@ export const recordList = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "vv931000-7140-4977-bd09-1ac233b8b8e5",
|
||||||
|
start: "2023-09-18T15:00:00Z",
|
||||||
|
end: "2023-09-18T15:30:00Z",
|
||||||
|
employee: {
|
||||||
|
id: "333101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||||
|
last_name: "Лебедев",
|
||||||
|
first_name: "Леонид",
|
||||||
|
patronymic: "Семенович",
|
||||||
|
},
|
||||||
|
person: {
|
||||||
|
id: "d340d344-4fc7-4fbe-9db8-b7562b70438d",
|
||||||
|
last_name: "Гаранова",
|
||||||
|
first_name: "Наталья",
|
||||||
|
patronymic: "Романовна",
|
||||||
|
birth_date: "1990-04-12",
|
||||||
|
photo: personImage,
|
||||||
|
contacts: [
|
||||||
|
{
|
||||||
|
value: "+7 (910) 424–13–13",
|
||||||
|
kind: "PHONE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "Haritonich@mail.ru",
|
||||||
|
kind: "EMAIL",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
status: "accepted",
|
||||||
|
medicalCard: {
|
||||||
|
status: "not_filled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "rr931000-7140-4977-bd09-1ac233b8b8e5",
|
||||||
|
start: "2023-09-18T15:00:00Z",
|
||||||
|
end: "2023-09-18T15:30:00Z",
|
||||||
|
employee: {
|
||||||
|
id: "666101e6-b4e6-46a4-8ef6-08ecb7721493",
|
||||||
|
last_name: "Петров",
|
||||||
|
first_name: "Леонид",
|
||||||
|
patronymic: "Семенович",
|
||||||
|
},
|
||||||
|
person: {
|
||||||
|
id: "d340d344-4fc7-4fbe-9db8-b7562b70438d",
|
||||||
|
last_name: "Гаранова",
|
||||||
|
first_name: "Наталья",
|
||||||
|
patronymic: "Романовна",
|
||||||
|
birth_date: "1990-04-12",
|
||||||
|
photo: personImage,
|
||||||
|
contacts: [
|
||||||
|
{
|
||||||
|
value: "+7 (910) 424–13–13",
|
||||||
|
kind: "PHONE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "Haritonich@mail.ru",
|
||||||
|
kind: "EMAIL",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
status: "accepted",
|
||||||
|
medicalCard: {
|
||||||
|
status: "not_filled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ma931000-7140-4977-bd09-1ac233b8b8e5",
|
||||||
|
start: "2023-09-18T15:00:00Z",
|
||||||
|
end: "2023-09-18T15:30:00Z",
|
||||||
|
employee: {
|
||||||
|
id: "999101e6-b4e6-46a4-8ef6-22ecb2921493",
|
||||||
|
last_name: "Ленин",
|
||||||
|
first_name: "Леонид",
|
||||||
|
patronymic: "Семенович",
|
||||||
|
},
|
||||||
|
person: {
|
||||||
|
id: "d340d344-4fc7-4fbe-9db8-b7562b70438d",
|
||||||
|
last_name: "Гаранова",
|
||||||
|
first_name: "Наталья",
|
||||||
|
patronymic: "Романовна",
|
||||||
|
birth_date: "1990-04-12",
|
||||||
|
photo: personImage,
|
||||||
|
contacts: [
|
||||||
|
{
|
||||||
|
value: "+7 (910) 424–13–13",
|
||||||
|
kind: "PHONE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "Haritonich@mail.ru",
|
||||||
|
kind: "EMAIL",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
status: "accepted",
|
||||||
|
medicalCard: {
|
||||||
|
status: "not_filled",
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const recordPreviewConfig = [
|
export const recordPreviewConfig = [
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ export function convertTime(str, startIndex, endIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function trimName(lastName, firstName, patronymic) {
|
export function trimName(lastName, firstName, patronymic) {
|
||||||
let checkedFirstName = firstName !== null ? firstName?.[0] + ". " : "";
|
let checkedFirstName = firstName ? firstName?.[0] + ". " : "";
|
||||||
let checkedPatronymic = patronymic !== null ? patronymic?.[0] + "." : "";
|
let checkedPatronymic = patronymic ? patronymic?.[0] + "." : "";
|
||||||
return `${lastName} ${checkedFirstName}${checkedPatronymic}`;
|
return `${lastName} ${checkedFirstName}${checkedPatronymic}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,3 +13,7 @@ export function verifyTime(dayTime) {
|
|||||||
let newTime = timeArray[1] >= 30 ? timeArray[0] + 1 : timeArray[0];
|
let newTime = timeArray[1] >= 30 ? timeArray[0] + 1 : timeArray[0];
|
||||||
return newTime;
|
return newTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function capitalizeFirstChar(str) {
|
||||||
|
return str[0]?.toUpperCase() + str?.slice(1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.w-full.h-full.flex.flex-col
|
.w-full.fit.row.no-wrap.justify-evenly
|
||||||
.flex.w-full.gap-x-2.pb-2
|
.col-grow.pr-2
|
||||||
medical-header(
|
medical-card-patient-form
|
||||||
v-model="currentMenuItem",
|
medical-base-info.mt-2
|
||||||
:change-shown-remove-modal="changeShownRemoveModal",
|
.h-full
|
||||||
)
|
the-right-menu
|
||||||
medical-records
|
|
||||||
component(
|
|
||||||
v-if="currentMenuItem",
|
|
||||||
v-bind:is="currentMenuItem",
|
|
||||||
)
|
|
||||||
base-modal(
|
|
||||||
v-model="isShownRemoveModal",
|
|
||||||
title="Удаление медкарты"
|
|
||||||
)
|
|
||||||
medical-remove-modal(:change-shown-remove-modal="changeShownRemoveModal")
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -24,6 +14,9 @@ import MedicalBaseInfo from "@/pages/newMedicalCard/components/MedicalBaseInfo.v
|
|||||||
import BaseModal from "@/components/base/BaseModal.vue";
|
import BaseModal from "@/components/base/BaseModal.vue";
|
||||||
import MedicalRemoveModal from "@/pages/newMedicalCard/components/MedicalRemoveModal.vue";
|
import MedicalRemoveModal from "@/pages/newMedicalCard/components/MedicalRemoveModal.vue";
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
|
import TheRightMenu from "@/components/TheRightMenu.vue";
|
||||||
|
import MedicalCardPatientForm from "@/pages/newMedicalCard/components/MedicalCardPatientForm.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TheMedicalCard",
|
name: "TheMedicalCard",
|
||||||
components: {
|
components: {
|
||||||
@@ -32,6 +25,8 @@ export default {
|
|||||||
MedicalBaseInfo,
|
MedicalBaseInfo,
|
||||||
BaseModal,
|
BaseModal,
|
||||||
MedicalRemoveModal,
|
MedicalRemoveModal,
|
||||||
|
TheRightMenu,
|
||||||
|
MedicalCardPatientForm,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -52,3 +47,5 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped></style>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
medical-form-wrapper(
|
medical-form-wrapper(
|
||||||
|
id="base"
|
||||||
title="Основные данные"
|
title="Основные данные"
|
||||||
:is-check-change="isCheckChange"
|
:is-check-change="isCheckChange"
|
||||||
:is-loading-data="isLoadingData"
|
:is-loading-data="isLoadingData"
|
||||||
@@ -8,12 +9,12 @@
|
|||||||
:cancel="cancelEdit"
|
:cancel="cancelEdit"
|
||||||
:open-edit="openEdit"
|
:open-edit="openEdit"
|
||||||
)
|
)
|
||||||
q-form.form-wrap.gap-24.w-full(ref="formBasicData")
|
q-form.form-wrap.gap-6.w-full(ref="formBasicData")
|
||||||
.flex.flex-col.gap-4(v-for="data in configData")
|
.flex.flex-col.gap-2(v-for="data in configData")
|
||||||
.font-semibold.text-sm.whitespace-nowrap {{data.dataLabel}}
|
.font-semibold.text-sm.whitespace-nowrap {{data.dataLabel}}
|
||||||
.flex.w-full.justify-between.items-center.gap-4(v-for="field in data.fields")
|
.flex.w-full.items-center.gap-4(v-for="field in data.fields")
|
||||||
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
||||||
.avatar-field.flex.gap-3.items-center(v-if="field.type === 'avatar'")
|
.flex.gap-3.items-center.h-10(v-if="field.type === 'avatar'")
|
||||||
base-avatar(:size="40")
|
base-avatar(:size="40")
|
||||||
img.avatar.object-cover(
|
img.avatar.object-cover(
|
||||||
v-if="basic[data.dataKey][field.key]?.photo"
|
v-if="basic[data.dataKey][field.key]?.photo"
|
||||||
@@ -37,15 +38,16 @@
|
|||||||
:standout="!isEdit"
|
:standout="!isEdit"
|
||||||
:items="genderOptions"
|
:items="genderOptions"
|
||||||
bg-color="#e9e9f6",
|
bg-color="#e9e9f6",
|
||||||
|
width="100%",
|
||||||
size="M"
|
size="M"
|
||||||
)
|
)
|
||||||
base-input-date(
|
base-input-date(
|
||||||
v-else-if="field.type === 'date'",
|
v-else-if="field.type === 'date'",
|
||||||
v-model="basic[data.dataKey][field.key]",
|
v-model="basic[data.dataKey][field.key]",
|
||||||
size="M",
|
size="M",
|
||||||
readonly
|
width="100%",
|
||||||
@update:model-value="checkChangeInput",
|
readonly,
|
||||||
:width="302"
|
@update:model-value="checkChangeInput"
|
||||||
)
|
)
|
||||||
base-input(
|
base-input(
|
||||||
v-else,
|
v-else,
|
||||||
@@ -54,9 +56,9 @@
|
|||||||
@update:model-value="checkChangeInput"
|
@update:model-value="checkChangeInput"
|
||||||
:type="field.type"
|
:type="field.type"
|
||||||
:name="field.key"
|
:name="field.key"
|
||||||
:width="302",
|
width="100%",
|
||||||
size="M",
|
size="M",
|
||||||
:rule="field.rules"
|
:rule="field.rules"
|
||||||
)
|
)
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -211,9 +213,7 @@ export default {
|
|||||||
|
|
||||||
<style lang="sass" scoped>
|
<style lang="sass" scoped>
|
||||||
.select
|
.select
|
||||||
width: 302px
|
width: 100%
|
||||||
.avatar-field
|
|
||||||
min-width: 302px
|
|
||||||
.avatar
|
.avatar
|
||||||
height: 100%
|
height: 100%
|
||||||
border-radius: 50%
|
border-radius: 50%
|
||||||
@@ -223,12 +223,10 @@ export default {
|
|||||||
display: grid
|
display: grid
|
||||||
grid-template-columns: repeat(3, 1fr)
|
grid-template-columns: repeat(3, 1fr)
|
||||||
grid-template-rows: repeat(1, 1fr)
|
grid-template-rows: repeat(1, 1fr)
|
||||||
@media(max-width: 1900px)
|
@media(max-width: 1440px)
|
||||||
grid-template-columns: repeat(2, 1fr)
|
grid-template-columns: repeat(2, 1fr)
|
||||||
grid-template-rows: repeat(2, 1fr)
|
grid-template-rows: repeat(2, 1fr)
|
||||||
@media(max-width: 1320px)
|
|
||||||
grid-template-columns: repeat(1, 1fr)
|
|
||||||
grid-template-rows: repeat(3, 1fr)
|
|
||||||
.label-field
|
.label-field
|
||||||
|
min-width: 110px
|
||||||
color: var(--font-grey-color)
|
color: var(--font-grey-color)
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
medical-form-wrapper(
|
medical-form-wrapper(
|
||||||
|
id="contacts"
|
||||||
title="Контакты"
|
title="Контакты"
|
||||||
:is-check-change="isCheckChange"
|
:is-check-change="isCheckChange"
|
||||||
:is-loading-data="isLoadingData"
|
:is-loading-data="isLoadingData"
|
||||||
:is-edit="isEdit"
|
:is-edit="isEdit"
|
||||||
:save="saveChange"
|
:save="saveChange"
|
||||||
:cancel="cancelEdit"
|
:cancel="cancelEdit"
|
||||||
:open-edit="openEdit"
|
:open-edit="openEdit"
|
||||||
)
|
)
|
||||||
q-form.form-wrap.gap-24.w-full(ref="formContacts")
|
q-form.form-wrap.gap-6.w-full(ref="formContacts")
|
||||||
.flex.flex-col.gap-4(v-for="(contact, key) in contacts")
|
.flex.flex-col.gap-2(v-for="(contact, key) in contacts")
|
||||||
.font-semibold.text-sm.whitespace-nowrap {{configData[key].title}}
|
.font-semibold.text-sm.whitespace-nowrap {{configData[key].title}}
|
||||||
.flex.w-full.justify-between.items-center.gap-4(v-for="(data, index) in contact")
|
.flex.w-full.items-center.gap-4(v-for="(data, index) in contact")
|
||||||
.label-field.font-sm.text-sm.whitespace-nowrap {{`${configData[key].fieldName} ${index+1} :`}}
|
.label-field.font-sm.text-sm.whitespace-nowrap {{`${configData[key].fieldName} ${index+1} :`}}
|
||||||
.input-wrapper.items-center.flex.h-10.gap-10px
|
.w-full.items-center.flex.h-10
|
||||||
.flex(v-if="key === 'networks'")
|
.flex.w-full(v-if="key === 'networks'")
|
||||||
.flex.rounded-full.cursor-pointer.items-center.gap-10px.py-1.pl-1.pr-2(
|
.flex.rounded-full.cursor-pointer.items-center.gap-10px.py-1.pl-1.pr-2(
|
||||||
v-if="data.id || data.filled"
|
v-if="data.id || data.filled"
|
||||||
@click="() => copyLinkNetwork(data.value)"
|
@click="() => copyLinkNetwork(data.value)"
|
||||||
style="background-color: var(--bg-light-grey)"
|
style="background-color: var(--bg-light-grey)"
|
||||||
)
|
)
|
||||||
q-icon.icon(:name="mapNetworks[data.category].icon" :class="{old: data.id, new: data.filled}")
|
q-icon.icon(:name="mapNetworks[data.category].icon" :class="{old: data.id, new: data.filled}")
|
||||||
span.text-sm.font-medium {{ mapNetworks[data.category].title || data.value }}
|
span.text-sm.font-medium {{ mapNetworks[data.category].title || data.value }}
|
||||||
.flex.gap-10px(v-else v-click-outside="() => checkNetworksField(index)" :key="key+index")
|
.flex.gap-10px.w-full(v-else v-click-outside="() => checkNetworksField(index)" :key="key+index")
|
||||||
base-select-networks(
|
base-select-networks(
|
||||||
:list-data="Object.values(mapNetworks)"
|
:list-data="Object.values(mapNetworks)"
|
||||||
:option-data="data.category"
|
:option-data="data.category"
|
||||||
@@ -30,13 +31,14 @@
|
|||||||
:style-border="true"
|
:style-border="true"
|
||||||
:size-input="50"
|
:size-input="50"
|
||||||
)
|
)
|
||||||
base-input.w-full(
|
base-input(
|
||||||
v-model="data.value",
|
v-model="data.value",
|
||||||
:name="key",
|
:name="key",
|
||||||
:rule="configData[key].rules",
|
:rule="configData[key].rules",
|
||||||
size="M"
|
size="M",
|
||||||
|
width="100%"
|
||||||
)
|
)
|
||||||
base-input.w-full(
|
base-input(
|
||||||
v-else,
|
v-else,
|
||||||
:readonly="!isEdit",
|
:readonly="!isEdit",
|
||||||
v-model="data.value",
|
v-model="data.value",
|
||||||
@@ -44,23 +46,25 @@
|
|||||||
:mask="configData[key].inputMask",
|
:mask="configData[key].inputMask",
|
||||||
:rule="configData[key].rules",
|
:rule="configData[key].rules",
|
||||||
@update:model-value="checkChangeInput",
|
@update:model-value="checkChangeInput",
|
||||||
size="M"
|
size="M",
|
||||||
|
width="100%"
|
||||||
)
|
)
|
||||||
.delete-contact.icon-cancel.text-xxs.cursor-pointer(
|
q-icon.delete-icon.ml-2.cursor-pointer(
|
||||||
v-if="isEdit"
|
v-if="isEdit"
|
||||||
@click="() => deleteContact(key, index)"
|
@click="() => deleteContact(key, index)"
|
||||||
)
|
name="app:cancel-mini",
|
||||||
|
size="24px"
|
||||||
|
)
|
||||||
q-btn.ml-2px(
|
q-btn.ml-2px(
|
||||||
v-if="isEdit",
|
v-if="isEdit",
|
||||||
color="primary",
|
color="primary",
|
||||||
flat,
|
flat,
|
||||||
:style="{'font-weight': 500, width: '104px', height: '24px'}",
|
:style="{'font-weight': 500, width: '76px', height: '40px'}",
|
||||||
no-caps,
|
no-caps,
|
||||||
padding="0",
|
padding="0",
|
||||||
@click="(e) => addNewContact(e, key)"
|
@click="(e) => addNewContact(e, key)"
|
||||||
|
label="Добавить"
|
||||||
)
|
)
|
||||||
q-icon(name="app:icon-plus", size="12px", left)
|
|
||||||
span Добавить
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -218,24 +222,20 @@ export default {
|
|||||||
color: var(--btn-blue-color)
|
color: var(--btn-blue-color)
|
||||||
&.new
|
&.new
|
||||||
color: var(--icon-violet-color)
|
color: var(--icon-violet-color)
|
||||||
.input-wrapper
|
|
||||||
width: 302px
|
|
||||||
.form-wrap
|
.form-wrap
|
||||||
display: grid
|
display: grid
|
||||||
grid-template-columns: repeat(3, 1fr)
|
grid-template-columns: repeat(3, 1fr)
|
||||||
grid-template-rows: repeat(1, auto)
|
grid-template-rows: repeat(1, 1fr)
|
||||||
@media(max-width: 1900px)
|
@media(max-width: 1440px)
|
||||||
grid-template-columns: repeat(2, 1fr)
|
grid-template-columns: repeat(2, 1fr)
|
||||||
grid-template-rows: repeat(2, auto)
|
grid-template-rows: repeat(2, 1fr)
|
||||||
@media(max-width: 1320px)
|
|
||||||
grid-template-columns: repeat(1, 1fr)
|
|
||||||
grid-template-rows: repeat(3, auto)
|
|
||||||
.network-field
|
.network-field
|
||||||
background-color: var(--bg-light-grey)
|
background-color: var(--bg-light-grey)
|
||||||
.label-field
|
.label-field
|
||||||
|
min-width: 110px
|
||||||
color: var(--font-grey-color)
|
color: var(--font-grey-color)
|
||||||
.delete-contact
|
.delete-icon :deep(path)
|
||||||
color: var(--font-grey-color)
|
fill: var(--font-grey-color)
|
||||||
.on-left
|
.on-left
|
||||||
margin-right: 10px
|
margin-right: 10px
|
||||||
.q-btn :deep(.q-ripple)
|
.q-btn :deep(.q-ripple)
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
medical-form-wrapper(
|
medical-form-wrapper(
|
||||||
|
id="documents",
|
||||||
title="Документы",
|
title="Документы",
|
||||||
:is-check-change="isCheckChange",
|
:is-check-change="isCheckChange",
|
||||||
:is-edit="isEdit",
|
:is-edit="isEdit",
|
||||||
:cancel="cancelEdit",
|
:cancel="cancelEdit",
|
||||||
:open-edit="openEdit",
|
:open-edit="openEdit",
|
||||||
:save="saveChange"
|
:save="saveChange"
|
||||||
)
|
)
|
||||||
q-form.form-wrap.gap-24.w-full(ref="documentForm", :no-error-focus="true")
|
q-form.form-wrap.gap-x-6.w-full(ref="documentForm", :no-error-focus="true")
|
||||||
.data-section.flex.flex-col.gap-4(v-for="data in configData", :key="data.dataLabel")
|
.data-section.flex.flex-col.gap-2(
|
||||||
|
v-for="data in configData",
|
||||||
|
:key="data.dataLabel",
|
||||||
|
:class="data?.dataClass"
|
||||||
|
)
|
||||||
.font-semibold.text-sm.whitespace-nowrap {{data.dataLabel}}
|
.font-semibold.text-sm.whitespace-nowrap {{data.dataLabel}}
|
||||||
.flex.w-full.justify-between.items-center.gap-4(
|
.flex.w-full.items-center.gap-4(
|
||||||
v-for="field in data.fields",
|
v-for="field in data.fields",
|
||||||
:key="field.label"
|
:key="field.label"
|
||||||
)
|
)
|
||||||
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
||||||
.photo-field.flex.gap-3.items-center(v-if="field.type === 'photo'")
|
.flex.gap-3.items-center.h-10(v-if="field.type === 'photo'")
|
||||||
q-avatar(
|
q-avatar(
|
||||||
rounded,
|
rounded,
|
||||||
size="40px",
|
size="40px",
|
||||||
@@ -48,7 +53,7 @@
|
|||||||
:name="data.dataKey + ':' + field.key",
|
:name="data.dataKey + ':' + field.key",
|
||||||
@update:model-value="checkChangeDocData",
|
@update:model-value="checkChangeDocData",
|
||||||
:readonly="!isEdit",
|
:readonly="!isEdit",
|
||||||
:width="302",
|
width="100%",
|
||||||
:mask="field?.inputMask",
|
:mask="field?.inputMask",
|
||||||
:rule="(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val)",
|
:rule="(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val)",
|
||||||
size="M",
|
size="M",
|
||||||
@@ -60,12 +65,14 @@
|
|||||||
@update:model-value="checkChangeDocData",
|
@update:model-value="checkChangeDocData",
|
||||||
:readonly="!isEdit",
|
:readonly="!isEdit",
|
||||||
:type="field.type",
|
:type="field.type",
|
||||||
:width="302",
|
width="100%",
|
||||||
:mask="field?.inputMask",
|
:mask="field?.inputMask",
|
||||||
:rule="[(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val, initialDocData?.[data.dataKey]?.id)]",
|
:rule="[(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val, initialDocData?.[data.dataKey]?.id)]",
|
||||||
size="M"
|
size="M"
|
||||||
)
|
)
|
||||||
.icon-copy.my-auto.text-lg.label-field.cursor-pointer(
|
q-icon.my-auto.cursor-pointer.copy(
|
||||||
|
size="20px",
|
||||||
|
name="app:copy",
|
||||||
v-if="checkCopiedFields(field.key) && !!docData[data.dataKey][field.key]",
|
v-if="checkCopiedFields(field.key) && !!docData[data.dataKey][field.key]",
|
||||||
@click="copyValue(docData[data.dataKey][field.key])"
|
@click="copyValue(docData[data.dataKey][field.key])"
|
||||||
)
|
)
|
||||||
@@ -148,7 +155,12 @@ export default {
|
|||||||
return this.$store.state.medical.documents;
|
return this.$store.state.medical.documents;
|
||||||
},
|
},
|
||||||
passportFields() {
|
passportFields() {
|
||||||
let excludedFields = ["attachments", "id", "category"];
|
let excludedFields = [
|
||||||
|
"attachments",
|
||||||
|
"id",
|
||||||
|
"category",
|
||||||
|
"issued_by_org_code",
|
||||||
|
];
|
||||||
return Object.keys(this.docData.passport).filter(
|
return Object.keys(this.docData.passport).filter(
|
||||||
(key) => !excludedFields.includes(key)
|
(key) => !excludedFields.includes(key)
|
||||||
);
|
);
|
||||||
@@ -308,14 +320,13 @@ export default {
|
|||||||
.form-wrap
|
.form-wrap
|
||||||
display: grid
|
display: grid
|
||||||
grid-template-columns: repeat(3, 1fr)
|
grid-template-columns: repeat(3, 1fr)
|
||||||
grid-template-rows: repeat(1, 1fr)
|
row-gap: 32px
|
||||||
@media(max-width: 1900px)
|
grid-template-rows: 1.2fr 1.8fr
|
||||||
|
@media(max-width: 1440px)
|
||||||
grid-template-columns: repeat(2, 1fr)
|
grid-template-columns: repeat(2, 1fr)
|
||||||
grid-template-rows: 2.5fr 0.5fr
|
grid-template-rows: 1.2fr 1.8fr
|
||||||
@media(max-width: 1320px)
|
|
||||||
grid-template-columns: repeat(1, 1fr)
|
|
||||||
grid-template-rows: 2.5fr 0.5fr 0.5fr
|
|
||||||
.label-field
|
.label-field
|
||||||
|
min-width: 110px
|
||||||
color: var(--font-grey-color)
|
color: var(--font-grey-color)
|
||||||
.replace-photo
|
.replace-photo
|
||||||
color: var(--btn-blue-color)
|
color: var(--btn-blue-color)
|
||||||
@@ -332,4 +343,15 @@ export default {
|
|||||||
background-color: var(--btn-red-color)
|
background-color: var(--btn-red-color)
|
||||||
.cancel-icon :deep(path)
|
.cancel-icon :deep(path)
|
||||||
fill: white
|
fill: white
|
||||||
|
.copy :deep(path)
|
||||||
|
fill: var(--font-grey-color)
|
||||||
|
.passport
|
||||||
|
grid-column: 1 / 2
|
||||||
|
grid-row: 1 / 3
|
||||||
|
.insurance
|
||||||
|
grid-column: 2 / 3
|
||||||
|
grid-row: 1 / 2
|
||||||
|
.tax
|
||||||
|
grid-column: 2 / 3
|
||||||
|
grid-row: 2 / 3
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
medical-form-wrapper(
|
medical-form-wrapper(
|
||||||
|
id="insurance",
|
||||||
title="Страховка",
|
title="Страховка",
|
||||||
:is-loading-data="isLoadingData",
|
:is-loading-data="isLoadingData",
|
||||||
:is-check-change="isCheckChange",
|
:is-check-change="isCheckChange",
|
||||||
@@ -8,18 +9,17 @@
|
|||||||
:save="saveChange",
|
:save="saveChange",
|
||||||
:cancel="cancelEdit"
|
:cancel="cancelEdit"
|
||||||
)
|
)
|
||||||
q-form.form-wrap.gap-24.w-full(ref="insuranceForm", :no-error-focus="true")
|
q-form.form-wrap.gap-6.w-full(ref="insuranceForm", :no-error-focus="true")
|
||||||
.flex.flex-col.gap-4(v-for="insurance in insuranceConfig", :key="insurance.insuranceKey")
|
.flex.flex-col.gap-2(v-for="insurance in insuranceConfig", :key="insurance.insuranceKey")
|
||||||
.font-semibold.text-sm.whitespace-nowrap {{insurance.insuranceLabel}}
|
.font-semibold.text-sm.whitespace-nowrap {{insurance.insuranceLabel}}
|
||||||
.flex.w-full.justify-between.items-center.gap-4(
|
.flex.w-full.items-center.gap-4(
|
||||||
v-for="field in insurance.fields",
|
v-for="field in insurance.fields",
|
||||||
:key="insurance.insuranceKey + field.key",
|
:key="insurance.insuranceKey + field.key",
|
||||||
:style="{marginTop: field.label === 'Документы' ? '20px' : null}"
|
:style="{marginTop: field.label === 'Документы' ? '20px' : null}"
|
||||||
)
|
)
|
||||||
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
||||||
.flex.gap-3.items-center.h-10.w-10(
|
.flex.gap-3.items-center.h-10(
|
||||||
v-if="field.type === 'photo'",
|
v-if="field.type === 'photo'",
|
||||||
:style="{'min-width': field.label === 'Документы' ? '324px' : '302px'}"
|
|
||||||
)
|
)
|
||||||
.flex.w-10.h-10.relative(v-if="insuranceData[insurance.insuranceKey]?.attachments?.photo")
|
.flex.w-10.h-10.relative(v-if="insuranceData[insurance.insuranceKey]?.attachments?.photo")
|
||||||
img.rounded.avatar.object-cover(
|
img.rounded.avatar.object-cover(
|
||||||
@@ -46,14 +46,14 @@
|
|||||||
base-upload-photo(
|
base-upload-photo(
|
||||||
:key="insurance.insuranceKey"
|
:key="insurance.insuranceKey"
|
||||||
v-model="insuranceData[photoId][field.key]"
|
v-model="insuranceData[photoId][field.key]"
|
||||||
:confirm-upload="confirmChangePhoto"
|
:confirm-upload="confirmChangePhoto"
|
||||||
)
|
)
|
||||||
.category.flex.h-10.relative.gap-x-2(v-else-if="field.type === 'select'")
|
.flex.h-10.relative.gap-x-2.w-full(v-else-if="field.type === 'select'")
|
||||||
.category-select.flex.items-center.change.px-4.rounded {{selectCategory(basic[insurance.insuranceKey][field.key])}}
|
.w-full.flex.items-center.change.px-4.rounded {{selectCategory(basic[insurance.insuranceKey][field.key])}}
|
||||||
q-btn.change.flex.w-7.h-9.rounded-md(
|
q-btn.change.flex.w-7.h-9.rounded-md(
|
||||||
v-if="isEdit",
|
v-if="isEdit",
|
||||||
@click="openModalCategories",
|
@click="openModalCategories",
|
||||||
dense,
|
dense,
|
||||||
padding="8px"
|
padding="8px"
|
||||||
)
|
)
|
||||||
q-icon.icon(name="app:folder", size="24px")
|
q-icon.icon(name="app:folder", size="24px")
|
||||||
@@ -75,21 +75,22 @@
|
|||||||
v-if="basic?.benefit[insurance?.discount]",
|
v-if="basic?.benefit[insurance?.discount]",
|
||||||
:style="{color: 'var(--font-grey-color)'}"
|
:style="{color: 'var(--font-grey-color)'}"
|
||||||
)
|
)
|
||||||
span Процент скидки:
|
span Процент скидки:
|
||||||
span(
|
span(
|
||||||
:style="{color: 'var(--font-dark-blue-color)'}"
|
:style="{color: 'var(--font-dark-blue-color)'}"
|
||||||
) {{"\xa0" + basic?.benefit[insurance?.discount] + "%"}}
|
) {{"\xa0" + basic?.benefit[insurance?.discount] + "%"}}
|
||||||
.input-container.flex.flex-col.relative(v-else)
|
.w-full.flex.flex-col.relative(v-else)
|
||||||
base-input(
|
base-input(
|
||||||
v-model="insuranceData[insurance.insuranceKey][field.key]",
|
v-model="insuranceData[insurance.insuranceKey][field.key]",
|
||||||
@update:model-value="checkChangeInput",
|
@update:model-value="checkChangeInput",
|
||||||
:readonly="!isEdit",
|
:readonly="!isEdit",
|
||||||
size="M",
|
size="M",
|
||||||
|
width="100%",
|
||||||
:name="insurance.insuranceKey + ':' + field.key",
|
:name="insurance.insuranceKey + ':' + field.key",
|
||||||
:rule="[(val) => checkFields(val, insurance.insuranceKey, field.rules)]"
|
:rule="[(val) => checkFields(val, insurance.insuranceKey, field.rules)]"
|
||||||
)
|
)
|
||||||
q-icon.my-auto.text-lg.label-field.cursor-pointer.copy(
|
q-icon.my-auto.cursor-pointer.copy(
|
||||||
size="18px",
|
size="20px",
|
||||||
name="app:copy",
|
name="app:copy",
|
||||||
v-if="checkCopiedFields(field.key, insuranceData[insurance.insuranceKey])",
|
v-if="checkCopiedFields(field.key, insuranceData[insurance.insuranceKey])",
|
||||||
@click="copyValue(insuranceData[insurance.insuranceKey][field.key])"
|
@click="copyValue(insuranceData[insurance.insuranceKey][field.key])"
|
||||||
@@ -354,9 +355,6 @@ export default {
|
|||||||
.avatar
|
.avatar
|
||||||
height: 100%
|
height: 100%
|
||||||
|
|
||||||
.input-container
|
|
||||||
width: 302px
|
|
||||||
|
|
||||||
.replace-photo
|
.replace-photo
|
||||||
color: var(--btn-blue-color)
|
color: var(--btn-blue-color)
|
||||||
|
|
||||||
@@ -364,14 +362,12 @@ export default {
|
|||||||
display: grid
|
display: grid
|
||||||
grid-template-columns: repeat(3, 1fr)
|
grid-template-columns: repeat(3, 1fr)
|
||||||
grid-template-rows: repeat(1, 1fr)
|
grid-template-rows: repeat(1, 1fr)
|
||||||
@media(max-width: 1900px)
|
@media(max-width: 1440px)
|
||||||
grid-template-columns: repeat(2, 1fr)
|
grid-template-columns: repeat(2, 1fr)
|
||||||
grid-template-rows: repeat(2, 1fr)
|
grid-template-rows: 1.2fr 0.8fr
|
||||||
@media(max-width: 1320px)
|
|
||||||
grid-template-columns: repeat(1, 1fr)
|
|
||||||
grid-template-rows: repeat(3, 1fr)
|
|
||||||
|
|
||||||
.label-field
|
.label-field
|
||||||
|
min-width: 110px
|
||||||
color: var(--font-grey-color)
|
color: var(--font-grey-color)
|
||||||
|
|
||||||
.q-badge
|
.q-badge
|
||||||
@@ -381,12 +377,6 @@ export default {
|
|||||||
.delete
|
.delete
|
||||||
background-color: var(--btn-red-color)
|
background-color: var(--btn-red-color)
|
||||||
|
|
||||||
.category
|
|
||||||
width: 324px
|
|
||||||
|
|
||||||
.category-select
|
|
||||||
min-width: 276px
|
|
||||||
|
|
||||||
.icon :deep(path)
|
.icon :deep(path)
|
||||||
fill: var(--font-grey-color)
|
fill: var(--font-grey-color)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.base-info-wrapper.w-full.flex.gap-x-2.flex-1.font-medium.text-m
|
.base-info-wrapper.w-full.flex.gap-x-2.flex-1.font-medium.text-m
|
||||||
medical-sidebar(v-model="currentMenuItem")
|
//- medical-sidebar(v-model="currentMenuItem")
|
||||||
component(
|
component(
|
||||||
v-if="currentMenuItem",
|
v-if="currentMenuItem",
|
||||||
v-bind="{...componentProps, updateCurrentItem:updateCurrentItem, clearProps:clearProps}"
|
v-bind="{...componentProps, updateCurrentItem:updateCurrentItem, clearProps:clearProps}"
|
||||||
|
|||||||
@@ -25,6 +25,4 @@ export default {
|
|||||||
min-height: 350px
|
min-height: 350px
|
||||||
@media (max-width: 600px)
|
@media (max-width: 600px)
|
||||||
width: fit-content
|
width: fit-content
|
||||||
&::-webkit-scrollbar
|
|
||||||
width: 0
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
206
src/pages/newMedicalCard/components/MedicalCardPatientForm.vue
Normal file
206
src/pages/newMedicalCard/components/MedicalCardPatientForm.vue
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.patient-info.pt-4.pr-6.flex.flex-col.justify-between.rounded.font-medium.text-m
|
||||||
|
.ml-6.flex.justify-between
|
||||||
|
//- TODO по клику переход на предыдущую страницу
|
||||||
|
q-breadcrumbs
|
||||||
|
template(v-slot:separator)
|
||||||
|
q-icon.rotate(
|
||||||
|
size="16px",
|
||||||
|
name="app:long-arrow",
|
||||||
|
color="grey",
|
||||||
|
)
|
||||||
|
q-breadcrumbs-el(:label="routes[routingHistory.state.back]")
|
||||||
|
q-breadcrumbs-el(:label="`Медкарта #${medicalCardData?.number}`")
|
||||||
|
|
||||||
|
q-btn(
|
||||||
|
@click="toggleEditMode",
|
||||||
|
:style="{backgroundColor: 'var(--bg-light-grey)', color: 'blue'}",
|
||||||
|
padding="10px",
|
||||||
|
)
|
||||||
|
q-icon(
|
||||||
|
name="edit",
|
||||||
|
size="20px",
|
||||||
|
)
|
||||||
|
.ml-6.flex.gap-x-4
|
||||||
|
q-avatar(size="80px", :style="{'background-color': 'var(--border-light-grey-color)', color: 'var(--font-dark-blue-color)'}")
|
||||||
|
img(v-if="patientData?.photo", :src="url + patientData?.photo")
|
||||||
|
span.text-2xl(v-else) {{patientAvatar}}
|
||||||
|
|
||||||
|
template(v-if="!editMode")
|
||||||
|
.flex.gap-y-1.flex-col
|
||||||
|
.flex.items-center
|
||||||
|
span.text-xxl.font-bold.mr-3(
|
||||||
|
:style="{color: 'var(--font-dark-blue-color)', 'line-height': '135%'}",
|
||||||
|
) {{patientName}}
|
||||||
|
|
||||||
|
|
||||||
|
span.text-smm.label-color Добавлен в систему:
|
||||||
|
span.date-color {{ patientData?.gender }}
|
||||||
|
span.date-color {{ patientData?.birth_date }}
|
||||||
|
span.text-smm.label-color Спец отметки:
|
||||||
|
|
||||||
|
template(v-else)
|
||||||
|
base-input(
|
||||||
|
v-model="fullname"
|
||||||
|
size="M",
|
||||||
|
label="Фамилия"
|
||||||
|
)
|
||||||
|
base-input(
|
||||||
|
v-model="fullname"
|
||||||
|
size="M",
|
||||||
|
label="Имя"
|
||||||
|
)
|
||||||
|
base-input(
|
||||||
|
v-model="fullname"
|
||||||
|
size="M",
|
||||||
|
label="Отчество"
|
||||||
|
)
|
||||||
|
|
||||||
|
.flex.justify-between.pt-4
|
||||||
|
.flex
|
||||||
|
.menu-item.px-6.py-10px.cursor-pointer.text-base.whitespace-nowrap(
|
||||||
|
v-for="item in menuItem",
|
||||||
|
@click="selectItem(item)",
|
||||||
|
:class="{'menu-item-active': item.component === modelValue}",
|
||||||
|
:key="item.id",
|
||||||
|
:id="item.id"
|
||||||
|
) {{item.title}}
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BaseInput from "@/components/base/BaseInput.vue";
|
||||||
|
import { v_model } from "@/shared/mixins/v-model";
|
||||||
|
import { column } from "@/pages/clients/utils/tableConfig.js";
|
||||||
|
import * as moment from "moment/moment";
|
||||||
|
import {
|
||||||
|
headerMenuItem,
|
||||||
|
routesDictionary,
|
||||||
|
} from "@/pages/newMedicalCard/utils/medicalConfig.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MedicalCardPatientForm",
|
||||||
|
mixins: [v_model],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
menuItem: headerMenuItem,
|
||||||
|
routes: routesDictionary,
|
||||||
|
editMode: true,
|
||||||
|
fullname: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
BaseInput,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
routingHistory() {
|
||||||
|
return this.$store.state.routingHistory;
|
||||||
|
},
|
||||||
|
url() {
|
||||||
|
return this.$store.state.url;
|
||||||
|
},
|
||||||
|
medicalCardData() {
|
||||||
|
return this.$store.state.medical.medicalCard;
|
||||||
|
},
|
||||||
|
patientData() {
|
||||||
|
return this.medicalCardData?.person;
|
||||||
|
},
|
||||||
|
patientName() {
|
||||||
|
let name = {
|
||||||
|
lastName: this.ckeckName("last_name"),
|
||||||
|
firstName: this.ckeckName("first_name"),
|
||||||
|
patronymic: this.ckeckName("patronymic"),
|
||||||
|
};
|
||||||
|
return `${name.lastName} ${name.firstName} ${name.patronymic}`;
|
||||||
|
},
|
||||||
|
patientAvatar() {
|
||||||
|
let checkedFirstName =
|
||||||
|
this.patientData?.first_name !== null
|
||||||
|
? this.patientData?.first_name[0]
|
||||||
|
: this.patientData?.last_name[1];
|
||||||
|
return `${this.patientData?.last_name[0]}${checkedFirstName}`;
|
||||||
|
},
|
||||||
|
priority() {
|
||||||
|
return column
|
||||||
|
.find((elem) => elem.name === "priority")
|
||||||
|
?.settings.find((elem) => elem.priority === this.patientData?.priority);
|
||||||
|
},
|
||||||
|
createdDate() {
|
||||||
|
return this.checkDate("created_at");
|
||||||
|
},
|
||||||
|
updatedDate() {
|
||||||
|
return this.checkDate("updated_at");
|
||||||
|
},
|
||||||
|
allergiesList() {
|
||||||
|
return this.patientData?.allergic?.map((elem) => ({
|
||||||
|
name: elem?.name,
|
||||||
|
title: elem?.title,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectItem(item) {
|
||||||
|
this.value = item?.component;
|
||||||
|
},
|
||||||
|
ckeckName(field) {
|
||||||
|
return this.patientData?.[field] ? this.patientData[field] : "";
|
||||||
|
},
|
||||||
|
checkDate(field) {
|
||||||
|
return this.medicalCardData?.[field]
|
||||||
|
? moment.parseZone(this.medicalCardData?.[field]).format("DD.MM.YYYY")
|
||||||
|
: "";
|
||||||
|
},
|
||||||
|
toggleEditMode() {
|
||||||
|
this.editMode = !this.editMode;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="sass">
|
||||||
|
.patient-info
|
||||||
|
background-color: var(--default-white)
|
||||||
|
min-height: 190px
|
||||||
|
.menu-item
|
||||||
|
color: var(--font-grey-color)
|
||||||
|
border-bottom: 1px solid transparent
|
||||||
|
.menu-item:first-child
|
||||||
|
border-bottom-left-radius: 4px
|
||||||
|
.menu-item-active
|
||||||
|
color: var(--font-dark-blue-color)
|
||||||
|
border-bottom: 1px solid var(--font-dark-blue-color)
|
||||||
|
.q-btn
|
||||||
|
font-weight: 500 !important
|
||||||
|
.q-btn :deep(.on-left)
|
||||||
|
margin-right: 4px !important
|
||||||
|
.q-btn :deep(.q-btn-dropdown__arrow)
|
||||||
|
margin-left: 0px !important
|
||||||
|
opacity: 0.7
|
||||||
|
.text-grey
|
||||||
|
color: var(--font-grey-color) !important
|
||||||
|
.q-breadcrumbs__el
|
||||||
|
font-size: 12px
|
||||||
|
line-height: 135%
|
||||||
|
color: var(--font-grey-color)
|
||||||
|
.q-breadcrumbs :deep(.q-breadcrumbs__separator)
|
||||||
|
margin: 10px 0 4px 8px !important
|
||||||
|
.label-color
|
||||||
|
color: var(--font-grey-color)
|
||||||
|
.date-color
|
||||||
|
color: var(--font-dark-blue-color)
|
||||||
|
.allergies-list
|
||||||
|
max-height: 190px
|
||||||
|
overflow-y: auto
|
||||||
|
&::-webkit-scrollbar
|
||||||
|
width: 4px
|
||||||
|
background-color: var(--default-white)
|
||||||
|
&::-webkit-scrollbar-track
|
||||||
|
margin: 0
|
||||||
|
.allergies-item
|
||||||
|
color: var(--font-dark-blue-color)
|
||||||
|
.allergies-item:hover
|
||||||
|
background-color: var(--bg-light-grey)
|
||||||
|
.icon-eye
|
||||||
|
display: block
|
||||||
|
.icon-eye
|
||||||
|
display: none
|
||||||
|
</style>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
name="app:edit",
|
name="app:edit",
|
||||||
v-if="!isEdit && !noEditBtn",
|
v-if="!isEdit && !noEditBtn",
|
||||||
@click="openEdit",
|
@click="openEdit",
|
||||||
size="20px"
|
size="20px",
|
||||||
)
|
)
|
||||||
.flex.w-full.gap-11px.items-center.justify-between(v-else)
|
.flex.w-full.gap-11px.items-center.justify-between(v-else)
|
||||||
span.font-bold.text-base.whitespace-nowrap {{title}}
|
span.font-bold.text-base.whitespace-nowrap {{title}}
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
q-icon.sample.mr-2(name="app:sample", size="20px")
|
q-icon.sample.mr-2(name="app:sample", size="20px")
|
||||||
span.text-smm.font-medium Шаблоны
|
span.text-smm.font-medium Шаблоны
|
||||||
.flex.w-fit.gap-10px.items-center.delete-button.cursor-pointer(
|
.flex.w-fit.gap-10px.items-center.delete-button.cursor-pointer(
|
||||||
v-if="!isEdit && titleDelete && deleteItem",
|
v-if="!isEdit && titleDelete && deleteItem",
|
||||||
@click="deleteItem"
|
@click="deleteItem"
|
||||||
)
|
)
|
||||||
q-icon(name="app:basket" size="20px")
|
q-icon(name="app:basket" size="20px")
|
||||||
@@ -113,6 +113,8 @@ export default {
|
|||||||
.form-wrapper
|
.form-wrapper
|
||||||
background-color: var(--default-white)
|
background-color: var(--default-white)
|
||||||
.edit-button
|
.edit-button
|
||||||
|
& > :deep(svg > path)
|
||||||
|
stroke: var(--btn-blue-color)
|
||||||
color: var(--btn-blue-color)
|
color: var(--btn-blue-color)
|
||||||
&:hover
|
&:hover
|
||||||
color: var(--btn-blue-color-hover)
|
color: var(--btn-blue-color-hover)
|
||||||
|
|||||||
@@ -167,10 +167,9 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<style scoped lang="sass">
|
<style scoped lang="sass">
|
||||||
.patient-info
|
.patient-info
|
||||||
width: 83.2%
|
|
||||||
height: 18.7%
|
|
||||||
background-color: var(--default-white)
|
background-color: var(--default-white)
|
||||||
min-width: 1050px
|
|
||||||
min-height: 190px
|
min-height: 190px
|
||||||
.menu-item
|
.menu-item
|
||||||
color: var(--font-grey-color)
|
color: var(--font-grey-color)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.sidebar-wrapper.h-full.rounded.px-2.py-6.flex.flex-col
|
.sidebar-wrapper.h-full.rounded.px-2.py-6.flex.flex-col.gap-1
|
||||||
.menu-item.text-base.px-4.py-3.rounded.cursor-pointer.whitespace-nowrap(
|
.menu-item.text-base.px-4.py-3.rounded.cursor-pointer.whitespace-nowrap(
|
||||||
v-for="item in menuItem",
|
v-for="item in menuItem",
|
||||||
:key="item.id",
|
:key="item.id",
|
||||||
:id="item.id",
|
:id="item.id",
|
||||||
@click="selectItem(item)",
|
@click="selectItem(item)",
|
||||||
|
:title="item.hint || item.title"
|
||||||
:class="{'menu-item-active': item.component === modelValue}"
|
:class="{'menu-item-active': item.component === modelValue}"
|
||||||
) {{item.title}}
|
) {{item.title}}
|
||||||
</template>
|
</template>
|
||||||
@@ -32,7 +33,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="sass" scoped>
|
<style lang="sass" scoped>
|
||||||
.sidebar-wrapper
|
.sidebar-wrapper
|
||||||
min-width: 300px
|
min-width: 200px
|
||||||
min-height: 350px
|
min-height: 350px
|
||||||
background-color: var(--default-white)
|
background-color: var(--default-white)
|
||||||
.menu-item
|
.menu-item
|
||||||
|
|||||||
@@ -345,7 +345,8 @@ export const baseInfoMenu = [
|
|||||||
component: "MedicalBasicDataWrapper",
|
component: "MedicalBasicDataWrapper",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Протоколы первичного осмотра",
|
title: "ППО",
|
||||||
|
hint: "Протоколы первичного осмотра",
|
||||||
id: "protocols",
|
id: "protocols",
|
||||||
component: "MedicalProtocolsWrapper",
|
component: "MedicalProtocolsWrapper",
|
||||||
},
|
},
|
||||||
@@ -467,6 +468,7 @@ export const documentForm = [
|
|||||||
{
|
{
|
||||||
dataLabel: "Паспорт",
|
dataLabel: "Паспорт",
|
||||||
dataKey: "passport",
|
dataKey: "passport",
|
||||||
|
dataClass: "passport",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
key: "series",
|
key: "series",
|
||||||
@@ -531,6 +533,7 @@ export const documentForm = [
|
|||||||
{
|
{
|
||||||
dataLabel: "СНИЛС",
|
dataLabel: "СНИЛС",
|
||||||
dataKey: "insurance_number",
|
dataKey: "insurance_number",
|
||||||
|
dataClass: "insurance",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
key: "number",
|
key: "number",
|
||||||
@@ -553,6 +556,7 @@ export const documentForm = [
|
|||||||
{
|
{
|
||||||
dataLabel: "ИНН",
|
dataLabel: "ИНН",
|
||||||
dataKey: "tax_identification_number",
|
dataKey: "tax_identification_number",
|
||||||
|
dataClass: "tax",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
key: "number",
|
key: "number",
|
||||||
|
|||||||
@@ -1,189 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.calendar-container.flex
|
|
||||||
calendar-sidebar(
|
|
||||||
:url="url",
|
|
||||||
:schedules-data="schedulesData",
|
|
||||||
:open-form-create="openFormCreateEvent",
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
@width="changeWidth",
|
|
||||||
)
|
|
||||||
calendar-schedule(
|
|
||||||
:url="url",
|
|
||||||
:schedules-data="schedulesData",
|
|
||||||
:current-date="currentDate",
|
|
||||||
:time-information="timeInformation",
|
|
||||||
:events-data="eventsData",
|
|
||||||
:sidebar-width="sidebarWidth",
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
@previous-date="switchPreviousDate",
|
|
||||||
@next-date="switchNextDate",
|
|
||||||
@selected-layout="changeCalendarLayout",
|
|
||||||
@selected-event="writeEventData",
|
|
||||||
@delete-event="openModal",
|
|
||||||
:open-form-create-event="openFormCreateEvent"
|
|
||||||
)
|
|
||||||
calendar-form-add-event(
|
|
||||||
v-model="isOpenForm",
|
|
||||||
:selected-event-data="selectedEvent",
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
:time-information="timeInformation",
|
|
||||||
:current-date="currentDate",
|
|
||||||
@clear-event-data="clearSelectedEvent"
|
|
||||||
)
|
|
||||||
base-modal(
|
|
||||||
v-model="showModal",
|
|
||||||
title="Удаление события"
|
|
||||||
)
|
|
||||||
calendar-delete-modal(
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
:owner-event="selectedEvent",
|
|
||||||
:close-modal="changeShowModal",
|
|
||||||
@update-events="fetchEventsData"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
//TODO: Вынести emits в массив
|
|
||||||
import { fetchWrapper } from "../../shared/fetchWrapper.js";
|
|
||||||
import * as moment from "moment/moment";
|
|
||||||
import CalendarSchedule from "./components/CalendarSchedule.vue";
|
|
||||||
import CalendarSidebar from "./components/CalendarSidebar.vue";
|
|
||||||
import CalendarFormAddEvent from "./components/CalendarFormAddEvent.vue";
|
|
||||||
import BaseModal from "@/components/base/BaseModal.vue";
|
|
||||||
import CalendarDeleteModal from "./components/CalendarDeleteModal.vue";
|
|
||||||
import { statusesConfig } from "@/pages/oldCalendar/utils/statusesConfig";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "TheCalendar",
|
|
||||||
components: {
|
|
||||||
CalendarSchedule,
|
|
||||||
CalendarSidebar,
|
|
||||||
CalendarFormAddEvent,
|
|
||||||
BaseModal,
|
|
||||||
CalendarDeleteModal,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
url: String,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
sidebarWidth: "72px",
|
|
||||||
calendarLayout: "",
|
|
||||||
currentDate: moment(),
|
|
||||||
selectedEvent: {},
|
|
||||||
showModal: false,
|
|
||||||
timeInformation: {
|
|
||||||
dayStartTime: "08:00",
|
|
||||||
dayEndTime: "22:00",
|
|
||||||
},
|
|
||||||
eventsData: [],
|
|
||||||
schedulesData: [],
|
|
||||||
isOpenForm: false,
|
|
||||||
//changeFormWasClosed: false,
|
|
||||||
eventStatuses: statusesConfig,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
switchPreviousDate() {
|
|
||||||
this.currentDate = this.currentDate.clone().subtract(1, "day");
|
|
||||||
},
|
|
||||||
switchNextDate() {
|
|
||||||
this.currentDate = this.currentDate.clone().add(1, "day");
|
|
||||||
},
|
|
||||||
changeCalendarLayout(option) {
|
|
||||||
this.calendarLayout = option;
|
|
||||||
},
|
|
||||||
saveEventsData(res) {
|
|
||||||
this.eventsData = res.results;
|
|
||||||
},
|
|
||||||
saveSchedulesData(res) {
|
|
||||||
if (res.results.length === 0) {
|
|
||||||
this.schedulesData = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let filteredEmployees = res.results.filter(
|
|
||||||
(elem) => elem.status !== "DAY_OFF" && elem.status !== "VACATION"
|
|
||||||
);
|
|
||||||
if (filteredEmployees.length === 0) {
|
|
||||||
this.schedulesData = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.schedulesData = filteredEmployees;
|
|
||||||
},
|
|
||||||
fetchSchedulesData() {
|
|
||||||
fetchWrapper
|
|
||||||
.get(
|
|
||||||
`accounts/schedules/?date_after=${this.currentDate.format(
|
|
||||||
"YYYY-MM-DD"
|
|
||||||
)}&date_before=${this.currentDate.format("YYYY-MM-DD")}`
|
|
||||||
)
|
|
||||||
.then((res) => this.saveSchedulesData(res));
|
|
||||||
},
|
|
||||||
fetchEventsData() {
|
|
||||||
fetchWrapper
|
|
||||||
.get(
|
|
||||||
`registry/event/?limit=100&start=${this.currentDate.format(
|
|
||||||
"YYYY-MM-DD"
|
|
||||||
)}T${
|
|
||||||
this.timeInformation.dayStartTime
|
|
||||||
}:00Z&end=${this.currentDate.format("YYYY-MM-DD")}T${
|
|
||||||
this.timeInformation.dayEndTime
|
|
||||||
}:00Z`
|
|
||||||
)
|
|
||||||
.then((res) => this.saveEventsData(res));
|
|
||||||
},
|
|
||||||
changeWidth(value) {
|
|
||||||
this.sidebarWidth = value;
|
|
||||||
},
|
|
||||||
openFormCreateEvent() {
|
|
||||||
this.isOpenForm = true;
|
|
||||||
},
|
|
||||||
closeFormCreateEvent() {
|
|
||||||
this.isOpenForm = false;
|
|
||||||
this.fetchEventsData();
|
|
||||||
},
|
|
||||||
/*setChangeFormState() {
|
|
||||||
this.changeFormWasClosed = true;
|
|
||||||
},
|
|
||||||
resetChangeFormState() {
|
|
||||||
this.changeFormWasClosed = false;
|
|
||||||
},*/
|
|
||||||
writeEventData(eventData) {
|
|
||||||
this.selectedEvent = eventData;
|
|
||||||
this.openFormCreateEvent();
|
|
||||||
},
|
|
||||||
clearSelectedEvent() {
|
|
||||||
this.selectedEvent = {};
|
|
||||||
this.closeFormCreateEvent();
|
|
||||||
},
|
|
||||||
openModal(eventData) {
|
|
||||||
this.selectedEvent = eventData;
|
|
||||||
this.showModal = true;
|
|
||||||
},
|
|
||||||
changeShowModal() {
|
|
||||||
this.showModal = false;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
showModal: function () {
|
|
||||||
if (this.showModal === false) {
|
|
||||||
//this.setChangeFormState();
|
|
||||||
this.clearSelectedEvent();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentDate() {
|
|
||||||
this.fetchSchedulesData();
|
|
||||||
this.fetchEventsData();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.fetchSchedulesData();
|
|
||||||
this.fetchEventsData();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.calendar-container
|
|
||||||
width: calc(100vw - 80px)
|
|
||||||
</style>
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.flex.flex-col(
|
|
||||||
:style="backgroundExtendedWidth"
|
|
||||||
)
|
|
||||||
.flex.flex-col
|
|
||||||
.line-wrapper
|
|
||||||
.line.flex.items-center(
|
|
||||||
v-for="hour in timeCoil",
|
|
||||||
:key="hour"
|
|
||||||
)
|
|
||||||
.middle-line
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "CalendarBackground",
|
|
||||||
props: {
|
|
||||||
timeCoil: Array,
|
|
||||||
ownersCount: Number,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
columnWidth: 0,
|
|
||||||
defaultColumnWidth: 470,
|
|
||||||
pixelsPerHour: 62,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
backgroundExtendedWidth() {
|
|
||||||
if (this.ownersCount > 3) {
|
|
||||||
return {
|
|
||||||
width: `${this.defaultColumnWidth * this.ownersCount}px`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
width: "100%",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.header
|
|
||||||
height: 48px
|
|
||||||
|
|
||||||
.line
|
|
||||||
border-bottom: 1px solid var(--border-light-grey-color)
|
|
||||||
height: 62px
|
|
||||||
&:first-child
|
|
||||||
height: 63px
|
|
||||||
border-top: 1px solid var(--border-light-grey-color)
|
|
||||||
&:last-child
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.middle-line
|
|
||||||
border-top: 1px dashed var(--border-light-grey-color)
|
|
||||||
width: 100%
|
|
||||||
</style>
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.calendar-clock-column.flex.flex-col.items-end.gap-y-43.pb-5.px-3
|
|
||||||
span.text-base(
|
|
||||||
v-for="hour in timeCoil",
|
|
||||||
:key="hour",
|
|
||||||
:class="currentHourStyle(hour)"
|
|
||||||
) {{ hour }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "CalendarClockColumn",
|
|
||||||
props: {
|
|
||||||
timeCoil: Array,
|
|
||||||
currentTime: String,
|
|
||||||
currentDate: Object,
|
|
||||||
dayEndTime: Number,
|
|
||||||
isCurrentDate: Boolean,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
currentHour() {
|
|
||||||
return this.convertTime(this.currentTime, 0, -6);
|
|
||||||
},
|
|
||||||
currentMinute() {
|
|
||||||
return this.convertTime(this.currentTime, 3, -3);
|
|
||||||
},
|
|
||||||
isEndDay() {
|
|
||||||
return this.dayEndTime === this.currentHour && this.currentMinute > 0;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
currentHourStyle(elem) {
|
|
||||||
if (
|
|
||||||
this.convertTime(elem, 0, 3) === this.currentHour &&
|
|
||||||
!this.isEndDay &&
|
|
||||||
this.isCurrentDate
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
"current-time": true,
|
|
||||||
"font-bold": true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
"current-time": false,
|
|
||||||
"font-medium": true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
convertTime(str, startIndex, endIndex) {
|
|
||||||
return parseInt(str.slice(startIndex, endIndex), 10);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.current-time
|
|
||||||
color: var(--bg-event-red-color)
|
|
||||||
.calendar-clock-column
|
|
||||||
width: 80px
|
|
||||||
height: 100%
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
background-color: var(--default-white)
|
|
||||||
</style>
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.calendar-column-wrapper.flex.flex-col
|
|
||||||
.header.flex.items-center.justify-between.py-2.px-6.top-0
|
|
||||||
.flex.items-center
|
|
||||||
base-avatar.mr-2(:size="32", :color="ownerData.color")
|
|
||||||
img.h-full.object-cover(
|
|
||||||
:src="url + ownerData.photo",
|
|
||||||
alt="Team member",
|
|
||||||
v-if="ownerData.photo"
|
|
||||||
)
|
|
||||||
span(v-if="!ownerData.photo") {{ defaultAvatar }}
|
|
||||||
span.owner-name.font-medium.text-base.mr-6 {{ ownerName }}
|
|
||||||
img.icon-wrapper.cursor-pointer(src="@/assets/icons/lock.svg")
|
|
||||||
column-header-checkbox
|
|
||||||
.body(@dblclick="clickOnBackground")
|
|
||||||
//.nonworking-time(:style="nonworkingStartTime")
|
|
||||||
transition-group(name="card")
|
|
||||||
calendar-event-card(
|
|
||||||
v-for="event, index in dayEvents",
|
|
||||||
:key="event.id + index",
|
|
||||||
:id="event.id",
|
|
||||||
:ownerEvent="event",
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
:style="eventCardPosition(event.start, event.end)",
|
|
||||||
@selected-event="transmitEventData",
|
|
||||||
@delete-event="transmitDeleteEvent",
|
|
||||||
:schedule-body-ref="scheduleBodyRef",
|
|
||||||
)
|
|
||||||
//.nonworking-time.absolute(:style="nonworkingEndTime")
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ColumnHeaderCheckbox from "./CalendarColumnHeaderCheckbox.vue";
|
|
||||||
import BaseAvatar from "@/components/base/BaseAvatar";
|
|
||||||
import CalendarEventCard from "./CalendarEventCard.vue";
|
|
||||||
//import * as moment from "moment/moment";
|
|
||||||
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
|
|
||||||
import { addNotification } from "@/components/Notifications/notificationContext";
|
|
||||||
export default {
|
|
||||||
name: "CalendarColumn",
|
|
||||||
components: {
|
|
||||||
CalendarEventCard,
|
|
||||||
BaseAvatar,
|
|
||||||
ColumnHeaderCheckbox,
|
|
||||||
TheNotificationProvider,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
ownerData: Object,
|
|
||||||
dayEvents: Array,
|
|
||||||
dayEndTime: Number,
|
|
||||||
dayStartTime: Number,
|
|
||||||
eventStatuses: Array,
|
|
||||||
//changeFormWasClosed: Boolean,
|
|
||||||
scheduleBodyRef: Node,
|
|
||||||
url: String,
|
|
||||||
openFormCreateEvent: Function,
|
|
||||||
currentDate: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
pixelsPerHour: 62,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
/*workingShift() {
|
|
||||||
if (!this.ownerData.id) return null;
|
|
||||||
let start = this.ownerData.start_time;
|
|
||||||
let end = this.ownerData.end_time;
|
|
||||||
return {
|
|
||||||
start: start?.split(":"),
|
|
||||||
end: end?.split(":"),
|
|
||||||
fulltime: `${start} - ${end}`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
nonworkingStartTime() {
|
|
||||||
if (!this.ownerData.id || !this.workingShift) return {};
|
|
||||||
let height =
|
|
||||||
(this.workingShift.start[0] - this.dayStartTime) * this.pixelsPerHour +
|
|
||||||
this.workingShift.start[1] * this.pixelsPerMinute;
|
|
||||||
if (height <= 0)
|
|
||||||
return {
|
|
||||||
height: 0,
|
|
||||||
display: "none",
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
height: `${height}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
nonworkingEndTime() {
|
|
||||||
if (!this.ownerData.id || !this.workingShift) return {};
|
|
||||||
let time = moment()
|
|
||||||
.hour(this.dayEndTime)
|
|
||||||
.minute(0)
|
|
||||||
.subtract(parseInt(this.workingShift.end[0]), "hours")
|
|
||||||
.subtract(parseInt(this.workingShift.end[1]), "minutes")
|
|
||||||
.format("HH:mm")
|
|
||||||
.split(":");
|
|
||||||
let position =
|
|
||||||
time[0] * this.pixelsPerHour + time[1] * this.pixelsPerMinute;
|
|
||||||
if (position <= 0)
|
|
||||||
return {
|
|
||||||
bottom: 0,
|
|
||||||
display: "none",
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
bottom: 0,
|
|
||||||
height: `${position}px`,
|
|
||||||
};
|
|
||||||
},*/
|
|
||||||
ownerName() {
|
|
||||||
if (this.ownerData.id) {
|
|
||||||
let checkedFirstName =
|
|
||||||
this.ownerData.first_name !== null
|
|
||||||
? this.ownerData.first_name[0] + "."
|
|
||||||
: "";
|
|
||||||
let checkedPatronymic =
|
|
||||||
this.ownerData.patronymic !== null
|
|
||||||
? this.ownerData.patronymic[0] + "."
|
|
||||||
: "";
|
|
||||||
return `${this.ownerData.last_name} ${checkedFirstName}${checkedPatronymic}`;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
defaultAvatar() {
|
|
||||||
let checkedFirstName =
|
|
||||||
this.ownerData.first_name !== null
|
|
||||||
? this.ownerData.first_name[0]
|
|
||||||
: this.ownerData.last_name[1];
|
|
||||||
return `${this.ownerData.last_name[0]}${checkedFirstName}`;
|
|
||||||
},
|
|
||||||
pixelsPerMinute() {
|
|
||||||
return this.pixelsPerHour / 60;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
eventCardPosition(startTime, endTime) {
|
|
||||||
let start = startTime
|
|
||||||
.slice(11, -4)
|
|
||||||
.split(":")
|
|
||||||
.map((elem) => parseInt(elem, 10));
|
|
||||||
let end = endTime.slice(11, -6);
|
|
||||||
let position =
|
|
||||||
(start[0] - this.dayStartTime) * this.pixelsPerHour +
|
|
||||||
start[1] * this.pixelsPerMinute;
|
|
||||||
if (
|
|
||||||
parseInt(start[0], 10) < this.dayStartTime ||
|
|
||||||
parseInt(end, 10) > this.dayEndTime
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
top: "0px",
|
|
||||||
visibility: "hidden",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
top: `${position}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
transmitEventData(eventData) {
|
|
||||||
this.$emit("selected-event", eventData);
|
|
||||||
},
|
|
||||||
/*transmitResetChangeForm() {
|
|
||||||
this.$emit("reset-change-form");
|
|
||||||
},*/
|
|
||||||
transmitDeleteEvent(eventData) {
|
|
||||||
this.$emit("delete-event", eventData);
|
|
||||||
},
|
|
||||||
addErrorNotification(title, message) {
|
|
||||||
addNotification(title, title, message, "error", 5000);
|
|
||||||
},
|
|
||||||
/*clickOnBackground(e) {
|
|
||||||
let res = String((e.offsetY / this.pixelsPerHour).toFixed(2)).split(".");
|
|
||||||
let hours = parseInt(res[0]) + this.dayStartTime;
|
|
||||||
let minuts = Math.round(res[1] * 0.6);
|
|
||||||
if (minuts < 10) minuts = "0" + minuts;
|
|
||||||
if (hours < 10) hours = "0" + hours;
|
|
||||||
if (e.target.className !== "body")
|
|
||||||
this.addErrorNotification(
|
|
||||||
`Для сотрудника ${this.ownerName} рабочие часы: ${this.workingShift.fulltime}`,
|
|
||||||
"Вы пытаетесь добавить запись вне рабочего времени"
|
|
||||||
);
|
|
||||||
else
|
|
||||||
this.$emit("selected-event", {
|
|
||||||
employees: [
|
|
||||||
{
|
|
||||||
employee: {
|
|
||||||
id: this.ownerData.id,
|
|
||||||
last_name: this.ownerData.last_name,
|
|
||||||
first_name: this.ownerData.first_name,
|
|
||||||
patronymic: this.ownerData.patronymic,
|
|
||||||
color: this.ownerData.color,
|
|
||||||
photo: this.ownerData.photo,
|
|
||||||
},
|
|
||||||
role: "owner",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
start: `${this.currentDate.format(
|
|
||||||
"YYYY-MM-DD"
|
|
||||||
)}T${hours}:${minuts}:00`,
|
|
||||||
end: `${this.currentDate.format("YYYY-MM-DD")}T${hours}:${minuts}:00`,
|
|
||||||
});
|
|
||||||
},*/
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.calendar-column-wrapper
|
|
||||||
border-right: 1px solid var(--border-light-grey-color)
|
|
||||||
&:last-child
|
|
||||||
border-right: none
|
|
||||||
|
|
||||||
.header
|
|
||||||
position: sticky
|
|
||||||
z-index: 5
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.body
|
|
||||||
position: relative
|
|
||||||
z-index: 3
|
|
||||||
height: 100%
|
|
||||||
|
|
||||||
.btn
|
|
||||||
opacity: 0.5
|
|
||||||
padding: 7px 13px !important
|
|
||||||
|
|
||||||
.icon-wrapper
|
|
||||||
width: 24px
|
|
||||||
height: 24px
|
|
||||||
|
|
||||||
.owner-name
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.card-enter-from
|
|
||||||
opacity: 0
|
|
||||||
pointer-events: none
|
|
||||||
|
|
||||||
.card-enter-active
|
|
||||||
transition: 0.3s ease
|
|
||||||
|
|
||||||
.card-leave-to
|
|
||||||
opacity: 0
|
|
||||||
pointer-events: none
|
|
||||||
|
|
||||||
.card-leave-active
|
|
||||||
transition: 0.3s ease
|
|
||||||
|
|
||||||
.card-move
|
|
||||||
transition: 0.3s ease
|
|
||||||
|
|
||||||
.nonworking-time
|
|
||||||
width: 100%
|
|
||||||
background-color: var(--btn-blue-sec-color)
|
|
||||||
opacity: 0.3
|
|
||||||
</style>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
div.icon-wrap.flex.items-center.justify-center.cursor-pointer.py-1.px-2(
|
|
||||||
:class="{disable: !isChecked}",
|
|
||||||
@click="changeState"
|
|
||||||
)
|
|
||||||
.icon-doc-ok.text-xxl
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "CalendarColumnHeaderCheckbox",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isChecked: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeState() {
|
|
||||||
this.isChecked = !this.isChecked;
|
|
||||||
this.$emit("isChecked", this.isChecked);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.disable
|
|
||||||
opacity: 0.5
|
|
||||||
.icon-wrap
|
|
||||||
height: 32px
|
|
||||||
background-color: var(--btn-blue-color-1)
|
|
||||||
color: var(--btn-blue-color)
|
|
||||||
border-radius: 4px
|
|
||||||
&:hover
|
|
||||||
background-color: var(--btn-blue-color-2)
|
|
||||||
&:active
|
|
||||||
background-color: var(--font-dark-blue-color)
|
|
||||||
color: var(--default-white)
|
|
||||||
.icon-doc-ok
|
|
||||||
width: 24px
|
|
||||||
height: 24px
|
|
||||||
</style>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.flex.flex-col.mb-1.mt-4
|
|
||||||
span.font-medium.text-base.modal-text.mb-3 Вы действительно хотите удалить это событие?
|
|
||||||
.card-container
|
|
||||||
calendar-event-description-card(
|
|
||||||
disabled,
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
:owner-event="ownerEvent"
|
|
||||||
)
|
|
||||||
.flex.gap-x-3.mt-6.font-semibold
|
|
||||||
q-btn(
|
|
||||||
label="Отменить",
|
|
||||||
no-caps,
|
|
||||||
outline,
|
|
||||||
color="primary",
|
|
||||||
padding="10px 22px",
|
|
||||||
@click="closeModal"
|
|
||||||
)
|
|
||||||
q-btn(
|
|
||||||
label="Удалить",
|
|
||||||
no-caps,
|
|
||||||
outline,
|
|
||||||
style="color: var(--border-red-color)",
|
|
||||||
padding="10px 22px",
|
|
||||||
@click="deleteEvent"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { fetchWrapper } from "@/shared/fetchWrapper.js";
|
|
||||||
import CalendarEventDescriptionCard from "./CalendarEventDescriptionCard.vue";
|
|
||||||
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
|
|
||||||
import { addNotification } from "@/components/Notifications/notificationContext";
|
|
||||||
export default {
|
|
||||||
name: "CalendarDeleteModal",
|
|
||||||
components: {
|
|
||||||
CalendarEventDescriptionCard,
|
|
||||||
TheNotificationProvider,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
ownerEvent: Object,
|
|
||||||
eventStatuses: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
closeModal: Function,
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async deleteEvent() {
|
|
||||||
await fetchWrapper.del(`registry/event/${this.ownerEvent.id}/delete/`);
|
|
||||||
this.$emit("update-events");
|
|
||||||
this.closeModal();
|
|
||||||
this.addSuccessNotification();
|
|
||||||
},
|
|
||||||
addSuccessNotification() {
|
|
||||||
addNotification(
|
|
||||||
new Date().getTime(),
|
|
||||||
"Событие успешно удалено",
|
|
||||||
"",
|
|
||||||
"success",
|
|
||||||
5000
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.modal-text
|
|
||||||
color: var(--font-grey-color)
|
|
||||||
|
|
||||||
.card-container
|
|
||||||
width: 374px
|
|
||||||
border-radius: 4px
|
|
||||||
border: 1px solid var(--border-light-grey-color-1)
|
|
||||||
</style>
|
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.wrapper.cursor-pointer.my-1.mx-1(
|
|
||||||
:style="themeColors",
|
|
||||||
:class="cardTheme",
|
|
||||||
ref="eventCard"
|
|
||||||
)
|
|
||||||
.card.flex.px-2(
|
|
||||||
:class="{'py-6px flex-col': longCard}",
|
|
||||||
:style="cardHeight",
|
|
||||||
@click="openDescriptionCard",
|
|
||||||
@dblclick.stop
|
|
||||||
)
|
|
||||||
.header.flex.justify-between.items-center(:class="{'items-start': longCard}")
|
|
||||||
.header-text
|
|
||||||
span.inline-block.align-middle.font-bold.text-base.mr-4 {{ eventTime }}
|
|
||||||
span.inline-block.align-middle.font-medium.text-base {{ eventMember }}
|
|
||||||
.details-count.flex.justify-center.items-center.text-xxs.font-medium(v-if="someDetailsShown") {{ `+${detailsCount}` }}
|
|
||||||
.body.flex.text-xxs.font-medium(v-if="longCard")
|
|
||||||
.col.mr-22px
|
|
||||||
ul
|
|
||||||
li.mt-2(v-for="elem in descriptionColumns.leftColumn" :key="elem") {{ elem }}
|
|
||||||
.col
|
|
||||||
ul
|
|
||||||
li.mt-2(v-for="elem in descriptionColumns.rightColumn" :key="elem") {{ elem }}
|
|
||||||
transition(name="description")
|
|
||||||
calendar-event-description-card(
|
|
||||||
v-if="isOpenDescriptionCard",
|
|
||||||
:owner-event="ownerEvent",
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
@selected-event="transmitEventData",
|
|
||||||
@close-description-card="closeDescriptionCard",
|
|
||||||
@delete-event="transmitDeleteEvent",
|
|
||||||
:schedule-body-ref="scheduleBodyRef"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CalendarEventDescriptionCard from "./CalendarEventDescriptionCard.vue";
|
|
||||||
export default {
|
|
||||||
name: "CalendarEventCard",
|
|
||||||
components: { CalendarEventDescriptionCard },
|
|
||||||
props: {
|
|
||||||
//changeFormWasClosed: Boolean,
|
|
||||||
ownerEvent: Object,
|
|
||||||
eventStatuses: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scheduleBodyRef: Node,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
pixelsPerHour: 62,
|
|
||||||
isActive: false,
|
|
||||||
someDetailsShown: true,
|
|
||||||
isOpenDescriptionCard: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
pixelsPerMinute() {
|
|
||||||
return this.pixelsPerHour / 60;
|
|
||||||
},
|
|
||||||
eventTime() {
|
|
||||||
return `${this.trimTime(this.ownerEvent.start)} - ${this.trimTime(
|
|
||||||
this.ownerEvent.end
|
|
||||||
)}`;
|
|
||||||
},
|
|
||||||
eventMember() {
|
|
||||||
let membersArray = this.ownerEvent.members;
|
|
||||||
if (membersArray.length > 1) {
|
|
||||||
let primaryMember = membersArray.find(
|
|
||||||
(elem) => elem.role === "primary"
|
|
||||||
);
|
|
||||||
return this.composeFullName(primaryMember.person);
|
|
||||||
}
|
|
||||||
return this.composeFullName(membersArray[0].person);
|
|
||||||
},
|
|
||||||
calculateCardHeight() {
|
|
||||||
let startTime = this.trimTime(this.ownerEvent.start)
|
|
||||||
.split(":")
|
|
||||||
.map((elem) => parseInt(elem, 10));
|
|
||||||
let endTime = this.trimTime(this.ownerEvent.end)
|
|
||||||
.split(":")
|
|
||||||
.map((elem) => parseInt(elem, 10));
|
|
||||||
return (
|
|
||||||
(endTime[0] * 60 + endTime[1] - (startTime[0] * 60 + startTime[1])) *
|
|
||||||
this.pixelsPerMinute
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cardHeight() {
|
|
||||||
return {
|
|
||||||
height: `${this.calculateCardHeight - 8}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
cardTheme() {
|
|
||||||
return {
|
|
||||||
"active-theme": this.isActive,
|
|
||||||
"default-theme": !this.isActive,
|
|
||||||
"long-card": this.longCard,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
themeColors() {
|
|
||||||
switch (this.ownerEvent.status) {
|
|
||||||
case this.eventStatuses[1].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-grey-color-0)",
|
|
||||||
"--bg-active": this.eventStatuses[1].color,
|
|
||||||
"--bg-hover": "var(--bg-event-grey-color-1)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--default-white)",
|
|
||||||
"--count-color": this.eventStatuses[1].color,
|
|
||||||
};
|
|
||||||
case this.eventStatuses[2].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-yellow-color-0)",
|
|
||||||
"--bg-active": this.eventStatuses[2].color,
|
|
||||||
"--bg-hover": "var(--bg-event-yellow-color-1)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--font-black-color)",
|
|
||||||
"--count-color": "var(--font-black-color)",
|
|
||||||
};
|
|
||||||
case this.eventStatuses[3].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-orange-color-0)",
|
|
||||||
"--bg-active": this.eventStatuses[3].color,
|
|
||||||
"--bg-hover": "var(--bg-event-orange-color-1)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--font-black-color)",
|
|
||||||
"--count-color": "var(--font-black-color)",
|
|
||||||
};
|
|
||||||
case this.eventStatuses[4].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-blue-color-0)",
|
|
||||||
"--bg-active": this.eventStatuses[4].color,
|
|
||||||
"--bg-hover": "var(--bg-event-blue-color-1)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--default-white)",
|
|
||||||
"--count-color": this.eventStatuses[4].color,
|
|
||||||
};
|
|
||||||
case this.eventStatuses[5].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-green-color-0)",
|
|
||||||
"--bg-active": this.eventStatuses[5].color,
|
|
||||||
"--bg-hover": "var(--bg-event-green-color-1)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--default-white)",
|
|
||||||
"--count-color": this.eventStatuses[5].color,
|
|
||||||
};
|
|
||||||
case this.eventStatuses[6].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-red-color-0)",
|
|
||||||
"--bg-active": this.eventStatuses[6].color,
|
|
||||||
"--bg-hover": "var(--bg-event-red-color-1)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--default-white)",
|
|
||||||
"--count-color": this.eventStatuses[6].color,
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--default-white)",
|
|
||||||
"--bg-active": "var(--btn-blue-color)",
|
|
||||||
"--bg-hover": "var(--bg-event-default-hover-color)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
"--font-active-color": "var(--default-white)",
|
|
||||||
"--border-color": "#b3c3f3",
|
|
||||||
"--border-active-color": "var(--btn-blue-color)",
|
|
||||||
"--count-color": "var(--btn-blue-color)",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
description() {
|
|
||||||
return this.ownerEvent.description
|
|
||||||
? this.ownerEvent.description.split(", ")
|
|
||||||
: [];
|
|
||||||
},
|
|
||||||
descriptionColumns() {
|
|
||||||
let leftCol = [],
|
|
||||||
rightCol = [],
|
|
||||||
heightParts = parseInt((this.calculateCardHeight - 8) / 23);
|
|
||||||
if (this.ownerEvent.description && heightParts > 1) {
|
|
||||||
let n = heightParts;
|
|
||||||
for (let i = 0; i < n * 2 - 2; i++) {
|
|
||||||
if (!this.description[i]) break;
|
|
||||||
i % 2 === 0
|
|
||||||
? leftCol.push(this.description[i])
|
|
||||||
: rightCol.push(this.description[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
leftColumn: leftCol,
|
|
||||||
rightColumn: rightCol,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
longCard() {
|
|
||||||
return parseInt((this.calculateCardHeight - 8) / 23) > 1 ? true : false;
|
|
||||||
},
|
|
||||||
detailsCount() {
|
|
||||||
let columnsLength =
|
|
||||||
this.descriptionColumns.leftColumn.length +
|
|
||||||
this.descriptionColumns.rightColumn.length,
|
|
||||||
remainingDetails = this.description.length - columnsLength;
|
|
||||||
if (!remainingDetails) this.changeDetailsShown();
|
|
||||||
return remainingDetails;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
trimTime(time) {
|
|
||||||
return time.slice(11, 16);
|
|
||||||
},
|
|
||||||
composeFullName(object) {
|
|
||||||
return `${object.last_name} ${object.first_name ?? ""} ${
|
|
||||||
object.patronymic ?? ""
|
|
||||||
}`;
|
|
||||||
},
|
|
||||||
setActiveTheme() {
|
|
||||||
this.isActive = true;
|
|
||||||
},
|
|
||||||
setDefaultTheme() {
|
|
||||||
this.isActive = false;
|
|
||||||
},
|
|
||||||
changeDetailsShown() {
|
|
||||||
this.someDetailsShown = false;
|
|
||||||
},
|
|
||||||
transmitEventData() {
|
|
||||||
this.$emit("selected-event", this.ownerEvent);
|
|
||||||
this.hideDescriptionCard();
|
|
||||||
},
|
|
||||||
transmitDeleteEvent() {
|
|
||||||
this.$emit("delete-event", this.ownerEvent);
|
|
||||||
},
|
|
||||||
hideDescriptionCard() {
|
|
||||||
this.isOpenDescriptionCard = false;
|
|
||||||
},
|
|
||||||
openDescriptionCard() {
|
|
||||||
if (!this.isOpenDescriptionCard && !this.isActive) {
|
|
||||||
this.isOpenDescriptionCard = true;
|
|
||||||
this.setActiveTheme();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
closeDescriptionCard() {
|
|
||||||
this.hideDescriptionCard();
|
|
||||||
this.setDefaultTheme();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/*watch: {
|
|
||||||
changeFormWasClosed: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newValue) {
|
|
||||||
if (newValue === true && this.isActive) {
|
|
||||||
this.isActive = false;
|
|
||||||
this.$emit("reset-change-form");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},*/
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.description-enter-from
|
|
||||||
opacity: 0
|
|
||||||
transform: translateY(2px)
|
|
||||||
pointer-events: none
|
|
||||||
|
|
||||||
.description-enter-active
|
|
||||||
transition: 0.5s ease
|
|
||||||
|
|
||||||
.description-leave-to
|
|
||||||
opacity: 0
|
|
||||||
transform: translateY(2px)
|
|
||||||
pointer-events: none
|
|
||||||
|
|
||||||
.description-leave-active
|
|
||||||
transition: 0.5s ease
|
|
||||||
|
|
||||||
.description-move
|
|
||||||
transition: 0.5s ease
|
|
||||||
|
|
||||||
.wrapper
|
|
||||||
position: absolute
|
|
||||||
width: calc(100% - 8px)
|
|
||||||
|
|
||||||
.default-theme
|
|
||||||
z-index: 2
|
|
||||||
.card
|
|
||||||
background-color: var(--bg-color)
|
|
||||||
border: 2px solid var(--border-color)
|
|
||||||
border-left: 4px solid var(--bg-active)
|
|
||||||
.card:hover
|
|
||||||
background-color: var(--bg-hover)
|
|
||||||
.header-text, .body
|
|
||||||
color: var(--font-color)
|
|
||||||
.details-count
|
|
||||||
background-color: var(--bg-active)
|
|
||||||
color: var(--font-active-color)
|
|
||||||
li:before
|
|
||||||
background-color: var(--font-color)
|
|
||||||
|
|
||||||
.active-theme
|
|
||||||
z-index: 3
|
|
||||||
.card
|
|
||||||
background-color: var(--bg-active)
|
|
||||||
border: 2px solid var(--border-active-color)
|
|
||||||
border-left: 4px solid var(--bg-active)
|
|
||||||
.header-text, .body
|
|
||||||
color: var(--font-active-color)
|
|
||||||
.details-count
|
|
||||||
background-color: var(--default-white)
|
|
||||||
color: var(--count-color)
|
|
||||||
li:before
|
|
||||||
background-color: var(--font-active-color)
|
|
||||||
|
|
||||||
.card
|
|
||||||
border-radius: 4px
|
|
||||||
min-height: 23px
|
|
||||||
|
|
||||||
.header
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
.details-count
|
|
||||||
width: 24px
|
|
||||||
height: 16px
|
|
||||||
border-radius: 16px
|
|
||||||
|
|
||||||
.col
|
|
||||||
max-width: calc(462px/2 - 22px)
|
|
||||||
|
|
||||||
ul
|
|
||||||
list-style-type: none
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
li
|
|
||||||
overflow: hidden
|
|
||||||
text-overflow: ellipsis
|
|
||||||
white-space: nowrap
|
|
||||||
|
|
||||||
li:before
|
|
||||||
content: ''
|
|
||||||
display: inline-block
|
|
||||||
height: 8px
|
|
||||||
width: 8px
|
|
||||||
border-radius: 50%
|
|
||||||
background-color : var(--font-black-color)
|
|
||||||
margin-right: 4px
|
|
||||||
</style>
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.wrapper.px-4.pt-14px.pb-4.font-medium.cursor-auto(
|
|
||||||
:style="{...typeColor, ...position, ...constantWidth}",
|
|
||||||
v-click-outside="close",
|
|
||||||
:class="{'shadow': !disabled}",
|
|
||||||
ref="descriptionCard"
|
|
||||||
)
|
|
||||||
.flex.justify-between.items-center.mb-2
|
|
||||||
.flex
|
|
||||||
span.inline-block.font-bold.text-base.mr-3.mt-2px {{ eventTime }}
|
|
||||||
.type.text-xs.font-medium.flex.items-center.justify-center.px-14px(v-if="isCertainType")
|
|
||||||
span.type-text {{ status }}
|
|
||||||
.right-side.flex.gap-x-4.text-sm(v-if="!disabled")
|
|
||||||
.icon-basket.flex.items-center.cursor-pointer(@click="transmitDeleteEvent")
|
|
||||||
.icon-edit.flex.items-center.cursor-pointer(@click="transmitEventData")
|
|
||||||
.icon-cancel.text-xxs.flex.items-center.cursor-pointer(@click="close")
|
|
||||||
.body.mr-6
|
|
||||||
span.text-base {{ eventMember }}
|
|
||||||
.flex.text-xxs.justify-between(
|
|
||||||
v-if="!disabled",
|
|
||||||
:class="{'mt-4': description.length > 0}"
|
|
||||||
)
|
|
||||||
.column
|
|
||||||
ul
|
|
||||||
li(v-for="elem in description" :key="elem") {{ elem }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { statusesConfig } from "@/pages/oldCalendar/utils/statusesConfig";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "CalendarEventDescriptionCard",
|
|
||||||
props: {
|
|
||||||
ownerEvent: Object,
|
|
||||||
eventStatuses: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
scheduleBodyRef: Node,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isCertainType: true,
|
|
||||||
position: {},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
status() {
|
|
||||||
return this.ownerEvent.status
|
|
||||||
? statusesConfig.find((e) => e.value === this.ownerEvent.status).label
|
|
||||||
: "";
|
|
||||||
},
|
|
||||||
typeColor() {
|
|
||||||
switch (this.ownerEvent.status) {
|
|
||||||
case this.eventStatuses[1].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-grey-color-0)",
|
|
||||||
"--font-color": this.eventStatuses[1].color,
|
|
||||||
};
|
|
||||||
case this.eventStatuses[2].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-yellow-color-0)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
};
|
|
||||||
case this.eventStatuses[3].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-orange-color-0)",
|
|
||||||
"--font-color": "var(--font-black-color)",
|
|
||||||
};
|
|
||||||
case this.eventStatuses[4].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-blue-color-0)",
|
|
||||||
"--font-color": this.eventStatuses[4].color,
|
|
||||||
};
|
|
||||||
case this.eventStatuses[5].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-green-color-0)",
|
|
||||||
"--font-color": this.eventStatuses[5].color,
|
|
||||||
};
|
|
||||||
case this.eventStatuses[6].value:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-red-color-0)",
|
|
||||||
"--font-color": this.eventStatuses[6].color,
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
"--bg-color": "var(--bg-event-default-hover-color)",
|
|
||||||
"--font-color": "var(--btn-blue-color)",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
eventTime() {
|
|
||||||
return `${this.trimTime(this.ownerEvent.start)} - ${this.trimTime(
|
|
||||||
this.ownerEvent.end
|
|
||||||
)}`;
|
|
||||||
},
|
|
||||||
eventMember() {
|
|
||||||
let membersArray = this.ownerEvent.members;
|
|
||||||
if (membersArray.length > 1) {
|
|
||||||
let primaryMember = membersArray.find(
|
|
||||||
(elem) => elem.role === "primary"
|
|
||||||
);
|
|
||||||
return this.composeFullName(primaryMember.person);
|
|
||||||
}
|
|
||||||
return this.composeFullName(membersArray[0].person);
|
|
||||||
},
|
|
||||||
description() {
|
|
||||||
return this.ownerEvent.description
|
|
||||||
? this.ownerEvent.description.split(", ")
|
|
||||||
: [];
|
|
||||||
},
|
|
||||||
constantWidth() {
|
|
||||||
if (!this.disabled) {
|
|
||||||
return {
|
|
||||||
width: "426px !important",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeType() {
|
|
||||||
this.isCertainType = false;
|
|
||||||
},
|
|
||||||
transmitEventData() {
|
|
||||||
this.$emit("selected-event");
|
|
||||||
},
|
|
||||||
transmitDeleteEvent() {
|
|
||||||
this.$emit("delete-event");
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
if (!this.disabled) this.$emit("close-description-card");
|
|
||||||
},
|
|
||||||
trimTime(time) {
|
|
||||||
return time.slice(11, 16);
|
|
||||||
},
|
|
||||||
composeFullName(object) {
|
|
||||||
return `${object.last_name} ${object.first_name ?? ""} ${
|
|
||||||
object.patronymic ?? ""
|
|
||||||
}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
if (!this.$refs.descriptionCard || !this.scheduleBodyRef) return;
|
|
||||||
const cardRect = this.$refs.descriptionCard.getBoundingClientRect();
|
|
||||||
const bodyRect = this.scheduleBodyRef.getBoundingClientRect();
|
|
||||||
const bodyHeight = this.scheduleBodyRef.clientHeight + bodyRect.y - 20;
|
|
||||||
if (cardRect.y + cardRect.height > bodyHeight) {
|
|
||||||
this.position = {
|
|
||||||
top: `-${cardRect.height + 8}px`,
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
this.position = {
|
|
||||||
"margin-top": "8px",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.wrapper
|
|
||||||
height: auto !important
|
|
||||||
background-color: var(--default-white)
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.shadow
|
|
||||||
border-radius: 4px
|
|
||||||
box-shadow: var(--default-shadow)
|
|
||||||
|
|
||||||
.type
|
|
||||||
background-color: var(--bg-color)
|
|
||||||
border-radius: 4px
|
|
||||||
|
|
||||||
.type-text
|
|
||||||
color: var(--font-color)
|
|
||||||
|
|
||||||
.right-side
|
|
||||||
height: 16px
|
|
||||||
color: var(--btn-blue-color)
|
|
||||||
|
|
||||||
.icon-basket
|
|
||||||
color: var(--border-red-color)
|
|
||||||
|
|
||||||
.column
|
|
||||||
max-width: calc(462px/2 - 36px)
|
|
||||||
|
|
||||||
ul
|
|
||||||
list-style-type: none
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
li
|
|
||||||
margin-bottom: 8px
|
|
||||||
overflow: hidden
|
|
||||||
text-overflow: ellipsis
|
|
||||||
white-space: nowrap
|
|
||||||
&:last-child
|
|
||||||
margin: 0px
|
|
||||||
|
|
||||||
li:before
|
|
||||||
content: ''
|
|
||||||
display: inline-block
|
|
||||||
height: 6px
|
|
||||||
width: 6px
|
|
||||||
border-radius: 50%
|
|
||||||
background-color: var(--font-black-color)
|
|
||||||
margin: 0 8px 1px 0
|
|
||||||
</style>
|
|
||||||
@@ -1,648 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
base-modal(
|
|
||||||
v-model="value",
|
|
||||||
:title="!selectedEventData.id ? 'Запись на прием' : 'Изменение записи'",
|
|
||||||
draggable,
|
|
||||||
hide-overlay
|
|
||||||
)
|
|
||||||
.event-form.flex.flex-col.gap-y-6.pt-8
|
|
||||||
.flex.flex-col.gap-y-8
|
|
||||||
base-select(
|
|
||||||
v-if="selectedEventData.id"
|
|
||||||
v-model="status",
|
|
||||||
:items="statusesList",
|
|
||||||
label="Статус приема",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
v-else,
|
|
||||||
disabled,
|
|
||||||
v-model="status.label",
|
|
||||||
label="Статус приема",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-select(
|
|
||||||
:items="ownersList",
|
|
||||||
v-model="employees.employee",
|
|
||||||
placeholder="Выберите сотрудника"
|
|
||||||
label="Сотрудник",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-select(
|
|
||||||
:items="membersList",
|
|
||||||
v-model="members.person",
|
|
||||||
placeholder="Выберите клиента",
|
|
||||||
label="Клиент",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.flex.gap-x-4
|
|
||||||
base-input(
|
|
||||||
v-model="eventDate",
|
|
||||||
label="Дата",
|
|
||||||
type="date",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.flex.gap-x-2.items-center.justify-between
|
|
||||||
base-input(
|
|
||||||
type="time",
|
|
||||||
v-model="startTime",
|
|
||||||
label="Начало",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
span.mt-4 —
|
|
||||||
base-input(
|
|
||||||
type="time",
|
|
||||||
v-model="endTime",
|
|
||||||
label="Конец",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
q-btn.create-button(
|
|
||||||
v-if="!selectedEventData.id",
|
|
||||||
label="Создать событие",
|
|
||||||
no-caps,
|
|
||||||
color="primary",
|
|
||||||
padding="10px 22px",
|
|
||||||
:disabled="disabledCreateButton",
|
|
||||||
@click="sendEventData",
|
|
||||||
)
|
|
||||||
q-btn.update-button(
|
|
||||||
v-else,
|
|
||||||
label="Сохранить",
|
|
||||||
no-caps,
|
|
||||||
color="primary",
|
|
||||||
padding="10px 22px",
|
|
||||||
:disabled="disabledUpdateButton",
|
|
||||||
@click="updateEventData",
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
|
|
||||||
import { addNotification } from "@/components/Notifications/notificationContext";
|
|
||||||
import { fetchWrapper } from "@/shared/fetchWrapper.js";
|
|
||||||
import BaseInput from "@/components/base/BaseInput.vue";
|
|
||||||
import BaseSelect from "@/components/base/BaseSelect.vue";
|
|
||||||
import * as moment from "moment/moment";
|
|
||||||
import BaseModal from "@/components/base/BaseModal.vue";
|
|
||||||
import { v_model } from "@/shared/mixins/v-model";
|
|
||||||
import { statusesConfig } from "@/pages/oldCalendar/utils/statusesConfig";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "FormChangeEvent",
|
|
||||||
components: {
|
|
||||||
BaseModal,
|
|
||||||
BaseSelect,
|
|
||||||
BaseInput,
|
|
||||||
TheNotificationProvider,
|
|
||||||
},
|
|
||||||
mixins: [v_model],
|
|
||||||
//emits: ["clear-selected-event-data", "close-change-form"],
|
|
||||||
emits: ["clear-event-data"],
|
|
||||||
props: {
|
|
||||||
//closeForm: Function,
|
|
||||||
selectedEventData: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
timeInformation: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
currentDate: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
EMPLOYEE_TYPE: "owner",
|
|
||||||
MEMBER_TYPE: "primary",
|
|
||||||
EVENT_KIND: "Прием",
|
|
||||||
eventData: {},
|
|
||||||
startTime: "",
|
|
||||||
endTime: "",
|
|
||||||
members: {},
|
|
||||||
employees: {},
|
|
||||||
eventDate: Date,
|
|
||||||
status: { label: "Планируется прием", id: null },
|
|
||||||
id: null,
|
|
||||||
//ifClearedForm: true,
|
|
||||||
membersData: [],
|
|
||||||
ownersData: [],
|
|
||||||
WORKING_STATUS: "WORKS",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
ownersList() {
|
|
||||||
if (this.ownersData) {
|
|
||||||
let filteredArray = [];
|
|
||||||
this.ownersData.forEach((elem) => {
|
|
||||||
filteredArray.push({
|
|
||||||
id: elem.id,
|
|
||||||
label: this.trimOwnerName(
|
|
||||||
elem.last_name,
|
|
||||||
elem.first_name,
|
|
||||||
elem.patronymic
|
|
||||||
),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return filteredArray;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
membersList() {
|
|
||||||
if (this.membersData) {
|
|
||||||
let filteredArray = [];
|
|
||||||
this.membersData.forEach((elem) => {
|
|
||||||
filteredArray.push({
|
|
||||||
id: elem.id,
|
|
||||||
label: this.trimMemberName(
|
|
||||||
elem.last_name,
|
|
||||||
elem.first_name,
|
|
||||||
elem.patronymic
|
|
||||||
),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return filteredArray;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
statusesList() {
|
|
||||||
let filteredArray = [];
|
|
||||||
statusesConfig.forEach((elem) => {
|
|
||||||
filteredArray.push({
|
|
||||||
id: elem.id,
|
|
||||||
label: elem.label,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return filteredArray;
|
|
||||||
},
|
|
||||||
disabledCreateButton() {
|
|
||||||
if (
|
|
||||||
this.eventDate &&
|
|
||||||
this.startTime &&
|
|
||||||
this.endTime &&
|
|
||||||
this.members.person.label &&
|
|
||||||
this.employees.employee.label &&
|
|
||||||
this.status.label
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
disabledUpdateButton() {
|
|
||||||
let start = moment(this.selectedEventData.start);
|
|
||||||
let end = moment(this.selectedEventData.end);
|
|
||||||
if (
|
|
||||||
moment(this.eventDate).format("YYYY-MM-DD") ===
|
|
||||||
start.format("YYYY-MM-DD") &&
|
|
||||||
this.startTime === start.format("HH:mm") &&
|
|
||||||
this.endTime === end.format("HH:mm") &&
|
|
||||||
this.findStatus(this.status.label) === this.selectedEventData.status &&
|
|
||||||
this.employees.employee.id ===
|
|
||||||
this.personId(this.selectedEventData.employees, "employee") &&
|
|
||||||
this.members.person.id ===
|
|
||||||
this.personId(this.selectedEventData.members, "person")
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!this.eventDate) return true;
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
startDate() {
|
|
||||||
return this.selectedEventData.start
|
|
||||||
? new Date(this.selectedEventData.start)
|
|
||||||
: this.currentDate.toDate();
|
|
||||||
},
|
|
||||||
endDate() {
|
|
||||||
return this.selectedEventData.end
|
|
||||||
? new Date(this.selectedEventData.end)
|
|
||||||
: this.currentDate.toDate();
|
|
||||||
},
|
|
||||||
eventEmployee() {
|
|
||||||
if (this.selectedEventData.employees) {
|
|
||||||
let foundEmployee = this.selectedEventData.employees.find(
|
|
||||||
({ role }) => role === this.EMPLOYEE_TYPE
|
|
||||||
);
|
|
||||||
let {
|
|
||||||
employee: { id, last_name, first_name, patronymic },
|
|
||||||
...rest
|
|
||||||
} = foundEmployee;
|
|
||||||
return {
|
|
||||||
employee: {
|
|
||||||
id: id,
|
|
||||||
label: this.trimOwnerName(last_name, first_name, patronymic),
|
|
||||||
},
|
|
||||||
id: rest?.id || null,
|
|
||||||
role: rest?.role || this.EMPLOYEE_TYPE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
employee: {
|
|
||||||
id: null,
|
|
||||||
label: "",
|
|
||||||
},
|
|
||||||
role: this.EMPLOYEE_TYPE,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
eventMember() {
|
|
||||||
if (this.selectedEventData.members) {
|
|
||||||
let foundMember = {};
|
|
||||||
if (this.selectedEventData.members.length > 1) {
|
|
||||||
foundMember = this.selectedEventData.members.find(
|
|
||||||
({ role }) => role === this.MEMBER_TYPE
|
|
||||||
);
|
|
||||||
} else foundMember = this.selectedEventData.members[0];
|
|
||||||
let {
|
|
||||||
person: { id, last_name, first_name, patronymic },
|
|
||||||
...rest
|
|
||||||
} = foundMember;
|
|
||||||
return {
|
|
||||||
person: {
|
|
||||||
id: id,
|
|
||||||
label: this.trimMemberName(last_name, first_name, patronymic),
|
|
||||||
},
|
|
||||||
id: rest.id,
|
|
||||||
role: rest?.role || this.MEMBER_TYPE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
person: {
|
|
||||||
id: null,
|
|
||||||
label: "",
|
|
||||||
},
|
|
||||||
role: this.MEMBER_TYPE,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
eventId() {
|
|
||||||
return this.selectedEventData.id ? this.selectedEventData.id : "";
|
|
||||||
},
|
|
||||||
eventStatus() {
|
|
||||||
return this.selectedEventData.status
|
|
||||||
? {
|
|
||||||
label: statusesConfig.find(
|
|
||||||
(e) => e.value === this.selectedEventData.status
|
|
||||||
).label,
|
|
||||||
id: statusesConfig.find(
|
|
||||||
(e) => e.value === this.selectedEventData.status
|
|
||||||
).id,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
label: statusesConfig.find((e) => e.value === "PLANNED").label,
|
|
||||||
id: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
findStatus(value) {
|
|
||||||
return statusesConfig.find((e) => e.label === value)?.value;
|
|
||||||
},
|
|
||||||
checkTimeLimits(eventTime, scheduleTime, timeType) {
|
|
||||||
if (timeType === "start")
|
|
||||||
return (
|
|
||||||
parseInt(eventTime.split(":")[0]) <
|
|
||||||
parseInt(scheduleTime.split(":")[0])
|
|
||||||
);
|
|
||||||
if (timeType === "end") {
|
|
||||||
let firstTime = eventTime.split(":").map((elem) => parseInt(elem));
|
|
||||||
let secondTime = scheduleTime.split(":").map((elem) => parseInt(elem));
|
|
||||||
if (firstTime[0] === secondTime[0]) return firstTime[1] > secondTime[1];
|
|
||||||
else return firstTime[0] > secondTime[0];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkTime() {
|
|
||||||
let counter = 0;
|
|
||||||
let foundedSchedule = {};
|
|
||||||
let foundedEmployee = this.ownersData.find(
|
|
||||||
(elem) => elem.id === this.employees.employee.id
|
|
||||||
);
|
|
||||||
if (foundedEmployee)
|
|
||||||
foundedSchedule = foundedEmployee.schedules.find(
|
|
||||||
(elem) =>
|
|
||||||
elem.date === moment(this.eventDate).format("YYYY-MM-DD") &&
|
|
||||||
elem.status === this.WORKING_STATUS
|
|
||||||
);
|
|
||||||
if (!foundedSchedule) {
|
|
||||||
this.addErrorNotification(
|
|
||||||
"Некорректная дата события",
|
|
||||||
`В данный день ${this.employees.employee.label} не работает`
|
|
||||||
);
|
|
||||||
counter += 1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.checkTimeLimits(
|
|
||||||
this.startTime,
|
|
||||||
foundedSchedule.start_time,
|
|
||||||
"start"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
this.addErrorNotification(
|
|
||||||
"Некорректное время начала события",
|
|
||||||
"Время начала события раньше начала рабочего дня"
|
|
||||||
);
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
if (this.checkTimeLimits(this.endTime, foundedSchedule.end_time, "end")) {
|
|
||||||
this.addErrorNotification(
|
|
||||||
"Некорректное время окончания события",
|
|
||||||
"Время окончания события позже окончания рабочего дня"
|
|
||||||
);
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.checkTimeLimits(this.endTime, foundedSchedule.start_time, "start")
|
|
||||||
) {
|
|
||||||
this.addErrorNotification(
|
|
||||||
"Некорректное время окончания события",
|
|
||||||
"Время окончания события раньше начала рабочего дня"
|
|
||||||
);
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.checkTimeLimits(this.startTime, foundedSchedule.end_time, "end")
|
|
||||||
) {
|
|
||||||
this.addErrorNotification(
|
|
||||||
"Некорректное время начала события",
|
|
||||||
"Время начала события позже окончания рабочего дня"
|
|
||||||
);
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
return counter === 0;
|
|
||||||
},
|
|
||||||
trimOwnerName(lastName, firstName, patronymic) {
|
|
||||||
let checkedFirstName = firstName !== null ? firstName[0] + "." : "";
|
|
||||||
let checkedPatronymic = patronymic !== null ? patronymic[0] + "." : "";
|
|
||||||
return `${lastName} ${checkedFirstName}${checkedPatronymic}`;
|
|
||||||
},
|
|
||||||
trimMemberName(lastName, firstName, patronymic) {
|
|
||||||
return `${lastName} ${firstName ?? ""} ${patronymic ?? ""}`;
|
|
||||||
},
|
|
||||||
async sendEventData() {
|
|
||||||
if (!this.checkTime()) return;
|
|
||||||
this.eventData = {
|
|
||||||
start: this.mergeDate(this.eventDate, this.startTime),
|
|
||||||
end: this.mergeDate(this.eventDate, this.endTime),
|
|
||||||
status: this.findStatus(this.status.label),
|
|
||||||
kind: this.EVENT_KIND,
|
|
||||||
employees: [
|
|
||||||
this.findPerson(this.ownersData, this.employees, "employee"),
|
|
||||||
],
|
|
||||||
members: [this.findPerson(this.membersData, this.members, "person")],
|
|
||||||
};
|
|
||||||
await this.postCreateEvent(this.eventData);
|
|
||||||
this.eventData = {};
|
|
||||||
this.value = false;
|
|
||||||
},
|
|
||||||
async updateEventData() {
|
|
||||||
if (!this.checkTime()) return;
|
|
||||||
if (
|
|
||||||
Object.keys(
|
|
||||||
this.findPerson(this.ownersData, this.employees, "employee")
|
|
||||||
).length > 0 &&
|
|
||||||
Object.keys(this.findPerson(this.membersData, this.members, "person"))
|
|
||||||
.length > 0
|
|
||||||
) {
|
|
||||||
this.eventData = {
|
|
||||||
start: this.mergeDate(this.eventDate, this.startTime),
|
|
||||||
end: this.mergeDate(this.eventDate, this.endTime),
|
|
||||||
status: this.findStatus(this.status.label),
|
|
||||||
employees: [
|
|
||||||
this.findPerson(this.ownersData, this.employees, "employee"),
|
|
||||||
],
|
|
||||||
members: [this.findPerson(this.membersData, this.members, "person")],
|
|
||||||
};
|
|
||||||
await this.postUpdateEvent(this.id, this.eventData);
|
|
||||||
this.eventData = {};
|
|
||||||
this.value = false;
|
|
||||||
} else
|
|
||||||
this.addErrorNotification(
|
|
||||||
"Событие не может быть изменено",
|
|
||||||
"Клиент был удален"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
//clearForm() {
|
|
||||||
// if (this.selectedEventData.id) this.$emit("close-change-form");
|
|
||||||
// this.$emit("clear-selected-event-data");
|
|
||||||
// this.closeForm();
|
|
||||||
//},
|
|
||||||
mergeDate(eventDate, time) {
|
|
||||||
let parseTime = time.split(":");
|
|
||||||
return moment(eventDate.setHours(parseTime[0], parseTime[1]), 0).format(
|
|
||||||
"YYYY-MM-DDTHH:mm:ss"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
findPerson(requestedList, object, field) {
|
|
||||||
let foundPerson = requestedList.find(({ id }) => id === object[field].id);
|
|
||||||
if (foundPerson) {
|
|
||||||
let returnedData = {
|
|
||||||
[field]: {
|
|
||||||
id: foundPerson.id,
|
|
||||||
last_name: foundPerson.last_name,
|
|
||||||
first_name: foundPerson.first_name,
|
|
||||||
patronymic: foundPerson.patronymic,
|
|
||||||
color: foundPerson.color,
|
|
||||||
},
|
|
||||||
role: object.role,
|
|
||||||
};
|
|
||||||
if (object.id) returnedData.id = object.id;
|
|
||||||
return returnedData;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
async postCreateEvent(event) {
|
|
||||||
const response = await fetchWrapper.post("registry/event/create/", event);
|
|
||||||
if (response.type && response.type === "validation_error") {
|
|
||||||
this.addErrorNotification(
|
|
||||||
response.errors[0].code,
|
|
||||||
response.errors[0].detail
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.addSuccessNotification("Событие успешно создано");
|
|
||||||
//this.clearForm();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async postUpdateEvent(id, event) {
|
|
||||||
const response = await fetchWrapper.post(
|
|
||||||
`registry/event/${id}/update/`,
|
|
||||||
event
|
|
||||||
);
|
|
||||||
if (response.type && response.type === "validation_error") {
|
|
||||||
this.addErrorNotification(
|
|
||||||
response.errors[0].code,
|
|
||||||
response.errors[0].detail
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.addSuccessNotification("Изменения успешно сохранены");
|
|
||||||
//this.clearForm();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
personId(object, field) {
|
|
||||||
if (object) {
|
|
||||||
let foundPerson = {};
|
|
||||||
if (field === "employee") {
|
|
||||||
foundPerson = object.find(({ role }) => role === this.EMPLOYEE_TYPE);
|
|
||||||
}
|
|
||||||
if (field === "person") {
|
|
||||||
if (object.length > 1) {
|
|
||||||
foundPerson = object.find(({ role }) => role === this.MEMBER_TYPE);
|
|
||||||
}
|
|
||||||
foundPerson = object[0];
|
|
||||||
}
|
|
||||||
let {
|
|
||||||
[field]: { id },
|
|
||||||
} = foundPerson;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addErrorNotification(title, message) {
|
|
||||||
addNotification(title, title, message, "error", 5000);
|
|
||||||
},
|
|
||||||
addSuccessNotification(message) {
|
|
||||||
addNotification(new Date().getTime(), message, "", "success", 5000);
|
|
||||||
},
|
|
||||||
fetchMembersData() {
|
|
||||||
fetchWrapper
|
|
||||||
.get("general/person/?limit=200")
|
|
||||||
.then((res) => this.saveMembersData(res));
|
|
||||||
},
|
|
||||||
fetchOwnersData() {
|
|
||||||
fetchWrapper
|
|
||||||
.get(
|
|
||||||
`accounts/schedules/?date_after=${this.currentDate
|
|
||||||
.clone()
|
|
||||||
.subtract(1, "month")
|
|
||||||
.format("YYYY-MM-DD")}&date_before=${this.currentDate
|
|
||||||
.clone()
|
|
||||||
.add(1, "month")
|
|
||||||
.format("YYYY-MM-DD")}`
|
|
||||||
)
|
|
||||||
.then((res) => this.saveOwnersData(res));
|
|
||||||
},
|
|
||||||
saveOwnersData(res) {
|
|
||||||
let serializedList = [];
|
|
||||||
if (res.results.length === 0) {
|
|
||||||
this.ownersData = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.results.forEach((elem) => {
|
|
||||||
let foundedElem = serializedList.find(
|
|
||||||
(item) => item.id === elem.employee.id
|
|
||||||
);
|
|
||||||
if (!foundedElem) {
|
|
||||||
serializedList.push({
|
|
||||||
id: elem.employee.id,
|
|
||||||
last_name: elem.employee.last_name,
|
|
||||||
first_name: elem.employee.first_name,
|
|
||||||
patronymic: elem.employee.patronymic,
|
|
||||||
color: elem.employee.color,
|
|
||||||
schedules: [
|
|
||||||
{
|
|
||||||
date: elem.date,
|
|
||||||
end_time: elem.end_time?.slice(0, elem.end_time.length - 3),
|
|
||||||
start_time: elem.start_time?.slice(
|
|
||||||
0,
|
|
||||||
elem.start_time.length - 3
|
|
||||||
),
|
|
||||||
status: elem.status,
|
|
||||||
id: elem.id,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
foundedElem.schedules.push({
|
|
||||||
date: elem.date,
|
|
||||||
end_time: elem.end_time?.slice(0, elem.end_time.length - 3),
|
|
||||||
start_time: elem.start_time?.slice(0, elem.start_time.length - 3),
|
|
||||||
status: elem.status,
|
|
||||||
id: elem.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.ownersData = serializedList;
|
|
||||||
},
|
|
||||||
saveMembersData(res) {
|
|
||||||
this.membersData = res.results;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
startDate: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newDate) {
|
|
||||||
if (newDate) {
|
|
||||||
this.eventDate = newDate;
|
|
||||||
this.startTime = moment(newDate).format("HH:mm");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
endDate: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newDate) {
|
|
||||||
if (newDate) {
|
|
||||||
this.endTime = moment(newDate).format("HH:mm");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selectedEventData: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newDate) {
|
|
||||||
if (newDate) {
|
|
||||||
this.id = this.eventId;
|
|
||||||
this.status = this.eventStatus;
|
|
||||||
this.employees = this.eventEmployee;
|
|
||||||
this.members = this.eventMember;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
value(newValue) {
|
|
||||||
if (newValue === false) this.$emit("clear-event-data");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.fetchOwnersData();
|
|
||||||
this.fetchMembersData();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.event-form
|
|
||||||
width: 550px
|
|
||||||
|
|
||||||
.form-item
|
|
||||||
border-radius: 4px
|
|
||||||
width: 344px
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.date-input
|
|
||||||
width: 174px
|
|
||||||
border-radius: 4px
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.icon
|
|
||||||
width: 24px
|
|
||||||
height: 24px
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.close-icon
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
&:hover
|
|
||||||
color: var(--btn-blue-color)
|
|
||||||
|
|
||||||
.create-button
|
|
||||||
width: 183px
|
|
||||||
|
|
||||||
.select
|
|
||||||
border: 1.5px solid var(--border-light-grey-color)
|
|
||||||
border-radius: 4px
|
|
||||||
|
|
||||||
.update-button
|
|
||||||
width: 132px
|
|
||||||
</style>
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.calendar-header-wrapper.flex.items-center.justify-between.py-4.pl-4.pr-6
|
|
||||||
.flex.items-center
|
|
||||||
q-btn.mr-4(
|
|
||||||
color="secondary",
|
|
||||||
round,
|
|
||||||
size="14px",
|
|
||||||
dense,
|
|
||||||
icon="arrow_back_ios_new"
|
|
||||||
text-color="primary",
|
|
||||||
@click="previousHandler"
|
|
||||||
)
|
|
||||||
q-btn.mr-4(
|
|
||||||
color="secondary",
|
|
||||||
icon="arrow_forward_ios",
|
|
||||||
round,
|
|
||||||
size="14px",
|
|
||||||
text-color="primary",
|
|
||||||
dense,
|
|
||||||
@click="nextHandler"
|
|
||||||
)
|
|
||||||
.text.flex.items-center
|
|
||||||
span.font-medium.text-base {{ dateString }}
|
|
||||||
span.today.font-bold.text-xxs(v-if="isCurrentDate") Сегодня
|
|
||||||
//q-btn(
|
|
||||||
color="blue-grey-1",
|
|
||||||
round,
|
|
||||||
size="14px",
|
|
||||||
text-color="primary",
|
|
||||||
@click="previousHandler"
|
|
||||||
icon="arrow_back_ios_new"
|
|
||||||
//)
|
|
||||||
//.text.flex.items-center.mx-4
|
|
||||||
span.font-medium.text-base {{ dateString }}
|
|
||||||
span.today.font-bold.text-xxs(v-if="isCurrentDate") Сегодня
|
|
||||||
//q-btn(
|
|
||||||
color="blue-grey-1",
|
|
||||||
icon="arrow_forward_ios",
|
|
||||||
round,
|
|
||||||
size="14px",
|
|
||||||
text-color="primary",
|
|
||||||
@click="nextHandler"
|
|
||||||
//)
|
|
||||||
//.flex.gap-x-4.ml-5.border-2.border-green-600.bg-lime-200.items-center
|
|
||||||
.w-120.h-10.flex.items-center {{ date }}
|
|
||||||
base-date-picker(v-model="date")
|
|
||||||
calendar-layout-switch(@selected="changeSelectedLayout")
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CalendarLayoutSwitch from "./CalendarLayoutSwitch.vue";
|
|
||||||
//import BaseDatePicker from "@/components/base/BaseDatePicker.vue";
|
|
||||||
export default {
|
|
||||||
name: "CalendarHeader",
|
|
||||||
components: { CalendarLayoutSwitch },
|
|
||||||
props: {
|
|
||||||
currentDate: Object,
|
|
||||||
isCurrentDate: Boolean,
|
|
||||||
},
|
|
||||||
/*data() {
|
|
||||||
return {
|
|
||||||
date: new Date(),
|
|
||||||
};
|
|
||||||
},*/
|
|
||||||
computed: {
|
|
||||||
dateString() {
|
|
||||||
let newStr = this.currentDate.format("D MMMM YYYY");
|
|
||||||
return newStr
|
|
||||||
.split(" ")
|
|
||||||
.map((elem, index) => {
|
|
||||||
if (index === 1) return elem[0].toUpperCase() + elem.slice(1);
|
|
||||||
return elem;
|
|
||||||
})
|
|
||||||
.join(" ");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeSelectedLayout(option) {
|
|
||||||
this.$emit("selected-layout", option);
|
|
||||||
},
|
|
||||||
previousHandler() {
|
|
||||||
this.$emit("previous-date");
|
|
||||||
},
|
|
||||||
nextHandler() {
|
|
||||||
this.$emit("next-date");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.calendar-header-wrapper
|
|
||||||
width: 100%
|
|
||||||
background-color: var(--default-white)
|
|
||||||
height: 72px
|
|
||||||
border-radius: 4px
|
|
||||||
z-index: 10
|
|
||||||
|
|
||||||
.left-arrow
|
|
||||||
padding: 3px 4px 0 4px !important
|
|
||||||
transform: rotate(90deg)
|
|
||||||
|
|
||||||
.right-arrow
|
|
||||||
padding: 3px 4px 0 4px !important
|
|
||||||
transform: rotate(270deg)
|
|
||||||
|
|
||||||
.text
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
|
|
||||||
.today
|
|
||||||
opacity: 0.5
|
|
||||||
|
|
||||||
.bg-blue-grey-1
|
|
||||||
background: var(--bg-light-grey) !important
|
|
||||||
|
|
||||||
//.text-primary
|
|
||||||
// color: var(--font-dark-blue-color-0) !important
|
|
||||||
|
|
||||||
.q-btn--round
|
|
||||||
width: 32px !important
|
|
||||||
height: 32px !important
|
|
||||||
min-width: 32px !important
|
|
||||||
min-height: 32px !important
|
|
||||||
</style>
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.layout-switch-wrapper.flex.h-10.p-1
|
|
||||||
button#day.flex.items-center.px-3.transition.duration-200.ease-linear(
|
|
||||||
:class="dayLayoutState",
|
|
||||||
@click="changeSelectedLayout"
|
|
||||||
) День
|
|
||||||
button#week.flex.items-center.px-3.transition.duration-200.ease-linear(
|
|
||||||
:class="weekLayoutState",
|
|
||||||
@click="changeSelectedLayout"
|
|
||||||
) Неделя
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "CalendarLayoutSwitch",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
selectedLayout: "day",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
dayLayoutState() {
|
|
||||||
return {
|
|
||||||
active: this.selectedLayout === "day",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
weekLayoutState() {
|
|
||||||
return {
|
|
||||||
active: this.selectedLayout === "week",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeSelectedLayout(event) {
|
|
||||||
this.selectedLayout = event.target.id;
|
|
||||||
this.$emit("selected", event.target.id);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.active
|
|
||||||
background-color: var(--bg-aqua-blue)
|
|
||||||
color: var(--default-white)
|
|
||||||
border-radius: 4px
|
|
||||||
|
|
||||||
.layout-switch-wrapper
|
|
||||||
background-color: var(--bg-light-grey)
|
|
||||||
color: var(--font-grey-color)
|
|
||||||
border-radius: 4px
|
|
||||||
</style>
|
|
||||||
@@ -1,424 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.schedule.mx-2.pb-22px(
|
|
||||||
ref="schedule",
|
|
||||||
:style="scheduleWidth"
|
|
||||||
)
|
|
||||||
calendar-header(
|
|
||||||
:current-date="currentDate",
|
|
||||||
:is-current-date="isCurrentDate",
|
|
||||||
@previous-date="previousDate",
|
|
||||||
@next-date="nextDate",
|
|
||||||
@selected-layout="selectedLayout"
|
|
||||||
)
|
|
||||||
.schedule-body(
|
|
||||||
@scroll="changeScrollingState",
|
|
||||||
ref="scheduleBody"
|
|
||||||
)
|
|
||||||
.hiding-container.fixed(v-if="isScrolling")
|
|
||||||
.column-wrapper.flex.ml-20(:style="columnWrapperWidth")
|
|
||||||
calendar-column(
|
|
||||||
v-for="(owner, index) in filteredOwners",
|
|
||||||
:key="owner.id",
|
|
||||||
:owner-data="owner",
|
|
||||||
:url="url",
|
|
||||||
:day-events="filterEventsByOwner(owner)",
|
|
||||||
:day-start-time="validateStartTime",
|
|
||||||
:day-end-time="validateEndTime",
|
|
||||||
:style="columnSize",
|
|
||||||
:event-statuses="eventStatuses",
|
|
||||||
@selected-event="transmitEventData",
|
|
||||||
@delete-event="transmitDeleteEvent",
|
|
||||||
:schedule-body-ref="$refs.scheduleBody",
|
|
||||||
:open-form-create-event="openFormCreateEvent",
|
|
||||||
:current-date="currentDate"
|
|
||||||
)
|
|
||||||
.flex.w-full.relative
|
|
||||||
.time-coil-wrapper.left-0.-mt-12.pt-9
|
|
||||||
calendar-clock-column(
|
|
||||||
:timeCoil="timeCoil",
|
|
||||||
:current-time="currentTime",
|
|
||||||
:is-current-date="isCurrentDate",
|
|
||||||
:day-end-time="validateEndTime"
|
|
||||||
)
|
|
||||||
.time-circle-indicator.left-74px(
|
|
||||||
v-if="isShownIndicator",
|
|
||||||
:style="circleIndicatorLocation"
|
|
||||||
)
|
|
||||||
span.time-line-indicator.block.left-20(
|
|
||||||
v-if="isShownIndicator",
|
|
||||||
:style="lineIndicatorLocation"
|
|
||||||
)
|
|
||||||
.flex(:class="calendarBackgroundWidth")
|
|
||||||
calendar-background(
|
|
||||||
:time-coil="timeCoil",
|
|
||||||
:owners-count="ownersCount"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import * as moment from "moment/moment";
|
|
||||||
import CalendarHeader from "./CalendarHeader.vue";
|
|
||||||
import CalendarBackground from "./CalendarBackground.vue";
|
|
||||||
import CalendarClockColumn from "./CalendarClockColumn.vue";
|
|
||||||
import CalendarColumn from "./CalendarColumn.vue";
|
|
||||||
export default {
|
|
||||||
name: "CalendarSchedule",
|
|
||||||
components: {
|
|
||||||
CalendarHeader,
|
|
||||||
CalendarBackground,
|
|
||||||
CalendarClockColumn,
|
|
||||||
CalendarColumn,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
openFormCreateEvent: Function,
|
|
||||||
url: String,
|
|
||||||
//changeFormWasClosed: Boolean,
|
|
||||||
currentDate: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
timeInformation: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eventsData: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sidebarWidth: String,
|
|
||||||
schedulesData: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eventStatuses: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
currentTime: "",
|
|
||||||
timeCoil: [],
|
|
||||||
timer: null,
|
|
||||||
isCurrentDate: true,
|
|
||||||
isShownIndicator: true,
|
|
||||||
pixelsPerHour: 62,
|
|
||||||
columnHeaderHeight: 48,
|
|
||||||
defaultColumnWidth: 470,
|
|
||||||
isScrolling: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
hours() {
|
|
||||||
return this.convertTime(this.currentTime, 0, -6);
|
|
||||||
},
|
|
||||||
minutes() {
|
|
||||||
return this.convertTime(this.currentTime, 3, -3);
|
|
||||||
},
|
|
||||||
hoursMinutes() {
|
|
||||||
return this.currentTime.slice(0, -3);
|
|
||||||
},
|
|
||||||
validateStartTime() {
|
|
||||||
return this.verifyTime(this.timeInformation.dayStartTime);
|
|
||||||
},
|
|
||||||
validateEndTime() {
|
|
||||||
return this.verifyTime(this.timeInformation.dayEndTime);
|
|
||||||
},
|
|
||||||
lineIndicatorLocation() {
|
|
||||||
if (this.ownersCount > 3) {
|
|
||||||
return {
|
|
||||||
width: `${this.defaultColumnWidth * this.ownersCount}px`,
|
|
||||||
top: `${this.calculateIndicatorLocation()}px`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
width: "calc(100% - 80px)",
|
|
||||||
top: `${this.calculateIndicatorLocation()}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
circleIndicatorLocation() {
|
|
||||||
return {
|
|
||||||
top: `${this.calculateIndicatorLocation() + 42}px`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
pixelsPerMinute() {
|
|
||||||
return this.pixelsPerHour / 60;
|
|
||||||
},
|
|
||||||
scheduleHeight() {
|
|
||||||
return (
|
|
||||||
(this.validateEndTime - this.validateStartTime) * this.pixelsPerHour
|
|
||||||
);
|
|
||||||
},
|
|
||||||
scheduleWidth() {
|
|
||||||
return {
|
|
||||||
"--sidebar-width": this.sidebarWidth,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
filteredOwners() {
|
|
||||||
let filteredArray = [];
|
|
||||||
this.schedulesData.forEach((elem) => {
|
|
||||||
filteredArray.push({
|
|
||||||
id: elem.employee?.id,
|
|
||||||
last_name: elem.employee?.last_name,
|
|
||||||
first_name: elem.employee?.first_name,
|
|
||||||
patronymic: elem.employee?.patronymic,
|
|
||||||
color: elem.employee?.color,
|
|
||||||
photo: elem.employee?.photo,
|
|
||||||
end_time: elem.end_time?.slice(0, elem.end_time.length - 3),
|
|
||||||
start_time: elem.start_time?.slice(0, elem.start_time.length - 3),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return filteredArray;
|
|
||||||
},
|
|
||||||
ownersCount() {
|
|
||||||
return this.filteredOwners.length;
|
|
||||||
},
|
|
||||||
columnHeight() {
|
|
||||||
return (
|
|
||||||
(this.timeCoil.length - 1) * this.pixelsPerHour +
|
|
||||||
this.columnHeaderHeight
|
|
||||||
);
|
|
||||||
},
|
|
||||||
columnSize() {
|
|
||||||
if (this.ownersCount > 3) {
|
|
||||||
return {
|
|
||||||
height: `${this.columnHeight}px`,
|
|
||||||
width: `${this.defaultColumnWidth}px`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
height: `${this.columnHeight}px`,
|
|
||||||
width: `calc(100% / ${this.ownersCount})`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
columnWrapperWidth() {
|
|
||||||
if (this.ownersCount > 3) {
|
|
||||||
return {
|
|
||||||
width: `${this.defaultColumnWidth * this.ownersCount}px`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
width: "calc(100% - 80px)",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
calendarBackgroundWidth() {
|
|
||||||
return {
|
|
||||||
"w-full": this.ownersCount <= 3,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
previousDate() {
|
|
||||||
this.$emit("previous-date");
|
|
||||||
},
|
|
||||||
nextDate() {
|
|
||||||
this.$emit("next-date");
|
|
||||||
},
|
|
||||||
selectedLayout(option) {
|
|
||||||
this.$emit("selected-layout", option);
|
|
||||||
},
|
|
||||||
startTimer() {
|
|
||||||
if (
|
|
||||||
this.hours >= this.validateStartTime &&
|
|
||||||
this.hours < this.validateEndTime
|
|
||||||
) {
|
|
||||||
this.timer = setInterval(() => {
|
|
||||||
this.changeCurrentTime();
|
|
||||||
this.changeTimeCoil();
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stopTimer() {
|
|
||||||
clearInterval(this.timer);
|
|
||||||
this.timer = null;
|
|
||||||
},
|
|
||||||
changeCurrentTime() {
|
|
||||||
this.currentTime = moment().format("HH:mm:ss");
|
|
||||||
},
|
|
||||||
timeCoilInitialization() {
|
|
||||||
this.timeCoil = [];
|
|
||||||
for (let i = this.validateStartTime; i <= this.validateEndTime; i++) {
|
|
||||||
if (
|
|
||||||
i === this.hours &&
|
|
||||||
this.hours !== this.validateEndTime &&
|
|
||||||
this.isCurrentDate
|
|
||||||
) {
|
|
||||||
this.timeCoil.push(this.hoursMinutes);
|
|
||||||
} else this.timeCoil.push(`${i}:00`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
changeTimeCoil() {
|
|
||||||
this.timeCoil = this.timeCoil.map((elem) => {
|
|
||||||
if (this.convertTime(elem, 0, -3) === this.hours) {
|
|
||||||
return this.hoursMinutes;
|
|
||||||
}
|
|
||||||
return elem.slice(0, -3) + ":00";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
verifyTime(dayTime) {
|
|
||||||
let timeArray = dayTime.split(":").map((elem) => parseInt(elem, 10));
|
|
||||||
let newTime = timeArray[1] > 30 ? timeArray[0] + 1 : timeArray[0];
|
|
||||||
return newTime;
|
|
||||||
},
|
|
||||||
convertTime(str, startIndex, endIndex) {
|
|
||||||
return parseInt(str.slice(startIndex, endIndex), 10);
|
|
||||||
},
|
|
||||||
calculateIndicatorLocation() {
|
|
||||||
let newTime = this.currentTime
|
|
||||||
.split(":")
|
|
||||||
.map((elem) => parseInt(elem, 10));
|
|
||||||
let result =
|
|
||||||
(newTime[0] - this.validateStartTime) * this.pixelsPerHour +
|
|
||||||
newTime[1] * this.pixelsPerMinute;
|
|
||||||
if (result > this.scheduleHeight || result < 0) {
|
|
||||||
this.isShownIndicator = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
findObjectInArray(array, object) {
|
|
||||||
return array.find(
|
|
||||||
(item) => JSON.stringify(item) === JSON.stringify(object)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
filterEventsByOwner(owner) {
|
|
||||||
let filteredArray = [];
|
|
||||||
this.eventsData.forEach((item) => {
|
|
||||||
let foundEvent = item.employees.find(
|
|
||||||
(elem) => elem.employee.id === owner.id && elem.role === "owner"
|
|
||||||
);
|
|
||||||
if (foundEvent) filteredArray.push(item);
|
|
||||||
});
|
|
||||||
return filteredArray;
|
|
||||||
},
|
|
||||||
changeScrollingState(e) {
|
|
||||||
this.isScrolling = e.target.scrollTop !== 0;
|
|
||||||
},
|
|
||||||
showCuttentTime() {
|
|
||||||
this.$nextTick(() =>
|
|
||||||
this.$refs["scheduleBody"].scrollTo({
|
|
||||||
top: `${this.lineIndicatorLocation.top.slice(0, -2) - 240}`,
|
|
||||||
behavior: "smooth",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
/*transmitResetChangeForm() {
|
|
||||||
this.$emit("reset-change-form");
|
|
||||||
},*/
|
|
||||||
transmitEventData(eventData) {
|
|
||||||
this.$emit("selected-event", eventData);
|
|
||||||
},
|
|
||||||
transmitDeleteEvent(eventData) {
|
|
||||||
this.$emit("delete-event", eventData);
|
|
||||||
},
|
|
||||||
bodyScroll() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
let presenceScroll =
|
|
||||||
this.$refs["scheduleBody"].scrollHeight !==
|
|
||||||
this.$refs["scheduleBody"].clientHeight;
|
|
||||||
if (presenceScroll) {
|
|
||||||
this.$refs["scheduleBody"].classList.add("pr-10px");
|
|
||||||
this.$refs["schedule"].classList.add("pr-10px");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
currentTime() {
|
|
||||||
if (
|
|
||||||
this.hours === this.validateEndTime &&
|
|
||||||
this.minutes > 0 &&
|
|
||||||
this.timer
|
|
||||||
) {
|
|
||||||
this.stopTimer();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentDate: function () {
|
|
||||||
this.isCurrentDate =
|
|
||||||
this.currentDate.format("DD.MM.YYYY") === moment().format("DD.MM.YYYY");
|
|
||||||
this.isShownIndicator = this.isCurrentDate;
|
|
||||||
if (this.timer) {
|
|
||||||
this.stopTimer();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
}
|
|
||||||
if (this.isCurrentDate) {
|
|
||||||
this.changeCurrentTime();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
this.startTimer();
|
|
||||||
this.showCuttentTime();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.changeCurrentTime();
|
|
||||||
this.timeCoilInitialization();
|
|
||||||
this.startTimer();
|
|
||||||
this.showCuttentTime();
|
|
||||||
this.bodyScroll();
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
this.stopTimer();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.schedule
|
|
||||||
border-top-left-radius: 4px
|
|
||||||
border-top-right-radius: 4px
|
|
||||||
position: relative
|
|
||||||
background-color: var(--default-white)
|
|
||||||
width: calc(100% - (var(--sidebar-width) + 16px))
|
|
||||||
height: calc(100vh - 56px - 8px)
|
|
||||||
|
|
||||||
.time-line-indicator
|
|
||||||
border-top: 1px solid var(--bg-event-red-color)
|
|
||||||
position: absolute
|
|
||||||
z-index: 4
|
|
||||||
|
|
||||||
.time-circle-indicator
|
|
||||||
width: 12px
|
|
||||||
height: 12px
|
|
||||||
background-color: var(--bg-event-red-color)
|
|
||||||
border-radius: 50%
|
|
||||||
position: absolute
|
|
||||||
z-index: 5
|
|
||||||
|
|
||||||
.column-wrapper
|
|
||||||
position: relative
|
|
||||||
height: 48px
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.time-coil-wrapper
|
|
||||||
position: sticky
|
|
||||||
z-index: 5
|
|
||||||
background-color: var(--default-white)
|
|
||||||
|
|
||||||
.schedule-body
|
|
||||||
width: 100%
|
|
||||||
height: calc(100vh - 56px * 2 - 8px - 22px)
|
|
||||||
overflow-y: auto
|
|
||||||
overflow-x: auto
|
|
||||||
&::-webkit-scrollbar-track:horizontal
|
|
||||||
margin: 0 24px 0 104px
|
|
||||||
&::-webkit-scrollbar-track:vertical
|
|
||||||
margin: 48px 0 24px 0
|
|
||||||
|
|
||||||
.hiding-container
|
|
||||||
width: 80px
|
|
||||||
height: 48px
|
|
||||||
top: calc(56px * 2 + 8px)
|
|
||||||
background-color: var(--default-white)
|
|
||||||
z-index: 6
|
|
||||||
</style>
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.sidebar.flex.flex-col.bg-white(:class="openSidebar")
|
|
||||||
.sidebar-wrapper.h-full.my-13px.flex.flex-col.justify-between(:style="sidebarWidth")
|
|
||||||
.sidebar-content.items-center.flex.flex-col.gap-y-8.px-4.py-19px
|
|
||||||
q-btn(
|
|
||||||
color="primary",
|
|
||||||
round,
|
|
||||||
icon="add",
|
|
||||||
size="13px",
|
|
||||||
@click="openFormCreate",
|
|
||||||
v-if="!isOpen"
|
|
||||||
)
|
|
||||||
q-btn(
|
|
||||||
no-caps
|
|
||||||
label="Создать событие",
|
|
||||||
color="primary",
|
|
||||||
class="text-weight-medium, full-width",
|
|
||||||
icon-right="add",
|
|
||||||
@click="openFormCreate",
|
|
||||||
v-else
|
|
||||||
)
|
|
||||||
calendar-sidebar-event(:is-open="isOpen", :event-statuses="eventStatuses")
|
|
||||||
calendar-sidebar-teammate(:team-data="teamData", :is-open="isOpen", :url="url")
|
|
||||||
//.button-wrapper.flex.justify-center.mb-23px
|
|
||||||
q-btn(
|
|
||||||
round,
|
|
||||||
icon="app:icon-long-arrow",
|
|
||||||
size="13px",
|
|
||||||
color="secondary",
|
|
||||||
text-color="primary"
|
|
||||||
:style="{ transform: `rotate(${turnButton})`}",
|
|
||||||
@click="changeSize",
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CalendarSidebarEvent from "./CalendarSidebarEvent.vue";
|
|
||||||
import CalendarSidebarTeammate from "./CalendarSidebarTeammate.vue";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "CalendarSidebar",
|
|
||||||
components: {
|
|
||||||
CalendarSidebarEvent,
|
|
||||||
CalendarSidebarTeammate,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
schedulesData: Array,
|
|
||||||
openFormCreate: Function,
|
|
||||||
eventStatuses: Array,
|
|
||||||
url: String,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
widthSidebarOpen: "232px",
|
|
||||||
widthSidebarClose: "72px",
|
|
||||||
isOpen: false,
|
|
||||||
turnButton: "180deg",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
openSidebar() {
|
|
||||||
return {
|
|
||||||
"open-sidebar": this.isOpen,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
sidebarWidth() {
|
|
||||||
if (this.isOpen) {
|
|
||||||
return {
|
|
||||||
width: this.widthSidebarOpen,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
width: this.widthSidebarClose,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
teamData() {
|
|
||||||
if (this.schedulesData.length === 0) return [];
|
|
||||||
return this.schedulesData.map((elem) => elem.employee);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeSize() {
|
|
||||||
this.isOpen = !this.isOpen;
|
|
||||||
this.$emit(
|
|
||||||
"width",
|
|
||||||
this.isOpen ? this.widthSidebarOpen : this.widthSidebarClose
|
|
||||||
);
|
|
||||||
this.turnButton = this.isOpen ? "0deg" : "180deg";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.sidebar
|
|
||||||
border-top-right-radius: 4px
|
|
||||||
|
|
||||||
.sidebar-wrapper
|
|
||||||
border-left: 2px solid var(--btn-blue-color-3)
|
|
||||||
|
|
||||||
.open-sidebar
|
|
||||||
.sidebar-content
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
row-gap: 32px
|
|
||||||
padding: 19px 16px
|
|
||||||
align-items: center
|
|
||||||
width: 232px
|
|
||||||
|
|
||||||
.button-wrapper
|
|
||||||
justify-content: end
|
|
||||||
padding-right: 16px
|
|
||||||
</style>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.flex.flex-col.items-center.w-full
|
|
||||||
.flex.flex-col.items-center(v-if="!isOpen")
|
|
||||||
q-btn(
|
|
||||||
round,
|
|
||||||
icon="add",
|
|
||||||
size="12px",
|
|
||||||
text-color="primary",
|
|
||||||
color="secondary"
|
|
||||||
padding="4px",
|
|
||||||
dense
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-y-2.items-center.mt-4
|
|
||||||
.event.flex.items-center.justify-center(v-for="event in eventStatuses" :key="event.id")
|
|
||||||
.event-type(:style="{ background: event.color }")
|
|
||||||
.flex.flex-col.gap-y-4.w-full(v-else)
|
|
||||||
.flex.items-center.justify-between
|
|
||||||
.flex.text-base.font-bold(:style="{ color: 'var(--font-dark-blue-color)' }") Виды событий
|
|
||||||
q-btn(
|
|
||||||
v-if="isOpen",
|
|
||||||
round,
|
|
||||||
icon="add",
|
|
||||||
size="12px",
|
|
||||||
text-color="primary",
|
|
||||||
color="secondary"
|
|
||||||
padding="4px"
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-y-2
|
|
||||||
.relative.flex.items-center.gap-x-3.h-8(v-for="event in eventStatuses")
|
|
||||||
input.custom-input.py-2.pl-6.h-full.not-italic.font-medium.text-xxs(
|
|
||||||
:placeholder="event.label"
|
|
||||||
:key="event.id"
|
|
||||||
)
|
|
||||||
.event-open(:style="{ background: event.color }")
|
|
||||||
span.icon-edit.cursor-pointer
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "CalendarSidebarEvent",
|
|
||||||
props: {
|
|
||||||
isOpen: Boolean,
|
|
||||||
eventStatuses: Array,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.event
|
|
||||||
width: 32px
|
|
||||||
height: 32px
|
|
||||||
background: var(--btn-blue-sec-color)
|
|
||||||
border-radius: 4px
|
|
||||||
|
|
||||||
.event-type
|
|
||||||
width: 16px
|
|
||||||
height: 16px
|
|
||||||
border-radius: 2px
|
|
||||||
|
|
||||||
.custom-input
|
|
||||||
padding-top: 9px
|
|
||||||
padding-left: 24px
|
|
||||||
border: none
|
|
||||||
border-radius: 4px
|
|
||||||
width: 169px
|
|
||||||
outline: none
|
|
||||||
background-color: var(--btn-blue-sec-color)
|
|
||||||
&::placeholder
|
|
||||||
color: var(--font-dark-blue-color)
|
|
||||||
&:focus
|
|
||||||
background-color: var(--font-dark-blue-color)
|
|
||||||
color: var(--default-white)
|
|
||||||
&::placeholder
|
|
||||||
color: var(--default-white)
|
|
||||||
|
|
||||||
.event-open
|
|
||||||
position: absolute
|
|
||||||
width: 8px
|
|
||||||
height: 16px
|
|
||||||
top: 8px
|
|
||||||
left: 8px
|
|
||||||
</style>
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.flex.flex-col.items-center.gap-y-2.justify-center(v-if="!isOpen")
|
|
||||||
q-btn(
|
|
||||||
round,
|
|
||||||
icon="add",
|
|
||||||
size="12px",
|
|
||||||
text-color="primary",
|
|
||||||
color="secondary"
|
|
||||||
padding="4px",
|
|
||||||
dense
|
|
||||||
)
|
|
||||||
.team-card(v-for="teammate in teamData" :key="teammate.id")
|
|
||||||
base-avatar(:size="32", :color="teammate.color")
|
|
||||||
img.h-full.object-cover(:src="url + teammate.photo", alt="Team member", v-if="teammate.photo")
|
|
||||||
span(v-if="!teammate.photo") {{teammateAvatar(teammate)}}
|
|
||||||
.flex.flex-col.gap-y-4.w-full(v-else, :style="{ color: 'var(--font-dark-blue-color)' }")
|
|
||||||
.flex.items-center.justify-between
|
|
||||||
.flex.text-base.font-bold Команды
|
|
||||||
q-btn(
|
|
||||||
round,
|
|
||||||
icon="add",
|
|
||||||
size="12px",
|
|
||||||
text-color="primary",
|
|
||||||
color="secondary"
|
|
||||||
padding="4px",
|
|
||||||
dense
|
|
||||||
)
|
|
||||||
.box-team.flex.flex-col.gap-y-2
|
|
||||||
.team-card.flex.items-center.justify-between.cursor-pointer(
|
|
||||||
v-for="teammate in teamData",
|
|
||||||
:key="teammate.id"
|
|
||||||
)
|
|
||||||
.flex.items-center
|
|
||||||
base-avatar(:size="32", :color="teammate.color")
|
|
||||||
img.h-full.object-cover(:src="url + teammate.photo", alt="Team member", v-if="teammate.photo")
|
|
||||||
span(v-if="!teammate.photo") {{teammateAvatar(teammate)}}
|
|
||||||
.flex.ml-2.not-italic.font-medium.text-xxs {{ changeName(teammate.last_name, teammate.first_name, teammate.patronymic) }}
|
|
||||||
span.icon-change-place.cursor-pointer.w-5.flex.items-center.justify-center.w-6.h-6
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import BaseAvatar from "@/components/base/BaseAvatar";
|
|
||||||
export default {
|
|
||||||
name: "CalendarSidebarTeammate",
|
|
||||||
props: {
|
|
||||||
teamData: Array,
|
|
||||||
isOpen: Boolean,
|
|
||||||
url: String,
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
BaseAvatar,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
maxLengthLastName: 13,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeName(lastName, firstName, patronymic) {
|
|
||||||
let checkedFirstName = firstName !== null ? firstName[0] + "." : "";
|
|
||||||
let checkedPatronymic = patronymic !== null ? patronymic[0] + "." : "";
|
|
||||||
return lastName.length > this.maxLengthLastName
|
|
||||||
? lastName.slice(0, this.maxLengthLastName) +
|
|
||||||
"... " +
|
|
||||||
checkedFirstName +
|
|
||||||
checkedPatronymic
|
|
||||||
: lastName + " " + checkedFirstName + checkedPatronymic;
|
|
||||||
},
|
|
||||||
teammateAvatar(teammate) {
|
|
||||||
let checkedFirstName =
|
|
||||||
teammate.first_name !== null
|
|
||||||
? teammate.first_name[0]
|
|
||||||
: teammate.last_name[1];
|
|
||||||
return `${teammate.last_name[0]}${checkedFirstName}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.team-card
|
|
||||||
border-radius: 16px
|
|
||||||
&:hover
|
|
||||||
background: var(--font-dark-blue-color)
|
|
||||||
color: var(--default-white)
|
|
||||||
</style>
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
export const statusesConfig = [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
label: "Планируется прием",
|
|
||||||
value: "PLANNED",
|
|
||||||
color: "var(--default-white)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
label: "Отменил",
|
|
||||||
value: "CANCELED",
|
|
||||||
color: "var(--bg-event-grey-color)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
label: "Ожидается прием",
|
|
||||||
value: "EXPECTED",
|
|
||||||
color: "var(--bg-event-yellow-color)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
label: "Опаздывает",
|
|
||||||
value: "LATE",
|
|
||||||
color: "var(--bg-event-orange-color)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
label: "Идет прием",
|
|
||||||
value: "RECEPTION",
|
|
||||||
color: "var(--bg-event-blue-color)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
label: "Прием завершен",
|
|
||||||
value: "COMPLETED",
|
|
||||||
color: "var(--bg-event-green-color)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
label: "Не пришел",
|
|
||||||
value: "DID_NOT_COME",
|
|
||||||
color: "var(--bg-event-red-color)",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
medical-card-wrapper
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import MedicalCardWrapper from "@/pages/oldMedicalCard/components/MedicalCardWrapper";
|
|
||||||
export default {
|
|
||||||
name: "TheMedicalCard",
|
|
||||||
components: { MedicalCardWrapper },
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped></style>
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.base.flex.flex-col.gap-y-6
|
|
||||||
.flex.flex-col.gap-y-6
|
|
||||||
span.font-bold Основное
|
|
||||||
.flex.flex-col.gap-y-6
|
|
||||||
base-input.w-full(
|
|
||||||
placeholder="ФИО*",
|
|
||||||
v-model="clientDetail.fullName",
|
|
||||||
disabled,
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-radio-buttons-group(
|
|
||||||
:items="gendersList",
|
|
||||||
radioButtonsLabel="Пол",
|
|
||||||
v-model="clientDetail.gender",
|
|
||||||
inline
|
|
||||||
)
|
|
||||||
.flex.gap-x-4
|
|
||||||
.input
|
|
||||||
base-input(
|
|
||||||
type="date",
|
|
||||||
label="Дата рождения",
|
|
||||||
v-model="clientDetail.birth_date",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.input
|
|
||||||
base-input(
|
|
||||||
placeholder="000–000–000 00",
|
|
||||||
mask="###-###-### ##",
|
|
||||||
label="СНИЛС",
|
|
||||||
v-model="clientDetail.insurance_number",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-y-6
|
|
||||||
base-input(
|
|
||||||
label="Адрес регистрации",
|
|
||||||
placeholder="Введите полный адрес",
|
|
||||||
v-model="clientDetail.registration_address"
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
label="Фактический адрес места жительства",
|
|
||||||
placeholder="Введите полный адрес",
|
|
||||||
v-model="clientDetail.temporary_address"
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.flex.gap-x-4
|
|
||||||
.input
|
|
||||||
base-input(
|
|
||||||
label="Номер телефона",
|
|
||||||
placeholder="+7 (915) 644–92–23",
|
|
||||||
mask="+7 (###) ###-##-##",
|
|
||||||
v-model="clientDetail.phone",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.input
|
|
||||||
base-input(
|
|
||||||
label="Email",
|
|
||||||
placeholder="user@yandex.ru"
|
|
||||||
v-model="clientDetail.email",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import BaseInput from "@/components/base/BaseInput";
|
|
||||||
import BaseSelect from "@/components/base/BaseSelect";
|
|
||||||
import BaseRadioButtonsGroup from "@/components/base/BaseRadioButtonsGroup.vue";
|
|
||||||
import { medicalDetailConfig } from "@/pages/oldMedicalCard/utils/medicalConfig.js";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "MedicalBaseData",
|
|
||||||
components: {
|
|
||||||
BaseInput,
|
|
||||||
BaseSelect,
|
|
||||||
BaseRadioButtonsGroup,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
clientDetail: Object,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
gendersList() {
|
|
||||||
return medicalDetailConfig.gendersList;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.input
|
|
||||||
width: 277px
|
|
||||||
</style>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.flex.w-full
|
|
||||||
.flex.w-full.text-lgx.font-bold.items-center.justify-center Медицинская карта №{{numberCard}}
|
|
||||||
.flex.h-10.gap-x-2
|
|
||||||
q-btn(
|
|
||||||
outline,
|
|
||||||
icon="icon-download",
|
|
||||||
color="primary",
|
|
||||||
size="12px",
|
|
||||||
padding="8px 24px",
|
|
||||||
)
|
|
||||||
q-btn(
|
|
||||||
color="primary",
|
|
||||||
icon="add",
|
|
||||||
label="Создать",
|
|
||||||
style="width: 146px"
|
|
||||||
padding="6px 24px",
|
|
||||||
no-caps
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "MedicalCardHeader",
|
|
||||||
props: {
|
|
||||||
numberCard: String,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,429 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.wrapper.flex.w-full.relative.mx-2
|
|
||||||
.wrapper-medical.relative.flex.gap-y-4.flex-col.h-full.w-full( class="pb-52px")
|
|
||||||
.card-upper.flex.flex-col.gap-y-4.px-6.py-6
|
|
||||||
medical-card-header(:number-card="numberCard")
|
|
||||||
.card-basic-info.flex
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.identity_document.title"
|
|
||||||
:height="configData.identity_document.height"
|
|
||||||
:data="defineEmptyData(configData.identity_document.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.identity_document.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
:mask="field.mask"
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-30px
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.registration_address.title"
|
|
||||||
:height="configData.registration_address.height"
|
|
||||||
:data="defineEmptyData(configData.registration_address.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.registration_address.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
)
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.temporary_address.title"
|
|
||||||
:height="configData.temporary_address.height"
|
|
||||||
:data="defineEmptyData(configData.temporary_address.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.temporary_address.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-2
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.snils.title"
|
|
||||||
:height="configData.snils.height"
|
|
||||||
:data="defineEmptyData(configData.snils.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.snils.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
:mask="field.mask"
|
|
||||||
)
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.policy.title"
|
|
||||||
:height="configData.policy.height"
|
|
||||||
:data="defineEmptyData(configData.policy.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.policy.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
:mask="field.mask"
|
|
||||||
)
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.policy_organization.title"
|
|
||||||
:height="configData.policy_organization.height"
|
|
||||||
:data="defineEmptyData(configData.policy_organization.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.policy_organization.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-4
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.additional.title"
|
|
||||||
:height="configData.additional.height"
|
|
||||||
:data="defineEmptyData(configData.additional.fields)"
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.additional.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
:mask="field.mask"
|
|
||||||
)
|
|
||||||
base-detail-info(
|
|
||||||
:title="configData.agreement_form.title"
|
|
||||||
:height="configData.agreement_form.height"
|
|
||||||
:data="defineEmptyData(configData.agreement_form.fields)"
|
|
||||||
direction-row
|
|
||||||
)
|
|
||||||
base-detail-input(
|
|
||||||
v-for="field in configData.agreement_form.fields"
|
|
||||||
:field="field"
|
|
||||||
:data="medicalDataInit"
|
|
||||||
)
|
|
||||||
.flex.flex-col(class="px-92px gap-y-60px")
|
|
||||||
.flex.flex-col(class="gap-y-2.5")
|
|
||||||
.flex.flex-col.gap-y-2(v-for="(key, index) in Object.keys(dentalIndications)")
|
|
||||||
span.font-bold.text-xsx {{`${index+1}. ${configData.dental_indications[key]}`}}
|
|
||||||
medical-dental-formula(v-if="key === 'dental_formula'" :formula-data="dentalIndications[key]")
|
|
||||||
base-input(v-model="dentalIndications[key]", v-else, size="M")
|
|
||||||
.flex.justify-center
|
|
||||||
q-btn(
|
|
||||||
@click="validateFormCard",
|
|
||||||
color="primary",
|
|
||||||
label="Сохранить",
|
|
||||||
padding="8px 24px",
|
|
||||||
no-caps
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import MedicalCardHeader from "@/pages/oldMedicalCard/components/MedicalCardHeader.vue";
|
|
||||||
import MedicalDentalFormula from "@/pages/oldMedicalCard/components/MedicalDentalFormula.vue";
|
|
||||||
import BaseDetailInput from "@/components/base/BaseDetailInput.vue";
|
|
||||||
import BaseDetailInfo from "@/components/base/BaseDetailInfo.vue";
|
|
||||||
import { formulaDataMap } from "@/pages/oldMedicalCard/utils/medicalConfig";
|
|
||||||
import { medicalDetailConfig } from "@/pages/oldMedicalCard/utils/medicalConfig";
|
|
||||||
import { mobilityMap } from "@/pages/oldMedicalCard/utils/medicalConfig";
|
|
||||||
import {
|
|
||||||
getDentalEntiesValue,
|
|
||||||
requestUpdateMedicalCard,
|
|
||||||
requestCreateMedicalCard,
|
|
||||||
getRequestDataPerson,
|
|
||||||
} from "@/pages/oldMedicalCard/utils/wrapperMedicalCard";
|
|
||||||
import { fetchWrapper } from "@/shared/fetchWrapper";
|
|
||||||
import BaseInput from "@/components/base/BaseInput.vue";
|
|
||||||
import ClientDetailInput from "@/pages/clients/components/ClientDetailInput.vue";
|
|
||||||
export default {
|
|
||||||
name: "MedicalCardWrapper",
|
|
||||||
components: {
|
|
||||||
ClientDetailInput,
|
|
||||||
BaseInput,
|
|
||||||
BaseDetailInfo,
|
|
||||||
BaseDetailInput,
|
|
||||||
MedicalCardHeader,
|
|
||||||
MedicalDentalFormula,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
personId: "",
|
|
||||||
identityDocumentId: "",
|
|
||||||
responseMedicalCardData: undefined,
|
|
||||||
responseMedicalDentalData: {},
|
|
||||||
numberCard: "",
|
|
||||||
configData: medicalDetailConfig,
|
|
||||||
medicalDataInit: {
|
|
||||||
number_series: undefined,
|
|
||||||
issued_by_org: undefined,
|
|
||||||
issued_by_org_code: undefined,
|
|
||||||
issued_by_date: undefined,
|
|
||||||
registration_address: undefined,
|
|
||||||
temporary_address: undefined,
|
|
||||||
insurance_number: undefined,
|
|
||||||
policy_series: undefined,
|
|
||||||
policy_number: undefined,
|
|
||||||
policy_organization: undefined,
|
|
||||||
name_confidant: undefined,
|
|
||||||
phone_confidant: undefined,
|
|
||||||
benefit_code: undefined,
|
|
||||||
agreement: undefined,
|
|
||||||
agreement_date: undefined,
|
|
||||||
},
|
|
||||||
dentalIndications: {
|
|
||||||
complaints: undefined,
|
|
||||||
allergic: undefined,
|
|
||||||
past_diseases: undefined,
|
|
||||||
medications_taken: undefined,
|
|
||||||
thermometry: undefined,
|
|
||||||
tonometry: undefined,
|
|
||||||
disease_progress: undefined,
|
|
||||||
visual_examination: undefined,
|
|
||||||
oral_examination: undefined,
|
|
||||||
dental_formula: formulaDataMap,
|
|
||||||
dental_bite: undefined,
|
|
||||||
hygiene_index: undefined,
|
|
||||||
dmf_index: undefined,
|
|
||||||
diagnostic_findings: undefined,
|
|
||||||
icd_code: undefined,
|
|
||||||
survey_plan: undefined,
|
|
||||||
survey_data: undefined,
|
|
||||||
clinical_diagnosis: undefined,
|
|
||||||
treatment_plan: undefined,
|
|
||||||
treatment_protocol: undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
defineEmptyData(fields) {
|
|
||||||
return fields.map((field) => this.medicalDataInit[field.label]);
|
|
||||||
},
|
|
||||||
validateFormCard() {
|
|
||||||
const dataRequestPerson = getRequestDataPerson(
|
|
||||||
this.medicalDataInit,
|
|
||||||
this.dentalIndications
|
|
||||||
);
|
|
||||||
Object.keys(dataRequestPerson).forEach((key) => {
|
|
||||||
let valuesData = [
|
|
||||||
...new Set(
|
|
||||||
Object.values(this.responseMedicalCardData[key]).map((el) =>
|
|
||||||
el === null || el === undefined ? undefined : el
|
|
||||||
)
|
|
||||||
),
|
|
||||||
];
|
|
||||||
let isUpdateData = false;
|
|
||||||
let isCreateData =
|
|
||||||
valuesData.length === 1 &&
|
|
||||||
valuesData[0] === undefined &&
|
|
||||||
Object.values(dataRequestPerson[key]).find((el) => el !== undefined);
|
|
||||||
Object.keys(dataRequestPerson[key]).forEach((entries) => {
|
|
||||||
if (
|
|
||||||
this.responseMedicalCardData[key][entries] &&
|
|
||||||
dataRequestPerson[key][entries] !==
|
|
||||||
this.responseMedicalCardData[key][entries]
|
|
||||||
) {
|
|
||||||
isUpdateData = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isUpdateData) {
|
|
||||||
requestUpdateMedicalCard(
|
|
||||||
dataRequestPerson[key],
|
|
||||||
key,
|
|
||||||
key === "identity_document"
|
|
||||||
? this.identityDocumentId
|
|
||||||
: this.personId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (isCreateData) {
|
|
||||||
requestCreateMedicalCard(
|
|
||||||
dataRequestPerson[key],
|
|
||||||
key,
|
|
||||||
key === "identity_document"
|
|
||||||
? this.identityDocumentId
|
|
||||||
: this.personId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Object.keys(this.dentalIndications).forEach((key) => {
|
|
||||||
if (key === "dental_formula") {
|
|
||||||
const notEmptyEntries =
|
|
||||||
this.dentalIndications.dental_formula[0].columns
|
|
||||||
.concat(this.dentalIndications.dental_formula[1].columns)
|
|
||||||
.filter((el) => el.dental_condition && el.tooth_mobility);
|
|
||||||
notEmptyEntries.forEach((tooth) => {
|
|
||||||
const toothResponse = this.responseMedicalDentalData[key].find(
|
|
||||||
(el) => el.tooth_number === tooth.tooth_number
|
|
||||||
);
|
|
||||||
const isCreate =
|
|
||||||
!toothResponse &&
|
|
||||||
!!tooth.tooth_mobility &&
|
|
||||||
!!tooth.dental_condition;
|
|
||||||
if (isCreate) {
|
|
||||||
requestCreateMedicalCard(tooth, key, this.$route.params.id);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
toothResponse &&
|
|
||||||
toothResponse.tooth_mobility.label !==
|
|
||||||
tooth.tooth_mobility.label &&
|
|
||||||
toothResponse.dental_condition !== tooth.dental_condition
|
|
||||||
) {
|
|
||||||
requestUpdateMedicalCard(tooth, key, toothResponse.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
key !== "dental_formula" &&
|
|
||||||
!this.responseMedicalDentalData[key] &&
|
|
||||||
this.dentalIndications[key]
|
|
||||||
) {
|
|
||||||
requestCreateMedicalCard(
|
|
||||||
this.dentalIndications[key],
|
|
||||||
key,
|
|
||||||
this.$route.params.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
key !== "dental_formula" &&
|
|
||||||
this.dentalIndications[key] &&
|
|
||||||
getDentalEntiesValue(this.responseMedicalDentalData[key], key) !==
|
|
||||||
this.dentalIndications[key]
|
|
||||||
) {
|
|
||||||
requestUpdateMedicalCard(
|
|
||||||
this.dentalIndications[key],
|
|
||||||
key,
|
|
||||||
this.responseMedicalDentalData[key]?.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
saveDataMedical(data) {
|
|
||||||
this.personId = data?.person?.id;
|
|
||||||
this.numberCard = data?.number;
|
|
||||||
const confidant = data ? data["confidant"] : undefined;
|
|
||||||
const pass = data
|
|
||||||
? data?.person?.identity_document?.find((el) => el.kind === "PASSPORT")
|
|
||||||
: null;
|
|
||||||
this.identityDocumentId = pass?.id;
|
|
||||||
this.medicalDataInit = {
|
|
||||||
...this.medicalDataInit,
|
|
||||||
issued_by_org: pass.issued_by_org,
|
|
||||||
issued_by_org_code: pass.issued_by_org_code,
|
|
||||||
number_series: `${pass.series} ${pass.number}`,
|
|
||||||
issued_by_date: new Date(pass.issued_by_date),
|
|
||||||
registration_address: data?.person?.address?.find(
|
|
||||||
(el) => el["registration_flg"]
|
|
||||||
)?.join_address,
|
|
||||||
temporary_address: data?.person?.address?.find(
|
|
||||||
(el) => el["temporary_registration_flg"]
|
|
||||||
)?.join_address,
|
|
||||||
insurance_number: data?.person["insurance_number"] || undefined,
|
|
||||||
policy_number: data?.person["insurance_policy"][0]?.number,
|
|
||||||
policy_series: data?.person["insurance_policy"][0]?.series,
|
|
||||||
policy_organization: data?.person["insurance_policy"][0]?.organization,
|
|
||||||
name_confidant:
|
|
||||||
confidant &&
|
|
||||||
`${confidant?.last_name} ${confidant?.last_name} ${confidant?.patronymic}`,
|
|
||||||
phone_confidant: confidant?.contacts?.find((el) => el?.kind === "PHONE")
|
|
||||||
?.username,
|
|
||||||
benefit_code: data?.person?.benefit_code,
|
|
||||||
agreement: data?.agreement,
|
|
||||||
agreement_date: undefined,
|
|
||||||
};
|
|
||||||
Object.keys(this.dentalIndications).forEach((key) => {
|
|
||||||
if (key === "dental_formula" && data[key].length) {
|
|
||||||
this.responseMedicalDentalData[key] = data[key];
|
|
||||||
data[key].forEach((tooth) => {
|
|
||||||
if (tooth.dental_condition && tooth.tooth_mobility) {
|
|
||||||
if (17 < tooth.tooth_number < 29) {
|
|
||||||
this.dentalIndications.dental_formula[0] = {
|
|
||||||
...this.dentalIndications.dental_formula[0],
|
|
||||||
columns: this.dentalIndications.dental_formula[0].columns.map(
|
|
||||||
(el) => {
|
|
||||||
if (el.tooth_number === tooth.tooth_number) {
|
|
||||||
return {
|
|
||||||
...tooth,
|
|
||||||
tooth_mobility: mobilityMap.find(
|
|
||||||
(el) => el.label === tooth.tooth_mobility
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (37 < tooth.tooth_number < 49) {
|
|
||||||
this.dentalIndications.dental_formula[1] = {
|
|
||||||
...this.dentalIndications.dental_formula[1],
|
|
||||||
columns: this.dentalIndications.dental_formula[1].columns.map(
|
|
||||||
(el) => {
|
|
||||||
if (el.tooth_number === tooth.tooth_number) {
|
|
||||||
return {
|
|
||||||
...tooth,
|
|
||||||
tooth_mobility: mobilityMap.find(
|
|
||||||
(el) => el.label === tooth.tooth_mobility
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.dentalIndications[key] = data[key]?.length
|
|
||||||
? getDentalEntiesValue(data[key].at(-1), key)
|
|
||||||
: this.dentalIndications[key];
|
|
||||||
this.dentalIndications.allergic = data?.person?.allergic
|
|
||||||
? data?.person?.allergic
|
|
||||||
: this.dentalIndications.allergic;
|
|
||||||
this.responseMedicalDentalData[key] = data[key]?.length
|
|
||||||
? data[key].at(-1)
|
|
||||||
: this.dentalIndications[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.responseMedicalCardData = getRequestDataPerson(
|
|
||||||
this.medicalDataInit,
|
|
||||||
this.dentalIndications
|
|
||||||
);
|
|
||||||
},
|
|
||||||
async fetchDataMedicalCard() {
|
|
||||||
await fetchWrapper
|
|
||||||
.get(`medical_card/medical_history/${this.$route.params.id}/detail/`)
|
|
||||||
.then((res) => this.saveDataMedical(res));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.fetchDataMedicalCard();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.wrapper
|
|
||||||
overflow: auto
|
|
||||||
border-top-left-radius: 4px
|
|
||||||
border-top-right-radius: 4px
|
|
||||||
.wrapper-medical
|
|
||||||
background-color: var(--default-white)
|
|
||||||
height: calc(100vh - 64px)
|
|
||||||
overflow: auto
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
height: 4px
|
|
||||||
width: 4px
|
|
||||||
&::-webkit-scrollbar-track
|
|
||||||
background-color: rgba(211, 212, 220, 0.5)
|
|
||||||
border-radius: 8px
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
border-radius: 8px
|
|
||||||
background-color: var(--btn-blue-color)
|
|
||||||
.card-basic-info
|
|
||||||
display: grid
|
|
||||||
grid-template-columns: 280px 292px 180px 360px 463px
|
|
||||||
gap: 16px
|
|
||||||
padding: 0 20px 20px 0
|
|
||||||
overflow-x: auto
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
height: 4px
|
|
||||||
width: 4px
|
|
||||||
&::-webkit-scrollbar-track
|
|
||||||
background-color: rgba(211, 212, 220, 0.5)
|
|
||||||
border-radius: 8px
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
border-radius: 8px
|
|
||||||
background-color: var(--btn-blue-color)
|
|
||||||
.card-upper
|
|
||||||
border-bottom: 1px solid var(--border-light-grey-color)
|
|
||||||
</style>
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.wrapper.flex.w-full.px-52px.py-7.gap-x-102px
|
|
||||||
.flex.flex-col.gap-y-5
|
|
||||||
.flex.flex-col.gap-y-4
|
|
||||||
span.font-bold.text-base Состояние зубов:
|
|
||||||
.flex.flex-col.gap-y-1
|
|
||||||
div(v-for="condition in dentalCondition")
|
|
||||||
span.font-bold.text-base {{condition.name}}
|
|
||||||
span.text-base {{` - ${condition.discription}`}}
|
|
||||||
.flex.flex-col.gap-y-1
|
|
||||||
.font-bold.text-base Подвижность:
|
|
||||||
span.text-base Степень -
|
|
||||||
span.font-bold.text-base I, II, III
|
|
||||||
.flex.flex-col.h-fit.rounded
|
|
||||||
medical-formula-table(:data="formulaData[0]")
|
|
||||||
medical-formula-table(:data="formulaData[1]")
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { dentalСonditionMap } from "@/pages/oldMedicalCard/utils/medicalConfig";
|
|
||||||
import MedicalFormulaTable from "@/pages/oldMedicalCard/components/MedicalFormulaTable.vue";
|
|
||||||
export default {
|
|
||||||
name: "MedicalDentalFormula",
|
|
||||||
components: { MedicalFormulaTable },
|
|
||||||
props: {
|
|
||||||
formulaData: Array,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dentalCondition: dentalСonditionMap,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.wrapper
|
|
||||||
border: 1.5px solid var(--border-light-grey-color)
|
|
||||||
border-radius: 4px
|
|
||||||
overflow: auto
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
height: 4px
|
|
||||||
width: 4px
|
|
||||||
&::-webkit-scrollbar-track
|
|
||||||
background-color: rgba(211, 212, 220, 0.5)
|
|
||||||
border-radius: 8px
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
border-radius: 8px
|
|
||||||
background-color: var(--btn-blue-color)
|
|
||||||
</style>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
//TODO: Поправить бордеры у таблицы
|
|
||||||
.table-formula.flex.border-collapse
|
|
||||||
.flex.flex-col.border-collapse
|
|
||||||
.cell-grey.flex.w-52.h-50px.font-bold.text-lg.justify-center.items-center.border-collapse(v-for="row in data.rowMap") {{row.label}}
|
|
||||||
.flex.flex-col.border-collapse(v-for="tooth in data.columns")
|
|
||||||
.cell.flex.w-50px.h-50px.font-bold.text-2xl.justify-center.items-center(v-for="(row, index) in data.rowMap" :class="{'cell-grey': row.name === 'tooth_number'}")
|
|
||||||
span(v-if="row.name === 'tooth_number'") {{tooth[row.name]}}
|
|
||||||
base-input.pl-4.pr-2(v-if="row.name === 'dental_condition'" v-model="tooth[row.name]" :rules="[ruleCondition]" :max-length="2" borderless no-error-icon)
|
|
||||||
label.flex.w-full.h-full.justify-center.items-center.cursor-pointer(v-if="row.name === 'tooth_mobility'")
|
|
||||||
base-select.pl-4.pr-4(v-model="tooth[row.name]" :id="`${row.name}_${index}`" :items="mobilityMap" :outlined="false" menu-anchor="bottom start" borderless hide-dropdown-icon)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { ruleDentalCondition } from "@/assets/rules/rulesInput";
|
|
||||||
import BaseInput from "@/components/base/BaseInput.vue";
|
|
||||||
import BaseSelect from "@/components/base/BaseSelect.vue";
|
|
||||||
import { mobilityMap } from "@/pages/oldMedicalCard/utils/medicalConfig";
|
|
||||||
export default {
|
|
||||||
name: "MedicalFormulaTable",
|
|
||||||
components: { BaseInput, BaseSelect },
|
|
||||||
props: {
|
|
||||||
data: Object,
|
|
||||||
rowMap: Array,
|
|
||||||
condition: Array,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
ruleCondition: ruleDentalCondition,
|
|
||||||
mobilityMap: mobilityMap,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.table-formula
|
|
||||||
border-left: 1.5px solid var(--font-black-color)
|
|
||||||
border-top: 1.5px solid var(--font-black-color)
|
|
||||||
.cell
|
|
||||||
border-bottom: 1.5px solid black
|
|
||||||
border-right: 1.5px solid black
|
|
||||||
.cell-grey
|
|
||||||
@extend .cell
|
|
||||||
background-color: var(--border-light-grey-color)
|
|
||||||
.not-border
|
|
||||||
border: none
|
|
||||||
</style>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.base.flex.flex-col.gap-y-6
|
|
||||||
.flex.flex-col.gap-y-6
|
|
||||||
span.font-bold Паспортные данные
|
|
||||||
.flex.flex-col.gap-y-6
|
|
||||||
base-input(
|
|
||||||
label="Серия и номер",
|
|
||||||
placeholder="0000 000000",
|
|
||||||
mask="#### ######",
|
|
||||||
v-model="clientDetail.identity_documents.series_number",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
label="Кем выдан",
|
|
||||||
placeholder="Точно как в паспорте",
|
|
||||||
v-model="clientDetail.identity_documents.issued_by_org",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.flex.gap-x-4
|
|
||||||
base-input(
|
|
||||||
label="Код подразделения",
|
|
||||||
placeholder="000-000",
|
|
||||||
mask="###-###",
|
|
||||||
v-model="clientDetail.identity_documents.issued_by_org_code",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
type="date",
|
|
||||||
label="Дата выдачи",
|
|
||||||
v-model="clientDetail.identity_documents.issued_by_date",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import BaseInput from "@/components/base/BaseInput";
|
|
||||||
import BaseSelect from "@/components/base/BaseSelect";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "MedicalIdentityDocuments",
|
|
||||||
components: { BaseInput, BaseSelect },
|
|
||||||
props: {
|
|
||||||
changeIdentityDoc: Function,
|
|
||||||
clientDetail: Object,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
.base.flex.flex-col.gap-y-6
|
|
||||||
span.font-bold Полис
|
|
||||||
base-radio-buttons-group(
|
|
||||||
:items="policiesList",
|
|
||||||
v-model="clientDetail.policy",
|
|
||||||
:columnGap="152",
|
|
||||||
inline
|
|
||||||
)
|
|
||||||
.flex.gap-x-4
|
|
||||||
.flex.flex-col.gap-y-4
|
|
||||||
base-input.input(
|
|
||||||
label="Серия и номер полиса ОМС",
|
|
||||||
placeholder="000000 0000000000",
|
|
||||||
v-model="clientDetail.OMSPolicy.number",
|
|
||||||
mask="###### ##########",
|
|
||||||
:disabled="!selectedOMSPolicy",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input.input(
|
|
||||||
label="Страховая организация полиса ОМС",
|
|
||||||
v-model="clientDetail.OMSPolicy.organization",
|
|
||||||
:disabled="!selectedOMSPolicy",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
.flex.flex-col.gap-y-4
|
|
||||||
base-input.input(
|
|
||||||
label="Серия и номер полиса ДМС",
|
|
||||||
placeholder="000000 0000000000",
|
|
||||||
v-model="clientDetail.DMSPolicy.number",
|
|
||||||
mask="###### ##########",
|
|
||||||
:disabled="selectedOMSPolicy",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input.input(
|
|
||||||
label="Страховая организация полиса ДМС",
|
|
||||||
v-model="clientDetail.DMSPolicy.organization",
|
|
||||||
:disabled="selectedOMSPolicy",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
label="Код категории льготы",
|
|
||||||
placeholder="000",
|
|
||||||
mask="###"
|
|
||||||
v-model="clientDetail.benefit_code",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
label="К кому обращаться в случае необходимости",
|
|
||||||
placeholder="ФИО*",
|
|
||||||
v-model="clientDetail.confidant_name",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
base-input(
|
|
||||||
label="Номер телефона",
|
|
||||||
placeholder="+7 (915) 644–92–23",
|
|
||||||
mask="+7 (###) ###-##-##",
|
|
||||||
v-model="clientDetail.confidant_phone",
|
|
||||||
size="M"
|
|
||||||
)
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import BaseInput from "@/components/base/BaseInput";
|
|
||||||
import BaseSelect from "@/components/base/BaseSelect";
|
|
||||||
import BaseRadioButtonsGroup from "@/components/base/BaseRadioButtonsGroup.vue";
|
|
||||||
import { medicalDetailConfig } from "@/pages/oldMedicalCard/utils/medicalConfig.js";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "MedicalPolicyDocuments",
|
|
||||||
components: {
|
|
||||||
BaseInput,
|
|
||||||
BaseSelect,
|
|
||||||
BaseRadioButtonsGroup,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
clientDetail: Object,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
policiesList() {
|
|
||||||
return medicalDetailConfig.policiesList;
|
|
||||||
},
|
|
||||||
selectedOMSPolicy() {
|
|
||||||
return this.clientDetail.policy === "OMS";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
|
||||||
.input
|
|
||||||
width: 277px
|
|
||||||
</style>
|
|
||||||
@@ -1,449 +0,0 @@
|
|||||||
export const medicalDetailConfig = {
|
|
||||||
gendersList: [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
label: "Мужской",
|
|
||||||
value: "MALE",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
label: "Женский",
|
|
||||||
value: "WOMEN",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
policiesList: [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
label: "Полис ОМС",
|
|
||||||
value: "OMS",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
label: "Полис ДМС",
|
|
||||||
value: "DMS",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
identity_document: {
|
|
||||||
height: 316,
|
|
||||||
title: "Паспортные данные",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "number_series",
|
|
||||||
title: "Серия и номер",
|
|
||||||
type: "text",
|
|
||||||
mask: "#### ######",
|
|
||||||
copy: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "issued_by_org",
|
|
||||||
title: "Выдан",
|
|
||||||
type: "textarea",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "issued_by_org_code",
|
|
||||||
title: "Код подразделения",
|
|
||||||
type: "text",
|
|
||||||
mask: "###-###",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "issued_by_date",
|
|
||||||
title: "Дата выдачи",
|
|
||||||
type: "date",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
registration_address: {
|
|
||||||
height: 85,
|
|
||||||
title: "Адрес регистрации",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "registration_address",
|
|
||||||
title: "Полный адрес",
|
|
||||||
type: "textarea",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
temporary_address: {
|
|
||||||
height: 85,
|
|
||||||
title: "Адрес проживания",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "temporary_address",
|
|
||||||
title: "Полный адрес",
|
|
||||||
type: "textarea",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
snils: {
|
|
||||||
height: 85,
|
|
||||||
title: "СНИЛС",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "insurance_number",
|
|
||||||
title: "Номер",
|
|
||||||
type: "text",
|
|
||||||
mask: "###-###-### ##",
|
|
||||||
copy: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
policy: {
|
|
||||||
height: 162,
|
|
||||||
title: "ПОЛИС",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "policy_series",
|
|
||||||
title: "Серия",
|
|
||||||
type: "text",
|
|
||||||
mask: "####",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "policy_number",
|
|
||||||
title: "Номер",
|
|
||||||
type: "text",
|
|
||||||
mask: "#######",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
policy_organization: {
|
|
||||||
height: 85,
|
|
||||||
title: "Страховая организация",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "policy_organization",
|
|
||||||
title: "Название",
|
|
||||||
type: "text",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
additional: {
|
|
||||||
height: 218,
|
|
||||||
title: "Дополнительная информация",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
icon: "icon-person",
|
|
||||||
label: "name_confidant",
|
|
||||||
title: "Доверенное лицо",
|
|
||||||
type: "text",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: "icon-phone",
|
|
||||||
label: "phone_confidant",
|
|
||||||
title: "",
|
|
||||||
type: "text",
|
|
||||||
mask: "+7 (###) ###-##-##",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "benefit_code",
|
|
||||||
title: "Код категории льготы",
|
|
||||||
type: "text",
|
|
||||||
mask: "###",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
agreement_form: {
|
|
||||||
height: 121,
|
|
||||||
title:
|
|
||||||
"Информированное добровольное согласие на виды медицинских вмешательств, включенные в Перечень определенных видов медицинских вмешательств:",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: "agreement",
|
|
||||||
title: "Получено",
|
|
||||||
type: "radio",
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
label: "Да",
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
label: "Нет",
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "agreement_date",
|
|
||||||
title: "Дата",
|
|
||||||
type: "date",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
dental_indications: {
|
|
||||||
complaints: "Жалобы",
|
|
||||||
allergic: "Аллергологический анамнез",
|
|
||||||
past_diseases: "Перенесённые и сопутствующие заболевания",
|
|
||||||
medications_taken: "Принимаемые лекарственные препараты",
|
|
||||||
thermometry: "Термометрия (по показаниям)",
|
|
||||||
tonometry: "Тонометрия, ЧСС (по показаниям)",
|
|
||||||
disease_progress: "Развитие настоящего заболевания",
|
|
||||||
visual_examination: "Внешний осмотр",
|
|
||||||
oral_examination: "Осмотр преддверия и полости рта",
|
|
||||||
dental_formula: "Зубная формула",
|
|
||||||
dental_bite: "Прикус",
|
|
||||||
hygiene_index: "Индекс гигиены",
|
|
||||||
dmf_index: "Индекс КПУ",
|
|
||||||
diagnostic_findings: "Предварительный диагноз",
|
|
||||||
icd_code: "Код МКБ-10",
|
|
||||||
survey_plan: "План обследования",
|
|
||||||
survey_data: "Данные обследования",
|
|
||||||
clinical_diagnosis: "Клинический диагноз",
|
|
||||||
treatment_plan: "План лечения",
|
|
||||||
treatment_protocol: "Протокол лечения",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dentalСonditionMap = [
|
|
||||||
{
|
|
||||||
name: "К",
|
|
||||||
discription: "кариес",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "П",
|
|
||||||
discription: "пульпит",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Пт",
|
|
||||||
discription: "периодонтит",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Д",
|
|
||||||
discription: "дефект",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Пл",
|
|
||||||
discription: "пломба",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Ик",
|
|
||||||
discription: "искусственная коронка",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Из",
|
|
||||||
discription: "искусственный зуб",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "В",
|
|
||||||
discription: "вкладка",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "И",
|
|
||||||
discription: "имплантат",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Кз",
|
|
||||||
discription: "корень зуба",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "О",
|
|
||||||
discription: "отсутствующий зуб",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const mobilityMap = [
|
|
||||||
{ id: 1, label: "I" },
|
|
||||||
{ id: 2, label: "II" },
|
|
||||||
{ id: 3, label: "III" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const formulaDataMap = [
|
|
||||||
{
|
|
||||||
name: "upperJaw",
|
|
||||||
rowMap: [
|
|
||||||
{
|
|
||||||
label: "Подвижность",
|
|
||||||
name: "tooth_mobility",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Cостояние зубов",
|
|
||||||
name: "dental_condition",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Верхняя челюсть",
|
|
||||||
name: "tooth_number",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
tooth_number: 18,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 17,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 16,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 15,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 14,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 13,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 12,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 11,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 21,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 22,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 23,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 24,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 25,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 26,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 27,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 28,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "lowerJaw",
|
|
||||||
rowMap: [
|
|
||||||
{
|
|
||||||
label: "Нижняя челюсть",
|
|
||||||
name: "tooth_number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Cостояние зубов",
|
|
||||||
name: "dental_condition",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Подвижность",
|
|
||||||
name: "tooth_mobility",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
tooth_number: 48,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 47,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 46,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 45,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 44,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 43,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 42,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 41,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 31,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 32,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 33,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 34,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 35,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 36,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 37,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tooth_number: 38,
|
|
||||||
dental_condition: "",
|
|
||||||
tooth_mobility: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
import { fetchWrapper } from "@/shared/fetchWrapper";
|
|
||||||
import moment from "moment";
|
|
||||||
export function requestCreateMedicalCard(entry, key, id) {
|
|
||||||
const url = `medical_card/${key}/create/`;
|
|
||||||
let arrayValue;
|
|
||||||
if (["tonometry", "dental_bite", "dmf_index"].includes(key)) {
|
|
||||||
arrayValue = entry.split(",");
|
|
||||||
}
|
|
||||||
switch (key) {
|
|
||||||
case "complaints":
|
|
||||||
case "medications_taken":
|
|
||||||
case "disease_progress":
|
|
||||||
case "visual_examination":
|
|
||||||
case "diagnostic_findings":
|
|
||||||
case "survey_plan":
|
|
||||||
case "treatment_plan":
|
|
||||||
case "treatment_protocol":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
description: entry,
|
|
||||||
medical_history: id,
|
|
||||||
});
|
|
||||||
case "thermometry":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
temperature: Number(entry),
|
|
||||||
medical_history: id,
|
|
||||||
});
|
|
||||||
case "tonometry":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
sys: Number(arrayValue[0]),
|
|
||||||
dia: Number(arrayValue[1]),
|
|
||||||
pul: Number(arrayValue[2]),
|
|
||||||
medical_history: id,
|
|
||||||
});
|
|
||||||
case "dental_bite":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
custom: arrayValue[0],
|
|
||||||
physiological: arrayValue[1],
|
|
||||||
abnormal: arrayValue[2],
|
|
||||||
medical_history: id,
|
|
||||||
});
|
|
||||||
case "dmf_index":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
caries: Number(arrayValue[0]),
|
|
||||||
filling: Number(arrayValue[1]),
|
|
||||||
remote: Number(arrayValue[2]),
|
|
||||||
medical_history: id,
|
|
||||||
});
|
|
||||||
case "clinical_diagnosis":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
description: "string",
|
|
||||||
medical_history: id,
|
|
||||||
icd10: id,
|
|
||||||
});
|
|
||||||
case "dental_formula":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
...entry,
|
|
||||||
tooth_mobility: entry.tooth_mobility ? entry.tooth_mobility.label : "",
|
|
||||||
tooth_number: entry.tooth_number,
|
|
||||||
medical_history: id,
|
|
||||||
});
|
|
||||||
case "registration_address":
|
|
||||||
return fetchWrapper.post(`general/address/create/`, {
|
|
||||||
...entry,
|
|
||||||
person: id,
|
|
||||||
registration_flg: true,
|
|
||||||
});
|
|
||||||
case "temporary_address":
|
|
||||||
return fetchWrapper.post(`general/address/create/`, {
|
|
||||||
...entry,
|
|
||||||
person: id,
|
|
||||||
temporary_registration_flg: true,
|
|
||||||
});
|
|
||||||
case "identity_document":
|
|
||||||
return fetchWrapper.post(`general/identity_document/create/`, {
|
|
||||||
...entry,
|
|
||||||
person: id,
|
|
||||||
});
|
|
||||||
case "insurance_policy":
|
|
||||||
return fetchWrapper.post(`general/insurance_policy/create/`, {
|
|
||||||
...entry,
|
|
||||||
title: "string",
|
|
||||||
person: id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function requestUpdateMedicalCard(entry, key, id) {
|
|
||||||
const url = `medical_card/${key}/${id}/update/`;
|
|
||||||
let arrayValue;
|
|
||||||
if (["tonometry", "dental_bite", "dmf_index"].includes(key)) {
|
|
||||||
arrayValue = entry.split(",");
|
|
||||||
}
|
|
||||||
switch (key) {
|
|
||||||
case "complaints":
|
|
||||||
case "medications_taken":
|
|
||||||
case "disease_progress":
|
|
||||||
case "visual_examination":
|
|
||||||
case "diagnostic_findings":
|
|
||||||
case "survey_plan":
|
|
||||||
case "treatment_plan":
|
|
||||||
case "treatment_protocol":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
description: entry,
|
|
||||||
});
|
|
||||||
case "thermometry":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
temperature: Number(entry),
|
|
||||||
});
|
|
||||||
case "tonometry":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
sys: Number(arrayValue[0]),
|
|
||||||
dia: Number(arrayValue[1]),
|
|
||||||
pul: Number(arrayValue[2]),
|
|
||||||
});
|
|
||||||
case "dental_bite":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
custom: entry,
|
|
||||||
physiological: entry,
|
|
||||||
abnormal: entry,
|
|
||||||
});
|
|
||||||
case "dmf_index":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
caries: Number(entry),
|
|
||||||
filling: Number(entry),
|
|
||||||
remote: Number(entry),
|
|
||||||
});
|
|
||||||
case "clinical_diagnosis":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
title: entry,
|
|
||||||
description: "string",
|
|
||||||
icd10: id,
|
|
||||||
});
|
|
||||||
case "dental_formula":
|
|
||||||
return fetchWrapper.post(url, {
|
|
||||||
...entry,
|
|
||||||
tooth_mobility: entry.tooth_mobility ? entry.tooth_mobility.label : "",
|
|
||||||
tooth_number: entry.tooth_number,
|
|
||||||
});
|
|
||||||
case "registration_address":
|
|
||||||
return fetchWrapper.post(`general/address/${id}/update/`, {
|
|
||||||
...entry,
|
|
||||||
registration_flg: true,
|
|
||||||
});
|
|
||||||
case "temporary_address":
|
|
||||||
return fetchWrapper.post(`general/address/${id}/update/`, {
|
|
||||||
...entry,
|
|
||||||
temporary_registration_flg: true,
|
|
||||||
});
|
|
||||||
case "identity_document":
|
|
||||||
return fetchWrapper.post(`general/identity_document/${id}/update/`, {
|
|
||||||
...entry,
|
|
||||||
});
|
|
||||||
case "insurance_policy":
|
|
||||||
return fetchWrapper.post(`general/insurance_policy/${id}/update/`, {
|
|
||||||
...entry,
|
|
||||||
title: "string",
|
|
||||||
});
|
|
||||||
case "person":
|
|
||||||
return fetchWrapper.post(`general/person/${id}/update/`, {
|
|
||||||
...entry,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRequestDataPerson(person, dental) {
|
|
||||||
const dataPersonRequest = {
|
|
||||||
identity_document: {
|
|
||||||
issued_by_org: person.issued_by_org,
|
|
||||||
issued_by_org_code: person.issued_by_org_code,
|
|
||||||
issued_by_date: moment(person.issued_by_date).format("YYYY-MM-DD"),
|
|
||||||
number: person.number_series.split(" ")[1],
|
|
||||||
series: person.number_series.split(" ")[0],
|
|
||||||
},
|
|
||||||
registration_address: {
|
|
||||||
full_address: person.registration_address,
|
|
||||||
},
|
|
||||||
temporary_address: {
|
|
||||||
full_address: person.temporary_address,
|
|
||||||
},
|
|
||||||
insurance_policy: {
|
|
||||||
series: person.policy_series,
|
|
||||||
number: person.policy_number,
|
|
||||||
organization: person.policy_organization,
|
|
||||||
},
|
|
||||||
person: {
|
|
||||||
insurance_number: person.insurance_number,
|
|
||||||
benefit_code: person.benefit_code,
|
|
||||||
allergic: dental.allergic,
|
|
||||||
},
|
|
||||||
agreement: {
|
|
||||||
agreement: person.agreement,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return dataPersonRequest;
|
|
||||||
}
|
|
||||||
export function getDentalEntiesValue(data, key) {
|
|
||||||
switch (key) {
|
|
||||||
case "complaints":
|
|
||||||
case "medications_taken":
|
|
||||||
case "disease_progress":
|
|
||||||
case "visual_examination":
|
|
||||||
case "diagnostic_findings":
|
|
||||||
case "survey_plan":
|
|
||||||
case "treatment_plan":
|
|
||||||
case "treatment_protocol":
|
|
||||||
case "clinical_diagnosis":
|
|
||||||
return data?.description;
|
|
||||||
case "thermometry":
|
|
||||||
return `${data?.temperature}`;
|
|
||||||
case "tonometry":
|
|
||||||
return `${data?.sys},${data?.dia},${data?.pul}`;
|
|
||||||
case "dental_bite":
|
|
||||||
return `${data?.custom},${data?.physiological},${data?.abnormal}`;
|
|
||||||
case "dmf_index":
|
|
||||||
return data["index_calculation"];
|
|
||||||
case "hygiene_index":
|
|
||||||
return data["index_calculation"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { createRouter, createWebHashHistory } from "vue-router";
|
import { createRouter, createWebHashHistory } from "vue-router";
|
||||||
import TheCalendar from "@/pages/newCalendar/TheCalendar";
|
import TheCalendar from "@/pages/newCalendar/TheCalendar";
|
||||||
import TheUser from "@/pages/clients/TheClients";
|
|
||||||
import TheSettings from "@/pages/settings/TheSettings";
|
import TheSettings from "@/pages/settings/TheSettings";
|
||||||
import TheMedcards from "@/pages/medcards/TheMedcards";
|
import TheMedcards from "@/pages/medcards/TheMedcards";
|
||||||
import TheLogin from "@/pages/login/TheLogin";
|
import TheLogin from "@/pages/login/TheLogin";
|
||||||
import LoggedInLayout from "@/components/LoggedInLayout";
|
import LoggedInLayout from "@/components/LoggedInLayout";
|
||||||
import TheMedicalCard from "@/pages/newMedicalCard/TheMedicalCard";
|
import TheMedicalCard from "@/pages/newMedicalCard/TheMedicalCard";
|
||||||
import { fetchWrapper } from "@/shared/fetchWrapper";
|
import { fetchWrapper } from "@/shared/fetchWrapper";
|
||||||
|
import TheHome from "@/pages/home/TheHome";
|
||||||
|
|
||||||
const ifNotAuthenticated = async (to, from, next) => {
|
const ifNotAuthenticated = async (to, from, next) => {
|
||||||
const data = await fetchWrapper.get("users/me");
|
const data = await fetchWrapper.get("users/me");
|
||||||
@@ -35,9 +35,9 @@ export default createRouter({
|
|||||||
beforeEnter: ifAuthenticated,
|
beforeEnter: ifAuthenticated,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
{ path: "", redirect: "calendar" },
|
{ path: "", redirect: "home" },
|
||||||
|
{ path: "home", component: TheHome },
|
||||||
{ path: "calendar", component: TheCalendar },
|
{ path: "calendar", component: TheCalendar },
|
||||||
{ path: "clients", component: TheUser },
|
|
||||||
{ path: "medcards", component: TheMedcards },
|
{ path: "medcards", component: TheMedcards },
|
||||||
{ path: "settings", component: TheSettings },
|
{ path: "settings", component: TheSettings },
|
||||||
{ path: "medical-card/:id", component: TheMedicalCard },
|
{ path: "medical-card/:id", component: TheMedicalCard },
|
||||||
|
|||||||
4
src/shared/errors.js
Normal file
4
src/shared/errors.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const errors = {
|
||||||
|
internal_error: "Внутренняя ошибка",
|
||||||
|
validation_error: "Ошибка валидации",
|
||||||
|
};
|
||||||
@@ -8,6 +8,7 @@ export default createStore({
|
|||||||
imgUrl: "https://astra-dev.dopcore.com/api/store/",
|
imgUrl: "https://astra-dev.dopcore.com/api/store/",
|
||||||
routingHistory: window.history,
|
routingHistory: window.history,
|
||||||
userData: {},
|
userData: {},
|
||||||
|
calendarShape: "manager",
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
medical,
|
medical,
|
||||||
|
|||||||
@@ -194,8 +194,7 @@ const getters = {
|
|||||||
series: document?.series || (isPolicy || isPassport ? "" : "000"),
|
series: document?.series || (isPolicy || isPassport ? "" : "000"),
|
||||||
number: document?.number || "",
|
number: document?.number || "",
|
||||||
issued_by: document?.issued_by || (isPassport ? "" : "000"),
|
issued_by: document?.issued_by || (isPassport ? "" : "000"),
|
||||||
issued_by_org_code:
|
issued_by_org_code: document?.issued_by_org_code || "",
|
||||||
document?.issued_by_org_code || (isPassport ? "000-000" : ""),
|
|
||||||
issued_at: document?.issued_at || "",
|
issued_at: document?.issued_at || "",
|
||||||
attachments: document?.attachments?.length
|
attachments: document?.attachments?.length
|
||||||
? {
|
? {
|
||||||
|
|||||||
Reference in New Issue
Block a user