358 lines
11 KiB
Vue
358 lines
11 KiB
Vue
<template lang="pug">
|
|
medical-form-wrapper(
|
|
id="documents",
|
|
title="Документы",
|
|
:is-check-change="isCheckChange",
|
|
:is-edit="isEdit",
|
|
:cancel="cancelEdit",
|
|
:open-edit="openEdit",
|
|
:save="saveChange"
|
|
)
|
|
q-form.form-wrap.gap-x-6.w-full(ref="documentForm", :no-error-focus="true")
|
|
.data-section.flex.flex-col.gap-2(
|
|
v-for="data in configData",
|
|
:key="data.dataLabel",
|
|
:class="data?.dataClass"
|
|
)
|
|
.font-semibold.text-sm.whitespace-nowrap {{data.dataLabel}}
|
|
.flex.w-full.items-center.gap-4(
|
|
v-for="field in data.fields",
|
|
:key="field.label"
|
|
)
|
|
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
|
|
.flex.gap-3.items-center.h-10(v-if="field.type === 'photo'")
|
|
q-avatar(
|
|
rounded,
|
|
size="40px",
|
|
v-if="docData[data.dataKey]?.attachments?.photo"
|
|
)
|
|
img.h-10.w-10.object-cover(
|
|
:src="docData[data.dataKey]?.attachments?.photo",
|
|
:alt="docData[data.dataKey][field.label]"
|
|
)
|
|
q-badge.delete(
|
|
floating,
|
|
v-if="isEdit",
|
|
rounded,
|
|
@click="removeImage(data?.dataKey, field?.key)",
|
|
:style="{padding: 0}"
|
|
)
|
|
q-icon.cancel-icon(name="app:cancel-mini", size="16px")
|
|
.replace-photo.font-medium.text-base.cursor-pointer(
|
|
v-if="isEdit",
|
|
@click="openModal(data.dataKey)",
|
|
) {{ docData[data.dataKey][field.key]?.photo ? "Заменить фото" : "Добавить фото"}}
|
|
base-modal(v-model="showModal", title="Загрузить изображение" v-if="photoId === data.dataKey")
|
|
base-upload-photo(
|
|
v-model="docData[photoId][field.key]",
|
|
:confirm-upload="confirmChangePhoto",
|
|
)
|
|
base-input-date(
|
|
v-if="field.type === 'date'",
|
|
v-model="docData[data.dataKey][field.key]",
|
|
:name="data.dataKey + ':' + field.key",
|
|
@update:model-value="checkChangeDocData",
|
|
:readonly="!isEdit",
|
|
width="100%",
|
|
:mask="field?.inputMask",
|
|
:rule="(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val)",
|
|
size="M",
|
|
)
|
|
base-input(
|
|
v-if="field.type === 'text'",
|
|
v-model="docData[data.dataKey][field.key]",
|
|
:name="data.dataKey + ':' + field.key",
|
|
@update:model-value="checkChangeDocData",
|
|
:readonly="!isEdit",
|
|
:type="field.type",
|
|
width="100%",
|
|
:mask="field?.inputMask",
|
|
:rule="[(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val, initialDocData?.[data.dataKey]?.id)]",
|
|
size="M"
|
|
)
|
|
q-icon.my-auto.cursor-pointer.copy(
|
|
size="20px",
|
|
name="app:copy",
|
|
v-if="checkCopiedFields(field.key) && !!docData[data.dataKey][field.key]",
|
|
@click="copyValue(docData[data.dataKey][field.key])"
|
|
)
|
|
</template>
|
|
|
|
<script>
|
|
import MedicalFormWrapper from "@/pages/newMedicalCard/components/MedicalFormWrapper.vue";
|
|
import { documentForm } from "@/pages/newMedicalCard/utils/medicalConfig";
|
|
import BaseAvatar from "@/components/base/BaseAvatar.vue";
|
|
import BaseModal from "@/components/base/BaseModal.vue";
|
|
import BaseUploadPhoto from "@/components/base/BaseUploadPhoto.vue";
|
|
import {
|
|
checkChangeData,
|
|
getFieldsNameUnvalidated,
|
|
} from "@/shared/utils/changesObjects.js";
|
|
import { fetchWrapper } from "@/shared/fetchWrapper.js";
|
|
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
|
|
import { addNotification } from "@/components/Notifications/notificationContext";
|
|
import BaseInput from "@/components/base/BaseInput.vue";
|
|
import BaseInputDate from "@/components/base/BaseInputDate.vue";
|
|
import { mapActions } from "vuex";
|
|
export default {
|
|
name: "DocumentsForm",
|
|
components: {
|
|
MedicalFormWrapper,
|
|
BaseInput,
|
|
BaseAvatar,
|
|
BaseModal,
|
|
BaseUploadPhoto,
|
|
TheNotificationProvider,
|
|
BaseInputDate,
|
|
},
|
|
data() {
|
|
return {
|
|
configData: documentForm,
|
|
isEdit: false,
|
|
docData: null,
|
|
isCheckChange: false,
|
|
isLoadingData: true,
|
|
copiedFields: [
|
|
"series",
|
|
"number",
|
|
"insurance_number",
|
|
"tax_identification_number",
|
|
],
|
|
initializationData: {
|
|
passport: {
|
|
category: "passport",
|
|
id: null,
|
|
series: null,
|
|
number: null,
|
|
issued_by: null,
|
|
issued_by_org_code: null,
|
|
issued_at: null,
|
|
attachments: null,
|
|
},
|
|
insurance_number: {
|
|
id: null,
|
|
category: "insurance_number",
|
|
number: null,
|
|
attachments: null,
|
|
},
|
|
tax_identification_number: {
|
|
id: null,
|
|
category: "tax_identification_number",
|
|
number: null,
|
|
attachments: null,
|
|
},
|
|
},
|
|
personDataField: [
|
|
"insurance_number:number",
|
|
"tax_identification_number:number",
|
|
],
|
|
showModal: false,
|
|
photoId: "",
|
|
};
|
|
},
|
|
computed: {
|
|
initialDocData() {
|
|
return this.$store.state.medical.documents;
|
|
},
|
|
passportFields() {
|
|
let excludedFields = [
|
|
"attachments",
|
|
"id",
|
|
"category",
|
|
"issued_by_org_code",
|
|
];
|
|
return Object.keys(this.docData.passport).filter(
|
|
(key) => !excludedFields.includes(key)
|
|
);
|
|
},
|
|
},
|
|
methods: {
|
|
checkPassportFields(val, defaultRule) {
|
|
if (
|
|
this.passportFields.every((elem) => !this.docData.passport[elem]) &&
|
|
!this.initialDocData.passport?.id
|
|
) {
|
|
this.$refs.documentForm
|
|
.getValidationComponents()
|
|
.filter((elem) => !this.personDataField.includes(elem.name))
|
|
.forEach((elem) => elem.resetValidation());
|
|
return true;
|
|
}
|
|
return defaultRule(val);
|
|
},
|
|
removeImage(docKey, field) {
|
|
this.docData[docKey][field] = {};
|
|
this.checkChangeDocData();
|
|
},
|
|
copyValue(text) {
|
|
navigator.clipboard.writeText(text);
|
|
},
|
|
checkCopiedFields(key) {
|
|
return !this.isEdit && this.copiedFields.some((elem) => elem === key);
|
|
},
|
|
cancelEdit() {
|
|
this.docData = this.destruct(this.initialDocData);
|
|
this.isEdit = false;
|
|
this.isCheckChange = false;
|
|
this.$refs.documentForm.resetValidation();
|
|
},
|
|
openEdit() {
|
|
this.isEdit = true;
|
|
},
|
|
checkChangeDocData() {
|
|
this.isCheckChange = checkChangeData(
|
|
this.destruct(this.initialDocData),
|
|
this.docData
|
|
);
|
|
},
|
|
openModal(id) {
|
|
this.photoId = id;
|
|
this.showModal = true;
|
|
},
|
|
confirmChangePhoto() {
|
|
this.showModal = false;
|
|
this.isCheckChange = true;
|
|
},
|
|
saveChange() {
|
|
const form = this.$refs.documentForm;
|
|
form.validate().then((validate) => {
|
|
if (!validate) {
|
|
getFieldsNameUnvalidated(form).forEach((elem) => {
|
|
let error = {};
|
|
this.configData.forEach(({ dataKey, fields }) => {
|
|
let findedElem = fields.find(
|
|
(el) => dataKey + ":" + el.key === elem
|
|
);
|
|
if (findedElem) error = findedElem?.errorMessage;
|
|
});
|
|
this.addErrorNotification(error?.title, error?.message);
|
|
});
|
|
} else {
|
|
let request = [];
|
|
Object.keys(this.docData).forEach((elem) => {
|
|
this.checkChangePhoto(elem, "attachments");
|
|
let newData = JSON.parse(JSON.stringify(this.docData[elem]));
|
|
newData.attachments = {};
|
|
if (!checkChangeData(this.initialDocData?.[elem], newData)) return;
|
|
delete newData.id;
|
|
if (newData?.issued_by_org_code) {
|
|
console.log(
|
|
"passport issued_by_org_code",
|
|
newData.issued_by_org_code
|
|
);
|
|
delete newData.issued_by_org_code;
|
|
}
|
|
delete newData.attachments;
|
|
Object.keys(this.docData[elem])?.forEach((key) => {
|
|
if (!this.docData[elem]?.[key]) delete newData?.[key];
|
|
});
|
|
if (!this.initialDocData?.[elem]?.id) {
|
|
newData.person_id =
|
|
this.$store.state.medical?.basicData?.personalData?.id;
|
|
request.push(this.createData("documents/", newData));
|
|
} else {
|
|
request.push(
|
|
this.updateData(
|
|
`documents/${this.initialDocData?.[elem]?.id}`,
|
|
newData
|
|
)
|
|
);
|
|
}
|
|
});
|
|
Promise.allSettled(request).then(() => {
|
|
this.getMedicalDataById(this.$route.params.id);
|
|
this.isEdit = false;
|
|
this.isCheckChange = false;
|
|
this.$refs.form?.resetValidation();
|
|
});
|
|
}
|
|
});
|
|
},
|
|
checkChangePhoto(updatedObjId, field) {
|
|
if (this.docData[updatedObjId][field]?.file)
|
|
console.log(
|
|
updatedObjId,
|
|
field,
|
|
this.docData[updatedObjId][field]?.file[0]
|
|
);
|
|
},
|
|
async createData(url, body) {
|
|
return await fetchWrapper.post(url, body);
|
|
},
|
|
async updateData(url, body) {
|
|
return await fetchWrapper.patch(url, body);
|
|
},
|
|
async deletePhoto(url) {
|
|
return await fetchWrapper.del(url);
|
|
},
|
|
addErrorNotification(title, message) {
|
|
addNotification(title + message, title, message, "error", 5000);
|
|
},
|
|
convertFormat(date) {
|
|
return date ? date.split(".").reverse().join("-") : "";
|
|
},
|
|
...mapActions({
|
|
getMedicalDataById: "getMedicalDataById",
|
|
}),
|
|
destruct(data) {
|
|
const { passport, insurance_number, tax_identification_number } =
|
|
JSON.parse(JSON.stringify(data));
|
|
return {
|
|
passport: passport,
|
|
insurance_number: insurance_number,
|
|
tax_identification_number: tax_identification_number,
|
|
};
|
|
},
|
|
},
|
|
watch: {
|
|
initialDocData: {
|
|
deep: true,
|
|
immediate: true,
|
|
handler(value) {
|
|
if (Object.keys(value).length) this.docData = this.destruct(value);
|
|
else this.docData = this.initializationData;
|
|
},
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
<style lang="sass" scoped>
|
|
.form-wrap
|
|
display: grid
|
|
grid-template-columns: repeat(3, 1fr)
|
|
row-gap: 32px
|
|
grid-template-rows: 1.2fr 1.8fr
|
|
@media(max-width: 1440px)
|
|
grid-template-columns: repeat(2, 1fr)
|
|
grid-template-rows: 1.2fr 1.8fr
|
|
.label-field
|
|
min-width: 110px
|
|
color: var(--font-grey-color)
|
|
.replace-photo
|
|
color: var(--btn-blue-color)
|
|
.photo-field
|
|
min-width: 302px
|
|
.icon-copy .cursor
|
|
cursor: pointer !important
|
|
.icon-cancel :deep(path)
|
|
fill: var(--default-white)
|
|
.q-badge
|
|
padding: 4px
|
|
cursor: pointer
|
|
.delete
|
|
background-color: var(--btn-red-color)
|
|
.cancel-icon :deep(path)
|
|
fill: white
|
|
.copy :deep(path)
|
|
fill: var(--font-grey-color)
|
|
.passport
|
|
grid-column: 1 / 2
|
|
grid-row: 1 / 3
|
|
.insurance
|
|
grid-column: 2 / 3
|
|
grid-row: 1 / 2
|
|
.tax
|
|
grid-column: 2 / 3
|
|
grid-row: 2 / 3
|
|
</style>
|