Files
astra-frontend/src/components/base/BaseClientFormCreate.vue
2023-07-18 17:40:12 +03:00

546 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template lang="pug">
base-modal(v-model="value", hide-overlay, title="Создание клиента", draggable )
.wrapper-create.gap-y-8.flex.flex-col.pt-8
.flex.gap-x-4.h-fit
.flex.gap-x-3.w-full
q-btn(
color="secondary",
text-color="primary",
style="width: 40px; height: 40px",
rounded
no-caps
padding="0 16px"
)
q-icon(
v-if="image === defaultIcon"
name="app:icon-download",
)
q-avatar(
v-else,
size="40px",
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
base-input(
circle,
type="file",
id="image-upload",
accept="image/*",
@change="(e) => previewImage(e)"
)
.avatar.flex.absolute.items-center.gap-x-6
img.avatar.object-cover(for="image-upload", :src="image", v-if="image")
base-button(
width="48px",
@click="closeAddImage",
size="L",
round,
padding="2px 0 0 0"
)
q-icon(name="app:ok", size="20px")
base-input.w-full(
v-model="infoClient.basic.full_name",
placeholder="ФИО*",
size="M"
)
.flex.flex-col.flex-auto.l.gap-y-8
.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",
:add-network="addNewNetwork",
:priority-list="priorityList",
:identity-document="infoClient.identity_document",
:addresses="infoClient.addresses",
:save-file="saveDocFile",
:networks-list="getNetworksList",
)
base-button(label="Создать клиента", width="180px", @click="saveClient")
</template>
<script>
import { column } from "@/pages/clients/utils/tableConfig";
import { fetchWrapper } from "@/shared/fetchWrapper";
import FormCreateBasicInfo from "@/pages/clients/components/FormCreateBasicInfo";
import FormCreateIdentityDocuments from "@/pages/clients/components/FormCreateIdentityDocuments";
import FormCreateAddresses from "@/pages/clients/components/FormCreateAddresses";
import BasePopup from "@/components/base/BasePopup";
import BaseModal from "@/components/base/BaseModal";
import addImageIcon from "@/assets/icons/photo.svg";
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
import { addNotification } from "@/components/Notifications/notificationContext";
import * as moment from "moment";
import { v_model } from "@/shared/mixins/v-model";
import BaseButton from "@/components/base/BaseButton.vue";
import BaseInput from "@/components/base/BaseInput.vue";
export default {
name: "BaseClientFormClient",
components: {
BaseInput,
FormCreateBasicInfo,
FormCreateIdentityDocuments,
FormCreateAddresses,
BasePopup,
BaseModal,
addImageIcon,
TheNotificationProvider,
BaseButton,
},
props: {
setUpdatedClients: Function,
writeCreatedClientId: Function,
},
mixins: [v_model],
data() {
return {
networksSettings: column.find((el) => el.name === "networks")?.settings,
prioritySettings: column.find((el) => el.name === "priority"),
networkId: "",
defaultInfoClient: {
basic: {
full_name: "",
birth_date: null,
priority: {
id: null,
label: "",
},
contacts: [
{
kind: {
id: "TELEGRAM",
icon: "app:icon-tg",
},
username: "",
},
],
},
phone: {
kind: "PHONE",
username: "",
},
email: {
kind: "EMAIL",
username: "",
},
identity_document: {
pass: {
series_number: "",
issued_by_org: "",
issued_by_date: null,
issued_by_org_code: "",
},
snils: {
kind: "СНИЛС",
number: "",
},
inn: {
kind: "ИНН",
number: "",
},
},
addresses: {
full_address: "",
region: "",
city: "",
street: "",
house_number: "",
apartment_number: "",
zip_code: "",
},
additional: [
{
id: "add",
header: "",
description: "",
file: {},
},
],
},
infoClient: {},
forms: [
{
title: "Основное",
id: "basic",
component: "form-create-basic-info",
},
{
title: "ДУЛ",
id: "doc",
component: "form-create-identity-documents",
},
{
title: "Адрес",
id: "address",
component: "form-create-addresses",
},
],
currentForm: "form-create-basic-info",
priorityList: [
{
id: 1,
label: "Высокий",
},
{
id: 2,
label: "Средний",
},
{
id: 3,
label: "Низкий",
},
{
id: 4,
label: "-",
},
],
defaultIcon: addImageIcon,
showModal: false,
showPopup: false,
image: addImageIcon,
imageData: null,
};
},
computed: {
getPriorityList() {
return this.prioritySettings.settings.map((el) => {
return { label: el.text, id: el.id };
});
},
getNetworksList() {
let contacts = [];
this.infoClient.basic.contacts.forEach((elem) =>
contacts.push(elem.kind.id)
);
let filteredNetworks = this.networksSettings.filter(
({ id }) => !contacts.includes(id)
);
return filteredNetworks;
},
},
methods: {
previewImage(event) {
let picture = event.target.files;
let reader = new FileReader();
reader.onload = (e) => {
this.image = e.target.result;
};
reader.readAsDataURL(picture[0]);
this.imageData = [...event.target.files];
},
closeAddImage() {
this.showModal = false;
this.showPopup = false;
},
closePopup() {
this.showPopup = false;
},
async createIdentityDocument(id) {
let doc = null;
let filteredData = Object.keys(
this.filterDataEmptyProperty(this.infoClient.identity_document.pass)
);
if (filteredData.length > 0) {
if (filteredData.length < 4) {
this.addErrorNotification(
"Паспортные данные заполнены не полностью",
"Паспортные данные не будут записаны в профиль клиента"
);
} else if (
moment(this.infoClient.identity_document.pass.issued_by_date).isAfter(
moment().format("YYYY-MM-DD")
)
) {
this.addErrorNotification(
"Некорректная дата выдачи паспорта",
"Паспортные данные не будут записаны в профиль клиента"
);
} else
doc = await fetchWrapper.post("general/identity_document/create/", {
series_number: this.infoClient.identity_document.pass.series_number,
issued_by_org: this.infoClient.identity_document.pass.issued_by_org,
issued_by_date: moment(
this.infoClient.identity_document.pass.issued_by_date
).format("YYYY-MM-DD"),
issued_by_org_code:
this.infoClient.identity_document.pass.issued_by_org_code,
person: id,
kind: "Паспорт",
});
return Promise.resolve(doc);
}
},
createAddress(id) {
let address = null;
Object.keys(this.filterDataEmptyProperty(this.infoClient.addresses))
.length > 0 &&
fetchWrapper
.post("general/address/create/", {
...this.filterDataEmptyProperty(this.infoClient.addresses),
person: id,
})
.then((res) => (address = res));
return Promise.resolve(address);
},
async createContacts(id) {
let phone = null,
email = null,
contacts = [];
if (this.infoClient.phone.username)
phone = await fetchWrapper.post("general/contact/create/", {
...this.filterDataEmptyProperty(this.infoClient.phone),
person: id,
});
if (this.infoClient.email.username)
email = await fetchWrapper.post("general/contact/create/", {
...this.filterDataEmptyProperty(this.infoClient.email),
person: id,
});
for (const network of this.infoClient.basic.contacts) {
if (network.username) {
contacts.push(
await fetchWrapper.post("general/contact/create/", {
kind: network.kind.id,
username: network.username,
person: id,
})
);
}
}
return Promise.allSettled([phone, email, contacts]);
},
postNewClient() {
const formData = new FormData();
formData.append("full_name", this.infoClient.basic.full_name);
if (this.imageData) formData.append("photo", this.imageData[0]);
if (this.infoClient.basic.birth_date)
formData.append(
"birth_date",
moment(this.infoClient.basic.birth_date).format("YYYY-MM-DD")
);
let foundElement = this.prioritySettings.settings.find(
(el) => el.priority === this.infoClient.basic.priority.id
);
if (foundElement.priority)
formData.append("priority", foundElement.priority);
fetchWrapper
.post("general/person/create/", formData, "formData")
.then((result) => {
if (result.id) {
Promise.allSettled([
this.createIdentityDocument(result.id),
this.createAddress(result.id),
this.createContacts(result.id),
]).then(() => {
this.writeCreatedClientId(result.id);
this.setUpdatedClients();
this.addSuccessNotification();
this.value = false;
});
} else {
this.addErrorNotification(
"Клиент не создан",
"Произошла ошибка сервера"
);
}
});
},
filterDataEmptyProperty(data) {
let postData = data;
let keys = Object.keys(postData);
keys.forEach((key) => {
if (!postData[key]) {
delete postData[key];
}
});
return postData;
},
choosePriority(e) {
this.infoClient.basic.priority = e.target.id;
},
saveClient() {
if (this.checkFormFullness()) this.postNewClient();
},
changeOpenModal() {
this.showModal = true;
this.showPopup = false;
},
saveDocFile(e) {
this.infoClient.doc = e.target.files;
},
saveAdditionalFiles(e) {
this.infoClient.additional.find((el) => el.id === e.target.id).file =
e.target.file;
},
addNewAdditionalInfo() {
this.infoClient.additional.push({
id:
this.infoClient.additional[0].id + this.infoClient.additional.length,
header: "",
description: "",
file: {},
});
},
addNewNetwork() {
const newNetwork = this.getNetworksList;
if (newNetwork[0])
this.infoClient.basic.contacts.push({
kind: {
id: newNetwork[0].id,
icon: newNetwork[0].icon,
},
username: "",
});
},
selectForm(componentName) {
this.currentForm = this.forms.find(
(elem) => elem.component === componentName
)?.component;
},
checkFormFullness() {
if (!this.infoClient.basic.full_name) {
this.addErrorNotification(
"Не заполнено ФИО клиента",
"Заполните ФИО клиента"
);
return false;
} else if (
this.infoClient.basic.birth_date &&
moment(this.infoClient.basic.birth_date).isAfter(
moment().format("YYYY-MM-DD")
)
) {
this.addErrorNotification(
"Некорректная дата рождения",
"Дата рождения позже текущего дня"
);
return false;
} else if (
this.infoClient.phone.username &&
this.infoClient.phone.username.length < 18
) {
this.addErrorNotification(
"Некорректный номер телефона",
"Введите мобильный номер, состоящий из 11 цифр"
);
return false;
}
return true;
},
addErrorNotification(title, message) {
addNotification(title, title, message, "error", 5000);
},
addSuccessNotification() {
addNotification(
"Клиент успешно создан",
"Клиент успешно создан",
"",
"success",
5000
);
},
},
watch: {
showModal: function () {
if (this.showModal === false) {
this.closeAddImage();
}
},
value(newValue) {
if (newValue === false)
this.infoClient = JSON.parse(JSON.stringify(this.defaultInfoClient));
},
},
mounted() {
this.infoClient = JSON.parse(JSON.stringify(this.defaultInfoClient));
},
};
</script>
<style lang="sass" scoped>
.wrapper-create
width: 570px
.title
color: var(--font-dark-blue-color)
.export-avatar
min-width: 40px
height: 40px
border-radius: 50%
background-color: var(--bg-btn-icons-color)
color: var(--btn-blue-color)
&:hover
color: var(--default-white)
background-color: var(--btn-blue-color)
.title-info
color: var(--font-grey-color)
border-bottom: 1.5px solid var(--font-grey-color)
&:hover
color: var(--btn-blue-color)
border-bottom: 1.5px solid var(--btn-blue-color)
&.active
color: var(--btn-blue-color)
border-bottom: 1.5px solid var(--btn-blue-color)
.avatar-wrapper
width: 400px
height: 400px
border-radius: 50%
.avatar
height: 100%
border-radius: 50%
.current-avatar
cursor: pointer
height: 100%
border-radius: 50%
background-size: cover
background-repeat: no-repeat
background-position: center
&:hover
display: none
.wrapper-img
background-size: 20px
background-repeat: no-repeat
background-position: center
background-image: url(@/assets/icons/download.svg)
</style>