global rework patient info

This commit is contained in:
dderbentsov
2023-11-02 01:19:05 +03:00
parent 35e8740f04
commit 92b7bd6d01
21 changed files with 562 additions and 109 deletions

View File

@@ -0,0 +1,55 @@
<template lang="pug">
.flex
template(v-if="value")
q-btn(
@click="toggleEditMode",
:style="{backgroundColor: 'var(--bg-light-grey)', color: 'blue'}",
padding="10px",
)
q-icon(
name="edit",
size="20px",
)
template(v-else)
q-btn.mr-2(
@click="save",
:style="{backgroundColor: 'var(--bg-light-grey)', color: 'blue'}",
padding="10px",
)
q-icon(
name="check",
size="20px",
)
q-btn(
@click="cancel",
:style="{backgroundColor: 'var(--bg-light-grey)', color: 'blue'}",
padding="10px",
)
q-icon(
name="cancel",
size="20px",
)
</template>
<script>
import { v_model } from "@/shared/mixins/v-model";
export default {
name: "BaseEditModeSwitcher",
mixins: [v_model],
emits: ["save", "cancel"],
methods: {
toggleEditMode() {
this.value = !this.value;
},
save() {
this.toggleEditMode();
this.$emit("save");
},
cancel() {
this.toggleEditMode();
this.$emit("cancel");
},
},
};
</script>

View File

@@ -0,0 +1,58 @@
<template lang="pug">
.XXX.p-2
template(v-if="!editMode")
template(v-if="value.length")
template(v-for="elem in value", :key="elem.id")
.text-m.pb-1 {{ elem.label }}
.font-medium.text-xl.pb-3 {{ elem.value }}
.flex.flex-col.justify-evenly.items-center.content-center(v-else, style="height:100px")
q-icon(
name="help_outline",
size="40px",
class="icon",
id="empty"
)
.text {{ emptyMessage }}
template(v-else)
template(v-for="elem in value", :key="elem.id")
.text-m.pb-1 {{ elem.label }}
base-input.pb-3(
v-model="elem.value",
size="M",
)
.flex.justify-center
q-btn-dropdown(label="Добавить", icon="add", outline, color="blue-6")
q-list(v-for="option in options", :key="option")
q-item(clickable, v-close-popup, @click="addOption(option)")
q-item-label {{ option }}
</template>
<script>
import BaseInput from "@/components/base/BaseInput.vue";
import { v_model } from "@/shared/mixins/v-model";
export default {
name: "BaseFieldList",
components: { BaseInput },
mixins: [v_model],
props: {
editMode: Boolean,
options: Array,
emptyMessage: String,
},
data() {
return {};
},
methods: {
addOption(option) {
this.value.push({ label: option, value: "" });
},
},
};
</script>
<style lang="sass" scoped>
.XXX
min-height: 100px
</style>

View File

