Files
astra-frontend/src/pages/clients/components/ClientsTableRow.vue
2023-01-24 16:45:13 +03:00

808 lines
26 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">
.wrapper.flex.relative
.row-overlay.flex.justify-center.items-center.gap-x-2.text-base(
v-if="rowOverlay",
)
button.recover-btn(@click="stopTimer") Восстановить
.countdown 0:{{ countdown }}
.row-wrapper.flex.flex-col.w-full(:class="closedDetail")
.row-body.flex.w-full.cursor-pointer(
:id="id",
@click="(e) => openDetailInfo(e)",
:class="{'row-overlay-color': rowOverlay}"
)
.dots-wrapper.flex.items-center.px-2
q-btn(
icon="app:icon-dots",
size="12px",
class="dots-button",
@click.stop,
v-if="!isOpenChange && !rowOverlay",
round,
dense,
no-caps,
padding="2px"
)
clients-action-popup(
:open-change-data="openChangeData",
:disabled-delete="!!deletedClientId && !rowOverlay",
@delete-client="transmitDeleteClient",
:create-medical-card="transmitMedicalCard"
)
q-btn(
icon="app:icon-ok",
size="8px",
class="ok-button",
v-if="isOpenChange && !rowOverlay",
@click="closeChangeData",
round,
dense,
no-caps,
padding="4px 3px 2px 3px"
)
//- .check-box.flex.justify-center.items-center(
//- :class="{'row-opacity': rowOverlay}"
//- )
//- clients-table-checkbox(
//- :id="id",
//- :check="check",
//- :is-check="isCheck"
//- )
table-cell-body-name(
:class="{'row-opacity': rowOverlay}"
:value="dataClient",
:avatar="dataClient.avatar",
:avatar-color="dataClient.color",
:photo="dataClient.photo",
:url="url",
:is-open-change="isOpenChange",
:width="columnBody.find(el => el.name === 'fullName').width"
)
table-cell-body-birthday(
v-if="!rowOverlay",
:value="dataClient",
:is-open-change="isOpenChange",
:width="columnBody.find(el => el.name === 'age').width"
)
table-cell-body-priority(
v-if="!rowOverlay",
:value="dataClient",
:choose-priority="choosePriority",
:is-open-change="isOpenChange",
:width="columnBody.find(el => el.name === 'priority').width"
)
table-cell-body-phone(
v-if="!rowOverlay",
:value="dataClient",
:is-open-change="isOpenChange",
:width="columnBody.find(el => el.name === 'phone').width"
)
table-cell-body-email(
v-if="!rowOverlay",
:value="dataClient",
:is-open-change="isOpenChange",
:width="columnBody.find(el => el.name === 'email').width"
)
table-cell-body-networks(
v-if="!rowOverlay",
:delete-network="deleteNetwork",
:add-network="addNetwork",
:networks="dataClient.contacts",
:is-open-change="isOpenChange",
:width="columnBody.find(el => el.name === 'networks').width"
)
client-detail-info-wrapper.detail.px-52px(
:class="{'pb-[30px] pt-4': isOpenDetailInfo}"
:data-address="dataAddress",
:data-attachments="dataAttachments",
:data-document="dataIdentityDocument",
:data-notes="dataNotes"
:save-new-doc="saveNewDoc",
:delete-doc="deleteDoc",
:delete-note="postDeleteNote"
:update-document="postUpdateIdentityDocument",
:update-address="postUpdateAddress",
:update-notes="postUpdateNotes",
:lack-data="lackData",
:lack-address="lackAddress",
:lack-attachments="lackAttachments",
:lack-notes="lackNotes",
:dope-address="dopeAddress",
:create-address="postCreateAddress",
:create-document="postCreateIdentityDocument",
:create-note="postCreateNote",
:address-id="addressId",
:doc-id="docId",
)
</template>
<script>
import TableCellBodyMeeting from "@/pages/clients/components/cells/TableCellBodyMeeting";
import TableCellBodyNetworks from "@/pages/clients/components/cells/TableCellBodyNetworks";
import TableCellBodyEmail from "@/pages/clients/components/cells/TableCellBodyEmail";
import TableCellBodyPhone from "@/pages/clients/components/cells/TableCellBodyPhone";
import TableCellBodyPriority from "@/pages/clients/components/cells/TableCellBodyPriority";
import TableCellBodyJobTitle from "@/pages/clients/components/cells/TableCellBodyJobTitle";
import TableCellBodyBirthday from "@/pages/clients/components/cells/TableCellBodyBirthday";
import TableCellBodyName from "@/pages/clients/components/cells/TableCellBodyName";
import ClientsActionPopup from "@/pages/clients/components/ClientsActionPopup";
import ClientsTableCheckbox from "@/pages/clients/components/ClientsTableCheckbox";
import ClientDetailInfoWrapper from "@/pages/clients/components/ClientDetailInfoWrapper";
import { fetchWrapper } from "@/shared/fetchWrapper";
import { column } from "@/pages/clients/utils/tableConfig";
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
import { addNotification } from "@/components/Notifications/notificationContext";
import * as moment from "moment";
export default {
name: "ClientsTableRow",
components: {
ClientsTableCheckbox,
ClientsActionPopup,
TableCellBodyName,
TableCellBodyBirthday,
TableCellBodyJobTitle,
TableCellBodyPriority,
TableCellBodyPhone,
TableCellBodyEmail,
TableCellBodyNetworks,
TableCellBodyMeeting,
ClientDetailInfoWrapper,
TheNotificationProvider,
},
data() {
return {
dataIdentityDocument: {},
dataAddress: {},
dataAttachments: [
{
initialization: true,
},
],
dataNotes: [
{
initialization: true,
},
],
isOpenDetailInfo: false,
isOpenPopup: false,
columnBody: column,
prioritySettings: column.find((el) => el.name === "priority"),
isOpenChange: false,
dataClient: {},
docId: "",
addressId: "",
lackData: true,
lackAddress: true,
lackAttachments: true,
lackNotes: true,
dopeAddress: {
city: "",
region: "",
street: "",
house: "",
flat: "",
index: "",
},
timer: null,
countdown: 0,
};
},
props: {
id: String,
check: Function,
isCheck: Boolean,
client: Object,
deletedClientId: String,
updateDataClient: Function,
url: String,
fetchDataClients: Function,
createMedicalCard: Function,
fetchCreatedClientData: Function,
createdClientName: String,
},
computed: {
rowOverlay() {
return this.deletedClientId === this.client.id;
},
closedDetail() {
return {
"closed-detail": !this.isOpenDetailInfo,
};
},
},
methods: {
stopTimer() {
if (this.countdown !== 0) this.countdown = 0;
this.$emit("recover-client");
clearInterval(this.timer);
this.timer = null;
},
startTimer() {
this.countdown = 30;
this.timer = setInterval(() => {
this.changeCountdown();
}, 1000);
},
changeCountdown() {
if (this.countdown === 0) {
this.deleteClient().then(() => {
this.updateDataClient();
this.stopTimer();
});
} else {
this.countdown -= 1;
}
},
postUpdateClient() {
let foundElement = this.prioritySettings.settings.find(
(el) => el.text === this.dataClient.priority
);
let data = {};
let clientName = `${this.client.last_name || ""} ${
this.client.first_name || ""
} ${this.client.patronymic || ""}`;
let age = this.dataClient.age
? moment(this.dataClient.age).format("YYYY-MM-DD")
: null;
if (!this.dataClient.fullName) this.dataClient.fullName = clientName;
else if (this.dataClient.fullName !== clientName)
data.full_name = this.dataClient.fullName;
if (age !== this.client.birth_date && age) data.birth_date = age;
else if (!age && this.client.birth_date) {
this.addErrorNotification(
"Некорректная дата рождения",
"Пожалуйста, введите дату рождения корректно"
);
this.dataClient.age = this.client.birth_date
? new Date(this.client.birth_date)
: null;
}
if (foundElement.id !== this.client.priority)
data.priority = foundElement.id;
if (
data.birth_date &&
moment(data.birth_date).isAfter(moment().format("YYYY-MM-DD"))
) {
this.addErrorNotification(
"Некорректная дата рождения",
"Дата рождения позже текущего дня"
);
this.dataClient.age = this.client.birth_date
? new Date(this.client.birth_date)
: null;
} else if (Object.keys(data).length !== 0)
fetchWrapper
.post(`general/person/${this.client.id}/update/`, {
...data,
})
.then(() => {
if (this.createdClientName) this.fetchCreatedClientData;
else this.fetchDataClients();
});
},
postContactsClient() {
let contacts = [...this.dataClient.contacts];
if (
this.dataClient.email.username &&
!contacts.find((el) => el.kind === "EMAIL")
)
contacts.push(this.dataClient.email);
if (
this.dataClient.phone.username &&
this.dataClient.phone.username.length === 18 &&
!contacts.find((el) => el.kind === "PHONE")
)
contacts.push(this.dataClient.phone);
else if (
this.dataClient.phone.username &&
this.dataClient.phone.username.length < 18
) {
this.dataClient.phone.username =
this.client.contacts.find((el) => el.kind === "PHONE")?.username ||
"";
this.addErrorNotification(
"Некорректный номер телефона",
"Введите мобильный номер состоящий из 11 цифр"
);
}
let mapCreateContacts = this.client.contacts.map((el) => el.kind);
let mapDeleteContacts = contacts.map((el) => el.kind);
let createContacts = contacts.filter((el) =>
el.kind === "EMAIL" || el.kind === "PHONE"
? !mapCreateContacts.includes(el.kind)
: el.kind
);
let deleteContacts = this.client.contacts.filter(
(el) => !mapDeleteContacts.includes(el.kind)
);
let updateContacts = [];
this.client.contacts.forEach((el) => {
if (
el.kind === "PHONE" &&
this.dataClient.phone.username.length === 18 &&
el.username !== this.dataClient.phone.username
)
updateContacts.push(this.dataClient.phone);
else if (
el.kind === "PHONE" &&
this.dataClient.phone.username &&
this.dataClient.phone.username.length < 18
) {
this.dataClient.phone.username =
this.client.contacts.find((el) => el.kind === "PHONE")?.username ||
"";
this.addErrorNotification(
"Некорректный номер телефона",
"Введите мобильный номер состоящий из 11 цифр"
);
}
if (
el.kind === "EMAIL" &&
el.username !== this.dataClient.email.username
)
updateContacts.push(this.dataClient.email);
});
createContacts.forEach((el) => {
if (!el.id) this.postCreateContact(el);
});
deleteContacts.forEach((el) => this.postDeleteContact(el));
updateContacts.forEach((el) => this.postUpdateContact(el));
},
postCreateContact(contact) {
fetchWrapper
.post("general/contact/create/", {
kind: contact.kind,
username: contact.username,
person: this.client.id,
})
.then(() => {
if (this.createdClientName) this.fetchCreatedClientData;
else this.fetchDataClients();
});
},
postUpdateContact(contact) {
fetchWrapper
.post(`general/contact/${contact.id}/update/`, {
kind: contact.kind,
username: contact.username,
person: this.client.id,
})
.then(() => {
if (this.createdClientName) this.fetchCreatedClientData;
else this.fetchDataClients();
});
},
postDeleteContact(contact) {
fetchWrapper.del(`general/contact/${contact.id}/delete/`).then(() => {
if (this.createdClientName) this.fetchCreatedClientData;
else this.fetchDataClients();
});
},
addNetwork(network) {
this.dataClient.contacts.push(network);
},
deleteNetwork(e) {
this.dataClient.contacts = this.dataClient.contacts.filter(
(el) => el.kind !== e.target.id
);
},
choosePriority(e) {
this.dataClient.priority = this.columnBody
.find((el) => el.name === "priority")
["settings"].find((el) => el.text === e.target.id).priority;
},
closeChangeData(e) {
e.stopPropagation();
this.isOpenChange = false;
this.postUpdateClient();
this.postContactsClient();
},
openChangeData() {
this.isOpenChange = true;
},
transmitMedicalCard() {
this.$emit(
"handler-click-popup",
"medical",
this.client.id,
this.client?.medical_history[0]?.id
);
},
transmitDeleteClient() {
this.isOpenDetailInfo = false;
this.$emit("handler-click-popup", "delete", this.client.id);
},
async deleteClient() {
await fetchWrapper.del(`general/person/${this.client.id}/delete/`);
this.addSuccessNotification("Клиент успешно удален", "");
this.handleUnFocusPopup();
},
addSuccessNotification(title, message) {
addNotification(new Date().getTime(), title, message, "success", 5000);
},
addErrorNotification(title, message) {
addNotification(title, title, message, "error", 5000);
},
fetchClientDetail(id) {
fetchWrapper.get(`general/person/${id}/detail/`).then((data) => {
this.saveClientDetail(data);
this.saveNote(data);
});
this.fetchAttachment();
},
saveClientDetail(data) {
this.saveIdentityDocument(
data.identity_documents.find(
(el) => el.kind === "Паспорт" || el.kind === "PASSPORT"
)
);
this.saveAddress(data.address[0]);
},
fetchAttachment() {
fetchWrapper
.get("general/attachment/?limit=1000")
.then((data) => this.saveAttachment(data.results));
},
saveAttachment(data) {
this.dataAttachments = data.filter((e) => e.person.id === this.id);
this.lackAttachments = this.dataAttachments[0]?.id ? true : false;
},
saveNote(data) {
this.dataNotes = data?.note.filter((e) => !e.deleted_flg);
if (this.dataNotes[0]) {
this.lackNotes = true;
} else {
this.lackNotes = false;
this.dataNotes = [{ title: "", description: "" }];
}
},
saveIdentityDocument(data) {
if (data?.id) {
this.docId = data.id;
this.dataIdentityDocument = {
number:
data.series && data.number ? data?.series + " " + data?.number : "",
issued_by_org: data.issued_by_org ? data?.issued_by_org : "",
issued_by_org_code: data.issued_by_org_code
? data?.issued_by_org_code
: "",
issued_by_date: data.issued_by_date
? new Date(data?.issued_by_date)
: null,
};
this.lackData = true;
} else {
this.lackData = false;
this.dataIdentityDocument = {
number: "",
issued_by_org: "",
issued_by_org_code: "",
issued_by_date: null,
};
}
},
postUpdateIdentityDocument() {
fetchWrapper
.post(`general/identity_document/${this.docId}/update/`, {
kind: "PASSPORT",
series_number: this.dataIdentityDocument.number,
issued_by_org: this.dataIdentityDocument.issued_by_org,
issued_by_org_code: this.dataIdentityDocument.issued_by_org_code,
issued_by_date: moment(
this.dataIdentityDocument.issued_by_date
).format("YYYY-MM-DD"),
})
.then((response) => {
this.fetchClientDetail(this.id);
if (response.type) {
if (response.errors[0].code === "blank")
this.addErrorNotification(
"Ошибка редактрирования ДУЛ",
"Часть паспортных данных не заполнена"
);
if (response.errors[0].code === "Ошибка редактирования ДУЛ")
this.addErrorNotification(
response.errors[0].code,
response.errors[0].detail
);
if (response?.errors[0].code === "invalid")
this.addErrorNotification(
"Ошибка редактрирования ДУЛ",
"Дата выдачи паспорта не заполнена"
);
} else this.addSuccessNotification("Изменения успешно сохранены", "");
});
},
saveAddress(data) {
this.addressId = data?.id;
if (data?.full_address) {
this.dataAddress = {
full_address: data.full_address,
};
this.lackAddress = true;
} else {
this.lackAddress = false;
this.dataAddress = {
full_address: "",
};
}
},
mergeFullAddress() {
if (
this.dopeAddress.region &&
this.dopeAddress.city &&
this.dopeAddress.street &&
this.dopeAddress.house
) {
return `${this.dopeAddress.index}, ${this.dopeAddress.region} обл., г.${this.dopeAddress.city}, ул.${this.dopeAddress.street}, д.${this.dopeAddress.house}, кв.${this.dopeAddress.flat}`;
}
},
clearAddress() {
this.dopeAddress = {
city: "",
region: "",
street: "",
flat: "",
house: "",
index: "",
};
},
postUpdateAddress() {
fetchWrapper
.post(`general/address/${this.addressId}/update/`, {
full_address:
this.mergeFullAddress() || this.dataAddress.full_address,
})
.then((response) => {
this.fetchClientDetail(this.id);
if (response.type && response.errors[0].code === "blank")
this.addErrorNotification(
"Ошибка именения адреса",
"Полный адрес не заполнен"
);
else this.addSuccessNotification("Изменения успешно сохранены", "");
});
this.clearAddress();
},
openPopup(e) {
e.target.focus();
e.stopPropagation();
this.isOpenPopup = !this.isOpenPopup;
},
openDetailInfo(e) {
if (!this.isOpenDetailInfo)
this.$store.state.currentPatient = this.client;
else this.$store.state.currentPatient = {};
this.isOpenDetailInfo = !this.isOpenDetailInfo;
this.isOpenDetailInfo && this.fetchClientDetail(e.currentTarget.id);
},
handleUnFocusPopup() {
this.isOpenPopup = false;
},
saveNewDoc(data) {
this.dataAttachments = [...data];
const formData = new FormData();
this.dataAttachments.forEach((e) => {
formData.append("person", this.id);
formData.append("document", e);
formData.append("title", e.name.substr(0, e.name.lastIndexOf(".")));
fetchWrapper
.post("general/attachment/create/", formData, "formData")
.then(() => this.fetchClientDetail(this.id));
});
},
deleteDoc(attachmentId) {
fetchWrapper
.del(`general/attachment/${attachmentId}/delete/`)
.then(() => this.fetchClientDetail(this.id));
},
postCreateAddress() {
fetchWrapper
.post("general/address/create/", {
person: this.id,
full_address:
this.mergeFullAddress() || this.dataAddress.full_address,
})
.then((response) => {
this.fetchClientDetail(this.id);
if (response.type && response.errors[0].code === "blank")
this.addErrorNotification(
"Ошибка создания адреса",
"Полный адрес не заполнен"
);
else this.addSuccessNotification("Полный адрес успешно создан", "");
});
},
postCreateIdentityDocument() {
fetchWrapper
.post("general/identity_document/create/", {
person: this.id,
kind: "PASSPORT",
series_number: this.dataIdentityDocument.number,
issued_by_org: this.dataIdentityDocument.issued_by_org,
issued_by_org_code: this.dataIdentityDocument.issued_by_org_code,
issued_by_date: moment(
this.dataIdentityDocument.issued_by_date
).format("YYYY-MM-DD"),
})
.then((response) => {
this.fetchClientDetail(this.id);
if (response.type) {
if (response.errors[0].code === "blank")
this.addErrorNotification(
"Ошибка создания ДУЛ",
"Часть паспортных данных не заполнена"
);
if (response.errors[0].code === "Ошибка создания ДУЛ")
this.addErrorNotification(
response.errors[0].code,
response.errors[0].detail
);
if (response.errors[0].code === "invalid")
this.addErrorNotification(
"Ошибка создания ДУЛ",
"Дата выдачи паспорта не заполнена"
);
} else
this.addSuccessNotification(
"Паспортные данные успешно созданы",
""
);
});
},
postCreateNote(title, description) {
if (!title || !description) {
this.addErrorNotification(
"Ошибка создания дополнительных данных",
"Все поля должны быть заполнены"
);
} else
fetchWrapper
.post("general/note/create/", {
person: this.id,
title: title,
description: description,
})
.then(() => this.fetchClientDetail(this.id));
},
postUpdateNotes() {
this.dataNotes.forEach((e) => {
if (!e.title || !e.description) {
this.addErrorNotification(
"Ошибка изменения дополнительных данных",
"Поля не могут быть пустыми"
);
this.fetchClientDetail(this.id);
} else
fetchWrapper
.post(`general/note/${e.id}/update/`, {
title: e.title,
description: e.description,
})
.then(() => this.fetchClientDetail(this.id));
});
},
postDeleteNote(noteId) {
fetchWrapper
.del(`general/note/${noteId}/delete/`)
.then(() => this.fetchClientDetail(this.id));
},
},
watch: {
rowOverlay() {
if (this.rowOverlay) this.startTimer();
},
client: {
deep: true,
immediate: true,
handler(newValue) {
if (newValue) {
this.dataClient = {
id: this.client.id,
fullName: `${this.client.last_name || ""} ${
this.client.first_name || ""
} ${this.client.patronymic || ""}`,
age: this.client.birth_date
? new Date(this.client.birth_date)
: null,
priority: this.prioritySettings.settings.find(
(el) =>
el.priority === this.client.priority ||
this.client.priority === el.id
).text,
phone: {
id:
this.client.contacts.find((el) => el.kind === "PHONE")?.id ||
"",
kind: "PHONE",
username:
this.client.contacts.find((el) => el.kind === "PHONE")
?.username || "",
},
email: {
id:
this.client.contacts.find((el) => el.kind === "EMAIL")?.id ||
"",
kind: "EMAIL",
username:
this.client.contacts.find((el) => el.kind === "EMAIL")
?.username || "",
},
contacts: this.client.contacts.filter(
(el) =>
!el.deleted_flg && el.kind !== "EMAIL" && el.kind !== "PHONE"
),
avatar: this.client.first_name
? this.client.last_name[0] + this.client.first_name[0]
: this.client.last_name.substr(0, 2),
color: this.client.color,
photo: this.client.photo,
};
}
},
},
},
beforeUnmount() {
if (this.timer) {
this.deleteClient();
this.stopTimer();
}
},
};
</script>
<style lang="sass" scoped>
.row-wrapper
border-bottom: 1px solid var(--border-light-grey-color)
min-width: 1556px
.row-wrapper:hover
background-color: var(--bg-hover-row-table)
.row-body
color: var(--font-dark-blue-color)
min-height: 56px
.check-box
min-width: 36px
.dots
min-width: 14px
.dots-button
color: var(--font-grey-color)
&:hover
background-color: var(--btn-blue-color)
color: var(--default-white)
.ok-button
color: var(--btn-blue-color)
border: 2px solid var(--btn-blue-color)
&:hover
background-color: var(--btn-blue-color)
color: var(--default-white)
&:active
background-color: var(--btn-light-green-color)
color: var(--btn-green-color)
border-color: var(--btn-light-green-color)
.row-opacity
opacity: 0.5
.row-overlay
background: transparent
position: absolute
z-index: 10
width: 100%
height: 100%
.row-overlay-color
background: var(--row-overlay-color)
.recover-btn
color: var(--btn-blue-color)
.countdown
color: var(--font-grey-color )
.detail
max-height: 560px
transition: 0.3s ease all
overflow: hidden
.closed-detail .detail
max-height: 0
.dots-wrapper
width: 53px
</style>