6 Commits

Author SHA1 Message Date
kandrusyak
4459b5df48 add multiple select 2025-01-31 22:00:04 +03:00
Dmitriy Derbentsov
7e18a794bf Merge branch 'ref-Med-Card' into 'master'
first step

See merge request astra/astra-frontend!514
2023-10-14 16:33:10 +00:00
kandrusyak
564860883e add validation to create event form 2023-10-13 02:34:46 +03:00
Kirill Andrusyak
2b4d04ae3a Merge branch 'move-tax-identification-number' into 'master'
Поправила баги, сдвинула ИНН

See merge request astra/astra-frontend!512
2023-10-09 00:19:41 +00:00
Dmitriy Derbentsov
c0eaad8e76 Merge branch 'dd-1' into 'master'
поиск карт

See merge request astra/astra-frontend!513
2023-10-08 21:26:03 +00:00
Daria Golova
a0b186a8d0 Поправила баги, сдвинула ИНН 2023-10-04 14:03:38 +03:00
12 changed files with 95 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
teleport(:to="appContainer") teleport(:to="appContainer")
.absolute.top-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.wrapper(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")
@@ -41,6 +41,9 @@ export default {
</script> </script>
<style scoped> <style scoped>
.wrapper {
z-index: 10000;
}
.list-enter-active, .list-enter-active,
.list-leave-active { .list-leave-active {
transition: all 0.5s ease; transition: all 0.5s ease;

View File

@@ -2,7 +2,7 @@ import { reactive } from "vue";
export const notifications = reactive({}); export const notifications = reactive({});
export const addNotification = (id, title, message, type, lifeTime = 0) => { export const addNotification = (id, title, message, type, lifeTime = 3000) => {
notifications[id] = { notifications[id] = {
title, title,
message, message,

View File

@@ -23,7 +23,7 @@
:debounce="debounce", :debounce="debounce",
:shadow-text="shadowText", :shadow-text="shadowText",
:autofocus="autofocus", :autofocus="autofocus",
hide-bottom-space hide-bottom-space,
:error="error", :error="error",
@focus="e => $emit('focus', e)" @focus="e => $emit('focus', e)"
) )
@@ -86,6 +86,7 @@ export default {
circle: Boolean, circle: Boolean,
height: String, height: String,
error: Boolean, error: Boolean,
hint: String,
}, },
emits: ["update:modelValue", "focus"], emits: ["update:modelValue", "focus"],
computed: { computed: {

View File

@@ -21,16 +21,25 @@
@filter="filterFn", @filter="filterFn",
:popup-content-style="popupContentStyle" :popup-content-style="popupContentStyle"
@blur="$emit('blur')" @blur="$emit('blur')"
:multiple="multiple"
) )
template(#selected) template(#selected, v-if="!multiple")
slot(name="selected") slot(name="selected")
template(v-slot:option="scope", v-if="!customOption") template(v-slot:option="{itemProps, opt}", v-if="!customOption")
q-item(v-bind="scope.itemProps", style="justify-content: center", v-if="value?.icon") q-item(v-bind="itemProps", style="justify-content: center", v-if="value?.icon")
q-item-section(avatar, style="padding: 0px; min-width: 0px") q-item-section(avatar, style="padding: 0px; min-width: 0px")
q-icon.icon(:name="scope.opt.icon", size="24px") q-icon.icon(:name="opt.icon", size="24px")
q-item.item.px-4.py-2(v-bind="scope.itemProps", style="justify-content: center", v-else) q-item.item.px-4.py-2.multiple(
:class="{ 'selected': value?.length && ~value?.lastIndexOf(opt.value) }"
v-bind="itemProps",
style="justify-content: center",
v-else-if="multiple"
)
q-item-section q-item-section
q-item-label.text-dark.text-base.font-medium {{ scope.opt.label }} q-item-label.text-dark.text-base.font-medium {{ opt.label }}
q-item.item.px-4.py-2(v-bind="itemProps", style="justify-content: center", v-else)
q-item-section
q-item-label.text-dark.text-base.font-medium {{ opt.label }}
template(v-slot:option="{itemProps, opt}", v-else) template(v-slot:option="{itemProps, opt}", v-else)
slot( slot(
name="customOption", name="customOption",
@@ -79,6 +88,7 @@ export default {
customOption: Boolean, customOption: Boolean,
filterFn: Function, filterFn: Function,
popupContentStyle: Object, popupContentStyle: Object,
multiple: Boolean,
}, },
emits: ["update:modelValue", "blur"], emits: ["update:modelValue", "blur"],
computed: { computed: {
@@ -248,8 +258,14 @@ export default {
border-bottom: 1px solid var(--gray-secondary) border-bottom: 1px solid var(--gray-secondary)
&:last-child &:last-child
border-bottom: none border-bottom: none
&.multiple.selected
background-color: var(--gray-thirdly)
.text-dark
color: var(--q-primary) !important
&:hover &:hover
background-color: var(--gray-thirdly) background-color: var(--gray-thirdly)
.q-focus-helper
display: none !important
.q-menu .q-menu
box-shadow: 1px 1px 8px 0px rgba(37, 40, 80, 0.15) !important box-shadow: 1px 1px 8px 0px rgba(37, 40, 80, 0.15) !important

View File

@@ -5,11 +5,28 @@
.text.pt-3.cursor-pointer(@click="gotoCalendar") Расписание приемов .text.pt-3.cursor-pointer(@click="gotoCalendar") Расписание приемов
.text.pt-3.cursor-pointer(@click="gotoMedicalCards") Медицинские карты .text.pt-3.cursor-pointer(@click="gotoMedicalCards") Медицинские карты
base-select(:items="options", v-model="multiple", size="M", multiple)
.res {{multiple}}
</template> </template>
<script> <script>
import BaseSelect from "@/components/base/BaseSelect.vue";
export default { export default {
name: "TheHome", name: "TheHome",
components: {
BaseSelect,
},
data() {
return {
options: ["Google", "Facebook", "Twitter", "Apple", "Oracle"].map(
(e) => ({ label: e, value: e + "v" })
),
multiple: null,
};
},
methods: { methods: {
gotoCalendar() { gotoCalendar() {
this.$router.push("/calendar"); this.$router.push("/calendar");

View File

@@ -3,8 +3,8 @@
header-record-form( header-record-form(
:current-status="currentStatus", :current-status="currentStatus",
:statuses="patientData.statuses", :statuses="patientData.statuses",
:choice-status="choiceStatus" :choice-status="choiceStatus",
v-model="time" v-model="time",
) )
base-input-with-search(v-model="patient", @create-person="createPerson") base-input-with-search(v-model="patient", @create-person="createPerson")
.flex.flex-col.flex-auto.l.gap-y-8 .flex.flex-col.flex-auto.l.gap-y-8
@@ -47,6 +47,8 @@ import { fetchWrapper } from "@/shared/fetchWrapper";
import { mapActions } from "vuex"; import { mapActions } from "vuex";
import PatientCreationForm from "@/components/PatientCreationForm.vue"; import PatientCreationForm from "@/components/PatientCreationForm.vue";
import BaseModal from "@/components/base/BaseModal.vue"; import BaseModal from "@/components/base/BaseModal.vue";
import { addNotification } from "@/components/Notifications/notificationContext";
import { errors } from "@/shared/errors";
export default { export default {
name: "CreateEventForm", name: "CreateEventForm",
@@ -70,6 +72,7 @@ export default {
patientData: patientData, patientData: patientData,
currentStatus: patientData.statuses.find((e) => e.name === "Не принят"), currentStatus: patientData.statuses.find((e) => e.name === "Не принят"),
showCreateModal: false, showCreateModal: false,
errors: {},
}; };
}, },
computed: { computed: {
@@ -106,6 +109,10 @@ export default {
await this.getEvents(); await this.getEvents();
this.closeForm(); this.closeForm();
} }
if (event?.code) {
this.errors = event?.fields;
addNotification(new Date(), "Ошибка", errors[event?.type], "error");
}
}, },
}, },
mounted() {}, mounted() {},

View File

@@ -35,7 +35,7 @@
.flex.gap-x-3.items-center .flex.gap-x-3.items-center
.text.font-semibold Время: .text.font-semibold Время:
.flex.gap-x-1 .flex.gap-x-1
base-input.input.no-border(size="XS", mask="##:## - ##:##", v-model="times" ) base-input.input.no-border(size="XS", mask="##:## - ##:##", v-model="times", :error="!!errors?.['start'] || !!errors?.['end']")
.flex.h-14.gap-x-3.items-center.text-smm .flex.h-14.gap-x-3.items-center.text-smm
.text.font-semibold Медкарта: .text.font-semibold Медкарта:
.flex.gap-x-1 .flex.gap-x-1
@@ -86,7 +86,12 @@ export default {
MedcardModal, MedcardModal,
}, },
mixins: [v_model], mixins: [v_model],
props: { currentStatus: Object, statuses: Array, choiceStatus: Function }, props: {
currentStatus: Object,
statuses: Array,
choiceStatus: Function,
errors: Object,
},
data() { data() {
return { return {
noname, noname,

View File

@@ -8,8 +8,12 @@
:open-edit="openEdit", :open-edit="openEdit",
:save="saveChange" :save="saveChange"
) )
q-form.form-wrap.gap-6.w-full(ref="documentForm", :no-error-focus="true") 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") .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}} .font-semibold.text-sm.whitespace-nowrap {{data.dataLabel}}
.flex.w-full.items-center.gap-4( .flex.w-full.items-center.gap-4(
v-for="field in data.fields", v-for="field in data.fields",
@@ -66,7 +70,9 @@
:rule="[(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val, initialDocData?.[data.dataKey]?.id)]", :rule="[(val) => !personDataField.includes(data.dataKey + ':' + field.key) ? checkPassportFields(val, field.rules) : field.rules(val, initialDocData?.[data.dataKey]?.id)]",
size="M" size="M"
) )
.icon-copy.my-auto.text-lg.label-field.cursor-pointer( q-icon.my-auto.cursor-pointer.copy(
size="20px",
name="app:copy",
v-if="checkCopiedFields(field.key) && !!docData[data.dataKey][field.key]", v-if="checkCopiedFields(field.key) && !!docData[data.dataKey][field.key]",
@click="copyValue(docData[data.dataKey][field.key])" @click="copyValue(docData[data.dataKey][field.key])"
) )
@@ -314,10 +320,11 @@ export default {
.form-wrap .form-wrap
display: grid display: grid
grid-template-columns: repeat(3, 1fr) grid-template-columns: repeat(3, 1fr)
grid-template-rows: repeat(1, 1fr) row-gap: 32px
grid-template-rows: 1.2fr 1.8fr
@media(max-width: 1440px) @media(max-width: 1440px)
grid-template-columns: repeat(2, 1fr) grid-template-columns: repeat(2, 1fr)
grid-template-rows: 3fr 1fr grid-template-rows: 1.2fr 1.8fr
.label-field .label-field
min-width: 110px min-width: 110px
color: var(--font-grey-color) color: var(--font-grey-color)
@@ -336,4 +343,15 @@ export default {
background-color: var(--btn-red-color) background-color: var(--btn-red-color)
.cancel-icon :deep(path) .cancel-icon :deep(path)
fill: white 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> </style>

View File

@@ -18,9 +18,8 @@
:style="{marginTop: field.label === 'Документы' ? '20px' : null}" :style="{marginTop: field.label === 'Документы' ? '20px' : null}"
) )
.label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}} .label-field.font-sm.text-sm.whitespace-nowrap {{`${field.label} :`}}
.flex.gap-3.items-center.h-10.w-10( .flex.gap-3.items-center.h-10(
v-if="field.type === 'photo'", v-if="field.type === 'photo'",
:style="{'min-width': field.label === 'Документы' ? '324px' : '302px'}"
) )
.flex.w-10.h-10.relative(v-if="insuranceData[insurance.insuranceKey]?.attachments?.photo") .flex.w-10.h-10.relative(v-if="insuranceData[insurance.insuranceKey]?.attachments?.photo")
img.rounded.avatar.object-cover( img.rounded.avatar.object-cover(
@@ -90,8 +89,8 @@
:name="insurance.insuranceKey + ':' + field.key", :name="insurance.insuranceKey + ':' + field.key",
:rule="[(val) => checkFields(val, insurance.insuranceKey, field.rules)]" :rule="[(val) => checkFields(val, insurance.insuranceKey, field.rules)]"
) )
q-icon.my-auto.text-lg.label-field.cursor-pointer.copy( q-icon.my-auto.cursor-pointer.copy(
size="18px", size="20px",
name="app:copy", name="app:copy",
v-if="checkCopiedFields(field.key, insuranceData[insurance.insuranceKey])", v-if="checkCopiedFields(field.key, insuranceData[insurance.insuranceKey])",
@click="copyValue(insuranceData[insurance.insuranceKey][field.key])" @click="copyValue(insuranceData[insurance.insuranceKey][field.key])"

View File

@@ -25,6 +25,4 @@ export default {
min-height: 350px min-height: 350px
@media (max-width: 600px) @media (max-width: 600px)
width: fit-content width: fit-content
&::-webkit-scrollbar
width: 0
</style> </style>

View File

@@ -468,6 +468,7 @@ export const documentForm = [
{ {
dataLabel: "Паспорт", dataLabel: "Паспорт",
dataKey: "passport", dataKey: "passport",
dataClass: "passport",
fields: [ fields: [
{ {
key: "series", key: "series",
@@ -532,6 +533,7 @@ export const documentForm = [
{ {
dataLabel: "СНИЛС", dataLabel: "СНИЛС",
dataKey: "insurance_number", dataKey: "insurance_number",
dataClass: "insurance",
fields: [ fields: [
{ {
key: "number", key: "number",
@@ -554,6 +556,7 @@ export const documentForm = [
{ {
dataLabel: "ИНН", dataLabel: "ИНН",
dataKey: "tax_identification_number", dataKey: "tax_identification_number",
dataClass: "tax",
fields: [ fields: [
{ {
key: "number", key: "number",

4
src/shared/errors.js Normal file
View File

@@ -0,0 +1,4 @@
export const errors = {
internal_error: "Внутренняя ошибка",
validation_error: "Ошибка валидации",
};