Merge branch 'add-admin-calendar' into 'master'
Добавлен календарь администратора See merge request astra/astra-frontend!509
This commit is contained in:
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 |
@@ -233,4 +233,10 @@ export default {
|
||||
|
||||
.input :deep(.q-field__marginal)
|
||||
height: auto !important
|
||||
|
||||
.input :deep(.q-field__shadow)
|
||||
opacity: 0.5
|
||||
top: 3px
|
||||
color: var(--font-grey-color)
|
||||
margin-left: 8px
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
.w-full.flex
|
||||
calendar-sidebar(v-if="!isOpen", :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)
|
||||
create-event-form(:close-form="closeForm")
|
||||
base-modal(v-model="previewVisibility", :hideHeader="true", :modalPadding="true")
|
||||
@@ -12,7 +15,8 @@
|
||||
<script>
|
||||
import CalendarSidebar from "@/pages/newCalendar/components/CalendarSidebar";
|
||||
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 * as moment from "moment/moment";
|
||||
import BaseModal from "@/components/base/BaseModal.vue";
|
||||
@@ -23,7 +27,8 @@ export default {
|
||||
components: {
|
||||
CalendarSidebar,
|
||||
CalendarOpenSidebar,
|
||||
CalendarWrapper,
|
||||
DoctorCalendarWrapper,
|
||||
ManagerCalendarWrapper,
|
||||
CreateEventForm,
|
||||
BaseModal,
|
||||
CalendarRecordPreview,
|
||||
@@ -40,7 +45,13 @@ export default {
|
||||
...mapState({
|
||||
selectedRecordId: (state) => state.calendar.selectedRecordId,
|
||||
selectedDates: (state) => state.calendar.selectedDates,
|
||||
calendarShape: (state) => state.calendarShape,
|
||||
}),
|
||||
calendarComponent() {
|
||||
return this.calendarShape === "doctor"
|
||||
? "doctor-calendar-wrapper"
|
||||
: "manager-calendar-wrapper";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openSidebar() {
|
||||
@@ -73,10 +84,11 @@ export default {
|
||||
deep: true,
|
||||
handler(value) {
|
||||
if (this.$route.path === "/calendar") {
|
||||
let dateType = this.calendarShape === "doctor" ? "week" : "day";
|
||||
if (!value?.start || !value?.end) {
|
||||
this.changeSelectedDates({
|
||||
from: moment().clone().startOf("week"),
|
||||
to: moment().clone().endOf("week"),
|
||||
from: moment().clone().startOf(dateType),
|
||||
to: moment().clone().endOf(dateType),
|
||||
});
|
||||
this.$router.replace({
|
||||
query: {
|
||||
@@ -87,11 +99,12 @@ export default {
|
||||
} else if (
|
||||
value?.start !== this.selectedDates?.from?.format("DD.MM.YYYY") ||
|
||||
value?.end !== this.selectedDates?.to?.format("DD.MM.YYYY")
|
||||
)
|
||||
) {
|
||||
this.changeSelectedDates({
|
||||
from: this.convertDate(value?.start),
|
||||
to: this.convertDate(value?.end),
|
||||
from: this.convertDate(value?.start).clone().startOf("day"),
|
||||
to: this.convertDate(value?.end).clone().endOf("day"),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ export default {
|
||||
timeCoil: Array,
|
||||
currentTime: String,
|
||||
dayEndTime: Number,
|
||||
isCurrentWeek: Boolean,
|
||||
isCurrent: Boolean,
|
||||
},
|
||||
computed: {
|
||||
currentHour() {
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
if (
|
||||
convertTime(elem, 0, 3) === this.currentHour &&
|
||||
!this.isEndDay &&
|
||||
this.isCurrentWeek
|
||||
this.isCurrent
|
||||
) {
|
||||
return {
|
||||
"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-2.items-center(
|
||||
v-for="contact in contacts",
|
||||
:key="contact.value",
|
||||
:key="contact?.value",
|
||||
)
|
||||
q-icon.network-icon(:name="contact.icon", size="16px")
|
||||
.text-xxs.cursor-default {{ contact.value }}
|
||||
q-icon.network-icon(:name="contact?.icon", size="16px")
|
||||
.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(
|
||||
v-if="collapsedDisplayCondition"
|
||||
v-if="collapsedDisplayCondition && contact"
|
||||
) +1
|
||||
</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>
|
||||
@@ -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>
|
||||
|
||||
<script>
|
||||
import BaseCalendar from "@/components/base/Calendar/BaseCalendar.vue";
|
||||
import { mapState, mapActions } from "vuex";
|
||||
import { v_model } from "@/shared/mixins/v-model";
|
||||
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 {
|
||||
name: "CalendarHeader",
|
||||
mixins: [v_model],
|
||||
components: { BaseInput, BaseCalendar, DateSwitcherSvg },
|
||||
mixins: [v_model, headerMixin],
|
||||
components: { DateSwitcherSvg },
|
||||
data() {
|
||||
return {
|
||||
displayTypesList: [
|
||||
@@ -99,7 +97,6 @@ export default {
|
||||
from: null,
|
||||
to: null,
|
||||
},
|
||||
calendarVisibility: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -108,9 +105,6 @@ export default {
|
||||
"D MMMM YYYY"
|
||||
)} — ${this.dates?.to?.format("D MMMM YYYY")}`;
|
||||
},
|
||||
...mapState({
|
||||
selectedDates: (state) => state.calendar.selectedDates,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
previousWeek() {
|
||||
@@ -123,13 +117,6 @@ export default {
|
||||
this.dates.from = this.dates.from.clone().add(diff, "day");
|
||||
this.dates.to = this.dates.to.clone().add(diff, "day");
|
||||
},
|
||||
...mapActions({
|
||||
changeSelectedDates: "changeSelectedDates",
|
||||
getEvents: "getEvents",
|
||||
}),
|
||||
saveDatesChange() {
|
||||
this.calendarVisibility = false;
|
||||
},
|
||||
initializeDates() {
|
||||
this.dates = {
|
||||
from: this.selectedDates.from.clone(),
|
||||
@@ -164,50 +151,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
.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)
|
||||
|
||||
.active-toggle
|
||||
background: var(--btn-blue-color)
|
||||
|
||||
.border-toggle
|
||||
border: 1px solid var(--gray-secondary)
|
||||
@import "@/pages/newCalendar/sass/headerStyle.sass"
|
||||
</style>
|
||||
<style lang="sass">
|
||||
.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,141 @@
|
||||
<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() {
|
||||
console.log(this.date, capitalizeFirstChar(this.date?.format("dddd")));
|
||||
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 = [
|
||||
{
|
||||
id: "c3df0a95-8093-41f1-9584-5b70ee05e71c",
|
||||
start: "2023-07-05T10:00:00Z",
|
||||
end: "2023-07-05T11:00:00Z",
|
||||
id: "asdf0a95-8093-41f1-9584-5b70ee05e71c",
|
||||
start: "2023-09-18T10:00:00Z",
|
||||
end: "2023-09-18T11:00:00Z",
|
||||
employee: {
|
||||
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||
last_name: "Каневский",
|
||||
first_name: "Леонид",
|
||||
patronymic: "Семенович",
|
||||
},
|
||||
member: {
|
||||
person: {
|
||||
id: "3e6e54e4-2706-47d3-8b54-b841ee8f0943",
|
||||
last_name: "Харитонова",
|
||||
first_name: "Ольга",
|
||||
@@ -823,16 +823,16 @@ export const recordList = [
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "ba931000-7140-4977-bd09-1ac212b8b8e5",
|
||||
start: "2023-07-06T15:00:00Z",
|
||||
end: "2023-07-06T15:30:00Z",
|
||||
id: "ss931000-7140-4977-bd09-1ac212b8b8e5",
|
||||
start: "2023-09-18T15:00:00Z",
|
||||
end: "2023-09-18T15:30:00Z",
|
||||
employee: {
|
||||
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||
last_name: "Каневский",
|
||||
first_name: "Леонид",
|
||||
patronymic: "Семенович",
|
||||
},
|
||||
member: {
|
||||
person: {
|
||||
id: "d340d344-4fc7-4fbe-9db8-b7562b70438d",
|
||||
last_name: "Гаранова",
|
||||
first_name: "Наталья",
|
||||
@@ -877,16 +877,16 @@ export const recordList = [
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "4cd94bec-a0df-4a18-879d-f64cd6d7098e",
|
||||
start: "2023-07-03T13:00:00Z",
|
||||
end: "2023-07-03T14:30:00Z",
|
||||
id: "ccd94bec-a0df-4a18-879d-f64cd6d5698e",
|
||||
start: "2023-09-18T13:00:00Z",
|
||||
end: "2023-09-18T14:30:00Z",
|
||||
employee: {
|
||||
id: "464101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||
last_name: "Каневский",
|
||||
first_name: "Леонид",
|
||||
id: "111101e6-b4e6-46a4-8ef6-08ecb2921493",
|
||||
last_name: "Гурцев",
|
||||
first_name: "Семен",
|
||||
patronymic: "Семенович",
|
||||
},
|
||||
member: {
|
||||
person: {
|
||||
id: "0b2d1db1-6aab-4e29-b857-fc7c9777280f",
|
||||
last_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 = [
|
||||
|
||||
@@ -3,8 +3,8 @@ export function convertTime(str, startIndex, endIndex) {
|
||||
}
|
||||
|
||||
export function trimName(lastName, firstName, patronymic) {
|
||||
let checkedFirstName = firstName !== null ? firstName?.[0] + ". " : "";
|
||||
let checkedPatronymic = patronymic !== null ? patronymic?.[0] + "." : "";
|
||||
let checkedFirstName = firstName ? firstName?.[0] + ". " : "";
|
||||
let checkedPatronymic = patronymic ? patronymic?.[0] + "." : "";
|
||||
return `${lastName} ${checkedFirstName}${checkedPatronymic}`;
|
||||
}
|
||||
|
||||
@@ -13,3 +13,7 @@ export function verifyTime(dayTime) {
|
||||
let newTime = timeArray[1] >= 30 ? timeArray[0] + 1 : timeArray[0];
|
||||
return newTime;
|
||||
}
|
||||
|
||||
export function capitalizeFirstChar(str) {
|
||||
return str[0]?.toUpperCase() + str?.slice(1);
|
||||
}
|
||||
|
||||
@@ -148,7 +148,12 @@ export default {
|
||||
return this.$store.state.medical.documents;
|
||||
},
|
||||
passportFields() {
|
||||
let excludedFields = ["attachments", "id", "category"];
|
||||
let excludedFields = [
|
||||
"attachments",
|
||||
"id",
|
||||
"category",
|
||||
"issued_by_org_code",
|
||||
];
|
||||
return Object.keys(this.docData.passport).filter(
|
||||
(key) => !excludedFields.includes(key)
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ export default createStore({
|
||||
imgUrl: "https://astra-dev.dopcore.com/api/store/",
|
||||
routingHistory: window.history,
|
||||
userData: {},
|
||||
calendarShape: "manager",
|
||||
},
|
||||
modules: {
|
||||
medical,
|
||||
|
||||
@@ -194,8 +194,7 @@ const getters = {
|
||||
series: document?.series || (isPolicy || isPassport ? "" : "000"),
|
||||
number: document?.number || "",
|
||||
issued_by: document?.issued_by || (isPassport ? "" : "000"),
|
||||
issued_by_org_code:
|
||||
document?.issued_by_org_code || (isPassport ? "000-000" : ""),
|
||||
issued_by_org_code: document?.issued_by_org_code || "",
|
||||
issued_at: document?.issued_at || "",
|
||||
attachments: document?.attachments?.length
|
||||
? {
|
||||
|
||||
Reference in New Issue
Block a user