@@ -53,9 +53,14 @@ export default {
...mapActions({
getMedicalCardData: "getMedicalCardDataByPersonId",
createMedicalCard: "createMedicalCard",
getPerson: "GET_PERSON",
}),
openMedicalCard() {
this.$router.push("medical-card/" + this.person["medical_card_id"]);
this.getPerson(this.person.id)
.then(() =>
this.$router.push("medical-card/" + this.person["medical_card_id"])
)
.catch((error) => alert(error));
},
createMedCard() {
this.createMedicalCard({

View File

@@ -1,10 +1,11 @@
<template lang="pug">
.w-full.fit.row.no-wrap.justify-evenly
.col-grow.pr-2
medical-card-patient-form
medical-base-info.mt-2
medical-card-patient-form(:edit-mode="editMode", :need-save="needSave")
medical-card-tabs(v-model="currentMenuItem")
medical-card-general-info(:edit-mode="editMode").mt-2
.h-full
the-right-menu
the-right-menu(v-model:edit-mode="editMode")
</template>
<script>
@@ -16,6 +17,9 @@ import MedicalRemoveModal from "@/pages/newMedicalCard/components/MedicalRemoveM
import { mapState } from "vuex";
import TheRightMenu from "@/components/TheRightMenu.vue";
import MedicalCardPatientForm from "@/pages/newMedicalCard/components/MedicalCardPatientForm.vue";
import MedicalCardTabs from "@/pages/newMedicalCard/components/MedicalCardTabs.vue";
import MedicalCardGeneralInfo from "@/pages/newMedicalCard/tabs/general/MedicalCardGeneralInfo.vue";
export default {
name: "TheMedicalCard",
@@ -27,11 +31,14 @@ export default {
MedicalRemoveModal,
TheRightMenu,
MedicalCardPatientForm,
MedicalCardTabs,
MedicalCardGeneralInfo,
},
data() {
return {
currentMenuItem: "MedicalBaseInfo",
isShownRemoveModal: false,
editMode: false,
};
},
methods: {

View File

@@ -10,8 +10,8 @@
</template>
<script>
import MedicalSidebar from "@/pages/newMedicalCard/components/MedicalSidebar.vue";
import MedicalBasicDataWrapper from "@/pages/newMedicalCard/components/MedicalBasicDataWrapper.vue";
// import MedicalSidebar from "@/pages/newMedicalCard/components/MedicalSidebar.vue";
// import MedicalBasicDataWrapper from "@/pages/newMedicalCard/components/MedicalBasicDataWrapper.vue";
import MedicalAllergiesWrapper from "@/pages/newMedicalCard/components/MedicalAllergiesWrapper.vue";
import MedicalConfidantWrapper from "@/pages/newMedicalCard/components/MedicalConfidantWrapper.vue";
import MedicalHealthStateWrapper from "@/pages/newMedicalCard/components/MedicalHealthStateWrapper.vue";
@@ -20,8 +20,8 @@ import MedicalDentalFormulasWrapper from "@/pages/newMedicalCard/components/Medi
export default {
name: "MedicalBaseInfo",
components: {
MedicalSidebar,
MedicalBasicDataWrapper,
// MedicalSidebar,
// MedicalBasicDataWrapper,
MedicalAllergiesWrapper,
MedicalConfidantWrapper,
MedicalHealthStateWrapper,

View File

@@ -1,30 +0,0 @@
<template lang="pug">
.flex.flex-col.gap-y-2.wrapper.h-full.w-full
basic-data-form
contacts-form
documents-form
insurance-form
</template>
<script>
import BasicDataForm from "@/pages/newMedicalCard/components/BasicDataForms/BasicDataForm.vue";
import DocumentsForm from "@/pages/newMedicalCard/components/BasicDataForms/DocumentsForm.vue";
import InsuranceForm from "@/pages/newMedicalCard/components/BasicDataForms/InsuranceForm.vue";
import ContactsForm from "@/pages/newMedicalCard/components/BasicDataForms/ContactsForm.vue";
export default {
name: "MedicalBasicDataWrapper",
components: { BasicDataForm, DocumentsForm, InsuranceForm, ContactsForm },
};
</script>
<style lang="sass" scoped>
.wrapper
flex: 1
overflow-y: auto
min-width: 560px
min-height: 350px
@media (max-width: 600px)
width: fit-content
&::-webkit-scrollbar
width: 0
</style>

View File

@@ -13,7 +13,8 @@
q-breadcrumbs-el(:label="`Медкарта #${medicalCardData?.number}`")
.mr-4.flex
.text {{ patient?.marks }}
special-marks(:marks="patient?.marks", :edit-mode="editMode")
.ml-6.flex.gap-x-4.col-grow.items-center
q-avatar(size="80px", :style="{'background-color': 'var(--border-light-grey-color)', color: 'var(--font-dark-blue-color)'}")
@@ -32,28 +33,28 @@
.flex-col(v-else)
.flex.gap-x-2
base-input(
v-model="patient.lastName"
v-model="patientEdit.lastName"
size="S",
label="Фамилия"
)
base-input(
v-model="patient.firstName"
v-model="patientEdit.firstName"
size="S",
label="Имя"
)
base-input(
v-model="patient.patronymic"
v-model="patientEdit.patronymic"
size="S",
label="Отчество"
)
.flex.gap-x-2
base-input(
v-model="patient.birthDate"
v-model="patientEdit.birthDate"
size="S",
label="Дата рождения"
)
base-input(
v-model="patient.gender"
v-model="patientEdit.gender"
size="S",
label="Пол"
)
@@ -62,6 +63,7 @@
<script>
import BaseInput from "@/components/base/BaseInput.vue";
import { routesDictionary } from "@/pages/newMedicalCard/utils/medicalConfig.js";
import SpecialMarks from "@/pages/newMedicalCard/components/SpecialMarks.vue";
export default {
name: "MedicalCardPatientForm",
@@ -72,19 +74,17 @@ export default {
return {
routes: routesDictionary,
fullname: "",
patientEdit: {},
patientData: null,
};
},
components: {
BaseInput,
SpecialMarks,
},
computed: {
patient: {
get() {
return this.$store.getters.getPerson;
},
set(value) {
value;
},
patient() {
return this.$store.getters.PERSON;
},
routingHistory() {
return this.$store.state.routingHistory;
@@ -105,6 +105,14 @@ export default {
return `${this.patientData?.last_name[0]}${checkedFirstName}`;
},
},
watch: {
editMode: {
immediate: true,
handler(val) {
val && (this.patientEdit = { ...this.patient });
},
},
},
};
</script>
<style scoped lang="sass">

View File

@@ -0,0 +1,91 @@
<template lang="pug">
template(v-if="!editMode")
.flex(v-for="specialMark in specialMarks")
.flex.special-mark.rounded.mr-2.items-center.justify-center.cursor-pointer(
:style="{'background':specialMark.bgColor}"
)
q-icon(
size="24px",
:name="specialMark.icon",
:color="specialMark.color",
)
q-tooltip(class="bg-blue" :offset="[10, 10]")
.text-m {{ specialMark.description }}
template(v-else)
.flex(v-for="specialMark in editSpecialMarks")
.flex.special-mark.edit-mode.rounded.mr-2.items-center.justify-center.cursor-pointer(
:style="{'background':specialMark.bgColor}"
@click="toggleMark(specialMark.name)"
)
q-icon(
size="24px",
:name="specialMark.icon",
:color="specialMark.color",
)
q-tooltip(class="bg-blue" :offset="[10, 10]")
.text-m {{ specialMark.description }}
</template>
<script>
import { specialMarksIconsConfig } from "@/pages/newMedicalCard/utils/medicalConfig.js";
export default {
name: "SpecialMarks",
props: {
marks: Array,
editMode: Boolean,
},
data() {
return {
editSpecialMarks: [],
};
},
computed: {
specialMarks() {
return this.marks.map(
(el) =>
specialMarksIconsConfig[el] || specialMarksIconsConfig["unknown"]
);
},
},
watch: {
editMode: {
immediate: true,
handler(val) {
if (!val) return;
this.editSpecialMarks = [];
for (let mark in specialMarksIconsConfig) {
if (mark === "unknown") continue;
let t = {
...specialMarksIconsConfig[mark],
name: mark,
};
if (this.marks.indexOf(mark) === -1) {
t.color = "blue-grey-3";
t.bgColor = "#eceff1";
}
this.editSpecialMarks.push({ ...t });
}
},
},
},
methods: {
toggleMark(value) {
alert(value);
},
},
};
</script>
<style lang="sass">
.special-mark
height: 32px
width: 32px
.special-mark.edit-mode
&:hover
border: 2px solid black
</style>

View File

@@ -15,13 +15,7 @@
.flex.w-full.items-center.gap-4(v-for="field in data.fields")
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
.flex.gap-3.items-center.h-10(v-if="field.type === 'avatar'")
base-avatar(:size="40")
img.avatar.object-cover(
v-if="basic[data.dataKey][field.key]?.photo"
:src="basic[data.dataKey][field.key].photo"
alt="AV"
)
span(v-else) {{ avatar }}
.replace-photo.font-medium.text-base.cursor-pointer(v-if="isEdit" @click="showModal = true") Заменить фото
base-modal(v-model="showModal" title="Загрузить изображение")
base-upload-photo(
@@ -64,7 +58,7 @@
<script>
import BaseSelect from "@/components/base/BaseSelect.vue";
import BaseAvatar from "@/components/base/BaseAvatar.vue";
import BaseModal from "@/components/base/BaseModal.vue";
import BaseUploadPhoto from "@/components/base/BaseUploadPhoto.vue";
import MedicalFormWrapper from "@/pages/newMedicalCard/components/MedicalFormWrapper.vue";
@@ -88,7 +82,7 @@ export default {
components: {
MedicalFormWrapper,
BaseInput,
BaseAvatar,
BaseSelect,
BaseModal,
BaseUploadPhoto,
@@ -127,11 +121,11 @@ export default {
updateBasicData() {
const photoFormData = new FormData();
if (
this.basic.personalData.photo.file &&
this.basic.personalData.photo.photo !==
this.initDataBasic.personalData.photo.photo
this.basic.patient.photo.file &&
this.basic.patient.photo.photo !==
this.initDataBasic.patient.photo.photo
) {
photoFormData.append("photo", this.basic.personalData?.photo?.file[0]);
photoFormData.append("photo", this.basic.patient?.photo?.file[0]);
console.log("photo_update");
}
Object.keys(this.basic).map((key) => {
@@ -156,7 +150,7 @@ export default {
if (Object.keys(removeEmptyFields(updateData)).length) {
if (!isInitDataEmpty)
return this.createAddress({
id: this.basic.personalData.id,
id: this.basic.patient.id,
address: updateData,
category: key,
});

View File

@@ -0,0 +1,79 @@
<template lang="pug">
.bg-white.p-4.rounded.fit.row.wrap.justify-start.items-start.content-start
.col-4
template(v-if="!editMode")
template(v-for="contact in contacts")
.font-medium.text-xl.pb-1 {{ contact.category }}
.text-m.pb-3 {{ contact.value }}
template(v-else)
template(v-for="contact in contacts")
base-input(
v-model="x",
size="S",
:label="contact.category"
)
q-icon(
name="add",
size="20px",
class="icon",
id="add"
)
.col
template(v-if="!editMode")
template(v-for="address in addresses")
.font-medium.text-xl.pb-1 {{ address.category }}
.text-m.pb-3 {{ address.full_address }}
template(v-else)
template(v-for="address in addresses")
base-input(
v-model="x",
size="S",
:label="address.category"
)
q-icon(
name="add",
size="20px",
class="icon",
id="add"
)
</template>
<script>
import BaseInput from "@/components/base/BaseInput.vue";
export default {
name: "GeneralInfo",
props: {
editMode: Boolean,
},
components: {
BaseInput,
},
data() {
return {
x: "",
};
},
computed: {
addresses: {
get() {
return this.$store.getters.ADDRESSES;
},
set(value) {
value;
},
},
contacts: {
get() {
return this.$store.getters.CONTACTS;
},
set(value) {
value;
},
},
},
};
</script>
<style lang="sass">
.cont
</style>

View File

@@ -0,0 +1,63 @@
<template lang="pug">
.bg-white.p-4.rounded.fit.row.wrap.justify-start.items-start.content-start
.col-3
base-field-list.mt-2(
:editMode="editMode",
:options="contactInfo.options",
:emptyMessage="contactInfo.emptyMessage",
v-model="contacts"
)
.col-5
base-field-list.mt-2(
:editMode="editMode",
:options="addressInfo.options",
:emptyMessage="addressInfo.emptyMessage",
v-model="addresses"
)
</template>
<script>
import BaseInput from "@/components/base/BaseInput.vue";
import BaseFieldList from "@/components/base/BaseFieldList";
import { contactInformation, addressInformation } from "./generalInfoData";
export default {
name: "GeneralInfo",
props: {
editMode: Boolean,
},
components: {
BaseInput,
BaseFieldList,
},
data() {
return {
x: "",
contactInfo: contactInformation,
addressInfo: addressInformation,
contacts: [
{
id: "1",
label: "E-mail",
value: "dol@yandex.ru",
type: "email",
},
{
id: "2",
label: "Контактный телефон",
value: "+7 910 523 65 98",
type: "phone",
},
],
addresses: [
{
id: "1",
label: "Адрес регистрации",
value: "г.Рязань, ул.Мамина Сибиряка, д.54, кв 78",
type: "input",
},
],
};
},
};
</script>

View File

@@ -0,0 +1,41 @@
<template lang="pug">
.flex.flex-col.gap-y-2.wrapper.h-full.w-full
general-info(:edit-mode="editMode")
//- basic-data-form
//- contacts-form
//- documents-form
//- insurance-form
</template>
<script>
import GeneralInfo from "@/pages/newMedicalCard/tabs/general/GeneralInfo.vue";
import BasicDataForm from "@/pages/newMedicalCard/tabs/general/BasicDataForm.vue";
import DocumentsForm from "@/pages/newMedicalCard/tabs/general/DocumentsForm.vue";
import InsuranceForm from "@/pages/newMedicalCard/tabs/general/InsuranceForm.vue";
import ContactsForm from "@/pages/newMedicalCard/tabs/general/ContactsForm.vue";
export default {
name: "MedicalCardGeneralInfo",
props: {
editMode: Boolean,
},
components: {
BasicDataForm,
DocumentsForm,
InsuranceForm,
ContactsForm,
GeneralInfo,
},
};
</script>
<style lang="sass" scoped>
.wrapper
flex: 1
overflow-y: auto
min-width: 560px
min-height: 350px
@media (max-width: 600px)
width: fit-content
&::-webkit-scrollbar
width: 0
</style>

View File

@@ -0,0 +1,9 @@
export const contactInformation = {
options: ["Email", "Telegram", "Телефон"],
emptyMessage: "Отсутствует контактная информация",
};
export const addressInformation = {
options: ["Адрес регистрации", "Адрес проживания", "Адрес дополнительный"],
emptyMessage: "Отсутствует адрес",
};

View File

@@ -10,49 +10,46 @@ import pdfIcon from "@/assets/icons/pdf.svg";
import wordIcon from "@/assets/icons/word.svg";
import exelIcon from "@/assets/icons/exel.svg";
export const baseDataForm = [
{
dataLabel: "Личные данные",
dataKey: "personalData",
fields: [
{
key: "last_name",
label: "Фамилия",
type: "text",
disabled: true,
},
{
key: "first_name",
label: "Имя",
type: "text",
disabled: true,
},
{
key: "patronymic",
label: "Отчество",
type: "text",
disabled: true,
},
{
key: "gender",
label: "Пол",
type: "select",
disabled: true,
},
{
key: "birth_date",
label: "Дата рождения",
type: "date",
disabled: true,
},
{
key: "photo",
label: "Фото",
type: "avatar",
disabled: true,
},
],
export const specialMarksIconsConfig = {
hard: {
icon: "thumb_down_alt",
color: "amber-2",
bgColor: "#8d6e63",
description: "Конфликтный",
},
debt: {
icon: "paid",
color: "yellow",
bgColor: "green",
description: "Долг",
},
allergic: {
icon: "bolt",
color: "red",
bgColor: "orange",
description: "Аллергик",
},
infected: {
icon: "sick",
color: "light-green-9",
bgColor: "#afb42b",
description: "Опасное заболевание",
},
ban: {
icon: "dangerous",
color: "grey-6",
bgColor: "black",
description: "Не записывать",
},
unknown: {
icon: "help",
color: "grey-6",
bgColor: "#bdbdbd",
description: "Неопознанная метка",
},
};
export const baseDataForm = [
{
dataLabel: "Адрес регистрации",
dataKey: "registrationAddress",

View File

@@ -1,6 +1,7 @@
import { createStore } from "vuex";
import medical from "./modules/medicalCard";
import calendar from "./modules/calendar";
import person from "./modules/person";
export default createStore({
state: {
@@ -13,6 +14,7 @@ export default createStore({
modules: {
medical,
calendar,
person,
},
getters: {
getUrl(state) {

View File

@@ -12,7 +12,7 @@ const state = () => ({
networks: [],
},
basicData: {
personalData: {
patient: {
last_name: null,
first_name: null,
patronymic: null,
@@ -129,7 +129,7 @@ const getters = {
) || {};
let person = state.medicalCard.person;
return {
personalData: {
patient: {
last_name: person?.last_name || "",
first_name: person?.first_name || "",
patronymic: person?.patronymic || "",

View File

@@ -0,0 +1,74 @@
import { fetchWrapper } from "@/shared/fetchWrapper";
const state = () => ({
firstName: "",
lastName: "",
patronymic: "",
birthDate: "",
gender: "",
marks: [],
addresses: [
{
category: "fact",
full_address: "г.Рязань, ул. Новикова-Прибоя, д.43/1, кв.2",
},
{
category: "registration",
full_address: "г.Санкт-Себастьянг, ул. Шоссе Энтузиастов, д.243, кв.4",
},
],
contacts: [
{ category: "email", value: "dol@yandex.ru" },
{ category: "phone", value: "+79586541252" },
],
});
const getters = {
PERSON(state) {
return {
firstName: state.firstName,
lastName: state.lastName,
patronymic: state.patronymic,
birthDate: state.birthDate,
gender: state.gender,
marks: ["hard", "rich", "allergic", "infected", "ban"],
};
},
ADDRESSES(state) {
return state.addresses;
},
CONTACTS(state) {
return state.contacts;
},
};
const actions = {
GET_PERSON({ commit }, id) {
fetchWrapper
.get(`persons/${id}`)
.then((res) => {
commit("SET_PERSON", res);
})
.catch((e) => alert(e));
},
UPDATE_PERSON(context, { obj, id }) {
fetchWrapper.patch(`persons/${id}`, obj);
},
};
const mutations = {
SET_PERSON(state, payload) {
state.firstName = payload.first_name;
state.lastName = payload.last_name;
state.patronymic = payload.patronymic;
state.birthDate = payload.birth_date;
state.gender = payload.gender;
},
};
export default {
state,
getters,
actions,
mutations,
};