Merge branch 'new_modal' into 'master'

New modal

See merge request andrusyakka/urban-couscous!268
This commit is contained in:
Kirill Andrusyak
2023-02-14 15:53:46 +00:00
9 changed files with 296 additions and 223 deletions

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
teleport(:to="appContainer") teleport(:to="appContainer")
.absolute.bottom-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.z-50(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")
@@ -54,7 +54,7 @@ export default {
.list-enter-from, .list-enter-from,
.list-leave-to { .list-leave-to {
opacity: 0; opacity: 0;
transform: translateY(30px); transform: translateY(-30px);
pointer-events: none; pointer-events: none;
} }
</style> </style>

View File

@@ -8,6 +8,7 @@
color="primary", color="primary",
dense, dense,
padding="4px 22px", padding="4px 22px",
@click="openForm"
) )
q-icon( q-icon(
name="app:icon-plus", name="app:icon-plus",
@@ -19,14 +20,11 @@
size="18px", size="18px",
style="margin-left: 4px" style="margin-left: 4px"
) )
q-menu( base-client-form-create(
v-model="isOpenFormInternal", v-model="isOpenFormInternal",
) :set-updated-clients="setUpdatedClients",
base-client-form-create( :write-created-client-id="writeCreatedClientId",
v-model="isOpenFormInternal", )
:set-updated-clients="setUpdatedClients",
:write-created-client-id="writeCreatedClientId",
)
q-btn.mr-8( q-btn.mr-8(
flat, flat,
dense, dense,
@@ -157,8 +155,3 @@ export default {
border-radius: 4px border-radius: 4px
background-color: var(--default-white) background-color: var(--default-white)
</style> </style>
<style lang="sass">
.q-menu
z-index: 40 !important
</style>

View File

@@ -1,99 +1,98 @@
<template lang="pug"> <template lang="pug">
.wrapper-create.flex.flex-col.fixed.right-6.bottom-6.px-8.py-7.gap-y-8 base-modal(v-model="value", hide-overlay, title="Создание клиента", draggable, height="696px" )
.icon-cancel.close.absolute.top-5.right-5.cursor-pointer(@click="closeForm") .wrapper-create.gap-y-8.flex.flex-col.pt-8
span.title.text-xl.font-bold Создание клиента .flex.gap-x-4.h-fit
.flex.gap-x-4.h-fit .flex.gap-x-3.w-full
.flex.gap-x-3.w-full q-btn(
q-btn( color="secondary",
color="secondary", text-color="primary",
text-color="primary", style="width: 40px; height: 40px",
style="width: 40px; height: 40px", rounded
rounded no-caps
no-caps padding="0 16px"
padding="0 16px"
)
q-icon(
v-if="image === defaultIcon"
name="app:icon-download",
) )
q-avatar( q-icon(
v-else, v-if="image === defaultIcon"
size="40px", name="app:icon-download",
round
)
img(:src="image")
q-menu(
anchor="bottom middle",
self="top right",
v-model="showPopup"
)
.flex.flex-col.p-4.gap-y-3
.flex.items-center.gap-x-2.cursor-pointer(@click="changeOpenModal")
q-icon(
name="app:computer",
size="18px",
color="primary"
)
span.text-smm.title Загрузить с компьютера
.flex.items-center.gap-x-2.cursor-pointer
q-icon(
name="app:camera",
size="18px",
color="primary"
)
span.text-smm.title Сделать фото
base-modal(v-model="showModal", title="Загрузить изображение")
.flex.flex-col.items-center.justify-center(
:style="{padding: '153px 370px'}"
) )
.avatar-wrapper.flex.relative q-avatar(
base-input( v-else,
circle, size="40px",
type="file", round
id="image-upload", )
accept="image/*", img(:src="image")
@change="(e) => previewImage(e)" q-menu(
) anchor="bottom middle",
.avatar.flex.absolute.items-center.gap-x-6 self="top right",
img.avatar.object-cover(for="image-upload", :src="image", v-if="image") v-model="showPopup"
q-btn( )
round, .flex.flex-col.p-4.gap-y-3
color="primary", .flex.items-center.gap-x-2.cursor-pointer(@click="changeOpenModal")
@click="closeAddImage", q-icon(
icon="app:icon-ok" name="app:computer",
size="18px",
color="primary"
) )
base-input.w-full(v-model="infoClient.basic.full_name", placeholder="ФИО*", outlined) span.text-smm.title Загрузить с компьютера
.flex.flex-col.flex-auto.l.gap-y-8 .flex.items-center.gap-x-2.cursor-pointer
.flex q-icon(
button.title-info.px-6.py-2.cursor-pointer.w-full.text-sm( name="app:camera",
v-for="form in forms", size="18px",
@click="selectForm(form.component)", color="primary"
:class="{active: form.component === currentForm}", )
:key="form.id", span.text-smm.title Сделать фото
:id="form.id" base-modal(v-model="showModal", title="Загрузить изображение")
) {{form.title}} .flex.flex-col.items-center.justify-center(
component( :style="{padding: '153px 370px'}"
v-bind:is="currentForm", )
:basic-info="infoClient.basic", .avatar-wrapper.flex.relative
:phone="infoClient.phone", base-input(
:email="infoClient.email", circle,
:save-network-id="saveNetworkId", type="file",
:add-network="addNewNetwork", id="image-upload",
:choose-option="chooseOptionNetworks", accept="image/*",
:choose-priority="choosePriority", @change="(e) => previewImage(e)"
:priority-list="priorityList", )
:identity-document="infoClient.identity_document", .avatar.flex.absolute.items-center.gap-x-6
:addresses="infoClient.addresses", img.avatar.object-cover(for="image-upload", :src="image", v-if="image")
:save-file="saveDocFile", q-btn(
) round,
q-btn( color="primary",
label="Создать клиента", @click="closeAddImage",
color="primary", icon="app:icon-ok"
style="height: 40px; width: 180px", )
no-caps, base-input.w-full(v-model="infoClient.basic.full_name", placeholder="ФИО*", outlined)
padding="8px 24px", .flex.flex-col.flex-auto.l.gap-y-8
@click="saveClient", .flex
) button.title-info.px-6.py-2.cursor-pointer.w-full.text-sm(
v-for="form in forms",
@click="selectForm(form.component)",
:class="{active: form.component === currentForm}",
:key="form.id",
:id="form.id"
) {{form.title}}
component(
v-bind:is="currentForm",
:basic-info="infoClient.basic",
:phone="infoClient.phone",
:email="infoClient.email",
:save-network-id="saveNetworkId",
:add-network="addNewNetwork",
:choose-option="chooseOptionNetworks",
:choose-priority="choosePriority",
:priority-list="priorityList",
:identity-document="infoClient.identity_document",
:addresses="infoClient.addresses",
:save-file="saveDocFile",
)
q-btn(
label="Создать клиента",
color="primary",
style="height: 40px; width: 180px",
no-caps,
padding="8px 24px",
@click="saveClient",
)
</template> </template>
<script> <script>
@@ -109,6 +108,7 @@ import addImageIcon from "@/assets/icons/photo.svg";
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider"; import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
import { addNotification } from "@/components/Notifications/notificationContext"; import { addNotification } from "@/components/Notifications/notificationContext";
import * as moment from "moment"; import * as moment from "moment";
import { v_model } from "@/shared/mixins/v-model";
export default { export default {
name: "BaseClientFormClient", name: "BaseClientFormClient",
@@ -122,12 +122,11 @@ export default {
addImageIcon, addImageIcon,
TheNotificationProvider, TheNotificationProvider,
}, },
emits: ["update:model-value"],
props: { props: {
setUpdatedClients: Function, setUpdatedClients: Function,
writeCreatedClientId: Function, writeCreatedClientId: Function,
modelValue: Boolean,
}, },
mixins: [v_model],
data() { data() {
return { return {
networksSettings: column.find((el) => el.name === "networks"), networksSettings: column.find((el) => el.name === "networks"),
@@ -243,9 +242,6 @@ export default {
}, },
}, },
methods: { methods: {
closeForm() {
this.$emit("update:model-value", false);
},
previewImage(event) { previewImage(event) {
let picture = event.target.files; let picture = event.target.files;
let reader = new FileReader(); let reader = new FileReader();
@@ -480,12 +476,7 @@ export default {
<style lang="sass" scoped> <style lang="sass" scoped>
.wrapper-create .wrapper-create
z-index: 5 width: 570px
background-color: var(--default-white)
border-radius: 4px
width: 634px
min-height: 585px
box-shadow: var(--default-shadow)
.title .title
color: var(--font-dark-blue-color) color: var(--font-dark-blue-color)
@@ -534,11 +525,4 @@ export default {
background-repeat: no-repeat background-repeat: no-repeat
background-position: center background-position: center
background-image: url(@/assets/icons/download.svg) background-image: url(@/assets/icons/download.svg)
.modal
max-width: 1220px
max-height: 794px
width: 1220px
height: 794px
background-color: var(--default-white)
</style> </style>

View File

@@ -1,29 +1,117 @@
<template lang="pug"> <template lang="pug">
q-dialog(v-model="value") q-dialog(
.base-content v-model="value"
.base-header @show="onShow",
@hide="onHide",
ref="dialog"
)
.base-content(:class="{'draggable': draggable}", ref="contentRef", :style="{...contentStyles, height}")
q-resize-observer(@resize="onResize")
.base-header(draggable, :class="{'cursor-move': draggable}", ref="headerRef")
.header-title.text {{ title }} .header-title.text {{ title }}
.icon-cancel.text-sm(@click="value = false", v-if="!showIcon") .icon-cancel.text-sm(@click="value = false", v-if="!showCloseIcon")
slot slot
</template> </template>
<script> <script>
import { v_model } from "@/shared/mixins/v-model";
export default { export default {
name: "BaseModal", name: "BaseModal",
mixins: [v_model],
emits: ["show", "hide"],
props: { props: {
title: String, title: String,
modelValue: Boolean, showCloseIcon: Boolean,
showIcon: Boolean, draggable: Boolean,
hideOverlay: Boolean,
height: {
type: String,
},
}, },
emits: ["update:modelValue"], data() {
computed: { return {
value: { contentStyles: {},
get() { };
return this.modelValue; },
}, methods: {
set(value) { onShow() {
this.$emit("update:modelValue", value); if (this.draggable) {
}, this.$refs.headerRef.addEventListener("mousedown", this.onGrab);
}
this.$emit("show");
},
onHide() {
if (this.draggable) {
document.removeEventListener("mousemove", this.onDrag);
document.removeEventListener("mouseup", this.onLetGo);
}
this.$emit("hide");
},
onDrag(e) {
const target = this.$refs.contentRef;
const originalStyles = window.getComputedStyle(target);
const { x, width, y, height } = target.getBoundingClientRect();
if (
x + e.movementX > 10 &&
x + e.movementX + width + 10 <= window.innerWidth
)
this.contentStyles.left =
parseInt(originalStyles.left) + e.movementX + "px";
if (
y + e.movementY > 10 &&
y + e.movementY + height + 10 <= window.innerHeight
)
this.contentStyles.top =
parseInt(originalStyles.top) + e.movementY + "px";
this.contentStyles.bottom = "unset";
this.contentStyles.right = "unset";
},
onLetGo() {
document.removeEventListener("mousemove", this.onDrag);
document.removeEventListener("mouseup", this.onLetGo);
},
onGrab() {
document.addEventListener("mousemove", this.onDrag);
document.addEventListener("mouseup", this.onLetGo);
},
onResize() {
const target = this.$refs.contentRef;
const originalStyles = window.getComputedStyle(target);
const { x, width, y, height } = target.getBoundingClientRect();
if (x < 10) {
const delta = 10 - x;
this.contentStyles.left = parseInt(originalStyles.left) + delta + "px";
}
if (y < 10) {
const delta = 10 - y;
this.contentStyles.top = parseInt(originalStyles.top) + delta + "px";
}
if (x + width + 10 > window.innerWidth) {
const delta = window.innerWidth - (x + width + 10);
this.contentStyles.left = parseInt(originalStyles.left) + delta + "px";
}
if (y + height + 10 > window.innerHeight) {
const delta = window.innerHeight - (y + height + 10);
this.contentStyles.top = parseInt(originalStyles.top) + delta + "px";
}
},
},
updated() {
const backdropEl = this.$refs.dialog?.contentEl?.previousSibling;
if (!backdropEl) return;
if (!this.hideOverlay) {
backdropEl.style.background = "rgba(37, 40, 80, 0.2)";
backdropEl.style.backdropFilter = "blur(4px)";
} else backdropEl.style.background = "rgba(0,0,0,0)";
console.log("123");
},
watch: {
value(val) {
if (val || !this.draggable) return;
this.contentStyles = {};
}, },
}, },
}; };
@@ -45,12 +133,17 @@ export default {
background-color: var(--default-white) background-color: var(--default-white)
box-shadow: 4px 4px 8px rgba(9, 10, 21, 0.1), -4px -4px 8px rgba(9, 10, 21, 0.1) box-shadow: 4px 4px 8px rgba(9, 10, 21, 0.1), -4px -4px 8px rgba(9, 10, 21, 0.1)
border-radius: 4px border-radius: 4px
&.draggable
position: fixed
bottom: 10px
right: 10px
.header-title .header-title
font-weight: 700 font-weight: 700
font-size: 20px font-size: 20px
line-height: 23px line-height: 23px
color: var(--font-dark-blue-color) color: var(--font-dark-blue-color)
user-select: none
.base-header .base-header
display: flex display: flex
justify-content: space-between justify-content: space-between
@@ -62,10 +155,6 @@ export default {
color: var(--font-grey-color) color: var(--font-grey-color)
</style> </style>
<style lang="sass"> <style lang="sass">
.q-dialog__backdrop
background: rgba(37, 40, 80, 0.2) !important
backdrop-filter: blur(4px) !important
@media (min-width: 600px) @media (min-width: 600px)
.q-dialog__inner--minimized > div .q-dialog__inner--minimized > div
max-width: 100vh !important max-width: 100vh !important

View File

@@ -26,7 +26,7 @@
) )
transition(name="form") transition(name="form")
calendar-form-add-event( calendar-form-add-event(
v-if="isOpenForm", v-model="isOpenForm"
:close-form="closeFormCreateEvent", :close-form="closeFormCreateEvent",
:selected-event-data="selectedEvent", :selected-event-data="selectedEvent",
:event-statuses="eventStatuses", :event-statuses="eventStatuses",

View File

@@ -1,76 +1,71 @@
<template lang="pug"> <template lang="pug">
.flex.flex-col.gap-y-6.pt-6.pb-7.px-8.event-form.fixed.right-6.bottom-6( base-modal(v-model="value", :title="!selectedEventData.id ? 'Запись на прием' : 'Изменение записи'", draggable, hide-overlay )
v-click-outside="clearForm" .event-form.flex.flex-col.gap-y-6.pt-8
) .flex.flex-col.gap-y-8
.flex.justify-between base-select(
span.title.text-xl.font-bold {{!selectedEventData.id ? "Запись на прием" : "Изменение записи"}} v-if="selectedEventData.id"
.flex.pt-2 v-model="status",
.icon-cancel.close-icon.tesxt-xs.cursor-pointer(@click="clearForm") :items="eventStatuses",
.flex.flex-col.gap-y-8 label="Статус приема"
base-select( )
v-if="selectedEventData.id" base-input(
v-model="status", v-else,
:items="eventStatuses", disabled,
label="Статус приема" v-model="status.label",
label="Статус приема",
outlined
)
base-select(
:items="ownersList",
v-model="employees.employee",
placeholder="Выберите сотрудника"
label="Сотрудник"
)
base-select(
:items="membersList",
v-model="members.person",
placeholder="Выберите клиента",
label="Клиент"
)
.flex.gap-x-4
base-input(
v-model="eventDate",
label="Дата",
type="date",
outlined
)
.flex.gap-x-2.items-center.justify-between
base-input(
type="time",
v-model="startTime",
label="Начало",
outlined
)
span.mt-4
base-input(
type="time",
v-model="endTime",
label="Конец",
outlined
)
q-btn.create-button(
v-if="!selectedEventData.id",
label="Создать событие",
no-caps,
color="primary",
padding="10px 22px",
:disabled="disabledCreateButton",
@click="sendEventData",
) )
base-input( q-btn.update-button(
v-else, v-else,
disabled, label="Сохранить",
v-model="status.label", no-caps,
label="Статус приема", color="primary",
outlined padding="10px 22px",
:disabled="disabledUpdateButton",
@click="updateEventData",
) )
base-select(
:items="ownersList",
v-model="employees.employee",
placeholder="Выберите сотрудника"
label="Сотрудник"
)
base-select(
:items="membersList",
v-model="members.person",
placeholder="Выберите клиента",
label="Клиент"
)
.flex.gap-x-4
base-input(
v-model="eventDate",
label="Дата",
type="date",
outlined
)
.flex.gap-x-2.items-center.justify-between
base-input(
type="time",
v-model="startTime",
label="Начало",
outlined
)
span.mt-4
base-input(
type="time",
v-model="endTime",
label="Конец",
outlined
)
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> </template>
<script> <script>
@@ -81,14 +76,18 @@ import BaseInput from "@/components/base/BaseInput.vue";
import BaseSelect from "@/components/base/BaseSelect.vue"; import BaseSelect from "@/components/base/BaseSelect.vue";
import * as moment from "moment/moment"; import * as moment from "moment/moment";
import { statusesDictionary } from "../utils/statusesDictionary.js"; import { statusesDictionary } from "../utils/statusesDictionary.js";
import BaseModal from "@/components/base/BaseModal.vue";
import { v_model } from "@/shared/mixins/v-model";
export default { export default {
name: "FormChangeEvent", name: "FormChangeEvent",
components: { components: {
BaseModal,
BaseSelect, BaseSelect,
BaseInput, BaseInput,
TheNotificationProvider, TheNotificationProvider,
}, },
mixins: [v_model],
emits: ["clear-selected-event-data", "close-change-form"], emits: ["clear-selected-event-data", "close-change-form"],
props: { props: {
closeForm: Function, closeForm: Function,
@@ -594,11 +593,7 @@ export default {
<style lang="sass" scoped> <style lang="sass" scoped>
.event-form .event-form
width: 634px width: 550px
background-color: var(--default-white)
box-shadow: var(--default-shadow)
border-radius: 4px
z-index: 5
.form-item .form-item
border-radius: 4px border-radius: 4px

View File

@@ -52,7 +52,7 @@
) )
base-modal( base-modal(
v-model="showModal", v-model="showModal",
:showIcon="isOpenAddDoc" :showCloseIcon="isOpenAddDoc"
) )
table-adding-new-doc( table-adding-new-doc(
v-if="isOpenAddDoc", v-if="isOpenAddDoc",

View File

@@ -50,7 +50,7 @@
//- ) //- )
base-modal( base-modal(
v-model="showModal", v-model="showModal",
:title="titleModal", :title="titleModal"
) )
client-table-modal( client-table-modal(
v-for="modal in modalConfig" v-for="modal in modalConfig"
@@ -68,7 +68,6 @@ import ClientsTableHeader from "@/pages/clients/components/ClientsTableHeader";
import ClientsTableHat from "@/pages/clients/components/ClientsTableHat"; import ClientsTableHat from "@/pages/clients/components/ClientsTableHat";
import ClientsTableRow from "@/pages/clients/components/ClientsTableRow"; import ClientsTableRow from "@/pages/clients/components/ClientsTableRow";
import ClientsTableCheckbox from "@/pages/clients/components/ClientsTableCheckbox"; import ClientsTableCheckbox from "@/pages/clients/components/ClientsTableCheckbox";
import BaseClientFormCreate from "@/components/base/BaseClientFormCreate";
import ClientTablePagination from "./ClientTablePagination.vue"; import ClientTablePagination from "./ClientTablePagination.vue";
import BaseModal from "@/components/base/BaseModal.vue"; import BaseModal from "@/components/base/BaseModal.vue";
import ClientTableModal from "./ClientTableModal.vue"; import ClientTableModal from "./ClientTableModal.vue";
@@ -82,7 +81,6 @@ export default {
ClientsTableRow, ClientsTableRow,
ClientsTableHat, ClientsTableHat,
ClientsTableHeader, ClientsTableHeader,
BaseClientFormCreate,
ClientTablePagination, ClientTablePagination,
BaseModal, BaseModal,
ClientTableModal, ClientTableModal,

View File

@@ -0,0 +1,14 @@
export const v_model = {
props: ["modelValue"],
emits: ["update:modelValue"],
computed: {
value: {
get() {
return this.modelValue;
},
set(val) {
this.$emit("update:modelValue", val);
},
},
},
};